//+------------------------------------------------------------------+
//|                                                         Base.mqh |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd." 
#property link      "https://www.mql5.com"

//+------------------------------------------------------------------+
//| Include libraries                                                |
//+------------------------------------------------------------------+
#include <Canvas\Canvas.mqh>              // CCanvas SL class
#include <Arrays\List.mqh>                // CList SL class
#include "..\Tables.mqh"

//--- Forward declaration of control element classes
class    CBoundedObj;                     // Base class storing object dimensions
class    CCanvasBase;                     // Base class of graphical elements canvas
class    CCounter;                        // Delay counter class
class    CAutoRepeat;                     // Event auto-repeat class
class    CImagePainter;                   // Image drawing class
class    CVisualHint;                     // Hint class
class    CLabel;                          // Text label class
class    CButton;                         // Simple button class
class    CButtonTriggered;                // Two-position button class
class    CButtonArrowUp;                  // Up arrow button class
class    CButtonArrowDown;                // Down arrow button class
class    CButtonArrowLeft;                // Left arrow button class
class    CButtonArrowRight;               // Right arrow button class
class    CCheckBox;                       // CheckBox control class
class    CRadioButton;                    // RadioButton control class
class    CScrollBarThumbH;                // Horizontal scrollbar slider class
class    CScrollBarThumbV;                // Vertical scrollbar slider class
class    CScrollBarH;                     // Horizontal scrollbar class
class    CScrollBarV;                     // Vertical scrollbar class
class    CTableCellView;                  // Class for visual representation of a table cell
class    CTableRowView;                   // Class for visual representation of a table row
class    CCaptionView;                    // Class for visual representation of a table header
class    CColumnCaptionView;              // Class for visual representation of table column header
class    CRowCaptionView;                 // Class for visual representation of table column header
class    CTableHeaderView;                // Class for visual representation of a table header
class    CTableRowsHeaderView;            // Class for visual representation of table column header
class    CTableView;                      // Class for visual representation of a table
class    CTableControl;                   // Table management class
class    CPanel;                          // Panel control class
class    CGroupBox;                       // GroupBox control class
class    CContainer;                      // Container control class

//+------------------------------------------------------------------+
//| Macro substitutions                                              |
//+------------------------------------------------------------------+
#define  clrNULL              0x00FFFFFF  // Transparent color for CCanvas
#ifndef  __TABLES__
#define  MARKER_START_DATA    -1          // Data start marker in a file</s2>
<100/100/65% Or
#endif 
#define  DEF_FONTNAME         "Calibri"   // Default font
#define  DEF_FONTSIZE         10          // Default font size
#define  DEF_EDGE_THICKNESS   3           // Zone width to capture the border/corner

//+------------------------------------------------------------------+
//| Enumerations                                                     |
//+------------------------------------------------------------------+
enum ENUM_ELEMENT_TYPE                    // Enumeration of graphical element type
  {
   ELEMENT_TYPE_BASE = 0x10000,           // Basic object of graphical elements
   ELEMENT_TYPE_COLOR,                    // Color object
   ELEMENT_TYPE_COLORS_ELEMENT,           // Color object of the graphical object element
   ELEMENT_TYPE_RECTANGLE_AREA,           // Rectangular area of the element
   ELEMENT_TYPE_IMAGE_PAINTER,            // Object for drawing images
   ELEMENT_TYPE_COUNTER,                  // Counter object
   ELEMENT_TYPE_AUTOREPEAT_CONTROL,       // Event auto-repeat object
   ELEMENT_TYPE_BOUNDED_BASE,             // Basic object of graphical element sizes
   ELEMENT_TYPE_CANVAS_BASE,              // Basic canvas object for graphical elements
   ELEMENT_TYPE_ELEMENT_BASE,             // Basic object of graphical elements
   ELEMENT_TYPE_HINT,                     // Hint
   ELEMENT_TYPE_LABEL,                    // Text label
   ELEMENT_TYPE_BUTTON,                   // Simple button
   ELEMENT_TYPE_BUTTON_TRIGGERED,         // Two-position button
   ELEMENT_TYPE_BUTTON_ARROW_UP,          // Up arrow button
   ELEMENT_TYPE_BUTTON_ARROW_DOWN,        // Down arrow button
   ELEMENT_TYPE_BUTTON_ARROW_LEFT,        // Left arrow button
   ELEMENT_TYPE_BUTTON_ARROW_RIGHT,       // Right arrow button
   ELEMENT_TYPE_CHECKBOX,                 // CheckBox control
   ELEMENT_TYPE_RADIOBUTTON,              // RadioButton control
   ELEMENT_TYPE_SCROLLBAR_THUMB_H,        // Horizontal scroll bar slider
   ELEMENT_TYPE_SCROLLBAR_THUMB_V,        // Vertical scroll bar slider
   ELEMENT_TYPE_SCROLLBAR_H,              // ScrollBarHorisontal control
   ELEMENT_TYPE_SCROLLBAR_V,              // ScrollBarVertical control
   ELEMENT_TYPE_TABLE_CELL_VIEW,          // Table cell (View)
   ELEMENT_TYPE_TABLE_ROW_VIEW,           // Table row (View)
   ELEMENT_TYPE_TABLE_CAPTION_VIEW,       // Basic header object (View)
   ELEMENT_TYPE_TABLE_COLUMN_CAPTION_VIEW,// Table column header (View)
   ELEMENT_TYPE_TABLE_ROW_CAPTION_VIEW,   // Table row header (View)
   ELEMENT_TYPE_TABLE_HEADER_VIEW,        // Table header (View)
   ELEMENT_TYPE_TABLE_ROWS_HEADER_VIEW,   // Table row header (View)
   ELEMENT_TYPE_TABLE_VIEW,               // Table (View)
   ELEMENT_TYPE_TABLE_CONTROL_VIEW,       // Table control (View)
   ELEMENT_TYPE_PANEL,                    // Panel control
   ELEMENT_TYPE_GROUPBOX,                 // GroupBox control
   ELEMENT_TYPE_CONTAINER,                // Container control
  };
#define  ACTIVE_ELEMENT_MIN   ELEMENT_TYPE_LABEL               // Minimum value of the list of active elements
#define  ACTIVE_ELEMENT_MAX   ELEMENT_TYPE_TABLE_HEADER_VIEW   // Maximum value of the list of active elements

enum ENUM_ELEMENT_STATE                   // Control state
  {
   ELEMENT_STATE_DEF,                     // By default (e.g. button released etc.)
   ELEMENT_STATE_ACT,                     // Activated (e.g. button pressed, etc.)
  };

enum ENUM_COLOR_STATE                     // Enumeration of element state colors
  {
   COLOR_STATE_DEFAULT,                   // Normal state color
   COLOR_STATE_FOCUSED,                   // Color when hovering over an element
   COLOR_STATE_PRESSED,                   // Color when clicking on an element
   COLOR_STATE_BLOCKED,                   // Blocked element color
  };
  
enum ENUM_BASE_COMPARE_BY                 // Compared properties of base objects
  {
   BASE_SORT_BY_ID   =  0,                // Compare base objects by ID
   BASE_SORT_BY_NAME,                     // Compare base objects by name
   BASE_SORT_BY_X,                        // Compare base objects by X coordinate
   BASE_SORT_BY_Y,                        // Compare base objects by Y coordinate
   BASE_SORT_BY_WIDTH,                    // Compare base objects by width
   BASE_SORT_BY_HEIGHT,                   // Compare base objects by height
   BASE_SORT_BY_ZORDER,                   // Compare by objects' Z-order
  };
  
enum ENUM_CURSOR_REGION                   // Enumerate the cursor location on the element borders
  {
   CURSOR_REGION_NONE,                    // None
   CURSOR_REGION_TOP,                     // On the top border
   CURSOR_REGION_BOTTOM,                  // On the bottom border
   CURSOR_REGION_LEFT,                    // On the left border
   CURSOR_REGION_RIGHT,                   // On the right border
   CURSOR_REGION_LEFT_TOP,                // In the upper left corner
   CURSOR_REGION_LEFT_BOTTOM,             // In the lower left corner
   CURSOR_REGION_RIGHT_TOP,               // In the upper right corner
   CURSOR_REGION_RIGHT_BOTTOM,            // In the lower right corner
  };
  
enum ENUM_RESIZE_ZONE_ACTION              // List interactions with the element dragging zone
  {
   RESIZE_ZONE_ACTION_NONE,               // None
   RESIZE_ZONE_ACTION_HOVER,              // Hovering the cursor over the zone
   RESIZE_ZONE_ACTION_BEGIN,              // Start dragging
   RESIZE_ZONE_ACTION_DRAG,               // Dragging
   RESIZE_ZONE_ACTION_END                 // Finish dragging
  };  
  
//+------------------------------------------------------------------+ 
//| Functions                                                        |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|  Return the element type as a string                             |
//+------------------------------------------------------------------+
string ElementDescription(const ENUM_ELEMENT_TYPE type)
  {
   string array[];
   int total=StringSplit(EnumToString(type),StringGetCharacter("_",0),array);
   if(array[array.Size()-1]=="V")
      array[array.Size()-1]="Vertical";
   if(array[array.Size()-1]=="H")
      array[array.Size()-1]="Horisontal";
      
   string result="";
   for(int i=2;i<total;i++)
     {
      array[i]+=" ";
      array[i].Lower();
      array[i].SetChar(0,ushort(array[i].GetChar(0)-0x20));
      result+=array[i];
     }
   result.TrimLeft();
   result.TrimRight();
   return result;
  }
//+------------------------------------------------------------------+
//|  Return the short name of the element by type                    |
//+------------------------------------------------------------------+
string ElementShortName(const ENUM_ELEMENT_TYPE type)
  {
   switch(type)
     {
      case ELEMENT_TYPE_ELEMENT_BASE               :  return "BASE";    // Basic object of graphical elements
      case ELEMENT_TYPE_HINT                       :  return "HNT";     // Hint
      case ELEMENT_TYPE_LABEL                      :  return "LBL";     // Text label
      case ELEMENT_TYPE_BUTTON                     :  return "SBTN";    // Simple button
      case ELEMENT_TYPE_BUTTON_TRIGGERED           :  return "TBTN";    // Toggle button
      case ELEMENT_TYPE_BUTTON_ARROW_UP            :  return "BTARU";   // Up arrow button
      case ELEMENT_TYPE_BUTTON_ARROW_DOWN          :  return "BTARD";   // Down arrow button
      case ELEMENT_TYPE_BUTTON_ARROW_LEFT          :  return "BTARL";   // Left arrow button
      case ELEMENT_TYPE_BUTTON_ARROW_RIGHT         :  return "BTARR";   // Right arrow button
      case ELEMENT_TYPE_CHECKBOX                   :  return "CHKB";    // CheckBox control
      case ELEMENT_TYPE_RADIOBUTTON                :  return "RBTN";    // RadioButton control
      case ELEMENT_TYPE_SCROLLBAR_THUMB_H          :  return "THMBH";   // Horizontal scroll bar slider
      case ELEMENT_TYPE_SCROLLBAR_THUMB_V          :  return "THMBV";   // Vertical scroll bar slider
      case ELEMENT_TYPE_SCROLLBAR_H                :  return "SCBH";    // ScrollBarHorisontal control
      case ELEMENT_TYPE_SCROLLBAR_V                :  return "SCBV";    // ScrollBarVertical control
      case ELEMENT_TYPE_TABLE_CELL_VIEW            :  return "TCELL";   // Table cell (View)
      case ELEMENT_TYPE_TABLE_ROW_VIEW             :  return "TROW";    // Table row (View)
      case ELEMENT_TYPE_TABLE_CAPTION_VIEW         :  return "TCAPT";   // Basic header object (View)
      case ELEMENT_TYPE_TABLE_COLUMN_CAPTION_VIEW  :  return "TCCAPT";  // Table column header (View)
      case ELEMENT_TYPE_TABLE_ROW_CAPTION_VIEW     :  return "TRCAPT";  // Table column header (View)
      case ELEMENT_TYPE_TABLE_HEADER_VIEW          :  return "TCHDR";   // Table header (View)
      case ELEMENT_TYPE_TABLE_ROWS_HEADER_VIEW     :  return "TRHDR";   // Table column header (View)
      case ELEMENT_TYPE_TABLE_VIEW                 :  return "TABLE";   // Table (View)
      case ELEMENT_TYPE_TABLE_CONTROL_VIEW         :  return "TBLCTRL"; // Table control (View)
      case ELEMENT_TYPE_PANEL                      :  return "PNL";     // Panel control
      case ELEMENT_TYPE_GROUPBOX                   :  return "GRBX";    // GroupBox control
      case ELEMENT_TYPE_CONTAINER                  :  return "CNTR";    // Container control
      default                                      :  return "Unknown"; // Unknown
     }
  }
//+------------------------------------------------------------------+
//| Return the array of element hierarchy names                      |
//+------------------------------------------------------------------+
int GetElementNames(string value, string sep, string &array[])
  {
   if(value=="" || value==NULL)
     {
      PrintFormat("%s: Error. Empty string passed");
      return 0;
     }
   ResetLastError();
   int res=StringSplit(value, StringGetCharacter(sep,0),array);
   if(res==WRONG_VALUE)
     {
      PrintFormat("%s: StringSplit() failed. Error %d",__FUNCTION__, GetLastError());
      return WRONG_VALUE;
     }
   return res;
  }
//+------------------------------------------------------------------+
//| Classes                                                          |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Singleton class for common flags and events of graphical element |
//+------------------------------------------------------------------+
class CCommonManager
  {
private:
   static CCommonManager *m_instance;                          // Class instance
   string            m_element_name;                           // Active element name
   int               m_cursor_x;                               // X cursor coordinate
   int               m_cursor_y;                               // Y cursor coordinate
   bool              m_resize_mode;                            // Resize mode
   ENUM_CURSOR_REGION m_resize_region;                         // The edge of the element where the size is changed
   
//--- Constructor/destructor
                     CCommonManager(void) : m_element_name("") {}
                    ~CCommonManager() {}
public:
//--- Method for getting a Singleton instance
   static CCommonManager *GetInstance(void)
                       {
                        if(m_instance==NULL)
                           m_instance=new CCommonManager();
                        return m_instance;
                       }
//--- Method for destroying a Singleton instance
   static void       DestroyInstance(void)
                       {
                        if(m_instance!=NULL)
                          {
                           delete m_instance;
                           m_instance=NULL;
                          }
                       }
//--- (1) Set and (2) return the name of the active current element
   void              SetElementName(const string name)            { this.m_element_name=name;   }
   string            ElementName(void)                      const { return this.m_element_name; }
   
//--- (1) Set and (2) return the X cursor coordinate
   void              SetCursorX(const int x)                      { this.m_cursor_x=x;          }
   int               CursorX(void)                          const { return this.m_cursor_x;     }
   
//--- (1) Set and (2) return the Y cursor coordinate
   void              SetCursorY(const int y)                      { this.m_cursor_y=y;          }
   int               CursorY(void)                          const { return this.m_cursor_y;     }
   
//--- (1) Set and return (2) the resizing mode
   void              SetResizeMode(const bool flag)               { this.m_resize_mode=flag;    }
   bool              ResizeMode(void)                       const { return this.m_resize_mode;  }
   
//--- (1) Set and (2) return the element edge
   void              SetResizeRegion(const ENUM_CURSOR_REGION edge){ this.m_resize_region=edge; }
   ENUM_CURSOR_REGION ResizeRegion(void)                    const { return this.m_resize_region;}

  };
