//+------------------------------------------------------------------+
//|                                                         Form.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "GCnvElement.mqh"
#include "ShadowObj.mqh"
//+------------------------------------------------------------------+
//| Form object class                                                |
//+------------------------------------------------------------------+
class CForm : public CGCnvElement
  {
private:
   CArrayObj         m_list_elements;                          // List of attached elements
   CShadowObj       *m_shadow_obj;                             // Pointer to the shadow object
   color             m_color_frame;                            // Form frame color
   int               m_frame_width_left;                       // Form frame width to the left
   int               m_frame_width_right;                      // Form frame width to the right
   int               m_frame_width_top;                        // Form frame width at the top
   int               m_frame_width_bottom;                     // Form frame width at the bottom

//--- Initialize the variables
   void              Initialize(void);
//--- Return the name of the dependent object
   string            CreateNameDependentObject(const string base_name)  const
                       { return ::StringSubstr(this.NameObj(),::StringLen(::MQLInfoString(MQL_PROGRAM_NAME))+1)+"_"+base_name;   }
   
//--- Create a new graphical object
   CGCnvElement     *CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                      const int element_num,
                                      const string name,
                                      const int x,
                                      const int y,
                                      const int w,
                                      const int h,
                                      const color colour,
                                      const uchar opacity,
                                      const bool movable,
                                      const bool activity);
//--- Create a shadow object
   void              CreateShadowObj(const color colour,const uchar opacity);
   
public:
   //--- Constructors
                     CForm(const long chart_id,
                           const int subwindow,
                           const string name,
                           const int x,
                           const int y,
                           const int w,
                           const int h);
                     CForm(const int subwindow,
                           const string name,
                           const int x,
                           const int y,
                           const int w,
                           const int h);
                     CForm(const string name,
                           const int x,
                           const int y,
                           const int w,
                           const int h);
                     CForm() { this.Initialize(); }
//--- Destructor
                    ~CForm();
                           
//--- Supported form properties (1) integer and (2) string ones
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property) { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property)  { return true; }
   
//--- Return (1) the list of attached objects and (2) the shadow object
   CArrayObj        *GetList(void)                                            { return &this.m_list_elements;  }
   CGCnvElement     *GetShadowObj(void)                                       { return this.m_shadow_obj;      }

//--- Set the form (1) color scheme and (2) style
   virtual void      SetColorTheme(const ENUM_COLOR_THEMES theme,const uchar opacity);
   virtual void      SetFormStyle(const ENUM_FORM_STYLE style,
                                  const ENUM_COLOR_THEMES theme,
                                  const uchar opacity,
                                  const bool shadow=false,
                                  const bool use_bg_color=true,
                                  const bool redraw=false);
   
//--- Create a new attached element
   bool              CreateNewElement(const int element_num,
                                      const string name,
                                      const int x,
                                      const int y,
                                      const int w,
                                      const int h,
                                      const color colour,
                                      const uchar opacity,
                                      const bool movable,
                                      const bool activity);

//--- Draw an object shadow
   void              DrawShadow(const int shift_x,const int shift_y,const color colour,const uchar opacity=127,const uchar blur=4);

//--- Draw the form frame
   void              DrawFormFrame(const int wd_top,                          // Frame upper segment width
                                   const int wd_bottom,                       // Frame lower segment width
                                   const int wd_left,                         // Frame left segment width
                                   const int wd_right,                        // Frame right segment width
                                   const color colour,                        // Frame color
                                   const uchar opacity,                       // Frame opacity
                                   const ENUM_FRAME_STYLE style);             // Frame style
//--- Draw a simple frame
   void              DrawFrameSimple(const int x,                             // X coordinate relative to the form
                                     const int y,                             // Y coordinate relative to the form
                                     const int width,                         // Frame width
                                     const int height,                        // Frame height
                                     const int wd_top,                        // Frame upper segment width
                                     const int wd_bottom,                     // Frame lower segment width
                                     const int wd_left,                       // Frame left segment width
                                     const int wd_right,                      // Frame right segment width
                                     const color colour,                      // Frame color
                                     const uchar opacity);                    // Frame opacity
//--- Draw a flat frame
   void              DrawFrameFlat(const int x,                               // X coordinate relative to the form
                                   const int y,                               // Y coordinate relative to the form
                                   const int width,                           // Frame width
                                   const int height,                          // Frame height
                                   const int wd_top,                          // Frame upper segment width
                                   const int wd_bottom,                       // Frame lower segment width
                                   const int wd_left,                         // Frame left segment width
                                   const int wd_right,                        // Frame right segment width
                                   const color colour,                        // Frame color
                                   const uchar opacity);                      // Frame opacity

//--- Draw an embossed (convex) frame
   void              DrawFrameBevel(const int x,                              // X coordinate relative to the form
                                    const int y,                              // Y coordinate relative to the form
                                    const int width,                          // Frame width
                                    const int height,                         // Frame height
                                    const int wd_top,                         // Frame upper segment width
                                    const int wd_bottom,                      // Frame lower segment width
                                    const int wd_left,                        // Frame left segment width
                                    const int wd_right,                       // Frame right segment width
                                    const color colour,                       // Frame color
                                    const uchar opacity);                     // Frame opacity

//--- Draw an embossed (concave) frame
   void              DrawFrameStamp(const int x,                              // X coordinate relative to the form
                                    const int y,                              // Y coordinate relative to the form
                                    const int width,                          // Frame width
                                    const int height,                         // Frame height
                                    const int wd_top,                         // Frame upper segment width
                                    const int wd_bottom,                      // Frame lower segment width
                                    const int wd_left,                        // Frame left segment width
                                    const int wd_right,                       // Frame right segment width
                                    const color colour,                       // Frame color
                                    const uchar opacity);                     // Frame opacity

//--- Draw a simple field
   void              DrawFieldFlat(const int x,                               // X coordinate relative to the form
                                   const int y,                               // Y coordinate relative to the form
                                   const int width,                           // Field width
                                   const int height,                          // Field height
                                   const color colour,                        // Field color
                                   const uchar opacity);                      // Field opacity

//--- Draw an embossed (convex) field
   void              DrawFieldBevel(const int x,                              // X coordinate relative to the form
                                    const int y,                              // Y coordinate relative to the form
                                    const int width,                          // Field width
                                    const int height,                         // Field height
                                    const color colour,                       // Field color
                                    const uchar opacity);                     // Field opacity

//--- Draw an embossed (concave) field
   void              DrawFieldStamp(const int x,                              // X coordinate relative to the form
                                    const int y,                              // Y coordinate relative to the form
                                    const int width,                          // Field width
                                    const int height,                         // Field height
                                    const color colour,                       // Field color
                                    const uchar opacity);                     // Field opacity
   
//+------------------------------------------------------------------+
//| Methods of simplified access to object properties                |
//+------------------------------------------------------------------+
//--- (1) Set and (2) get the form frame color
   void              SetColorFrame(const color colour)                        { this.m_color_frame=colour;     }
   color             ColorFrame(void)                                   const { return this.m_color_frame;     }
//--- (1) Set and (2) return the form shadow color
   void              SetColorShadow(const color colour);
   color             ColorShadow(void) const;
//--- (1) Set and (2) return the form shadow opacity
   void              SetOpacityShadow(const uchar opacity);
   uchar             OpacityShadow(void) const;

  };
//+------------------------------------------------------------------+
//| Constructor indicating the chart and subwindow ID                |
//+------------------------------------------------------------------+
CForm::CForm(const long chart_id,
             const int subwindow,
             const string name,
             const int x,
             const int y,
             const int w,
             const int h) : CGCnvElement(GRAPH_ELEMENT_TYPE_FORM,chart_id,subwindow,name,x,y,w,h)
  {
   this.Initialize();
  }
//+------------------------------------------------------------------+
//| Current chart constructor specifying the subwindow               |
//+------------------------------------------------------------------+
CForm::CForm(const int subwindow,
             const string name,
             const int x,
             const int y,
             const int w,
             const int h) : CGCnvElement(GRAPH_ELEMENT_TYPE_FORM,::ChartID(),subwindow,name,x,y,w,h)
  {
   this.Initialize();
  }