//--- Initialize a static instance variable of a class
CCommonManager* CCommonManager::m_instance=NULL;
//+------------------------------------------------------------------+
//| Base class of graphical elements                                 |
//+------------------------------------------------------------------+
class CBaseObj : public CObject
  {
protected:
   int               m_id;                                     // ID
   ushort            m_name[];                                 // Name
   
public:
//--- Set (1) name and (2) ID
   void              SetName(const string name)                { ::StringToShortArray(name,this.m_name);          }
   virtual void      SetID(const int id)                       { this.m_id=id;                                    }
//--- Return (1) name and (2) ID
   string            Name(void)                          const { return ::ShortArrayToString(this.m_name);        }
   int               ID(void)                            const { return this.m_id;                                }

//--- Return the cursor coordinates
   int               CursorX(void)                       const { return CCommonManager::GetInstance().CursorX();  }
   int               CursorY(void)                       const { return CCommonManager::GetInstance().CursorY();  }

//--- Virtual methods of (1) comparing, (2) saving to file, (3) loading from file, (4) object type
   virtual int       Compare(const CObject *node,const int mode=0) const;
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);
   virtual int       Type(void)                          const { return(ELEMENT_TYPE_BASE); }
   
//--- (1) Return and (2) display the object description in the journal
   virtual string    Description(void);
   virtual void      Print(void);
   
//--- Constructor/destructor
                     CBaseObj (void) : m_id(-1) { this.SetName(""); }
                    ~CBaseObj (void) {}
  };
//+------------------------------------------------------------------+
//| CBaseObj::Compare two object                                     |
//+------------------------------------------------------------------+
int CBaseObj::Compare(const CObject *node,const int mode=0) const
  {
   if(node==NULL)
      return -1;
   const CBaseObj *obj=node;
   switch(mode)
     {
      case 0   :  return(this.ID()  >obj.ID()   ? 1 : this.ID()  <obj.ID()   ? -1 : 0);
      default  :  return(this.Name()>obj.Name() ? 1 : this.Name()<obj.Name() ? -1 : 0);
     }
  }
//+------------------------------------------------------------------+
//| CBaseObj::Return the object description                          |
//+------------------------------------------------------------------+
string CBaseObj::Description(void)
  {
   string nm=this.Name();
   string name=(nm!="" ? ::StringFormat(" \"%s\"",nm) : nm);
   return ::StringFormat("%s%s ID %d",ElementDescription((ENUM_ELEMENT_TYPE)this.Type()),name,this.ID());
  }
//+------------------------------------------------------------------+
//| CBaseObj::Display the object description in the journal          |
//+------------------------------------------------------------------+
void CBaseObj::Print(void)
  {
   ::Print(this.Description());
  }