//+------------------------------------------------------------------+
//| Constructor on the current chart in the main chart window        |
//+------------------------------------------------------------------+
CForm::CForm(const string name,
             const int x,
             const int y,
             const int w,
             const int h) : CGCnvElement(GRAPH_ELEMENT_TYPE_FORM,::ChartID(),0,name,x,y,w,h)
  {
   this.Initialize();
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CForm::~CForm()
  {
   if(m_shadow_obj!=NULL)
      delete m_shadow_obj;
  }
//+------------------------------------------------------------------+
//| Initialize the variables                                         |
//+------------------------------------------------------------------+
void CForm::Initialize(void)
  {
   this.m_list_elements.Clear();
   this.m_list_elements.Sort();
   this.m_shadow_obj=NULL;
   this.m_shadow=false;
   this.m_frame_width_right=2;
   this.m_frame_width_left=2;
   this.m_frame_width_top=2;
   this.m_frame_width_bottom=2;
  }
//+------------------------------------------------------------------+
//| Create a new graphical object                                    |
//+------------------------------------------------------------------+
CGCnvElement *CForm::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                      const int obj_num,
                                      const string obj_name,
                                      const int x,
                                      const int y,
                                      const int w,
                                      const int h,
                                      const color colour,
                                      const uchar opacity,
                                      const bool movable,
                                      const bool activity)
  {
   string name=this.CreateNameDependentObject(obj_name);
   CGCnvElement *element=new CGCnvElement(type,this.ID(),obj_num,this.ChartID(),this.SubWindow(),name,x,y,w,h,colour,opacity,movable,activity);
   if(element==NULL)
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),": ",name);
   return element;
  }
//+------------------------------------------------------------------+
//| Create a new attached element                                    |
//+------------------------------------------------------------------+
bool CForm::CreateNewElement(const int element_num,
                             const string element_name,
                             const int x,
                             const int y,
                             const int w,
                             const int h,
                             const color colour,
                             const uchar opacity,
                             const bool movable,
                             const bool activity)
  {
   CGCnvElement *obj=this.CreateNewGObject(GRAPH_ELEMENT_TYPE_ELEMENT,element_num,element_name,x,y,w,h,colour,opacity,movable,activity);
   if(obj==NULL)
      return false;
   this.m_list_elements.Sort(SORT_BY_CANV_ELEMENT_NAME_OBJ);
   int index=this.m_list_elements.Search(obj);
   if(index>WRONG_VALUE)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_OBJ_ALREADY_IN_LIST),": ",obj.NameObj());
      delete obj;
      return false;
     }
   if(!this.m_list_elements.Add(obj))
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST),": ",obj.NameObj());
      delete obj;
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+
//| Create the shadow object                                         |
//+------------------------------------------------------------------+
void CForm::CreateShadowObj(const color colour,const uchar opacity)
  {
//--- If the shadow flag is disabled or the shadow object already exists, exit
   if(!this.m_shadow || this.m_shadow_obj!=NULL)
      return;
//--- Calculate the shadow object coordinates according to the offset from the top and left
   int x=this.CoordX()-OUTER_AREA_SIZE;
   int y=this.CoordY()-OUTER_AREA_SIZE;
//--- Calculate the width and height in accordance with the top, bottom, left and right offsets
   int w=this.Width()+OUTER_AREA_SIZE*2;
   int h=this.Height()+OUTER_AREA_SIZE*2;
//--- Create a new shadow object and set the pointer to it in the variable
   this.m_shadow_obj=new CShadowObj(this.ChartID(),this.SubWindow(),this.CreateNameDependentObject("Shadow"),x,y,w,h);
   if(this.m_shadow_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_FAILED_CREATE_SHADOW_OBJ));
      return;
     }
//--- Set the properties for the created shadow object
   this.m_shadow_obj.SetID(this.ID());
   this.m_shadow_obj.SetNumber(-1);
   this.m_shadow_obj.SetOpacityShadow(opacity);
   this.m_shadow_obj.SetColorShadow(colour);
   this.m_shadow_obj.SetMovable(true);
   this.m_shadow_obj.SetActive(false);
   this.m_shadow_obj.SetVisible(false);
//--- Move the form object to the foreground
   this.BringToTop();
  }
//+------------------------------------------------------------------+
//| Draw the shadow                                                  |
//+------------------------------------------------------------------+
void CForm::DrawShadow(const int shift_x,const int shift_y,const color colour,const uchar opacity=127,const uchar blur=4)
  {
//--- If the shadow flag is disabled, exit
   if(!this.m_shadow)
      return;
//--- If there is no shadow object, create it
   if(this.m_shadow_obj==NULL)
      this.CreateShadowObj(colour,opacity);
//--- If the shadow object exists, draw the shadow on it,
//--- set the shadow object visibility flag and
//--- move the form object to the foreground
   if(this.m_shadow_obj!=NULL)
     {
      this.m_shadow_obj.DrawShadow(shift_x,shift_y,blur);
      this.m_shadow_obj.SetVisible(true);
      this.BringToTop();
     }
  }
//+------------------------------------------------------------------+
//| Set a color scheme                                               |
//+------------------------------------------------------------------+
void CForm::SetColorTheme(const ENUM_COLOR_THEMES theme,const uchar opacity)
  {
   this.SetOpacity(opacity);
   this.SetColorBackground(array_color_themes[theme][COLOR_THEME_COLOR_FORM_BG]);
   this.SetColorFrame(array_color_themes[theme][COLOR_THEME_COLOR_FORM_FRAME]);
   if(this.m_shadow && this.m_shadow_obj!=NULL)
      this.SetColorShadow(array_color_themes[theme][COLOR_THEME_COLOR_FORM_SHADOW]);
  }
//+------------------------------------------------------------------+
//| Set the form style                                               |
//+------------------------------------------------------------------+
void CForm::SetFormStyle(const ENUM_FORM_STYLE style,
                         const ENUM_COLOR_THEMES theme,
                         const uchar opacity,
                         const bool shadow=false,
                         const bool use_bg_color=true,
                         const bool redraw=false)
  {
//--- Set opacity parameters and the size of the form frame side
   this.m_shadow=shadow;
   this.m_frame_width_top=array_form_style[style][FORM_STYLE_FRAME_WIDTH_TOP];
   this.m_frame_width_bottom=array_form_style[style][FORM_STYLE_FRAME_WIDTH_BOTTOM];
   this.m_frame_width_left=array_form_style[style][FORM_STYLE_FRAME_WIDTH_LEFT];
   this.m_frame_width_right=array_form_style[style][FORM_STYLE_FRAME_WIDTH_RIGHT];
   
//--- Create the shadow object
   this.CreateShadowObj(clrNONE,(uchar)array_form_style[style][FORM_STYLE_FRAME_SHADOW_OPACITY]);
   
//--- Set a color scheme
   this.SetColorTheme(theme,opacity);
//--- Calculate a shadow color with color darkening
   color clr=array_color_themes[theme][COLOR_THEME_COLOR_FORM_SHADOW];
   color gray=CGCnvElement::ChangeColorSaturation(ChartColorBackground(),-100);
   color color_shadow=CGCnvElement::ChangeColorLightness((use_bg_color ? gray : clr),-fabs(array_form_style[style][FORM_STYLE_DARKENING_COLOR_FOR_SHADOW]));
   this.SetColorShadow(color_shadow);
   
//--- Draw a rectangular shadow
   int shift_x=array_form_style[style][FORM_STYLE_FRAME_SHADOW_X_SHIFT];
   int shift_y=array_form_style[style][FORM_STYLE_FRAME_SHADOW_Y_SHIFT];
   this.DrawShadow(shift_x,shift_y,color_shadow,this.OpacityShadow(),(uchar)array_form_style[style][FORM_STYLE_FRAME_SHADOW_BLUR]);
   
//--- Fill in the form background with color and opacity
   this.Erase(this.ColorBackground(),this.Opacity());
//--- Depending on the selected form style, draw the corresponding form frame and the outer bounding frame
   switch(style)
     {
      case FORM_STYLE_BEVEL   :
        this.DrawFormFrame(this.m_frame_width_top,this.m_frame_width_bottom,this.m_frame_width_left,this.m_frame_width_right,this.ColorFrame(),this.Opacity(),FRAME_STYLE_BEVEL);
        break;
      //---FORM_STYLE_FLAT
      default:
        this.DrawFormFrame(this.m_frame_width_top,this.m_frame_width_bottom,this.m_frame_width_left,this.m_frame_width_right,this.ColorFrame(),this.Opacity(),FRAME_STYLE_FLAT);
        break;
     }
   this.DrawRectangle(0,0,Width()-1,Height()-1,array_color_themes[theme][COLOR_THEME_COLOR_FORM_RECT_OUTER],this.Opacity());
  }