//+------------------------------------------------------------------+
//| CBaseObj::Save to file                                           |
//+------------------------------------------------------------------+
bool CBaseObj::Save(const int file_handle)
  {
//--- Check the handle
   if(file_handle==INVALID_HANDLE)
      return false;
//--- Save data start marker - 0xFFFFFFFFFFFFFFFF
   if(::FileWriteLong(file_handle,-1)!=sizeof(long))
      return false;
//--- Save the object type
   if(::FileWriteInteger(file_handle,this.Type(),INT_VALUE)!=INT_VALUE)
      return false;

//--- Save the ID
   if(::FileWriteInteger(file_handle,this.m_id,INT_VALUE)!=INT_VALUE)
      return false;
//--- Save the name
   if(::FileWriteArray(file_handle,this.m_name)!=sizeof(this.m_name))
      return false;
   
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//| CBaseObj::Load from file                                         |
//+------------------------------------------------------------------+
bool CBaseObj::Load(const int file_handle)
  {
//--- Check the handle
   if(file_handle==INVALID_HANDLE)
      return false;
//--- Load and check the data start marker - 0xFFFFFFFFFFFFFFFF
   if(::FileReadLong(file_handle)!=-1)
      return false;
//--- Load the object type
   if(::FileReadInteger(file_handle,INT_VALUE)!=this.Type())
      return false;

//--- Load the ID
   this.m_id=::FileReadInteger(file_handle,INT_VALUE);
//--- Load the name
   if(::FileReadArray(file_handle,this.m_name)!=sizeof(this.m_name))
      return false;
   
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Color class                                                      |
//+------------------------------------------------------------------+
class CColor : public CBaseObj
  {
protected:
   color             m_color;                                  // Color
   
public:
//--- Set color
   bool              SetColor(const color clr)
                       {
                        if(this.m_color==clr)
                           return false;
                        this.m_color=clr;
                        return true;
                       }
//--- Return color
   color             Get(void)                           const { return this.m_color;              }

//--- Return the object description
   virtual string    Description(void);
   
//--- Virtual methods of (1) saving to file, (2) loading from file and (3) object type
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);
   virtual int       Type(void)                          const { return(ELEMENT_TYPE_COLOR);       }
   
//--- Constructors/destructor
                     CColor(void) : m_color(clrNULL)                          { this.SetName("");  }
                     CColor(const color clr) : m_color(clr)                   { this.SetName("");  }
                     CColor(const color clr,const string name) : m_color(clr) { this.SetName(name);}
                    ~CColor(void) {}
  };
//+------------------------------------------------------------------+
//| CColor::Return the object description                            |
//+------------------------------------------------------------------+
string CColor::Description(void)
  {
   string color_name=(this.Get()!=clrNULL ? ::ColorToString(this.Get(),true) : "clrNULL (0x00FFFFFF)");
   return(this.Name()+(this.Name()!="" ? " " : "")+"Color: "+color_name);
  }
//+------------------------------------------------------------------+
//| CColor::Save to file                                             |
//+------------------------------------------------------------------+
bool CColor::Save(const int file_handle)
  {
//--- Save the parent object data
   if(!CBaseObj::Save(file_handle))
      return false;
      
//--- Save the color
   if(::FileWriteInteger(file_handle,this.m_color,INT_VALUE)!=INT_VALUE)
      return false;
   
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//| CColor::Load from file                                           |
//+------------------------------------------------------------------+
bool CColor::Load(const int file_handle)
  {
//--- Load parent object data
   if(!CBaseObj::Load(file_handle))
      return false;
      
//--- Load the color
   this.m_color=(color)::FileReadInteger(file_handle,INT_VALUE);
   
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Color class of a graphical object element                        |
//+------------------------------------------------------------------+
class CColorElement : public CBaseObj
  {
protected:
   CColor            m_current;                                // Current color. It could be one of the following
   CColor            m_default;                                // Normal state color
   CColor            m_focused;                                // Color on hover
   CColor            m_pressed;                                // Color on click
   CColor            m_blocked;                                // Blocked element color
   
//--- Convert RGB to color
   color             RGBToColor(const double r,const double g,const double b) const;
//--- Write RGB component values to variables
   void              ColorToRGB(const color clr,double &r,double &g,double &b);
//--- Return (1) Red, (2) Green, (3) Blue color components
   double            GetR(const color clr)                     { return clr&0xFF;                           }
   double            GetG(const color clr)                     { return(clr>>8)&0xFF;                       }
   double            GetB(const color clr)                     { return(clr>>16)&0xFF;                      }
   
public:
//--- Return a new color
   color             NewColor(color base_color, int shift_red, int shift_green, int shift_blue);

//--- Return an interpolated color between three colors depending on the coefficient value (from -1 to +1)
   color             InterpolateColorByCoeff(const color color1, const color color2, const color color3, const double coeff);

//--- Class initialization
   void              Init(void);

//--- Initialize colors for different states
   bool              InitDefault(const color clr)              { return this.m_default.SetColor(clr);       }
   bool              InitFocused(const color clr)              { return this.m_focused.SetColor(clr);       }
   bool              InitPressed(const color clr)              { return this.m_pressed.SetColor(clr);       }
   bool              InitBlocked(const color clr)              { return this.m_blocked.SetColor(clr);       }
   
//--- Set colors for all states
   void              InitColors(const color clr_default, const color clr_focused, const color clr_pressed, const color clr_blocked);
   void              InitColors(const color clr);
    
//--- Return colors of different states
   color             GetCurrent(void)                    const { return this.m_current.Get();               }
   color             GetDefault(void)                    const { return this.m_default.Get();               }
   color             GetFocused(void)                    const { return this.m_focused.Get();               }
   color             GetPressed(void)                    const { return this.m_pressed.Get();               }
   color             GetBlocked(void)                    const { return this.m_blocked.Get();               }
   
//--- Set one of the colors from the list as the current one
   bool              SetCurrentAs(const ENUM_COLOR_STATE color_state);

//--- Return the object description
   virtual string    Description(void);
   
//--- Virtual methods of (1) saving to file, (2) loading from file and (3) object type
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);
   virtual int       Type(void)                          const { return(ELEMENT_TYPE_COLORS_ELEMENT);       }
   
//--- Constructors/destructor
                     CColorElement(void);
                     CColorElement(const color clr);
                     CColorElement(const color clr_default,const color clr_focused,const color clr_pressed,const color clr_blocked);
                    ~CColorElement(void) {}
  };
//+-----------------------------------------------------------------------------+
//| CColorElement::Constructor with setting the transparent colors of the object|
//+-----------------------------------------------------------------------------+
CColorElement::CColorElement(void)
  {
   this.InitColors(clrNULL,clrNULL,clrNULL,clrNULL);
   this.Init();
  }
//+------------------------------------------------------------------+
//| CColorElement::Constructor specifying the object colors          |
//+------------------------------------------------------------------+
CColorElement::CColorElement(const color clr_default,const color clr_focused,const color clr_pressed,const color clr_blocked)
  {
   this.InitColors(clr_default,clr_focused,clr_pressed,clr_blocked);
   this.Init();
  }
//+------------------------------------------------------------------+
//| CColorElement::Constructor specifying the object colors          |
//+------------------------------------------------------------------+
CColorElement::CColorElement(const color clr)
  {
   this.InitColors(clr);
   this.Init();
  }
//+------------------------------------------------------------------+
//| CColorElement::Class initialization                              |
//+------------------------------------------------------------------+
void CColorElement::Init(void)
  {
   this.m_default.SetName("Default"); this.m_default.SetID(1);
   this.m_focused.SetName("Focused"); this.m_focused.SetID(2);
   this.m_pressed.SetName("Pressed"); this.m_pressed.SetID(3);
   this.m_blocked.SetName("Blocked"); this.m_blocked.SetID(4);
   this.SetCurrentAs(COLOR_STATE_DEFAULT);
   this.m_current.SetName("Current");
   this.m_current.SetID(0);
  }
//+------------------------------------------------------------------+
//| CColorElement::Set colors for all states                         |
//+------------------------------------------------------------------+
void CColorElement::InitColors(const color clr_default,const color clr_focused,const color clr_pressed,const color clr_blocked)
  {
   this.InitDefault(clr_default);
   this.InitFocused(clr_focused);
   this.InitPressed(clr_pressed);
   this.InitBlocked(clr_blocked);   
  }
//+----------------------------------------------------------------------+
//| CColorElement::Set the colors for all states based on the current one|
//+----------------------------------------------------------------------+
void CColorElement::InitColors(const color clr)
  {
   this.InitDefault(clr);
   this.InitFocused(clr!=clrNULL ? this.NewColor(clr,-20,-20,-20) : clrNULL);
   this.InitPressed(clr!=clrNULL ? this.NewColor(clr,-40,-40,-40) : clrNULL);
   this.InitBlocked(clrWhiteSmoke);   
  }
//+---------------------------------------------------------------------+
//|CColorElement::Set one of the colors from the list as the current one|
//+---------------------------------------------------------------------+
bool CColorElement::SetCurrentAs(const ENUM_COLOR_STATE color_state)
  {
   switch(color_state)
     {
      case COLOR_STATE_DEFAULT   :  return this.m_current.SetColor(this.m_default.Get());
      case COLOR_STATE_FOCUSED   :  return this.m_current.SetColor(this.m_focused.Get());
      case COLOR_STATE_PRESSED   :  return this.m_current.SetColor(this.m_pressed.Get());
      case COLOR_STATE_BLOCKED   :  return this.m_current.SetColor(this.m_blocked.Get());
      default                    :  return false;
     }
  }
//+------------------------------------------------------------------+
//| CColorElement::Convert RGB to color                              |
//+------------------------------------------------------------------+
color CColorElement::RGBToColor(const double r,const double g,const double b) const
  {
   int int_r=(int)::round(r);
   int int_g=(int)::round(g);
   int int_b=(int)::round(b);
   int clr=0;
   clr=int_b;
   clr<<=8;
   clr|=int_g;
   clr<<=8;
   clr|=int_r;

   return (color)clr;
  }
//+------------------------------------------------------------------+
//| CColorElement::Get RGB component values                          |
//+------------------------------------------------------------------+
void CColorElement::ColorToRGB(const color clr,double &r,double &g,double &b)
  {
   r=this.GetR(clr);
   g=this.GetG(clr);
   b=this.GetB(clr);
  }
//+------------------------------------------------------------------+
//| CColorElement::Return color with a new color component           |
//+------------------------------------------------------------------+
color CColorElement::NewColor(color base_color, int shift_red, int shift_green, int shift_blue)
  {
   double clrR=0, clrG=0, clrB=0;
   this.ColorToRGB(base_color,clrR,clrG,clrB);
   double clrRx=(clrR+shift_red  < 0 ? 0 : clrR+shift_red  > 255 ? 255 : clrR+shift_red);
   double clrGx=(clrG+shift_green< 0 ? 0 : clrG+shift_green> 255 ? 255 : clrG+shift_green);
   double clrBx=(clrB+shift_blue < 0 ? 0 : clrB+shift_blue > 255 ? 255 : clrB+shift_blue);
   return this.RGBToColor(clrRx,clrGx,clrBx);
  }
//+------------------------------------------------------------------+
//| Return an interpolated color between three colors                |
//| depending on the coefficient value (from -1 to +1)               |
//+------------------------------------------------------------------+
color CColorElement::InterpolateColorByCoeff(const color color1,const color color2,const color color3,const double coeff)
  {
//--- Limit the value of the coefficient
   double val=::fmax(-1.0,::fmin(1.0,coeff));

//--- Variables for getting RGB components for each color
   double r1, g1, b1, r2, g2, b2;
   double r, g, b, t;

//--- Interpolation between the initial and average color
   if(val<0.0)
     {
      this.ColorToRGB(color1,r1,g1,b1);
      this.ColorToRGB(color2,r2,g2,b2);
      t=(val+1.0)/1.0;
      r=r1+(r2-r1)*t;
      g=g1+(g2-g1)*t;
      b=b1+(b2-b1)*t;
     }
//--- Interpolation between the average and final color
   else
     {
      this.ColorToRGB(color3,r1,g1,b1); 
      this.ColorToRGB(color2,r2,g2,b2);
      t=val/1.0;
      r=r2+(r1-r2)*t;
      g=g2+(g1-g2)*t;
      b=b2+(b1-b2)*t;
     }
//--- Return the calculated color
   return this.RGBToColor(r,g,b);
  }
//+------------------------------------------------------------------+
//| CColorElement::Return the object description                     |
//+------------------------------------------------------------------+
string CColorElement::Description(void)
  {
   string res=::StringFormat("%s Colors. %s",this.Name(),this.m_current.Description());
   res+="\n  1: "+this.m_default.Description();
   res+="\n  2: "+this.m_focused.Description();
   res+="\n  3: "+this.m_pressed.Description();
   res+="\n  4: "+this.m_blocked.Description();
   return res;
  }
//+------------------------------------------------------------------+
//| CColorElement::Save to file                                      |
//+------------------------------------------------------------------+
bool CColorElement::Save(const int file_handle)
  {
//--- Save the parent object data
   if(!CBaseObj::Save(file_handle))
      return false;
   
//--- Save the current color
   if(!this.m_current.Save(file_handle))
      return false;
//--- Save the color of the normal state
   if(!this.m_default.Save(file_handle))
      return false;
//--- Save the color when hovering the cursor
   if(!this.m_focused.Save(file_handle))
      return false;
//--- Save the color when clicking
   if(!this.m_pressed.Save(file_handle))
      return false;
//--- Save the color of the blocked element
   if(!this.m_blocked.Save(file_handle))
      return false;
   
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//| CColorElement::Load from file                                    |
//+------------------------------------------------------------------+
bool CColorElement::Load(const int file_handle)
  {
//--- Load parent object data
   if(!CBaseObj::Load(file_handle))
      return false;
      
//--- Load the current color
   if(!this.m_current.Load(file_handle))
      return false;
//--- Load the normal state color
   if(!this.m_default.Load(file_handle))
      return false;
//--- Load the color on hover
   if(!this.m_focused.Load(file_handle))
      return false;
//--- Load the color on click
   if(!this.m_pressed.Load(file_handle))
      return false;
//--- Load the color of the blocked element
   if(!this.m_blocked.Load(file_handle))
      return false;
   
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Rectangular region class                                         |
//+------------------------------------------------------------------+
class CBound : public CBaseObj
  {
protected:
   CBaseObj         *m_assigned_obj;                           // Object assigned to the region
   CRect             m_bound;                                  // Rectangular area structure

public:
//--- Change the bounding rectangular (1) width, (2) height and (3) size
   void              ResizeW(const int size)                   { this.m_bound.Width(size);                                    }
   void              ResizeH(const int size)                   { this.m_bound.Height(size);                                   }
   void              Resize(const int w,const int h)           { this.m_bound.Width(w); this.m_bound.Height(h);               }
   
//--- Set (1) X, (2) Y and (3) both coordinates of the bounding rectangle
   void              SetX(const int x)                         { this.m_bound.left=x;                                         }
   void              SetY(const int y)                         { this.m_bound.top=y;                                          }
   void              SetXY(const int x,const int y)            { this.m_bound.LeftTop(x,y);                                   }
   
//--- (1) Set and (2) shift the bounding rectangle by the specified coordinates/offset size
   void              Move(const int x,const int y)             { this.m_bound.Move(x,y);                                      }
   void              Shift(const int dx,const int dy)          { this.m_bound.Shift(dx,dy);                                   }
   
//--- Returns the object coordinates, dimensions, and boundaries
   int               X(void)                             const { return this.m_bound.left;                                    }
   int               Y(void)                             const { return this.m_bound.top;                                     }
   int               Width(void)                         const { return this.m_bound.Width();                                 }
   int               Height(void)                        const { return this.m_bound.Height();                                }
   int               Right(void)                         const { return this.m_bound.right-(this.m_bound.Width()  >0 ? 1 : 0);}
   int               Bottom(void)                        const { return this.m_bound.bottom-(this.m_bound.Height()>0 ? 1 : 0);}

//--- Returns the flag indicating whether the cursor is inside the area
   bool              Contains(const int x,const int y)   const { return this.m_bound.Contains(x,y);                           }
   
//--- (1) Assign, (2) unassign and (3) return the pointer to the assigned element
   void              AssignObject(CBaseObj *obj)               { this.m_assigned_obj=obj;                                     }
   void              UnassignObject(void)                      { this.m_assigned_obj=NULL;                                    }           
   CBaseObj         *GetAssignedObj(void)                      { return this.m_assigned_obj;                                  }
   
//--- Return the object description
   virtual string    Description(void);
   
//--- Virtual methods of (1) comparing, (2) saving to file, (3) loading from file, (4) object type
   virtual int       Compare(const CObject *node,const int mode=0) const;
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);
   virtual int       Type(void)                          const { return(ELEMENT_TYPE_RECTANGLE_AREA);                         }
   
//--- Constructors/destructor
                     CBound(void) { ::ZeroMemory(this.m_bound); }
                     CBound(const int x,const int y,const int w,const int h) { this.SetXY(x,y); this.Resize(w,h);             }
                    ~CBound(void) { ::ZeroMemory(this.m_bound); }
  };
//+------------------------------------------------------------------+
//| CBound::Return the object description                            |
//+------------------------------------------------------------------+
string CBound::Description(void)
  {
   string nm=this.Name();
   string name=(nm!="" ? ::StringFormat(" \"%s\"",nm) : nm);
   return ::StringFormat("%s%s: id %d, x %d, y %d, w %d, h %d, right %d, bottom %d",
                         ElementDescription((ENUM_ELEMENT_TYPE)this.Type()),name,this.ID(),
                         this.X(),this.Y(),this.Width(),this.Height(),this.Right(),this.Bottom());
  }
//+------------------------------------------------------------------+
//| CBound::Compare two objects                                      |
//+------------------------------------------------------------------+
int CBound::Compare(const CObject *node,const int mode=0) const
  {
   if(node==NULL)
      return -1;
   const CBound *obj=node;
   switch(mode)
     {
      case BASE_SORT_BY_NAME  :  return(this.Name()   >obj.Name()    ? 1 : this.Name()    <obj.Name()    ? -1 : 0);
      case BASE_SORT_BY_X     :  return(this.X()      >obj.X()       ? 1 : this.X()       <obj.X()       ? -1 : 0);
      case BASE_SORT_BY_Y     :  return(this.Y()      >obj.Y()       ? 1 : this.Y()       <obj.Y()       ? -1 : 0);
      case BASE_SORT_BY_WIDTH :  return(this.Width()  >obj.Width()   ? 1 : this.Width()   <obj.Width()   ? -1 : 0);
      case BASE_SORT_BY_HEIGHT:  return(this.Height() >obj.Height()  ? 1 : this.Height()  <obj.Height()  ? -1 : 0);
      default                 :  return(this.ID()     >obj.ID()      ? 1 : this.ID()      <obj.ID()      ? -1 : 0);
     }
  }
//+------------------------------------------------------------------+
//| CBound::Save to file                                             |
//+------------------------------------------------------------------+
bool CBound::Save(const int file_handle)
  {
//--- Save the parent object data
   if(!CBaseObj::Save(file_handle))
      return false;
      
//--- Save the area structure
   if(::FileWriteStruct(file_handle,this.m_bound)!=sizeof(this.m_bound))
      return(false);
   
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//| CBound::Load from file                                           |
//+------------------------------------------------------------------+
bool CBound::Load(const int file_handle)
  {
//--- Load parent object data
   if(!CBaseObj::Load(file_handle))
      return false;
      
//--- Load the region structure
   if(::FileReadStruct(file_handle,this.m_bound)!=sizeof(this.m_bound))
      return(false);
   
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Millisecond counter class                                        |
//+------------------------------------------------------------------+
class CCounter : public CBaseObj
  {
private:
   bool              m_launched;                               // Launched countdown flag
//--- Start the countdown
   void              Run(const uint delay)
                       {
                        //--- If the countdown has already started, leave
                        if(this.m_launched)
                           return;
                        //--- If a non-zero delay value is passed, set a new value
                        if(delay!=0)
                           this.m_delay=delay;
                        //--- Save the start time and set a flag that the countdown has already started
                        this.m_start=::GetTickCount64();
                        this.m_launched=true;
                       }
protected:
   ulong             m_start;                                  // Countdown start time
   uint              m_delay;                                  // Delay

public:
//--- (1) Set a delay, start the countdown with the (2) set and (3) specified delay
   void              SetDelay(const uint delay)                { this.m_delay=delay;            }
   void              Start(void)                               { this.Run(0);                   }
   void              Start(const uint delay)                   { this.Run(delay);               }
//--- Return the countdown end flag
   bool              IsDone(void)
                       {
                        //--- If the countdown has not started, return 'false'
                        if(!this.m_launched)
                           return false;
                        //--- If more milliseconds have passed than the timeout
                        if(::GetTickCount64()-this.m_start>this.m_delay)
                          {
                           //--- reset the flag of the launched countdown and return 'true'
                           this.m_launched=false;
                           return true;
                          }
                        //--- Specified time has not yet passed
                        return false;
                       }
   
//--- Virtual methods of (1) saving to file, (2) loading from file and (3) object type
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);
   virtual int       Type(void)                          const { return(ELEMENT_TYPE_COUNTER);  }
   
//--- Constructor/destructor
                     CCounter(void) : m_start(0), m_delay(0), m_launched(false) {}
                    ~CCounter(void) {}
  };
//+------------------------------------------------------------------+
//| CCounter::Save to file                                           |
//+------------------------------------------------------------------+
bool CCounter::Save(const int file_handle)
  {
//--- Save the parent object data
   if(!CBaseObj::Save(file_handle))
      return false;
      
//--- Save the delay value
   if(::FileWriteInteger(file_handle,this.m_delay,INT_VALUE)!=INT_VALUE)
      return false;
   
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//| CCounter::Load from file                                         |
//+------------------------------------------------------------------+
bool CCounter::Load(const int file_handle)
  {
//--- Load parent object data
   if(!CBaseObj::Load(file_handle))
      return false;
      
//--- Load the delay value
   this.m_delay=::FileReadInteger(file_handle,INT_VALUE);
   
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Event auto-repeat class                                          |
//+------------------------------------------------------------------+
class CAutoRepeat : public CBaseObj
  {
private:
   CCounter          m_delay_counter;                          // Counter for delay before auto-repeat
   CCounter          m_repeat_counter;                         // Counter for periodic sending of events
   long              m_chart_id;                               // Chart for sending a custom event
   bool              m_button_pressed;                         // Flag indicating whether the button is pressed
   bool              m_auto_repeat_started;                    // Flag indicating whether auto-repeat has started
   uint              m_delay_before_repeat;                    // Delay before auto-repeat starts (ms)
   uint              m_repeat_interval;                        // Frequency of sending events (ms)
   ushort            m_event_id;                               // Custom event ID
   long              m_event_lparam;                           // long parameter of the user event
   double            m_event_dparam;                           // double parameter of the custom event
   string            m_event_sparam;                           // string parameter of the custom event

//--- Send a custom event
   void              SendEvent() { ::EventChartCustom((this.m_chart_id<=0 ? ::ChartID() : this.m_chart_id), this.m_event_id, this.m_event_lparam, this.m_event_dparam, this.m_event_sparam); }
public:
//--- Object type
   virtual int       Type(void)                          const { return(ELEMENT_TYPE_AUTOREPEAT_CONTROL);   }
                       
//--- Constructors
                     CAutoRepeat(void) : 
                        m_button_pressed(false), m_auto_repeat_started(false), m_delay_before_repeat(350), m_repeat_interval(100),
                        m_event_id(0), m_event_lparam(0), m_event_dparam(0), m_event_sparam(""), m_chart_id(::ChartID()) {}
                     
                     CAutoRepeat(long chart_id, int delay_before_repeat=350, int repeat_interval=100, ushort event_id=0, long event_lparam=0, double event_dparam=0, string event_sparam="") :
                        m_button_pressed(false), m_auto_repeat_started(false), m_delay_before_repeat(delay_before_repeat), m_repeat_interval(repeat_interval),
                        m_event_id(event_id), m_event_lparam(event_lparam), m_event_dparam(event_dparam), m_event_sparam(event_sparam), m_chart_id(chart_id) {}

//--- Set the chart ID
   void              SetChartID(const long chart_id)              { this.m_chart_id=chart_id;         }
   void              SetDelay(const uint delay)                   { this.m_delay_before_repeat=delay; }
   void              SetInterval(const uint interval)             { this.m_repeat_interval=interval;  }

//--- Set the ID and parameters of a custom event
   void              SetEvent(ushort event_id, long event_lparam, double event_dparam, string event_sparam)
                       {
                        this.m_event_id=event_id;
                        this.m_event_lparam=event_lparam;
                        this.m_event_dparam=event_dparam;
                        this.m_event_sparam=event_sparam;
                       }

//--- Return flags
   bool              ButtonPressedFlag(void)                const { return this.m_button_pressed;     }
   bool              AutorepeatStartedFlag(void)            const { return this.m_auto_repeat_started;}
   uint              Delay(void)                            const { return this.m_delay_before_repeat;}
   uint              Interval(void)                         const { return this.m_repeat_interval;    }

//--- Handle a button click (starting auto-repeat)
   void              OnButtonPress(void)
                       {
                        if(this.m_button_pressed)
                           return;
                        this.m_button_pressed=true;
                        this.m_auto_repeat_started=false;
                        this.m_delay_counter.Start(this.m_delay_before_repeat);  // Start the delay counter
                       }

//--- Handle button release (stopping auto-repeat)
   void              OnButtonRelease(void)
                       {
                        this.m_button_pressed=false;
                        this.m_auto_repeat_started=false;
                       }

//--- Method for performing auto-repeat (started in the timer)
   void              Process(void)
                       {
                        //--- If the button is held down
                        if(this.m_button_pressed)
                          {
                           //--- Check if the delay before starting the auto-repeat has expired
                           if(!this.m_auto_repeat_started && this.m_delay_counter.IsDone())
                             {
                              this.m_auto_repeat_started=true;
                              this.m_repeat_counter.Start(this.m_repeat_interval); // Start the auto-repeat counter
                             }
                           //--- If auto-repeat has started, check the frequency of sending events
                           if(this.m_auto_repeat_started && this.m_repeat_counter.IsDone())
                             {
                              //--- Send an event and restart the counter
                              this.SendEvent();
                              this.m_repeat_counter.Start(this.m_repeat_interval);
                             }
                          }
                       }
  };
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Base class storing object dimensions                             |
//+------------------------------------------------------------------+
class CBoundedObj : public CBaseObj
  {
protected:
   CBound            m_bound;                                  // Object boundaries
   bool              m_canvas_owner;                           // Canvas ownership flag
public:
//--- Returns the object coordinates, dimensions, and boundaries
   int               X(void)                             const { return this.m_bound.X();                                                          }
   int               Y(void)                             const { return this.m_bound.Y();                                                          }
   int               Width(void)                         const { return this.m_bound.Width();                                                      }
   int               Height(void)                        const { return this.m_bound.Height();                                                     }
   int               Right(void)                         const { return this.m_bound.Right();                                                      }
   int               Bottom(void)                        const { return this.m_bound.Bottom();                                                     }

//--- Change the bounding rectangular (1) width, (2) height and (3) size
   void              BoundResizeW(const int size)              { this.m_bound.ResizeW(size);                                                       }
   void              BoundResizeH(const int size)              { this.m_bound.ResizeH(size);                                                       }
   void              BoundResize(const int w,const int h)      { this.m_bound.Resize(w,h);                                                         }
   
//--- Set (1) X, (2) Y and (3) both coordinates of the bounding rectangle
   void              BoundSetX(const int x)                    { this.m_bound.SetX(x);                                                             }
   void              BoundSetY(const int y)                    { this.m_bound.SetY(y);                                                             }
   void              BoundSetXY(const int x,const int y)       { this.m_bound.SetXY(x,y);                                                          }
   
//--- (1) Set and (2) shift the bounding rectangle by the specified coordinates/offset size
   void              BoundMove(const int x,const int y)        { this.m_bound.Move(x,y);                                                           }
   void              BoundShift(const int dx,const int dy)     { this.m_bound.Shift(dx,dy);                                                        }
   
//--- Virtual methods of (1) comparing, (2) saving to file, (3) loading from file, (4) object type
   //virtual int       Compare(const CObject *node,const int mode=0) const;
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);
   virtual int       Type(void)                          const { return(ELEMENT_TYPE_BOUNDED_BASE); }
                     
                     CBoundedObj (void) : m_canvas_owner(true) {}
                     CBoundedObj (const string user_name,const int id,const int x,const int y,const int w,const int h);
                    ~CBoundedObj (void){}
  };
//+------------------------------------------------------------------+
//| CBoundedObj::Constructor                                         |
//+------------------------------------------------------------------+
CBoundedObj::CBoundedObj(const string user_name,const int id,const int x,const int y,const int w,const int h) : m_canvas_owner(true)
  {
//--- Get the adjusted chart ID and the distance in pixels along the vertical Y axis
   this.m_bound.SetName(user_name);
   this.m_bound.SetID(id);
   this.m_bound.SetXY(x,y);
   this.m_bound.Resize(w,h);
  }
//+------------------------------------------------------------------+
//| CBoundedObj::Save to file                                        |
//+------------------------------------------------------------------+
bool CBoundedObj::Save(const int file_handle)
  {
//--- Save the parent object data
   if(!CBaseObj::Save(file_handle))
      return false;
 
//--- Save the canvas ownership flag
   if(::FileWriteInteger(file_handle,this.m_canvas_owner,INT_VALUE)!=INT_VALUE)
      return false;
//--- Save the dimensions
   return this.m_bound.Save(file_handle);
  }
//+------------------------------------------------------------------+
//| CBoundedObj::Load from file                                      |
//+------------------------------------------------------------------+
bool CBoundedObj::Load(const int file_handle)
  {
//--- Load parent object data
   if(!CBaseObj::Load(file_handle))
      return false;
   
//--- Load the canvas ownership flag
   this.m_canvas_owner=::FileReadInteger(file_handle,INT_VALUE);
//--- Load dimensions
   return this.m_bound.Load(file_handle);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Base class of graphical elements canvas                          |
//+------------------------------------------------------------------+
class CCanvasBase : public CBoundedObj
  {
private: 
   bool              m_chart_mouse_wheel_flag;                 // Flag for sending mouse wheel scroll messages
   bool              m_chart_mouse_move_flag;                  // Flag for sending mouse cursor movement messages
   bool              m_chart_object_create_flag;               // Flag for sending messages about the graphical object creation event
   bool              m_chart_mouse_scroll_flag;                // Flag for scrolling the chart with the left button and mouse wheel
   bool              m_chart_context_menu_flag;                // Flag of access to the context menu using the right click
   bool              m_chart_crosshair_tool_flag;              // Flag of access to the Crosshair tool using the middle click
   bool              m_flags_state;                            // State of the flags for scrolling the chart with the wheel, the context menu, and the crosshair
   
//--- Set chart restrictions (wheel scrolling, context menu, and crosshair)
   void              SetFlags(const bool flag);
   
protected:
   CCanvas          *m_background;                             // Background canvas
   CCanvas          *m_foreground;                             // Foreground canvas
   CCanvasBase      *m_container;                              // Parent container object
   CColorElement     m_color_background;                       // Background color control object
   CColorElement     m_color_foreground;                       // Foreground color control object
   CColorElement     m_color_border;                           // Border color control object
   
   CColorElement     m_color_background_act;                   // Activated element background color control object
   CColorElement     m_color_foreground_act;                   // Activated element foreground color control object
   CColorElement     m_color_border_act;                       // Activated element frame color control object
   
   CAutoRepeat       m_autorepeat;                             // Event auto-repeat control object
   
   ENUM_ELEMENT_STATE m_state;                                 // Control state (e.g. buttons (on/off))
   long              m_chart_id;                               // Chart ID
   int               m_wnd;                                    // Chart subwindow index
   int               m_wnd_y;                                  // Cursor Y coordinate offset in the subwindow
   int               m_obj_x;                                  // Graphical object X coordinate
   int               m_obj_y;                                  // Graphical object Y coordinate
   uchar             m_alpha_bg;                               // Background transparency
   uchar             m_alpha_fg;                               // Foreground transparency
   uint              m_border_width_lt;                        // Left frame width
   uint              m_border_width_rt;                        // Right frame width
   uint              m_border_width_up;                        // Top frame width
   uint              m_border_width_dn;                        // Bottom frame width
   string            m_program_name;                           // Program name
   bool              m_hidden;                                 // Hidden object flag
   bool              m_blocked;                                // Blocked element flag
   bool              m_movable;                                // Moved element flag
   bool              m_resizable;                              // Resizing flag
   bool              m_focused;                                // Element flag in focus
   bool              m_main;                                   // Main object flag
   bool              m_autorepeat_flag;                        // Event sending auto-repeat flag
   bool              m_scroll_flag;                            // Flag for scrolling content using scrollbars
   bool              m_trim_flag;                              // Flag for clipping the element to the container borders
   bool              m_cropped;                                // Flag indicating that the object is hidden outside the container borders
   int               m_cursor_delta_x;                         // Distance from the cursor to the left edge of the element
   int               m_cursor_delta_y;                         // Distance from the cursor to the top edge of the element
   int               m_z_order;                                // Graphical object Z-order
   
//--- (1) Set, return (2) the name and (3) the active element flag
   void              SetActiveElementName(const string name)   { CCommonManager::GetInstance().SetElementName(name);                               }
   string            ActiveElementName(void)             const { return CCommonManager::GetInstance().ElementName();                               }
   bool              IsCurrentActiveElement(void)        const { return this.ActiveElementName()==this.NameFG();                                   }
   
//--- (1) Set and (2) return the resize mode flag
   void              SetResizeMode(const bool flag)            { CCommonManager::GetInstance().SetResizeMode(flag);                                }
   bool              ResizeMode(void)                    const { return CCommonManager::GetInstance().ResizeMode();                                }
   
//--- (1) Set and (2) return the element edge, above which the size is changed
   void              SetResizeRegion(const ENUM_CURSOR_REGION edge){ CCommonManager::GetInstance().SetResizeRegion(edge);                          }
   ENUM_CURSOR_REGION ResizeRegion(void)                 const { return CCommonManager::GetInstance().ResizeRegion();                              }
   
//--- Return the offset of the initial drawing coordinates on the canvas relative to the canvas and the object coordinates
   int               CanvasOffsetX(void)                 const { return(this.ObjectX()-this.X());                                                  }
   int               CanvasOffsetY(void)                 const { return(this.ObjectY()-this.Y());                                                  }
//--- Return the adjusted coordinate of a point on the canvas, taking into account the offset of the canvas relative to the object
   int               AdjX(const int x)                   const { return(x-this.CanvasOffsetX());                                                   }
   int               AdjY(const int y)                   const { return(y-this.CanvasOffsetY());                                                   }
   
//--- Returns the adjusted chart ID
   long              CorrectChartID(const long chart_id) const { return(chart_id!=0 ? chart_id : ::ChartID());                                     }

public:
//--- Get the boundaries of the parent container object
   int               ContainerLimitLeft(void)            const { return(this.m_container==NULL ? this.ObjectX()     : this.m_container.LimitLeft());  }
   int               ContainerLimitRight(void)           const { return(this.m_container==NULL ? this.ObjectRight() : this.m_container.LimitRight()); }
   int               ContainerLimitTop(void)             const { return(this.m_container==NULL ? this.ObjectY()     : this.m_container.LimitTop());   }
   int               ContainerLimitBottom(void)          const { return(this.m_container==NULL ? this.ObjectBottom(): this.m_container.LimitBottom());}
   string            ContainerDescription(void)          const { return(this.m_container==NULL ? "Not specified"    : this.m_container.Description());}
   
//--- Return the graphical object coordinates, boundaries and dimensions
   int               ObjectX(void)                       const { return this.m_obj_x;                                                              }
   int               ObjectY(void)                       const { return this.m_obj_y;                                                              }
   int               ObjectWidth(void)                   const { return this.m_background.Width();                                                 }
   int               ObjectHeight(void)                  const { return this.m_background.Height();                                                }
   int               ObjectRight(void)                   const { return this.ObjectX()+this.ObjectWidth()-1;                                       }
   int               ObjectBottom(void)                  const { return this.ObjectY()+this.ObjectHeight()-1;                                      }
   
//--- Change the graphical object (1) width, (2) height and (3) size
protected:
   virtual bool      ObjectResizeW(const int size);
   virtual bool      ObjectResizeH(const int size);
   bool              ObjectResize(const int w,const int h);
   
//--- Set the graphical object (1) X, (2) Y and (3) both coordinates
   virtual bool      ObjectSetX(const int x);
   virtual bool      ObjectSetY(const int y);
   bool              ObjectSetXY(const int x,const int y)      { return(this.ObjectSetX(x) && this.ObjectSetY(y));                                 }
   
//--- Set both the coordinates and dimensions of a graphical object
   virtual bool      ObjectSetXYWidthResize(const int x,const int y,const int w,const int h);
   
//--- (1) Set and (2) relocate the graphical object by the specified coordinates/offset size
   bool              ObjectMove(const int x,const int y)       { return this.ObjectSetXY(x,y);                                                     }
   bool              ObjectShift(const int dx,const int dy)    { return this.ObjectSetXY(this.ObjectX()+dx,this.ObjectY()+dy);                     }
   
//--- Returns the flag indicating whether the cursor is inside the object
   bool              Contains(const int x,const int y);
//--- Return the cursor location on the object borders
   ENUM_CURSOR_REGION CheckResizeZone(const int x,const int y);
   
//--- Check if the set color is equal to the specified one
   bool              CheckColor(const ENUM_COLOR_STATE state) const;
//--- Change the background, text, and border colors depending on the condition
   void              ColorChange(const ENUM_COLOR_STATE state);
   
//--- Initialize (1) the class object and (2) default object colors 
   void              Init(void);
   void              InitColors(void);

//--- Cursor hovering (Focus), (2) button click (Press),
//--- (3) cursor moving (Move), (4) leaving focus (Release), (5) graphical object creation (Create),
//--- (6) wheel scrolling (Wheel) and (7) resizing (Resize) event handlers. Redefined in descendants.
   virtual void      OnFocusEvent(const int id, const long lparam, const double dparam, const string sparam);
   virtual void      OnPressEvent(const int id, const long lparam, const double dparam, const string sparam);
   virtual void      OnMoveEvent(const int id, const long lparam, const double dparam, const string sparam);
   virtual void      OnReleaseEvent(const int id, const long lparam, const double dparam, const string sparam);
   virtual void      OnCreateEvent(const int id, const long lparam, const double dparam, const string sparam);
   virtual void      OnWheelEvent(const int id, const long lparam, const double dparam, const string sparam)         { return;         }  // handler is disabled here
   virtual void      OnResizeZoneEvent(const int id, const long lparam, const double dparam, const string sparam)    { return;         }  // handler is disabled here
   
//--- Handlers for resizing the element by sides and corners
   virtual bool      OnResizeZoneLeft(const int x, const int y)                                                      { return false;   }  // handler is disabled here
   virtual bool      OnResizeZoneRight(const int x, const int y)                                                     { return false;   }  // handler is disabled here
   virtual bool      OnResizeZoneTop(const int x, const int y)                                                       { return false;   }  // handler is disabled here
   virtual bool      OnResizeZoneBottom(const int x, const int y)                                                    { return false;   }  // handler is disabled here
   virtual bool      OnResizeZoneLeftTop(const int x, const int y)                                                   { return false;   }  // handler is disabled here
   virtual bool      OnResizeZoneRightTop(const int x, const int y)                                                  { return false;   }  // handler is disabled here
   virtual bool      OnResizeZoneLeftBottom(const int x, const int y)                                                { return false;   }  // handler is disabled here
   virtual bool      OnResizeZoneRightBottom(const int x, const int y)                                               { return false;   }  // handler is disabled here
     
//--- Handlers for custom events of the element when hovering, clicking, and scrolling the wheel in the object area, as well as changing it
   virtual void      MouseMoveHandler(const int id, const long lparam, const double dparam, const string sparam)     { return;         }  // handler is disabled here
   virtual void      MousePressHandler(const int id, const long lparam, const double dparam, const string sparam)    { return;         }  // handler is disabled here
   virtual void      MouseWheelHandler(const int id, const long lparam, const double dparam, const string sparam)    { return;         }  // handler is disabled here
   virtual void      ObjectChangeHandler(const int id, const long lparam, const double dparam, const string sparam)  { return;         }  // handler is disabled here
   
public:
//--- Return the pointer to (1) a container and (2) event auto-repeat class object
   CCanvasBase      *GetContainer(void)                  const { return this.m_container;                                                          } 
   CAutoRepeat      *GetAutorepeatObj(void)                    { return &this.m_autorepeat;                                                        }

//--- Return the pointer to the (1) background and (2) foreground canvas
   CCanvas          *GetBackground(void)                       { return this.m_background;                                                         }
   CCanvas          *GetForeground(void)                       { return this.m_foreground;                                                         }
   
//--- Return the pointer to the color management object for the (1) background, (2) foreground and (3) border
   CColorElement    *GetBackColorControl(void)                 { return &this.m_color_background;                                                  }
   CColorElement    *GetForeColorControl(void)                 { return &this.m_color_foreground;                                                  }
   CColorElement    *GetBorderColorControl(void)               { return &this.m_color_border;                                                      }
   
//--- Return the pointer to the color management object for the (1) background, (2) foreground and (3) activated element border
   CColorElement    *GetBackColorActControl(void)              { return &this.m_color_background_act;                                              }
   CColorElement    *GetForeColorActControl(void)              { return &this.m_color_foreground_act;                                              }
   CColorElement    *GetBorderColorActControl(void)            { return &this.m_color_border_act;                                                  }

//--- Return the (1) background, (2) foreground and (3) border color
   color             BackColor(void)         const { return(!this.State() ? this.m_color_background.GetCurrent() : this.m_color_background_act.GetCurrent());  }
   color             ForeColor(void)         const { return(!this.State() ? this.m_color_foreground.GetCurrent() : this.m_color_foreground_act.GetCurrent());  }
   color             BorderColor(void)       const { return(!this.State() ? this.m_color_border.GetCurrent()     : this.m_color_border_act.GetCurrent());      }
   
//--- Return the DEFAULT color of (1) background, (2) foreground, (3) border
   color             BackColorDefault(void)  const { return(!this.State() ? this.m_color_background.GetDefault() : this.m_color_background_act.GetDefault());  }
   color             ForeColorDefault(void)  const { return(!this.State() ? this.m_color_foreground.GetDefault() : this.m_color_foreground_act.GetDefault());  }
   color             BorderColorDefault(void)const { return(!this.State() ? this.m_color_border.GetDefault()     : this.m_color_border_act.GetDefault());      }
   
//--- Return the FOCUSED preset color of the (1) background, (2) foreground, (3) border
   color             BackColorFocused(void)  const { return(!this.State() ? this.m_color_background.GetFocused() : this.m_color_background_act.GetFocused());  }
   color             ForeColorFocused(void)  const { return(!this.State() ? this.m_color_foreground.GetFocused() : this.m_color_foreground_act.GetFocused());  }
   color             BorderColorFocused(void)const { return(!this.State() ? this.m_color_border.GetFocused()     : this.m_color_border_act.GetFocused());      }
   
//--- Return the preset PRESSED color of the (1) background, (2) foreground, (3) frame
   color             BackColorPressed(void)  const { return(!this.State() ? this.m_color_background.GetPressed() : this.m_color_background_act.GetPressed());  }
   color             ForeColorPressed(void)  const { return(!this.State() ? this.m_color_foreground.GetPressed() : this.m_color_foreground_act.GetPressed());  }
   color             BorderColorPressed(void)const { return(!this.State() ? this.m_color_border.GetPressed()     : this.m_color_border_act.GetPressed());      }
   
//--- Return the BLOCKED color of (1) background, (2) foreground, (3) border
   color             BackColorBlocked(void)              const { return this.m_color_background.GetBlocked();                                      }
   color             ForeColorBlocked(void)              const { return this.m_color_foreground.GetBlocked();                                      }
   color             BorderColorBlocked(void)            const { return this.m_color_border.GetBlocked();                                          }
   
//--- Set background colors for all states
   void              InitBackColors(const color clr_default, const color clr_focused, const color clr_pressed, const color clr_blocked)
                       {
                        this.m_color_background.InitColors(clr_default,clr_focused,clr_pressed,clr_blocked);
                       }
   void              InitBackColors(const color clr)           { this.m_color_background.InitColors(clr);                                          }

//--- Set foreground colors for all states
   void              InitForeColors(const color clr_default, const color clr_focused, const color clr_pressed, const color clr_blocked)
                       {
                        this.m_color_foreground.InitColors(clr_default,clr_focused,clr_pressed,clr_blocked);
                       }
   void              InitForeColors(const color clr)           { this.m_color_foreground.InitColors(clr);                                          }

//--- Set border colors for all states
   void              InitBorderColors(const color clr_default, const color clr_focused, const color clr_pressed, const color clr_blocked)
                       {
                        this.m_color_border.InitColors(clr_default,clr_focused,clr_pressed,clr_blocked);
                       }
   void              InitBorderColors(const color clr)         { this.m_color_border.InitColors(clr);                                              }

//--- Initialize the color of (1) background, (2) foreground and (3) frame with initial values
   void              InitBackColorDefault(const color clr)     { this.m_color_background.InitDefault(clr);                                         }
   void              InitForeColorDefault(const color clr)     { this.m_color_foreground.InitDefault(clr);                                         }
   void              InitBorderColorDefault(const color clr)   { this.m_color_border.InitDefault(clr);                                             }
   
//--- Initialize the color of (1) background, (2) foreground and (3) frame on hover with initial values
   void              InitBackColorFocused(const color clr)     { this.m_color_background.InitFocused(clr);                                         }
   void              InitForeColorFocused(const color clr)     { this.m_color_foreground.InitFocused(clr);                                         }
   void              InitBorderColorFocused(const color clr)   { this.m_color_border.InitFocused(clr);                                             }
   
//--- Initialize the color of (1) background, (2) foreground and (3) frame on click with initial values
   void              InitBackColorPressed(const color clr)     { this.m_color_background.InitPressed(clr);                                         }
   void              InitForeColorPressed(const color clr)     { this.m_color_foreground.InitPressed(clr);                                         }
   void              InitBorderColorPressed(const color clr)   { this.m_color_border.InitPressed(clr);                                             }
   
//--- Initialize the color of (1) background, (2) foreground and (3) frame of a blocked object with initial values
   void              InitBackColorBlocked(const color clr)     { this.m_color_background.InitBlocked(clr);                                         }
   void              InitForeColorBlocked(const color clr)     { this.m_color_foreground.InitBlocked(clr);                                         }
   void              InitBorderColorBlocked(const color clr)   { this.m_color_border.InitBlocked(clr);                                             }
   
//--- Set background colors for all states
   void              InitBackColorsAct(const color clr_default, const color clr_focused, const color clr_pressed, const color clr_blocked)
                       {
                        this.m_color_background_act.InitColors(clr_default,clr_focused,clr_pressed,clr_blocked);
                       }
   void              InitBackColorsAct(const color clr)        { this.m_color_background_act.InitColors(clr);                                      }

//--- Set foreground colors for all states
   void              InitForeColorsAct(const color clr_default, const color clr_focused, const color clr_pressed, const color clr_blocked)
                       {
                        this.m_color_foreground_act.InitColors(clr_default,clr_focused,clr_pressed,clr_blocked);
                       }
   void              InitForeColorsAct(const color clr)        { this.m_color_foreground_act.InitColors(clr);                                      }

//--- Set border colors for all states
   void              InitBorderColorsAct(const color clr_default, const color clr_focused, const color clr_pressed, const color clr_blocked)
                       {
                        this.m_color_border_act.InitColors(clr_default,clr_focused,clr_pressed,clr_blocked);
                       }
   void              InitBorderColorsAct(const color clr)      { this.m_color_border_act.InitColors(clr);                                          }

//--- Initialize the color of (1) background, (2) foreground and (3) frame with initial values
   void              InitBackColorActDefault(const color clr)  { this.m_color_background_act.InitDefault(clr);                                     }
   void              InitForeColorActDefault(const color clr)  { this.m_color_foreground_act.InitDefault(clr);                                     }
   void              InitBorderColorActDefault(const color clr){ this.m_color_border_act.InitDefault(clr);                                         }
   
//--- Initialize the color of (1) background, (2) foreground and (3) frame on hover with initial values
   void              InitBackColorActFocused(const color clr)  { this.m_color_background_act.InitFocused(clr);                                     }
   void              InitForeColorActFocused(const color clr)  { this.m_color_foreground_act.InitFocused(clr);                                     }
   void              InitBorderColorActFocused(const color clr){ this.m_color_border_act.InitFocused(clr);                                         }
   
//--- Initialize the color of (1) background, (2) foreground and (3) frame on click with initial values
   void              InitBackColorActPressed(const color clr)  { this.m_color_background_act.InitPressed(clr);                                     }
   void              InitForeColorActPressed(const color clr)  { this.m_color_foreground_act.InitPressed(clr);                                     }
   void              InitBorderColorActPressed(const color clr){ this.m_color_border_act.InitPressed(clr);                                         }
   
//--- Set the current background color to different states
   bool              BackColorToDefault(void)
                       {
                        return(!this.State() ? this.m_color_background.SetCurrentAs(COLOR_STATE_DEFAULT) :
                                               this.m_color_background_act.SetCurrentAs(COLOR_STATE_DEFAULT));
                       }
   bool              BackColorToFocused(void)
                       {
                        return(!this.State() ? this.m_color_background.SetCurrentAs(COLOR_STATE_FOCUSED) :
                                               this.m_color_background_act.SetCurrentAs(COLOR_STATE_FOCUSED));
                       }
   bool              BackColorToPressed(void)
                       {
                        return(!this.State() ? this.m_color_background.SetCurrentAs(COLOR_STATE_PRESSED) :
                                               this.m_color_background_act.SetCurrentAs(COLOR_STATE_PRESSED));
                       }
   bool              BackColorToBlocked(void)   { return this.m_color_background.SetCurrentAs(COLOR_STATE_BLOCKED);  }
   
//--- Set the current foreground color to different states
   bool              ForeColorToDefault(void)
                       { return(!this.State() ? this.m_color_foreground.SetCurrentAs(COLOR_STATE_DEFAULT) :
                                                this.m_color_foreground_act.SetCurrentAs(COLOR_STATE_DEFAULT));
                       }
   bool              ForeColorToFocused(void)
                       { return(!this.State() ? this.m_color_foreground.SetCurrentAs(COLOR_STATE_FOCUSED) :
                                                this.m_color_foreground_act.SetCurrentAs(COLOR_STATE_FOCUSED));
                       }
   bool              ForeColorToPressed(void)
                       { return(!this.State() ? this.m_color_foreground.SetCurrentAs(COLOR_STATE_PRESSED) :
                                                this.m_color_foreground_act.SetCurrentAs(COLOR_STATE_PRESSED));
                       }
   bool              ForeColorToBlocked(void)   { return this.m_color_foreground.SetCurrentAs(COLOR_STATE_BLOCKED);  }
   
//--- Set the current frame color to different states
   bool              BorderColorToDefault(void)
                       { return(!this.State() ? this.m_color_border.SetCurrentAs(COLOR_STATE_DEFAULT) :
                                                this.m_color_border_act.SetCurrentAs(COLOR_STATE_DEFAULT));
                       }
   bool              BorderColorToFocused(void)
                       { return(!this.State() ? this.m_color_border.SetCurrentAs(COLOR_STATE_FOCUSED) :
                                                this.m_color_border_act.SetCurrentAs(COLOR_STATE_FOCUSED));
                       }
   bool              BorderColorToPressed(void)
                       { return(!this.State() ? this.m_color_border.SetCurrentAs(COLOR_STATE_PRESSED) :
                                                this.m_color_border_act.SetCurrentAs(COLOR_STATE_PRESSED));
                       }
   bool              BorderColorToBlocked(void) { return this.m_color_border.SetCurrentAs(COLOR_STATE_BLOCKED);      }
   
//--- Set the current colors of the element to different states
   bool              ColorsToDefault(void);
   bool              ColorsToFocused(void);
   bool              ColorsToPressed(void);
   bool              ColorsToBlocked(void);
   
//--- Set the pointer to the parent container object
   void              SetContainerObj(CCanvasBase *obj);
   
protected:
//--- Create background and foreground canvases
   bool              CreateCanvasObjects(void);
//--- Create OBJ_BITMAP_LABEL
   bool              Create(const long chart_id,const int wnd,const string object_name,const int x,const int y,const int w,const int h); 
public:
//--- (1) Set and (2) return the state
   void              SetState(ENUM_ELEMENT_STATE state)        { this.m_state=state; this.ColorsToDefault();                                       }
   ENUM_ELEMENT_STATE State(void)                        const { return this.m_state;                                                              }

//--- (1) Set and (2) return z-order
   bool              ObjectSetZOrder(const int value);
   int               ObjectZOrder(void)                  const { return this.m_z_order;                                                            }
   
//--- Return (1) the object's belonging to the program, the flag (2) of a hidden element, (3) a blocked element,
//--- (4) moved, (5) resized, (6) main element, (7) in focus, (8, 9) graphical object name (background, text)
   bool              IsBelongsToThis(const string name)  const { return(::ObjectGetString(this.m_chart_id,name,OBJPROP_TEXT)==this.m_program_name);}
   bool              IsHidden(void)                      const { return this.m_hidden;                                                             }
   bool              IsBlocked(void)                     const { return this.m_blocked;                                                            }
   bool              IsMovable(void)                     const { return this.m_movable;                                                            }
   bool              IsResizable(void)                   const { return this.m_resizable;                                                          }
   bool              IsMain(void)                        const { return this.m_main;                                                               }
   bool              IsFocused(void)                     const { return this.m_focused;                                                            }
   bool              IsAutorepeat(void)                  const { return this.m_autorepeat_flag;                                                    }
   bool              IsScrollable(void)                  const { return this.m_scroll_flag;                                                        }
   bool              IsTrimmed(void)                     const { return this.m_trim_flag;                                                          }
   bool              IsCropped(void)                     const { return this.m_cropped;                                                            }
   string            NameBG(void)                        const { return this.m_background.ChartObjectName();                                       }
   string            NameFG(void)                        const { return this.m_foreground.ChartObjectName();                                       }
   
//--- (1) Return and (2) set background transparency
   uchar             AlphaBG(void)                       const { return this.m_alpha_bg;                                                           }
   void              SetAlphaBG(const uchar value)             { this.m_alpha_bg=value;                                                            }
//--- (1) Return and (2) set the foreground transparency
   uchar             AlphaFG(void)                       const { return this.m_alpha_fg;                                                           }
   void              SetAlphaFG(const uchar value)             { this.m_alpha_fg=value;                                                            }

//--- Sets the background and foreground transparency
   void              SetAlpha(const uchar value)               { this.m_alpha_fg=this.m_alpha_bg=value;                                            }
   
//--- (1) Return and (2) set the left border width
    uint             BorderWidthLeft(void)               const { return this.m_border_width_lt;                                                    } 
    void             SetBorderWidthLeft(const uint width)      { this.m_border_width_lt=width;                                                     }
    
//--- (1) Return and (2) set the right border width
    uint             BorderWidthRight(void)              const { return this.m_border_width_rt;                                                    } 
    void             SetBorderWidthRight(const uint width)     { this.m_border_width_rt=width;                                                     }
                      
//--- (1) Return and (2) set the top border width
    uint             BorderWidthTop(void)                const { return this.m_border_width_up;                                                    } 
    void             SetBorderWidthTop(const uint width)       { this.m_border_width_up=width;                                                     }
                      
//--- (1) Return and (2) set the bottom border width
    uint             BorderWidthBottom(void)             const { return this.m_border_width_dn;                                                    } 
    void             SetBorderWidthBottom(const uint width)    { this.m_border_width_dn=width;                                                     }
                      
//--- Set the same border width on all sides
    void             SetBorderWidth(const uint width)
                       {
                        this.m_border_width_lt=this.m_border_width_rt=this.m_border_width_up=this.m_border_width_dn=width;
                       }
                      
//--- Set the frame width
    void             SetBorderWidth(const uint left,const uint right,const uint top,const uint bottom)
                       {
                        this.m_border_width_lt=left;
                        this.m_border_width_rt=right;
                        this.m_border_width_up=top;
                        this.m_border_width_dn=bottom;
                       }
    
//--- Return the object boundaries considering the frame
   int               LimitLeft(void)                     const { return this.ObjectX()+(int)this.m_border_width_lt;                                }
   int               LimitRight(void)                    const { return this.ObjectRight()-(int)this.m_border_width_rt;                            }
   int               LimitTop(void)                      const { return this.ObjectY()+(int)this.m_border_width_up;                                }
   int               LimitBottom(void)                   const { return this.ObjectBottom()-(int)this.m_border_width_dn;                           }
   
//--- Set (1) movability, (2) main object flag for the object and (3) resizability,
//--- (4) auto-repeat events, (5) scrolling within the container and (6) clipping by the container borders
   void              SetMovable(const bool flag)               { this.m_movable=flag;                                                              }
   void              SetAsMain(void)                           { this.m_main=true;                                                                 }
   virtual void      SetResizable(const bool flag)             { this.m_resizable=flag;                                                            }
   void              SetAutorepeat(const bool flag)            { this.m_autorepeat_flag=flag;                                                      }
   void              SetScrollable(const bool flag)            { this.m_scroll_flag=flag;                                                          }
   virtual void      SetTrimmered(const bool flag)             { this.m_trim_flag=flag;                                                            }
   void              SetCropped(const bool flag)               { this.m_cropped=flag;                                                              }
   
//--- Return the flag that the object is located outside its container
   virtual bool      IsOutOfContainer(void);
//--- Limit the graphical object by the container dimensions
   virtual bool      ObjectTrim(void);
   
//--- Resize the object
   virtual bool      ResizeW(const int w);
   virtual bool      ResizeH(const int h);
   virtual bool      Resize(const int w,const int h);

//--- Set the new (1) X, (2) Y, (3) XY coordinate for the object
   virtual bool      MoveX(const int x);
   virtual bool      MoveY(const int y);
   virtual bool      Move(const int x,const int y);
   
//--- Set both the element coordinates and dimensions
   virtual bool      MoveXYWidthResize(const int x,const int y,const int w,const int h);
   
//--- Shift the object by (1) X, (2) Y, (3) XY xis by the specified offset

   virtual bool      ShiftX(const int dx);
   virtual bool      ShiftY(const int dy);
   virtual bool      Shift(const int dx,const int dy);
   
//--- (1) Hide and (2) display the object on all chart periods,
//--- (3) bring the object to the front, (4) block, (5) unblock the element,
//--- (6) fill the object with the specified color with the set transparency
   virtual void      Hide(const bool chart_redraw);
   virtual void      Show(const bool chart_redraw);
   virtual void      BringToTop(const bool chart_redraw);
   virtual void      Block(const bool chart_redraw);
   virtual void      Unblock(const bool chart_redraw);
   void              Fill(const color clr,const bool chart_redraw);
   
//--- (1) Fill the object with a transparent color, (2) update the object to reflect the changes,
//--- (3) draw the appearance and (4) destroy the object
   virtual void      Clear(const bool chart_redraw);
   virtual void      Update(const bool chart_redraw);
   virtual void      Draw(const bool chart_redraw);
   virtual void      Destroy(void);
   
//--- Return the object description
   virtual string    Description(void);
   
//--- Virtual methods of (1) comparing, (2) saving to file, (3) loading from file, (4) object type
   virtual int       Compare(const CObject *node,const int mode=0) const;
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);
   virtual int       Type(void)                          const { return(ELEMENT_TYPE_CANVAS_BASE); }
   
//--- Event handler
   virtual void      OnChartEvent(const int id,const long& lparam,const double& dparam,const string& sparam);
   
//--- (1) Timer and (2) timer event handler
   virtual void      OnTimer()                                 { this.TimerEventHandler();         }
   virtual void      TimerEventHandler(void)                   { return;                           }
   
//--- Constructors/destructor
                     CCanvasBase(void) :
                        m_program_name(::MQLInfoString(MQL_PROGRAM_NAME)), m_chart_id(::ChartID()), m_wnd(0), m_alpha_bg(0), m_alpha_fg(255), 
                        m_hidden(false), m_blocked(false), m_focused(false), m_movable(false), m_resizable(false), m_main(false), 
                        m_autorepeat_flag(false), m_trim_flag(true), m_cropped(false), m_scroll_flag(false),
                        m_border_width_lt(0), m_border_width_rt(0), m_border_width_up(0), m_border_width_dn(0), m_z_order(0),
                        m_state(0), m_wnd_y(0), m_cursor_delta_x(0), m_cursor_delta_y(0) { this.CreateCanvasObjects(); this.Init(); }
                     CCanvasBase(const string object_name,const long chart_id,const int wnd,const int x,const int y,const int w,const int h);
                    ~CCanvasBase(void);
  };
//+------------------------------------------------------------------+
//| CCanvasBase::Constructor                                         |
//+------------------------------------------------------------------+
CCanvasBase::CCanvasBase(const string object_name,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) :
   m_program_name(::MQLInfoString(MQL_PROGRAM_NAME)), m_wnd(wnd<0 ? 0 : wnd), m_alpha_bg(0), m_alpha_fg(255),
   m_hidden(false), m_blocked(false), m_focused(false), m_movable(false), m_resizable(false), m_main(false), 
   m_autorepeat_flag(false), m_trim_flag(true), m_cropped(false), m_scroll_flag(false),
   m_border_width_lt(0), m_border_width_rt(0), m_border_width_up(0), m_border_width_dn(0), m_z_order(0),
   m_state(0), m_cursor_delta_x(0), m_cursor_delta_y(0)
  {
//--- Get the adjusted chart ID and the distance in pixels along the vertical Y axis
//--- between the upper frame of the indicator subwindow and the upper frame of the chart main window
   this.m_chart_id=this.CorrectChartID(chart_id);
   
//--- If failed to create canvases, leave
   if(!this.CreateCanvasObjects())
      return;
      
//--- If the graphical resource and graphical object are created
   if(this.Create(this.m_chart_id,this.m_wnd,object_name,x,y,w,h))
     {
      //--- Clear the background and foreground canvases and set the initial coordinate values,
      //--- names of graphic objects and properties of text drawn in the foreground
      this.Clear(false);
      this.m_obj_x=x;
      this.m_obj_y=y;
      this.m_color_background.SetName("Background");
      this.m_color_foreground.SetName("Foreground");
      this.m_color_border.SetName("Border");
      this.m_foreground.FontSet(DEF_FONTNAME,-DEF_FONTSIZE*10,FW_MEDIUM);
      this.m_bound.SetName("Perimeter");
      
      //--- Remember permissions for the mouse and chart tools
      this.Init();
     }
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Destructor                                          |
//+------------------------------------------------------------------+
CCanvasBase::~CCanvasBase(void)
  {
//--- Destroy the object
   this.Destroy();
//--- Return permissions for the mouse and chart tools
   ::ChartSetInteger(this.m_chart_id, CHART_EVENT_MOUSE_WHEEL, this.m_chart_mouse_wheel_flag);
   ::ChartSetInteger(this.m_chart_id, CHART_EVENT_MOUSE_MOVE, this.m_chart_mouse_move_flag);
   ::ChartSetInteger(this.m_chart_id, CHART_EVENT_OBJECT_CREATE, this.m_chart_object_create_flag);
   ::ChartSetInteger(this.m_chart_id, CHART_MOUSE_SCROLL, this.m_chart_mouse_scroll_flag);
   ::ChartSetInteger(this.m_chart_id, CHART_CONTEXT_MENU, this.m_chart_context_menu_flag);
   ::ChartSetInteger(this.m_chart_id, CHART_CROSSHAIR_TOOL, this.m_chart_crosshair_tool_flag);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Compare two objects                                 |
//+------------------------------------------------------------------+
int CCanvasBase::Compare(const CObject *node,const int mode=0) const
  {
   if(node==NULL)
      return -1;
   const CCanvasBase *obj=node;
   switch(mode)
     {
      case BASE_SORT_BY_NAME  :  return(this.Name()         >obj.Name()          ? 1 : this.Name()          <obj.Name()          ? -1 : 0);
      case BASE_SORT_BY_X     :  return(this.X()            >obj.X()             ? 1 : this.X()             <obj.X()             ? -1 : 0);
      case BASE_SORT_BY_Y     :  return(this.Y()            >obj.Y()             ? 1 : this.Y()             <obj.Y()             ? -1 : 0);
      case BASE_SORT_BY_WIDTH :  return(this.Width()        >obj.Width()         ? 1 : this.Width()         <obj.Width()         ? -1 : 0);
      case BASE_SORT_BY_HEIGHT:  return(this.Height()       >obj.Height()        ? 1 : this.Height()        <obj.Height()        ? -1 : 0);
      case BASE_SORT_BY_ZORDER:  return(this.ObjectZOrder() >obj.ObjectZOrder()  ? 1 : this.ObjectZOrder()  <obj.ObjectZOrder()  ? -1 : 0);
      default                 :  return(this.ID()           >obj.ID()            ? 1 : this.ID()            <obj.ID()            ? -1 : 0);
     }
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Create background and foreground canvases           |
//+------------------------------------------------------------------+
bool CCanvasBase::CreateCanvasObjects(void)
  {
//--- If both canvases have already been created, or the class does not manage canvases, return 'true'
   if((this.m_background!=NULL && this.m_foreground!=NULL) || !this.m_canvas_owner)
      return true;
//--- Create the background canvas
   this.m_background=new CCanvas();
   if(this.m_background==NULL)
     {
      ::PrintFormat("%s: Error! Failed to create background canvas",__FUNCTION__);
      return false;
     }
//--- Create the foreground canvas
   this.m_foreground=new CCanvas();
   if(this.m_foreground==NULL)
     {
      ::PrintFormat("%s: Error! Failed to create foreground canvas",__FUNCTION__);
      return false;
     }
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Create background and foreground graphical objects  |
//+------------------------------------------------------------------+
bool CCanvasBase::Create(const long chart_id,const int wnd,const string object_name,const int x,const int y,const int w,const int h)
  {
//--- Get the adjusted chart ID
   long id=this.CorrectChartID(chart_id);
//--- Correct the passed object name
   string nm=object_name;
   ::StringReplace(nm," ","");
//--- Create a graphical object name for the background and create a canvas
   string obj_name=nm+"BG";
   if(!this.m_background.CreateBitmapLabel(id,(wnd<0 ? 0 : wnd),obj_name,x,y,(w>0 ? w : 1),(h>0 ? h : 1),COLOR_FORMAT_ARGB_NORMALIZE))
     {
      ::PrintFormat("%s: The CreateBitmapLabel() method of the CCanvas class returned an error creating a \"%s\" graphic object",__FUNCTION__,obj_name);
      return false;
     }
//--- Create a graphical object name for the foreground and create a canvas
   obj_name=nm+"FG";
   if(!this.m_foreground.CreateBitmapLabel(id,(wnd<0 ? 0 : wnd),obj_name,x,y,(w>0 ? w : 1),(h>0 ? h : 1),COLOR_FORMAT_ARGB_NORMALIZE))
     {
      ::PrintFormat("%s: The CreateBitmapLabel() method of the CCanvas class returned an error creating a \"%s\" graphic object",__FUNCTION__,obj_name);
      return false;
     }
//--- If created successfully, enter the program name into the OBJPROP_TEXT property of the graphical object
   ::ObjectSetString(id,this.NameBG(),OBJPROP_TEXT,this.m_program_name);
   ::ObjectSetString(id,this.NameFG(),OBJPROP_TEXT,this.m_program_name);
   ::ObjectSetString(id,this.NameBG(),OBJPROP_TOOLTIP,"\n");
   ::ObjectSetString(id,this.NameFG(),OBJPROP_TOOLTIP,"\n");
   ::ObjectSetInteger(id,this.NameBG(),OBJPROP_ZORDER,0);
   ::ObjectSetInteger(id,this.NameFG(),OBJPROP_ZORDER,0);
      
//--- Set the dimensions of the rectangular area and return 'true'
   this.m_bound.SetXY(x,y);
   this.m_bound.Resize(w,h);
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set the pointer                                     |
//| to the parent container object                                   |
//+------------------------------------------------------------------+
void CCanvasBase::SetContainerObj(CCanvasBase *obj)
  {
//--- Set the passed pointer to the object
   this.m_container=obj;
//--- If the pointer is empty, leave
   if(this.m_container==NULL)
      return;
//--- If an invalid pointer is passed, zero it in the object and leave
   if(::CheckPointer(this.m_container)==POINTER_INVALID)
     {
      this.m_container=NULL;
      return;
     }
//--- Clip the object along the boundaries of the container assigned to it
   this.ObjectTrim();
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Return a flag that the object is                    |
//| located outside of its container                                 |
//+------------------------------------------------------------------+
bool CCanvasBase::IsOutOfContainer(void)
  {
//--- Return the result of checking that the object is completely outside the container
   return(this.Right() <= this.ContainerLimitLeft() || this.X() >= this.ContainerLimitRight() ||
          this.Bottom()<= this.ContainerLimitTop()  || this.Y() >= this.ContainerLimitBottom());
  }
//+-----------------------------------------------------------------------+
//| CCanvasBase::Crop a graphical object to the outline of its container  |
//+-----------------------------------------------------------------------+
bool CCanvasBase::ObjectTrim()
  {
//--- Check the element cropping permission flag and
//--- if the element should not be clipped by the container borders, return 'false'
   if(!this.m_trim_flag)
      return false;
//--- Get the container boundaries
   int container_left   = this.ContainerLimitLeft();
   int container_right  = this.ContainerLimitRight();
   int container_top    = this.ContainerLimitTop();
   int container_bottom = this.ContainerLimitBottom();
   
//--- Get the current object boundaries
   int object_left   = this.X();
   int object_right  = this.Right();
   int object_top    = this.Y();
   int object_bottom = this.Bottom();

//--- Check if the object is completely outside the container and hide it if it is
   if(this.IsOutOfContainer())
     {
      //--- Set the flag that the object is outside the container
      this.m_cropped=true;
      //--- Hide the object and restore its dimensions
      this.Hide(false);
      if(this.ObjectResize(this.Width(),this.Height()))
         this.BoundResize(this.Width(),this.Height());
      return true;
     }
//--- The object is fully or partially located within the visible area of the container
   else
     {
      //--- Remove the flag indicating that the object is located outside the container
      this.m_cropped=false;
      //--- If the element is completely inside the container
      if(object_right<=container_right && object_left>=container_left &&
         object_bottom<=container_bottom && object_top>=container_top)
        {
         //--- If the width or height of the graphical object does not match the width or height of the element,
         //--- modify the graphical object according to the element dimensions and return 'true'
         if(this.ObjectWidth()!=this.Width() || this.ObjectHeight()!=this.Height())
           {
            if(this.ObjectResize(this.Width(),this.Height()))
               return true;
           }
        }
      //--- If the element is partially within the container visible area
      else
        {
         //--- If the element is vertically within the container visible area
         if(object_bottom<=container_bottom && object_top>=container_top)
           {
            //--- If the height of the graphic object does not match the height of the element,
            //--- modify the graphical object by the element height
            if(this.ObjectHeight()!=this.Height())
               this.ObjectResizeH(this.Height());
           }
         else
           {
            //--- If the element is horizontally within the container visible area
            if(object_right<=container_right && object_left>=container_left)
              {
               //--- If the width of the graphic object does not match the width of the element,
               //--- modify the graphical object by the element width
               if(this.ObjectWidth()!=this.Width())
                  this.ObjectResizeW(this.Width());
              }
           }
        }
     }
     
//--- Check whether the object extends horizontally and vertically beyond the container boundaries
   bool modified_horizontal=false;     // Horizontal change flag
   bool modified_vertical  =false;     // Vertical change flag
   
//--- Horizontal cropping
   int new_left = object_left;
   int new_width = this.Width();
//--- If the object extends beyond the container left border
   if(object_left<=container_left)
     {
      int crop_left=container_left-object_left;
      new_left=container_left;
      new_width-=crop_left;
      modified_horizontal=true;
     }
//--- If the object extends beyond the container right border
   if(object_right>=container_right)
     {
      int crop_right=object_right-container_right;
      new_width-=crop_right;
      modified_horizontal=true;
     }
//--- If there were changes horizontally
   if(modified_horizontal)
     {
      this.ObjectSetX(new_left);
      this.ObjectResizeW(new_width);
     }

//--- Vertical cropping
   int new_top=object_top;
   int new_height=this.Height();
//--- If the object extends beyond the top edge of the container
   if(object_top<=container_top)
     {
      int crop_top=container_top-object_top;
      new_top=container_top;
      new_height-=crop_top;
      modified_vertical=true;
     }
//--- If the object extends beyond the bottom border of the container 
   if(object_bottom>=container_bottom)
     {
      int crop_bottom=object_bottom-container_bottom;
      new_height-=crop_bottom;
      modified_vertical=true;
     }
//--- If there were vertical changes
   if(modified_vertical)
     {
      this.ObjectSetY(new_top);
      this.ObjectResizeH(new_height);
     }

//--- After calculations, the object may be hidden, but is now in the container area - display it
   this.Show(false);
      
//--- If the object has been changed, redraw it
   if(modified_horizontal || modified_vertical)
     {
      this.Update(false);
      this.Draw(false);
      return true;
     }

   return false;
  }
//+-----------------------------------------------------------------------------------+
//| CCanvasBase::Return the flag indicating whether the cursor is inside the object   |
//+-----------------------------------------------------------------------------------+
bool CCanvasBase::Contains(const int x,const int y)
  {
   int left=::fmax(this.X(),this.ObjectX());
   int right=::fmin(this.Right(),this.ObjectRight());
   int top=::fmax(this.Y(),this.ObjectY());
   int bottom=::fmin(this.Bottom(),this.ObjectBottom());
   return(x>=left && x<=right && y>=top && y<=bottom);
  }
//+--------------------------------------------------------------------+
//|CCanvasBase::Return the cursor location on the object borders       |
//+--------------------------------------------------------------------+
ENUM_CURSOR_REGION CCanvasBase::CheckResizeZone(const int x,const int y)
  {
//--- Coordinates of the element borders
   int top=this.Y();
   int bottom=this.Bottom();
   int left=this.X();
   int right=this.Right();
   
//--- If outside the object, return CURSOR_REGION_NONE
   if(x<left || x>right || y<top || y>bottom)
      return CURSOR_REGION_NONE;

//--- Left edge and corners
   if(x>=left && x<=left+DEF_EDGE_THICKNESS)
     {
      //--- Upper left corner
      if(y>=top && y<=top+DEF_EDGE_THICKNESS)
         return CURSOR_REGION_LEFT_TOP;
      //--- Bottom left corner
      if(y>=bottom-DEF_EDGE_THICKNESS && y<=bottom)
         return CURSOR_REGION_LEFT_BOTTOM;
      //--- Left edge
      return CURSOR_REGION_LEFT;
     }
   
//--- Right edge and corners
   if(x>=right-DEF_EDGE_THICKNESS && x<=right)
     {
      //--- Upper right corne
      if(y>=top && y<=top+DEF_EDGE_THICKNESS)
         return CURSOR_REGION_RIGHT_TOP;
      //--- Bottom right corner
      if(y>=bottom-DEF_EDGE_THICKNESS && y<=bottom)
         return CURSOR_REGION_RIGHT_BOTTOM;
      //--- Right side
      return CURSOR_REGION_RIGHT;
     }
     
//--- Upper edge
   if(y>=top && y<=top+DEF_EDGE_THICKNESS)
      return CURSOR_REGION_TOP;

//--- Bottom edge
   if(y>=bottom-DEF_EDGE_THICKNESS && y<=bottom)
      return CURSOR_REGION_BOTTOM;

//--- The cursor is not on the edges of the element
   return CURSOR_REGION_NONE;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set the z-order of a graphical object               |
//+------------------------------------------------------------------+
bool CCanvasBase::ObjectSetZOrder(const int value)
  {
//--- If an already set value is passed, return 'true'
   if(this.ObjectZOrder()==value)
      return true;
//--- If failed to set a new value to the background and foreground graphical objects, return 'false'
   if(!::ObjectSetInteger(this.m_chart_id,this.NameBG(),OBJPROP_ZORDER,value) || !::ObjectSetInteger(this.m_chart_id,this.NameFG(),OBJPROP_ZORDER,value))
      return false;
//--- Set the new z-order value to the variable and return 'true'
   this.m_z_order=value;
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set the X coordinate of the graphical object        |
//+------------------------------------------------------------------+
bool CCanvasBase::ObjectSetX(const int x)
  {
//--- If an existing coordinate is passed, return 'true' 
   if(this.ObjectX()==x)
      return true;
//--- If failed to set a new coordinate in the background and foreground graphical objects, return 'false'
   if(!::ObjectSetInteger(this.m_chart_id,this.NameBG(),OBJPROP_XDISTANCE,x) || !::ObjectSetInteger(this.m_chart_id,this.NameFG(),OBJPROP_XDISTANCE,x))
      return false;
//--- Set the new coordinate to the variable and return 'true'
   this.m_obj_x=x;
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set the Y coordinate of the graphical object        |
//+------------------------------------------------------------------+
bool CCanvasBase::ObjectSetY(const int y)
  {
//--- If an existing coordinate is passed, return 'true'
   if(this.ObjectY()==y)
      return true;
//--- If failed to set a new coordinate in the background and foreground graphical objects, return 'false'
   if(!::ObjectSetInteger(this.m_chart_id,this.NameBG(),OBJPROP_YDISTANCE,y) || !::ObjectSetInteger(this.m_chart_id,this.NameFG(),OBJPROP_YDISTANCE,y))
      return false;
//--- Set the new coordinate to the variable and return 'true'
   this.m_obj_y=y;
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Change the graphical object width                   |
//+------------------------------------------------------------------+
bool CCanvasBase::ObjectResizeW(const int size)
  {
//--- If an existing width is passed, return 'true'
   if(this.ObjectWidth()==size)
      return true;
//--- If the passed size is greater than 0, return the result of changing the background and foreground widths, otherwise - 'false'
   return(size>0 ? (this.m_background.Resize(size,this.ObjectHeight()) && this.m_foreground.Resize(size,this.ObjectHeight())) : false);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Change the graphical object height                  |
//+------------------------------------------------------------------+
bool CCanvasBase::ObjectResizeH(const int size)
  {
//--- If an existing height is passed, return 'true'
   if(this.ObjectHeight()==size)
      return true;
//--- If the passed size is greater than 0, return the result of changing the background and foreground heights, otherwise - 'false'
   return(size>0 ? (this.m_background.Resize(this.ObjectWidth(),size) && this.m_foreground.Resize(this.ObjectWidth(),size)) : false);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Change the graphical object size                    |
//+------------------------------------------------------------------+
bool CCanvasBase::ObjectResize(const int w,const int h)
  {
   if(!this.ObjectResizeW(w))
      return false;
   return this.ObjectResizeH(h);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set coordinates                                     |
//| and size of the graphical object simultaneously                  |
//+------------------------------------------------------------------+
bool CCanvasBase::ObjectSetXYWidthResize(const int x,const int y,const int w,const int h)
  {
//--- If new coordinates are set, return the resize result
   if(this.ObjectSetXY(x,y))
      return this.ObjectResize(w,h);
//--- Failed to set new coordinates - return 'false'
   return false;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Change the object width                             |
//+------------------------------------------------------------------+
bool CCanvasBase::ResizeW(const int w)
  {
   if(!this.ObjectResizeW(w))
      return false;
   this.BoundResizeW(w);
   if(!this.ObjectTrim())
     {
      this.Update(false);
      this.Draw(false);
     }
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Change the object height                            |
//+------------------------------------------------------------------+
bool CCanvasBase::ResizeH(const int h)
  {
   if(!this.ObjectResizeH(h))
      return false;
   this.BoundResizeH(h);
   if(!this.ObjectTrim())
     {
      this.Update(false);
      this.Draw(false);
     }
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Resize the object                                   |
//+------------------------------------------------------------------+
bool CCanvasBase::Resize(const int w,const int h)
  {
   if(!this.ObjectResize(w,h))
      return false;
   this.BoundResize(w,h);
   if(!this.ObjectTrim())
     {
      this.Update(false);
      this.Draw(false);
     }
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set new X and Y object coordinates                  |
//+------------------------------------------------------------------+
bool CCanvasBase::Move(const int x,const int y)
  {
   if(!this.ObjectMove(x,y))
      return false;
   this.BoundMove(x,y);
   this.ObjectTrim();
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set the object new X coordinate                     |
//+------------------------------------------------------------------+
bool CCanvasBase::MoveX(const int x)
  {
   return this.Move(x,this.AdjY(this.ObjectY()));
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set the object new Y coordinate                     |
//+------------------------------------------------------------------+
bool CCanvasBase::MoveY(const int y)
  {
   return this.Move(this.AdjX(this.ObjectX()),y);
  }
//+--------------------------------------------------------------------------------+
//| CCanvasBase::Offset the object along the X and Y axes by the specified offset  |
//+--------------------------------------------------------------------------------+
bool CCanvasBase::Shift(const int dx,const int dy)
  {
   if(!this.ObjectShift(dx,dy))
      return false;
   this.BoundShift(dx,dy);
   this.ObjectTrim();
   return true;
  }
//+-------------------------------------------------------------------------------+
//| CCanvasBase::Offset the object along the X axis by the specified offset       |
//+-------------------------------------------------------------------------------+
bool CCanvasBase::ShiftX(const int dx)
  {
   return this.Shift(dx,0);
  }
//+-------------------------------------------------------------------------------+
//| CCanvasBase::Offset the object along the Y axis by the specified offset       |
//+-------------------------------------------------------------------------------+
bool CCanvasBase::ShiftY(const int dy)
  {
   return this.Shift(0,dy);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set both the element coordinates and dimensions     |
//+------------------------------------------------------------------+
bool CCanvasBase::MoveXYWidthResize(const int x,const int y,const int w,const int h)
  {
   if(!this.ObjectSetXYWidthResize(x,y,w,h))
      return false;
   this.BoundMove(x,y);
   this.BoundResize(w,h);
   if(!this.ObjectTrim())
     {
      this.Update(false);
      this.Draw(false);
     }
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Hide the object on all chart periods                |
//+------------------------------------------------------------------+
void CCanvasBase::Hide(const bool chart_redraw)
  {
//--- If the object is already hidden, leave
   if(this.m_hidden)
      return;
//--- If the visibility change for background and foreground is successfully set
//--- in the chart command queue - set the hidden object flag
   if(::ObjectSetInteger(this.m_chart_id,this.NameBG(),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS) &&
      ::ObjectSetInteger(this.m_chart_id,this.NameFG(),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS)
      ) this.m_hidden=true;
//--- If specified, redraw the chart
   if(chart_redraw)
      ::ChartRedraw(this.m_chart_id);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Display an object on all chart periods              |
//+------------------------------------------------------------------+
void CCanvasBase::Show(const bool chart_redraw)
  {
//--- If the object is already visible, leave
   if(!this.m_hidden)
      return;
//--- If the visibility change for background and foreground is successfully set
//--- in the chart command queue - reset the hidden object flag
   if(::ObjectSetInteger(this.m_chart_id,this.NameBG(),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS) &&
      ::ObjectSetInteger(this.m_chart_id,this.NameFG(),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS)
      ) this.m_hidden=false;
//--- If specified, redraw the chart
   if(chart_redraw)
      ::ChartRedraw(this.m_chart_id);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Bring an object to the foreground                   |
//+------------------------------------------------------------------+
void CCanvasBase::BringToTop(const bool chart_redraw)
  {
   if(this.m_cropped)
      return;
   this.Hide(false);
   this.Show(chart_redraw);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Block the element                                   |
//+------------------------------------------------------------------+
void CCanvasBase::Block(const bool chart_redraw)
  {
//--- If the element has already been blocked, leave
   if(this.m_blocked)
      return;
//--- Set the current colors as the colors of the blocked element, 
//--- set the lock flag and redraw the object
   this.ColorsToBlocked();
   this.m_blocked=true;
   this.Draw(chart_redraw);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Unblock the element                                 |
//+------------------------------------------------------------------+
void CCanvasBase::Unblock(const bool chart_redraw)
  {
//--- If the element has already been unblocked, leave
   if(!this.m_blocked)
      return;
//--- Set the current colors as the colors of the element in its normal state, 
//--- redraw the object and reset the block flag
   this.ColorsToDefault();
   this.Draw(chart_redraw);
   this.m_blocked=false;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set the current element colors                      |
//| to default state                                                 |
//+------------------------------------------------------------------+
bool CCanvasBase::ColorsToDefault(void)
  {
   bool res=true;
   res &=this.BackColorToDefault();
   res &=this.ForeColorToDefault();
   res &=this.BorderColorToDefault();
   return res;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set the current element colors                      |
//| to on-hover state                                                |
//+------------------------------------------------------------------+
bool CCanvasBase::ColorsToFocused(void)
  {
   bool res=true;
   res &=this.BackColorToFocused();
   res &=this.ForeColorToFocused();
   res &=this.BorderColorToFocused();
   return res;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set the current element colors                      |
//| to on-click state                                                |
//+------------------------------------------------------------------+
bool CCanvasBase::ColorsToPressed(void)
  {
   bool res=true;
   res &=this.BackColorToPressed();
   res &=this.ForeColorToPressed();
   res &=this.BorderColorToPressed();
   return res;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set the current element colors                      |
//| to blocked state                                                 |
//+------------------------------------------------------------------+
bool CCanvasBase::ColorsToBlocked(void)
  {
   bool res=true;
   res &=this.BackColorToBlocked();
   res &=this.ForeColorToBlocked();
   res &=this.BorderColorToBlocked();
   return res;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Fill an object with the specified color             |
//| with transparency set to m_alpha                                 |
//+------------------------------------------------------------------+
void CCanvasBase::Fill(const color clr,const bool chart_redraw)
  {
   this.m_background.Erase(::ColorToARGB(clr,this.m_alpha_bg));
   this.m_background.Update(chart_redraw);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Fill an object with transparent color               |
//+------------------------------------------------------------------+
void CCanvasBase::Clear(const bool chart_redraw)
  {
   this.m_background.Erase(clrNULL);
   this.m_foreground.Erase(clrNULL);
   this.Update(chart_redraw);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Update the object to display the changes            |
//+------------------------------------------------------------------+
void CCanvasBase::Update(const bool chart_redraw)
  {
   this.m_background.Update(false);
   this.m_foreground.Update(chart_redraw);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Draw the appearance                                 |
//+------------------------------------------------------------------+
void CCanvasBase::Draw(const bool chart_redraw)
  {
   return;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Destroy the object                                  |
//+------------------------------------------------------------------+
void CCanvasBase::Destroy(void)
  {
   if(this.m_canvas_owner)
     {
      this.m_background.Destroy();
      this.m_foreground.Destroy();
      delete this.m_background;
      delete this.m_foreground;
      this.m_background=NULL;
      this.m_foreground=NULL;
     }
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Return the object description                       |
//+------------------------------------------------------------------+
string CCanvasBase::Description(void)
  {
   string nm=this.Name();
   string name=(nm!="" ? ::StringFormat(" \"%s\"",nm) : nm);
   string area=::StringFormat("x %d, y %d, w %d, h %d",this.X(),this.Y(),this.Width(),this.Height());
   return ::StringFormat("%s%s (%s, %s): ID %d, %s",ElementDescription((ENUM_ELEMENT_TYPE)this.Type()),name,this.NameBG(),this.NameFG(),this.ID(),area);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Save to file                                        |
//+------------------------------------------------------------------+
bool CCanvasBase::Save(const int file_handle)
  {
//--- Method temporarily disabled
   return false;
   
//--- Save the parent object data
   if(!CBaseObj::Save(file_handle))
      return false;
/*
//--- Store the properties
      
*/
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Load from file                                      |
//+------------------------------------------------------------------+
bool CCanvasBase::Load(const int file_handle)
  {
//--- Method temporarily disabled
   return false;
   
//--- Load parent object data
   if(!CBaseObj::Load(file_handle))
      return false;
/*
//--- Load properties
   
*/
//--- All is successful
   return true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Set chart restrictions                              |
//| (wheel scrolling, context menu and crosshair)                    |
//+------------------------------------------------------------------+
void CCanvasBase::SetFlags(const bool flag)
  {
//--- If you need to set flags, and they have already been set before, leave
   if(flag && this.m_flags_state)
      return;
//--- If we need to reset the flags, and they have already been reset earlier, leave
   if(!flag && !this.m_flags_state)
      return;
//--- Set the required flag for the context menu,
//--- crosshair tool and scrolling the chart with the mouse wheel.
//--- After installation, remember the value of the set flag
   ::ChartSetInteger(this.m_chart_id, CHART_CONTEXT_MENU,  flag);
   ::ChartSetInteger(this.m_chart_id, CHART_CROSSHAIR_TOOL,flag);
   ::ChartSetInteger(this.m_chart_id, CHART_MOUSE_SCROLL,  flag);
   this.m_flags_state=flag;
//--- Update the chart to immediately apply the set flags
   ::ChartRedraw(this.m_chart_id);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Class initialization                                |
//+------------------------------------------------------------------+
void CCanvasBase::Init(void)
  {
//--- Remember permissions for the mouse and chart tools
   this.m_chart_mouse_wheel_flag   = ::ChartGetInteger(this.m_chart_id, CHART_EVENT_MOUSE_WHEEL);
   this.m_chart_mouse_move_flag    = ::ChartGetInteger(this.m_chart_id, CHART_EVENT_MOUSE_MOVE);
   this.m_chart_object_create_flag = ::ChartGetInteger(this.m_chart_id, CHART_EVENT_OBJECT_CREATE);
   this.m_chart_mouse_scroll_flag  = ::ChartGetInteger(this.m_chart_id, CHART_MOUSE_SCROLL);
   this.m_chart_context_menu_flag  = ::ChartGetInteger(this.m_chart_id, CHART_CONTEXT_MENU);
   this.m_chart_crosshair_tool_flag= ::ChartGetInteger(this.m_chart_id, CHART_CROSSHAIR_TOOL);
//--- Set permissions for the mouse and chart
   ::ChartSetInteger(this.m_chart_id, CHART_EVENT_MOUSE_WHEEL, true);
   ::ChartSetInteger(this.m_chart_id, CHART_EVENT_MOUSE_MOVE, true);
   ::ChartSetInteger(this.m_chart_id, CHART_EVENT_OBJECT_CREATE, true);

//--- Initialize the object default colors
   this.InitColors();
//--- Initialize the millisecond timer
   ::EventSetMillisecondTimer(16);
   
//--- Canvas ownership flag
   this.m_canvas_owner=true;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Initialize the object default colors                |
//+------------------------------------------------------------------+
void CCanvasBase::InitColors(void)
  {
//--- Initialize the background colors for the normal and activated states and make it the current background color
   this.InitBackColors(clrWhiteSmoke);
   this.InitBackColorsAct(clrWhiteSmoke);
   this.BackColorToDefault();
   
//--- Initialize the foreground colors for the normal and activated states and make it the current text color
   this.InitForeColors(clrBlack);
   this.InitForeColorsAct(clrBlack);
   this.ForeColorToDefault();
   
//--- Initialize the border colors for the normal and activated states and make it the current border color
   this.InitBorderColors(clrDarkGray);
   this.InitBorderColorsAct(clrDarkGray);
   this.BorderColorToDefault();
   
//--- Initialize the border color and foreground color for the disabled element
   this.InitBorderColorBlocked(clrLightGray);
   this.InitForeColorBlocked(clrSilver);
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Check if the set color is equal to the specified one|
//+------------------------------------------------------------------+
bool CCanvasBase::CheckColor(const ENUM_COLOR_STATE state) const
  {
   bool res=true;
 //--- Depending on the event being checked
   switch(state)
     {
//--- check that all STANDARD background, text, and frame colors are equal to the preset values
      case COLOR_STATE_DEFAULT :
        res &=this.BackColor()==this.BackColorDefault();
        res &=this.ForeColor()==this.ForeColorDefault();
        res &=this.BorderColor()==this.BorderColorDefault();
        break;

//--- check if all FOCUSED background, text, and border colors are equal to the preset values
      case COLOR_STATE_FOCUSED :
        res &=this.BackColor()==this.BackColorFocused();
        res &=this.ForeColor()==this.ForeColorFocused();
        res &=this.BorderColor()==this.BorderColorFocused();
        break;
     
//--- check if all PRESSED background, text, and border colors are equal to the preset values
      case COLOR_STATE_PRESSED :
        res &=this.BackColor()==this.BackColorPressed();
        res &=this.ForeColor()==this.ForeColorPressed();
        res &=this.BorderColor()==this.BorderColorPressed();
        break;
     
//--- check if all BLOCKED background, text, and border colors are equal to the preset values
      case COLOR_STATE_BLOCKED :
        res &=this.BackColor()==this.BackColorBlocked();
        res &=this.ForeColor()==this.ForeColorBlocked();
        res &=this.BorderColor()==this.BorderColorBlocked();
        break;
        
      default: res=false;
        break;
     }
   return res;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Change the color of object elements by event        |
//+------------------------------------------------------------------+
void CCanvasBase::ColorChange(const ENUM_COLOR_STATE state)
  {
//--- Depending on the event, set the event colors as primary ones
   switch(state)
     {
      case COLOR_STATE_DEFAULT   :  this.ColorsToDefault(); break;
      case COLOR_STATE_FOCUSED   :  this.ColorsToFocused(); break;
      case COLOR_STATE_PRESSED   :  this.ColorsToPressed(); break;
      case COLOR_STATE_BLOCKED   :  this.ColorsToBlocked(); break;
      default                    :  break;
     }
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Event handler                                       |
//+------------------------------------------------------------------+
void CCanvasBase::OnChartEvent(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
//--- If at the moment of launching the terminal with the indicator the height of the subwindow has not yet been determined,
//--- adjust the distance between the top frame of the indicator subwindow and the top frame of the main window
   if(this.m_wnd>0 && this.m_wnd_y==0)
      this.m_wnd_y=(int)::ChartGetInteger(this.m_chart_id,CHART_WINDOW_YDISTANCE,this.m_wnd);

//--- Chart change event
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- adjust the distance between the upper frame of the indicator subwindow and the upper frame of the chart main window
      this.m_wnd_y=(int)::ChartGetInteger(this.m_chart_id,CHART_WINDOW_YDISTANCE,this.m_wnd);
     }
     
//--- Graphical object creation event
   if(id==CHARTEVENT_OBJECT_CREATE)
     {
      //--- If this is not a container element, leave
      if(this.Type()<ELEMENT_TYPE_PANEL)
         return;
      //--- Call the handler for creating the graphical object
      this.OnCreateEvent(id,lparam,dparam,sparam);
     }

//--- If the element is blocked or hidden, leave
   if(this.IsBlocked() || this.IsHidden())
      return;
      
//--- Mouse cursor coordinates
   int x=(int)lparam;
   int y=(int)dparam-this.m_wnd_y;  // Adjust Y by the height of the indicator window 
   
//--- Cursor move event
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Send the cursor coordinates to the resource manager
      CCommonManager::GetInstance().SetCursorX(x);
      CCommonManager::GetInstance().SetCursorY(y);

      //--- Do not handle inactive elements, except for the main one
      if(!this.IsMain() && (this.Type()<ACTIVE_ELEMENT_MIN || this.Type()>ACTIVE_ELEMENT_MAX))
         return;

      //--- Hold down the mouse button
      if(sparam=="1")
        {
         //--- Cursor within the object
         if(this.Contains(x, y))
           {
            //--- If this is the main object, disable the chart tools
            if(this.IsMain())
               this.SetFlags(false);
            
            //--- If the mouse button was clicked on the chart, there is nothing to handle, leave
            if(this.ActiveElementName()=="Chart")
               return;
               
            //--- Fix the name of the active element over which the cursor was when the mouse button was clicked
            this.SetActiveElementName(this.ActiveElementName());
            //--- If this is the current active element, handle its movement
            if(this.IsCurrentActiveElement())
              {
               this.OnMoveEvent(id,lparam,dparam,sparam);
               
               //--- If the element has auto-repeat events active, indicate that the button is clicked
               if(this.m_autorepeat_flag)
                  this.m_autorepeat.OnButtonPress();
            
               //--- For resizable elements
               if(this.m_resizable)
                 {
                  //--- If the resize mode is not activated,
                  //--- call the resize start handler
                  if(!this.ResizeMode())
                     this.OnResizeZoneEvent(RESIZE_ZONE_ACTION_BEGIN,x,y,this.NameFG());
                  //--- otherwise, when the resizing mode is active
                  //--- call the edge dragging handler for resizing
                  else
                     this.OnResizeZoneEvent(RESIZE_ZONE_ACTION_DRAG,x,y,this.NameFG());
                 }
              }
           }
         //--- Cursor outside the object
         else
           {
            //--- If this is the active main object, or the mouse button is clicked on the chart, and this is not the resizing mode, enable graphical tools
            if(this.IsMain() && (this.ActiveElementName()==this.NameFG() || this.ActiveElementName()=="Chart"))
               if(!this.ResizeMode())
                  this.SetFlags(true);
               
            //--- If this is the current active element
            if(this.IsCurrentActiveElement())
              {
               //--- If the element is not movable
               if(!this.IsMovable())
                 {
                  //--- call the mouse hover handler
                  this.OnFocusEvent(id,lparam,dparam,sparam);
                  //--- If the element has auto-repeat events active, indicate that the button is released
                  if(this.m_autorepeat_flag)
                     this.m_autorepeat.OnButtonRelease();
                 }
               //--- If the element is movable, call the move handler
               else
                  this.OnMoveEvent(id,lparam,dparam,sparam);
            
               //--- For resizable elements
               //--- call the edge dragging handler for resizing
               if(this.m_resizable)
                  this.OnResizeZoneEvent(RESIZE_ZONE_ACTION_DRAG,x,y,this.NameFG());
              }
           }
        }
      
      //--- Mouse button not pressed
      else
        {
         //--- Cursor within the object
         if(this.Contains(x, y))
           {
            //--- If this is the main element, disable the chart tools
            if(this.IsMain())
               this.SetFlags(false);
            
            //--- Call the cursor hover handler and
            //--- set the element as the current active one
            this.OnFocusEvent(id,lparam,dparam,sparam);
            this.SetActiveElementName(this.NameFG());
           
            //--- For resizable elements
            //--- call the handler for hovering the cursor over the resizing area
            if(this.m_resizable)
               this.OnResizeZoneEvent(RESIZE_ZONE_ACTION_HOVER,x,y,this.NameFG());
           }
         
         //--- Cursor outside the object
         else
           {
            //--- If this is the main object
            if(this.IsMain())
              {
               //--- Enable chart tools and
               //--- set the chart as the currently active element
               this.SetFlags(true);
               this.SetActiveElementName("Chart");
              }
            //--- Call the handler for removing the cursor from focus 
            this.OnReleaseEvent(id,lparam,dparam,sparam);
            
            //--- For resizable elements
            //--- call the handler for the non-resizing mode
            if(this.m_resizable)
               this.OnResizeZoneEvent(RESIZE_ZONE_ACTION_NONE,x,y,this.NameFG());
           }
        }
     }
     
//--- Event of clicking the mouse button on an object (releasing the button)
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- If the click (releasing the mouse button) was performed on this object
      if(sparam==this.NameFG())
        {
         //--- Call the mouse click handler and release the current active object
         this.OnPressEvent(id, lparam, dparam, sparam);
         this.SetActiveElementName("");
               
         //--- If the element has auto-repeat events active, indicate that the button is released
         if(this.m_autorepeat_flag)
            this.m_autorepeat.OnButtonRelease();
            
         //--- For resizable elements
         if(this.m_resizable)
           {
            //--- Disable the resizing mode, reset the interaction area,
            //--- call the handler for completing the resizing by dragging the edges
            this.SetResizeMode(false);
            this.SetResizeRegion(CURSOR_REGION_NONE);
            this.OnResizeZoneEvent(RESIZE_ZONE_ACTION_END,x,y,this.NameFG());
           }
        }
     }
   
//--- Mouse wheel scroll event
   if(id==CHARTEVENT_MOUSE_WHEEL)
     {
      //--- If this is an active element, call its scroll wheel event handler
      if(this.IsCurrentActiveElement())
         this.OnWheelEvent(id,lparam,dparam,this.ActiveElementName());  // pass the name of the active element to sparam
     }

//--- If a custom chart event has arrived
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- do not handle its own events
      if(sparam==this.NameFG())
         return;

      //--- bring the custom event in line with the standard ones
      ENUM_CHART_EVENT chart_event=ENUM_CHART_EVENT(id-CHARTEVENT_CUSTOM);
      //--- In case of the mouse click on the object, call the user event handler
      if(chart_event==CHARTEVENT_OBJECT_CLICK)
        {
         this.MousePressHandler(chart_event, lparam, dparam, sparam);
        }
      //--- If the mouse cursor is moving, call the user event handler
      if(chart_event==CHARTEVENT_MOUSE_MOVE)
        {
         this.MouseMoveHandler(chart_event, lparam, dparam, sparam);
        }
      //--- In case of scrolling the mouse wheel, call the user event handle
      if(chart_event==CHARTEVENT_MOUSE_WHEEL)
        {
         this.MouseWheelHandler(chart_event, lparam, dparam, sparam);
        }
      //--- If the graphical element changes, call the user event handler
      if(chart_event==CHARTEVENT_OBJECT_CHANGE)
        {
         this.ObjectChangeHandler(chart_event, lparam, dparam, sparam);
        }
     }
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Out of focus handler                                |
//+------------------------------------------------------------------+
void CCanvasBase::OnReleaseEvent(const int id,const long lparam,const double dparam,const string sparam)
  {
//--- The element is not in focus when the cursor is moved away
   this.m_focused=false;
//--- restore the original colors and redraw the object
   if(!this.CheckColor(COLOR_STATE_DEFAULT))
     {
      this.ColorChange(COLOR_STATE_DEFAULT);
      this.Draw(true);
     }
//--- Initialize the cursor offset from the upper left corner of the element along the X and Y axes
   this.m_cursor_delta_x=0;
   this.m_cursor_delta_y=0;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Hover positioning handler                           |
//+------------------------------------------------------------------+
void CCanvasBase::OnFocusEvent(const int id,const long lparam,const double dparam,const string sparam)
  {
//--- Element in focus
   this.m_focused=true;
//--- If the object colors are not for Focused mode
   if(!this.CheckColor(COLOR_STATE_FOCUSED))
     {
      //--- set the colors and the Focused flag and redraw the object
      this.ColorChange(COLOR_STATE_FOCUSED);
      this.Draw(true);
     }
//--- Initialize the cursor offset from the upper left corner of the element along the X and Y axes
   this.m_cursor_delta_x=0;
   this.m_cursor_delta_y=0;
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Object click handler                                |
//+------------------------------------------------------------------+
void CCanvasBase::OnPressEvent(const int id,const long lparam,const double dparam,const string sparam)
  {
//--- The element is in focus when clicked on
   this.m_focused=true;
//--- If the object colors are not for Pressed mode
   if(!this.CheckColor(COLOR_STATE_PRESSED))
     {
      //--- set the Pressed colors and redraw the object
      this.ColorChange(COLOR_STATE_PRESSED);
      this.Draw(true);
     }
//--- Initialize the cursor offset from the upper left corner of the element along the X and Y axes
   this.m_cursor_delta_x=0;
   this.m_cursor_delta_y=0;
//--- send a custom event to the chart with the passed values in lparam, dparam, and the object name in sparam
   ::EventChartCustom(this.m_chart_id, (ushort)CHARTEVENT_OBJECT_CLICK, lparam, dparam, this.NameFG());
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Cursor move handler                                 |
//+------------------------------------------------------------------+
void CCanvasBase::OnMoveEvent(const int id,const long lparam,const double dparam,const string sparam)
  {
//--- The element is in focus when clicked on
   this.m_focused=true;
//--- If the object colors are not for Pressed mode
   if(!this.CheckColor(COLOR_STATE_PRESSED))
     {
      //--- set the Pressed colors and redraw the object
      this.ColorChange(COLOR_STATE_PRESSED);
      this.Draw(true);
     }
//--- Calculate the cursor offset from the upper left corner of the element along the X and Y axes
   if(this.m_cursor_delta_x==0)
      this.m_cursor_delta_x=(int)lparam-this.X();
   if(this.m_cursor_delta_y==0)
      this.m_cursor_delta_y=(int)::round(dparam-this.Y());
  }
//+------------------------------------------------------------------+
//| CCanvasBase::Graphical object creation event handler             |
//+------------------------------------------------------------------+
void CCanvasBase::OnCreateEvent(const int id,const long lparam,const double dparam,const string sparam)
  {
//--- if the created object belongs to this program, leave
   if(this.IsBelongsToThis(sparam))
      return;
//--- bring the object to the front
   this.BringToTop(true);
  }
//+------------------------------------------------------------------+