//+------------------------------------------------------------------+
//| Draw the form frame                                              |
//+------------------------------------------------------------------+
void CForm::DrawFormFrame(const int wd_top,              // Frame upper segment width
                          const int wd_bottom,           // Frame lower segment width
                          const int wd_left,             // Frame left segment width
                          const int wd_right,            // Frame right segment width
                          const color colour,            // Frame color
                          const uchar opacity,           // Frame opacity
                          const ENUM_FRAME_STYLE style)  // Frame style
  {
//--- Depending on the passed frame style
   switch(style)
     {
      //--- draw a dimensional (convex) frame
      case FRAME_STYLE_BEVEL :
         DrawFrameBevel(0,0,Width(),Height(),wd_top,wd_bottom,wd_left,wd_right,colour,opacity);
        break;
      //--- draw a dimensional (concave) frame
      case FRAME_STYLE_STAMP :
         DrawFrameStamp(0,0,Width(),Height(),wd_top,wd_bottom,wd_left,wd_right,colour,opacity);
        break;
      //--- draw a flat frame
      case FRAME_STYLE_FLAT :
         DrawFrameFlat(0,0,Width(),Height(),wd_top,wd_bottom,wd_left,wd_right,colour,opacity);
        break;
      //--- draw a simple frame
      default:
        //---FRAME_STYLE_SIMPLE
         DrawFrameSimple(0,0,Width(),Height(),wd_top,wd_bottom,wd_left,wd_right,colour,opacity);
        break;
     }
  }
//+------------------------------------------------------------------+
//| Draw a simple frame                                              |
//+------------------------------------------------------------------+
void CForm::DrawFrameSimple(const int x,           // X coordinate relative to the form
                            const int y,           // Y coordinate relative to the form
                            const int width,       // Frame width
                            const int height,      // Frame height
                            const int wd_top,      // Frame upper segment width
                            const int wd_bottom,   // Frame lower segment width
                            const int wd_left,     // Frame left segment width
                            const int wd_right,    // Frame right segment width
                            const color colour,    // Frame color
                            const uchar opacity)   // Frame opacity
  {
//--- Set rectangle coordinates
   int x1=x, y1=y;
   int x2=x1+width-1;
   int y2=y1+height-1;
//--- Draw the first rectangle
   CGCnvElement::DrawRectangle(x1,y1,x2,y2,colour,opacity);
//--- If the frame width exceeds 1 on all sides, draw the second rectangle
   if(wd_left>1 || wd_right>1 || wd_top>1 || wd_bottom>1)
      CGCnvElement::DrawRectangle(x1+wd_left-1,y1+wd_top-1,x2-wd_right+1,y2-wd_bottom+1,colour,opacity);
//--- Search for "voids" between the lines of two rectangles and fill them with color
   if(wd_left>2 && wd_right>2 && wd_top>2 && wd_bottom>2)
      this.Fill(x1+1,y1+1,colour,opacity);
   else if(wd_left>2 && wd_top>2)
      this.Fill(x1+1,y1+1,colour,opacity);
   else if(wd_right>2 && wd_bottom>2)
      this.Fill(x2-1,y2-1,colour,opacity);
   else if(wd_left<3 && wd_right<3)
     {
      if(wd_top>2)
         this.Fill(x1+1,y1+1,colour,opacity);
      if(wd_bottom>2)
         this.Fill(x1+1,y2-1,colour,opacity);
     }
   else if(wd_top<3 && wd_bottom<3)
     {
      if(wd_left>2)
         this.Fill(x1+1,y1+1,colour,opacity);
      if(wd_right>2)
         this.Fill(x2-1,y1+1,colour,opacity);
     }
  }
//+------------------------------------------------------------------+
//| Draw a flat frame                                                |
//+------------------------------------------------------------------+
void CForm::DrawFrameFlat(const int x,
                          const int y,
                          const int width,
                          const int height,
                          const int wd_top,
                          const int wd_bottom,
                          const int wd_left,
                          const int wd_right,
                          const color colour,
                          const uchar opacity)
  {
//--- Draw a simple frame
   this.DrawFrameSimple(x,y,width,height,wd_top,wd_bottom,wd_left,wd_right,colour,opacity);
//--- If the width of the frame top and bottom exceeds one pixel
   if(wd_top>1 && wd_bottom>1)
     {
      //--- Darken the horizontal sides of the frame
      for(int i=0;i<width;i++)
        {
         this.m_canvas.PixelSet(x+i,y,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y),-5));
         this.m_canvas.PixelSet(x+i,y+height-1,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y+height-1),-7));
        }
     }
//--- If the width of the frame left and right sides exceeds one pixel
   if(wd_left>1 && wd_right>1)
     {
      //--- Darken the vertical sides of the frame
      for(int i=1;i<height-1;i++)
        {
         this.m_canvas.PixelSet(x,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x,y+1),-1));
         this.m_canvas.PixelSet(x+width-1,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x+width-1,y+1),-2));
        }
     }
  }
//+------------------------------------------------------------------+
//| Draw an embossed (convex) frame                                  |
//+------------------------------------------------------------------+
void CForm::DrawFrameBevel(const int x,
                           const int y,
                           const int width,
                           const int height,
                           const int wd_top,
                           const int wd_bottom,
                           const int wd_left,
                           const int wd_right,
                           const color colour,
                           const uchar opacity)
  {
//--- Draw a simple frame
   this.DrawFrameSimple(x,y,width,height,wd_top,wd_bottom,wd_left,wd_right,colour,opacity);
//--- If the width of the frame top and bottom exceeds one pixel
   if(wd_top>1 && wd_bottom>1)
     {
      //--- Lighten and darken the required sides of the frame edges
      for(int i=0;i<width;i++)
        {
         this.m_canvas.PixelSet(x+i,y,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y),25));
         this.m_canvas.PixelSet(x+i,y+height-1,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y+height-1),-20));
        }
      for(int i=wd_left;i<width-wd_right;i++)
        {
         this.m_canvas.PixelSet(x+i,y+wd_top-1,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y+wd_top-1),-20));
         this.m_canvas.PixelSet(x+i,y+height-wd_bottom,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y+height-wd_bottom),10));
        }
     }
//--- If the width of the frame left and right sides exceeds one pixel
   if(wd_left>1 && wd_right>1)
     {
      //--- Lighten and darken the required sides of the frame edges
      for(int i=1;i<height-1;i++)
        {
         this.m_canvas.PixelSet(x,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x,y+i),10));
         this.m_canvas.PixelSet(x+width-1,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x+width-1,y+i),-10));
        }
      for(int i=wd_top;i<height-wd_bottom;i++)
        {
         this.m_canvas.PixelSet(x+wd_left-1,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x+wd_left-1,y+i),-10));
         this.m_canvas.PixelSet(x+width-wd_right,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x+width-wd_right,y+i),10));
        }
     }
  }
//+------------------------------------------------------------------+
//| Draw an embossed (concave) frame                                 |
//+------------------------------------------------------------------+
void CForm::DrawFrameStamp(const int x,
                           const int y,
                           const int width,
                           const int height,
                           const int wd_top,
                           const int wd_bottom,
                           const int wd_left,
                           const int wd_right,
                           const color colour,
                           const uchar opacity)
  {
//--- Draw a simple frame
   this.DrawFrameSimple(x,y,width,height,wd_top,wd_bottom,wd_left,wd_right,colour,opacity);
//--- If the width of the frame top and bottom exceeds one pixel
   if(wd_top>1 && wd_bottom>1)
     {
      //--- Lighten and darken the required sides of the frame edges
      for(int i=0;i<width;i++)
        {
         this.m_canvas.PixelSet(x+i,y,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y),-25));
         this.m_canvas.PixelSet(x+i,y+height-1,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y+height-1),20));
        }
      for(int i=wd_left;i<width-wd_right;i++)
        {
         this.m_canvas.PixelSet(x+i,y+wd_top-1,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y+wd_top-1),20));
         this.m_canvas.PixelSet(x+i,y+height-wd_bottom,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y+height-wd_bottom),-25));
        }
     }
//--- If the width of the frame left and right sides exceeds one pixel
   if(wd_left>1 && wd_right>1)
     {
      //--- Lighten and darken the required sides of the frame edges
      for(int i=1;i<height-1;i++)
        {
         this.m_canvas.PixelSet(x,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x,y+i),-10));
         this.m_canvas.PixelSet(x+width-1,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x+width-1,y+i),20));
        }
      for(int i=wd_top;i<height-wd_bottom;i++)
        {
         this.m_canvas.PixelSet(x+wd_left-1,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x+wd_left-1,y+i),20));
         this.m_canvas.PixelSet(x+width-wd_right,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x+width-wd_right,y+i),-20));
        }
     }
  }
//+------------------------------------------------------------------+
//| Draw a simple field                                              |
//+------------------------------------------------------------------+
void CForm::DrawFieldFlat(const int x,const int y,const int width,const int height,const color colour,const uchar opacity)
  {
//--- Draw a filled rectangle
   CGCnvElement::DrawRectangleFill(x,y,x+width-1,y+height-1,colour,opacity);
//--- Darken all its edges
   for(int i=0;i<width;i++)
     {
      this.m_canvas.PixelSet(x+i,y,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y),-5));
      this.m_canvas.PixelSet(x+i,y+height-1,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y+height-1),-5));
     }
   for(int i=1;i<height-1;i++)
     {
      this.m_canvas.PixelSet(x,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x,y+1),-5));
      this.m_canvas.PixelSet(x+width-1,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x+width-1,y+1),-5));
     }
  }
//+------------------------------------------------------------------+
//| Draw an embossed (convex) field                                  |
//+------------------------------------------------------------------+
void CForm::DrawFieldBevel(const int x,const int y,const int width,const int height,const color colour,const uchar opacity)
  {
//--- Draw a filled rectangle
   CGCnvElement::DrawRectangleFill(x,y,x+width-1,y+height-1,colour,opacity);
//--- Lighten its top and left and darken its bottom and right
   for(int i=0;i<width;i++)
     {
      this.m_canvas.PixelSet(x+i,y,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y),10));
      this.m_canvas.PixelSet(x+i,y+height-1,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y+height-1),-10));
     }
   for(int i=1;i<height-1;i++)
     {
      this.m_canvas.PixelSet(x,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x,y+1),5));
      this.m_canvas.PixelSet(x+width-1,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x+width-1,y+1),-5));
     }
  }
//+------------------------------------------------------------------+
//| Draw an embossed (concave) field                                 |
//+------------------------------------------------------------------+
void CForm::DrawFieldStamp(const int x,const int y,const int width,const int height,const color colour,const uchar opacity)
  {
//--- Draw a filled rectangle
   CGCnvElement::DrawRectangleFill(x,y,x+width-1,y+height-1,colour,opacity);
//--- Darken its top and left and lighten its bottom and right
   for(int i=0;i<width;i++)
     {
      this.m_canvas.PixelSet(x+i,y,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y),-10));
      this.m_canvas.PixelSet(x+i,y+height-1,CGCnvElement::ChangeColorLightness(this.GetPixel(x+i,y+height-1),10));
     }
   for(int i=1;i<height-1;i++)
     {
      this.m_canvas.PixelSet(x,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x,y+1),-5));
      this.m_canvas.PixelSet(x+width-1,y+i,CGCnvElement::ChangeColorLightness(this.GetPixel(x+width-1,y+1),5));
     }
  }
//+------------------------------------------------------------------+
//| Set the form shadow color                                        |
//+------------------------------------------------------------------+
void CForm::SetColorShadow(const color colour)
  {
   if(this.m_shadow_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_TEXT_NO_SHADOW_OBJ_FIRST_CREATE_IT));
      return;
     }
   this.m_shadow_obj.SetColorShadow(colour);
  }
//+------------------------------------------------------------------+
//| Return the form shadow color                                     |
//+------------------------------------------------------------------+
color CForm::ColorShadow(void) const
  {
   if(this.m_shadow_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_TEXT_NO_SHADOW_OBJ_FIRST_CREATE_IT));
      return clrNONE;
     }
   return this.m_shadow_obj.ColorShadow();
  }
//+------------------------------------------------------------------+
//| Set the form shadow opacity                                      |
//+------------------------------------------------------------------+
void CForm::SetOpacityShadow(const uchar opacity)
  {
   if(this.m_shadow_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_TEXT_NO_SHADOW_OBJ_FIRST_CREATE_IT));
      return;
     }
   this.m_shadow_obj.SetOpacityShadow(opacity);
  }
//+------------------------------------------------------------------+
//| Return the form shadow opacity                                   |
//+------------------------------------------------------------------+
uchar CForm::OpacityShadow(void) const
  {
   if(this.m_shadow_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_TEXT_NO_SHADOW_OBJ_FIRST_CREATE_IT));
      return 0;
     }
   return this.m_shadow_obj.OpacityShadow();
  }
//+------------------------------------------------------------------+
