Русский 中文 Español Deutsch 日本語 Português
Graphics in DoEasy library (Part 79): "Animation frame" object class and its descendant objects

Graphics in DoEasy library (Part 79): "Animation frame" object class and its descendant objects

MetaTrader 5Examples | 6 September 2021, 11:06
6 274 0
Artyom Trishkin
Artyom Trishkin

Contents


Concept

In the previous article, I have created the class for saving and subsequent restoring of a part of a background located under a drawn shape. Here I will resume working on the concept and create several classes based on it: the base class of a single animation frame and its descendants — the text animation frame and the rectangle animation frame classes.

The base class is to contain a common set of properties for a single animation frame, while its descendants are to have their own inherent methods for drawing shapes. The text animation class is to allow working with texts, while the rectangle animation frame is to allow creating a single animation frame and drawing various shapes in it using drawing methods based on such CCanvas class methods.

Each created form object is to have a set of methods for drawing on a custom canvas, which allows us to quickly create and manage new images on the form. To be able to conveniently use drawing tools in each form, I will create a common class to feature the lists of all created text and shape images on the form. Later, I will add new animation methods, and their lists will also be placed to the common class. Such a concept allows us to dynamically create new images and save them to the appropriate lists. Next, it will be possible to quickly retrieve them from the form object and display on its background. In this case, such objects will automatically save the background of the form under them. In case the objects are deleted, changed or moved, the saved background is restored.

Thus, in the current article, I will slightly revise drawing frames created in the previous articles, develop the class of the basic animation frame object and develop two classes of its descendants — the text animation frame and the rectangle animation frame classes. Let's create the class for storing the lists of these frame objects and provide the ability to work with them from the form object.


Improving library classes

First of all, let's improve the previously created library classes. In \MQL5\Include\DoEasy\Defines.mqh, add the list of animation frames and the list of drawn shape types in the rectangle animation frame class:

//+------------------------------------------------------------------+
//| Data for working with graphical element animation                |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| List of animation frame types                                    |
//+------------------------------------------------------------------+
enum ENUM_ANIMATION_FRAME_TYPE
  {
   ANIMATION_FRAME_TYPE_TEXT,                         // Text animation frame
   ANIMATION_FRAME_TYPE_QUAD,                         // Rectangle animation frame
  };
//+------------------------------------------------------------------+
//| List of drawn shape types                                        |
//+------------------------------------------------------------------+
enum ENUM_FIGURE_TYPE
  {
   FIGURE_TYPE_PIXEL,                                 // Pixel
   FIGURE_TYPE_PIXEL_AA,                              // Pixel with antialiasing
   
   FIGURE_TYPE_LINE_VERTICAL,                         // Vertical line
   FIGURE_TYPE_LINE_VERTICAL_THICK,                   // Vertical segment of a freehand line having a specified width using antialiasing algorithm
   
   FIGURE_TYPE_LINE_HORIZONTAL,                       // Horizontal line
   FIGURE_TYPE_LINE_HORIZONTAL_THICK,                 // Horizontal segment of a freehand line having a specified width using antialiasing algorithm
   
   FIGURE_TYPE_LINE,                                  // Arbitrary line
   FIGURE_TYPE_LINE_AA,                               // Line with antialiasing
   FIGURE_TYPE_LINE_WU,                               // Line with WU smoothing
   FIGURE_TYPE_LINE_THICK,                            // Segment of a freehand line having a specified width using antialiasing algorithm
   
   FIGURE_TYPE_POLYLINE,                              // Polyline
   FIGURE_TYPE_POLYLINE_AA,                           // Polyline with antialiasing
   FIGURE_TYPE_POLYLINE_WU,                           // Polyline with WU smoothing
   FIGURE_TYPE_POLYLINE_SMOOTH,                       // Polyline with a specified width using two smoothing algorithms
   FIGURE_TYPE_POLYLINE_THICK,                        // Polyline with a specified width using a smoothing algorithm    
   
   FIGURE_TYPE_POLYGON,                               // Polygon
   FIGURE_TYPE_POLYGON_FILL,                          // Filled polygon
   FIGURE_TYPE_POLYGON_AA,                            // Polygon with antialiasing
   FIGURE_TYPE_POLYGON_WU,                            // Polygon with WU smoothing
   FIGURE_TYPE_POLYGON_SMOOTH,                        // Polygon with a specified width using two smoothing algorithms
   FIGURE_TYPE_POLYGON_THICK,                         // Polygon with a specified width using a smoothing algorithm
   
   FIGURE_TYPE_RECTANGLE,                             // Rectangle
   FIGURE_TYPE_RECTANGLE_FILL,                        // Filled rectangle
   
   FIGURE_TYPE_CIRCLE,                                // Circle
   FIGURE_TYPE_CIRCLE_FILL,                           // Filled circle
   FIGURE_TYPE_CIRCLE_AA,                             // Circle with antialiasing
   FIGURE_TYPE_CIRCLE_WU,                             // Circle with WU smoothing
   
   FIGURE_TYPE_TRIANGLE,                              // Triangle
   FIGURE_TYPE_TRIANGLE_FILL,                         // Filled triangle
   FIGURE_TYPE_TRIANGLE_AA,                           // Triangle with antialiasing
   FIGURE_TYPE_TRIANGLE_WU,                           // Triangle with WU smoothing
   
   FIGURE_TYPE_ELLIPSE,                               // Ellipse
   FIGURE_TYPE_ELLIPSE_FILL,                          // Filled ellipse
   FIGURE_TYPE_ELLIPSE_AA,                            // Ellipse with antialiasing
   FIGURE_TYPE_ELLIPSE_WU,                            // Ellipse with WU smoothing
   
   FIGURE_TYPE_ARC,                                   // Ellipse arc
   FIGURE_TYPE_PIE,                                   // Ellipse sector
   
  };
//+------------------------------------------------------------------+

I will use animation frame types to identify animation frame objects (be it a text, a drawn shape or any other animation frame type I will introduce in the following articles. Types of drawn shapes will indicate what exactly is drawn in a single rectangle animation frame. These types correspond to existing drawing methods in the CCanvas class ("Data access", "Draws primitives", "Draws filled primitives" and "Draws primitives with antialiasing" sections in the table of class methods).

In \MQL5\Include\DoEasy\Data.mqh, add new message indices:

//--- CForm
   MSG_FORM_OBJECT_TEXT_NO_SHADOW_OBJ_FIRST_CREATE_IT,// No shadow object. Create it using the CreateShadowObj() method
   MSG_FORM_OBJECT_ERR_FAILED_CREATE_SHADOW_OBJ,      // Failed to create new shadow object
   MSG_FORM_OBJECT_ERR_FAILED_CREATE_PC_OBJ,          // Failed to create new pixel copier object
   MSG_FORM_OBJECT_PC_OBJ_ALREADY_IN_LIST,            // Pixel copier object with ID already present in the list 
   MSG_FORM_OBJECT_PC_OBJ_NOT_EXIST_LIST,             // No pixel copier object with ID in the list 

//--- CFrame
   MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME,           // Failed to create a new animation frame object
   MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST,             // Animation frame object with ID already present in the list 
   MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST,              // Animation frame object with ID not present in the list 

//--- CShadowObj
   MSG_SHADOW_OBJ_IMG_SMALL_BLUR_LARGE,               // Error! Image size too small or blur too extensive

and message texts corresponding to newly added indices:

//--- CForm
   {"Отсутствует объект тени. Необходимо сначала его создать при помощи метода CreateShadowObj()","There is no shadow object. You must first create it using the CreateShadowObj () method"},
   {"Не удалось создать новый объект для тени","Failed to create new object for shadow"},
   {"Не удалось создать новый объект-копировщик пикселей","Failed to create new pixel copier object"},
   {"В списке уже есть объект-копировщик пикселей с идентификатором ","There is already a pixel copier object in the list with ID "},
   {"В списке нет объекта-копировщика пикселей с идентификатором ","No pixel copier object with ID "},
   
//--- CFrame
   {"Не удалось создать новый объект-кадр анимации","Failed to create new animation frame object"},
   {"В списке уже есть объект-кадр анимации с идентификатором ","The list already contains an animation frame object with an ID "},
   {"В списке нет объекта-кадра анимации с идентификатором ","No animation frame object with ID "},
   
//--- CShadowObj
   {"Ошибка! Размер изображения очень маленький или очень большое размытие","Error! Image size is very small or very large blur"},


In the file of the library service functions \MQL5\Include\DoEasy\Services\DELib.mqh, add the functions returning the maximum and minimum values in the array:

//+------------------------------------------------------------------+
//| Return the maximum value in the array                            |
//+------------------------------------------------------------------+
template<typename T>
bool ArrayMaximumValue(const string source,const T &array[],T &max_value)
  {
   if(ArraySize(array)==0)
     {
      CMessage::ToLog(source,MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY);
      return false;
     }
   max_value=0;
   int index=ArrayMaximum(array);
   if(index==WRONG_VALUE)
      return false;
   max_value=array[index];
   return true;
  }
//+------------------------------------------------------------------+
//| Return the minimum value in the array                            |
//+------------------------------------------------------------------+
template<typename T>
bool ArrayMinimumValue(const string source,const T &array[],T &min_value)
  {
   if(ArraySize(array)==0)
     {
      CMessage::ToLog(source,MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY);
      return false;
     }
   min_value=0;
   int index=ArrayMinimum(array);
   if(index==WRONG_VALUE)
      return false;
   min_value=array[index];
   return true;
  }
//+------------------------------------------------------------------+

The functions return the maximum or minimum value located in the array passed to them via a link. They are of bool type since any returned value from the function may be located in the array cells as an "invalid" one. For example, if -1 is returned upon receiving data from the array (like it is done in many functions), such a value can be one of those set in the array. When returning a valid value (-1), our program assumes that this is an error. This is incorrect. Therefore, we will return false in case of an error, while the found maximum or minimum value in the array will be set to the variable passed to the function via a link. If the function returns true, the variable stores the desired value. The source variable receives the name of the method the function was called from. In case of an error, this allows us to see the name of the method the function has been called from, as well as the error message.

The variable also receives the function returning the description of the drawn shape type:

//+------------------------------------------------------------------+
//| Return the description of the drawn shape type                   |
//+------------------------------------------------------------------+
string FigureTypeDescription(const ENUM_FIGURE_TYPE figure_type)
  {
   return(StringSubstr(EnumToString(figure_type),12));
  }
//+------------------------------------------------------------------+

Here, the type passed to the function in the enumeration format is converted into the string description. The substring from the position of the 12th symbol is retrieved from the type text representation for cropping an unnecessary text. For example, FIGURE_TYPE_TRIANGLE figure type is converted into "FIGURE_TYPE_TRIANGLE", and the necessary substring starting from the 12th symbol "FIGURE_TYPE_TRIANGLE" is retrieved from this text. The "TRIANGLE" string is returned as a result.

In the previous article, when creating the methods for copying a part of the background to the array, I defined the size and coordinates of the copied background rectangle by a text size displayed on the form. Here I will display images as well. Their size will no longer be defined by a text size. Therefore, we need to create a method defining the coordinates and the size of the copied rectangle of the background part.

In the \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh file of the graphical element class, rename the method

//--- Return coordinate offsets relative to the text anchor point
   void              TextGetShiftXY(const string text,            // Text for calculating the size of its outlining rectangle
                                    const ENUM_TEXT_ANCHOR anchor,// Text anchor point, relative to which the offsets are calculated
                                    int &shift_x,                 // X coordinate of the rectangle upper left corner
                                    int &shift_y);                // Y coordinate of the rectangle upper left corner

Now the method is called GetShiftXYbyText(). Let's declare a new method returning the coordinates and the size of the copied part of the image by the specified size relative to the object anchor point:

//--- Return coordinate offsets relative to the text anchor point by text
   void              GetShiftXYbyText(const string text,             // Text for calculating the size of its outlining rectangle
                                      const ENUM_TEXT_ANCHOR anchor, // Text anchor point, relative to which the offsets are calculated
                                      int &shift_x,                  // X coordinate of the rectangle upper left corner
                                      int &shift_y);                 // Y coordinate of the rectangle upper left corner
//--- Return coordinate offsets relative to the rectangle anchor point by size
   void              GetShiftXYbySize(const int width,               //Rectangle size by width
                                      const int height,              //Rectangle size by height
                                      const ENUM_TEXT_ANCHOR anchor, // Rectangle anchor point, relative to which the offsets are calculated
                                      int &shift_x,                  // X coordinate of the rectangle upper left corner
                                      int &shift_y);                 // Y coordinate of the rectangle upper left corner

Implement them in the end of the class listing.

The method returning coordinate offsets relative to the rectangle anchor point by size:

//+------------------------------------------------------------------+
//| Return coordinate offsets relative to the rectangle anchor point |
//| by size                                                          |
//+------------------------------------------------------------------+
void CGCnvElement::GetShiftXYbySize(const int width,const int height,const ENUM_TEXT_ANCHOR anchor,int &shift_x,int &shift_y)
  {
   switch(anchor)
     {
      case TEXT_ANCHOR_LEFT_TOP        :  shift_x=0;        shift_y=0;           break;
      case TEXT_ANCHOR_LEFT_CENTER     :  shift_x=0;        shift_y=-height/2;   break;
      case TEXT_ANCHOR_LEFT_BOTTOM     :  shift_x=0;        shift_y=-height;     break;
      case TEXT_ANCHOR_CENTER_TOP      :  shift_x=-width/2; shift_y=0;           break;
      case TEXT_ANCHOR_CENTER          :  shift_x=-width/2; shift_y=-height/2;   break;
      case TEXT_ANCHOR_CENTER_BOTTOM   :  shift_x=-width/2; shift_y=-height;     break;
      case TEXT_ANCHOR_RIGHT_TOP       :  shift_x=-width;   shift_y=0;           break;
      case TEXT_ANCHOR_RIGHT_CENTER    :  shift_x=-width;   shift_y=-height/2;   break;
      case TEXT_ANCHOR_RIGHT_BOTTOM    :  shift_x=-width;   shift_y=-height;     break;
      default                          :  shift_x=0;        shift_y=0;           break;
     }
  }
//+------------------------------------------------------------------+

Here, depending on the width and height of the copied area, as well as on the anchor point passed to the method, calculate coordinate offsets relative to the anchor point and write them to the variables passed to the method via a link.

The method returning coordinate offsets relative to the text anchor point:

//+------------------------------------------------------------------+
//| Return coordinate offsets relative to the text anchor point      |
//+------------------------------------------------------------------+
void CGCnvElement::GetShiftXYbyText(const string text,const ENUM_TEXT_ANCHOR anchor,int &shift_x,int &shift_y)
  {
   int tw=0,th=0;
   this.TextSize(text,tw,th);
   this.GetShiftXYbySize(tw,th,anchor,shift_x,shift_y);
  }
//+------------------------------------------------------------------+

Here we first define the size of the text passed to the method and call the method considered above for defining the coordinate offset of the saved form background image area.

In the previous article, I developed the class for copying a part of the form background image and its subsequent restoration from the array. The class was set in the form object class file. Now I am going to remove the class from the form object class file relocating it to the new file of a new created frame object class (once again I find out that it is better to write and store classes in separate files).

So, let's create a base class for a single animation frame. The class is to contain the properties that are common for all of its descendants.

"Animation frame" object class

In \MQL5\Include\DoEasy\Objects\Graph\, create the new Animations\ folder with the new Frame.mqh file of the CFrame class.

The file of the graphical element object class should be included to the class file:

//+------------------------------------------------------------------+
//|                                                        Frame.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"
//+------------------------------------------------------------------+

Next, place the pixel copier object class removed from the form object class file (considered in the previous article):

//+------------------------------------------------------------------+
//|                                                        Frame.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"
//+------------------------------------------------------------------+
//| Pixel copier class                                               |
//+------------------------------------------------------------------+
class CPixelCopier : public CObject
  {
protected:
   CGCnvElement     *m_element;                             // Pointer to the graphical element
   uint              m_array[];                             // Pixel array
   int               m_id;                                  // ID
   int               m_x;                                   // X coordinate of the upper left corner
   int               m_y;                                   // Y coordinate of the upper left corner
   int               m_w;                                   // Copied image width
   int               m_h;                                   // Copied image height
   int               m_wr;                                  // Calculated copied image width
   int               m_hr;                                  // Calculated copied image height
public:
//--- Compare CPixelCopier objects by a specified property (to sort the list by an object property)
   virtual int       Compare(const CObject *node,const int mode=0) const
                       {
                        const CPixelCopier *obj_compared=node;
                        return(mode==0 ? (this.ID()>obj_compared.ID() ? 1 : this.ID()<obj_compared.ID() ? -1 : 0) : WRONG_VALUE);
                       }
   
//--- Set the properties
   void              SetElement(CGCnvElement *element)         { this.m_element=element;  }
   void              SetID(const int id)                       { this.m_id=id;            }
   void              SetCoordX(const int value)                { this.m_x=value;          }
   void              SetCoordY(const int value)                { this.m_y=value;          }
   void              SetWidth(const int value)                 { this.m_w=value;          }
   void              SetHeight(const int value)                { this.m_h=value;          }
//--- Get the properties
   int               ID(void)                            const { return this.m_id;        }
   int               CoordX(void)                        const { return this.m_x;         }
   int               CoordY(void)                        const { return this.m_y;         }
   int               Width(void)                         const { return this.m_w;         }
   int               Height(void)                        const { return this.m_h;         }
   int               WidthReal(void)                     const { return this.m_wr;        }
   int               HeightReal(void)                    const { return this.m_hr;        }

//--- Copy the part or the entire image to the array
   bool              CopyImgDataToArray(const uint x_coord,const uint y_coord,uint width,uint height);
//--- Copy the part or the entire image from the array to the canvas
   bool              CopyImgDataToCanvas(const int x_coord,const int y_coord);

//--- Constructors
                     CPixelCopier (void){;}
                     CPixelCopier (const int id,
                                   const int x,
                                   const int y,
                                   const int w,
                                   const int h,
                                   CGCnvElement *element) : m_id(id), m_x(x),m_y(y),m_w(w),m_wr(w),m_h(h),m_hr(h) { this.m_element=element; }
                    ~CPixelCopier (void){;}
  };
//+------------------------------------------------------------------+
//| Copy part or all of the image to the array                       |
//+------------------------------------------------------------------+
bool CPixelCopier::CopyImgDataToArray(const uint x_coord,const uint y_coord,uint width,uint height)
  {
//--- Assign coordinate values, passed to the method, to the variables
   int x1=(int)x_coord;
   int y1=(int)y_coord;
//--- If X coordinates goes beyond the form on the right or Y coordinate goes beyond the form at the bottom,
//--- there is nothing to copy, the copied area is outside the form. Return 'false'
   if(x1>this.m_element.Width()-1 || y1>this.m_element.Height()-1)
      return false;
//--- Assign the width and height values of the copied area to the variables
//--- If the passed width and height are equal to zero, assign the form width and height to them
   this.m_wr=int(width==0  ? this.m_element.Width()  : width);
   this.m_hr=int(height==0 ? this.m_element.Height() : height);

//--- If X and Y coordinates are equal to zero (the upper left corner of the form), as well as the width and height are equal to the form width and height,
//--- the copied area is equal to the entire form area. Copy the entire form (returning it from the method) using the ImageCopy() method
   //if(x1==0 && y1==0 && this.m_wr==this.m_element.Width() && this.m_hr==this.m_element.Height())
   //   return this.m_element.ImageCopy(DFUN,this.m_array);

//--- Calculate the right X coordinate and lower Y coordinate of the rectangle area
   int x2=int(x1+this.m_wr-1);
   int y2=int(y1+this.m_hr-1);
//--- If the calculated X coordinate goes beyond the form, the right edge of the form will be used as the coordinate
   if(x2>=this.m_element.Width()-1)
      x2=this.m_element.Width()-1;
//--- If the calculated Y coordinate goes beyond the form, the bottom edge of the form will be used as the coordinate
   if(y2>=this.m_element.Height()-1)
      y2=this.m_element.Height()-1;
//--- Calculate the copied width and height
   this.m_wr=x2-x1+1;
   this.m_hr=y2-y1+1;
//--- Define the necessary size of the array, which is to store all image pixels with calculated width and height
   int size=this.m_wr*this.m_hr;
//--- If failed to set the array size, inform of that and return 'false'
   if(::ArrayResize(this.m_array,size)!=size)
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE,true);
      return false;
     }
//--- Set the index in the array for recording the image pixel
   int n=0;
//--- In a loop by the calculated height of the copied area, starting from the specified Y coordinate
   for(int y=y1;y<y1+this.m_hr;y++)
     {
      //--- in a loop by the calculated width of the copied area, starting from the specified X coordinate
      for(int x=x1;x<x1+this.m_wr;x++)
        {
         //--- Copy the next image pixel to the array and increase the array index
         this.m_array[n]=this.m_element.GetCanvasObj().PixelGet(x,y);
         n++;
        }
     }
//--- Successful - return 'true'
   return true;
  }
//+------------------------------------------------------------------+
//| Copy the part or the entire image from the array to the canvas   |
//+------------------------------------------------------------------+
bool CPixelCopier::CopyImgDataToCanvas(const int x_coord,const int y_coord)
  {
//--- If the array of saved pixels is empty, inform of that and return 'false'
   int size=::ArraySize(this.m_array);
   if(size==0)
     {
      CMessage::ToLog(DFUN,MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY,true);
      return false;
     }
//--- Set the index of the array for reading the image pixel
   int n=0;
//--- In a loop by the previously calculated height of the copied area, starting from the specified Y coordinate
   for(int y=y_coord;y<y_coord+this.m_hr;y++)
     {
      //--- in a loop by the previously calculated width of the copied area, starting from the specified X coordinate
      for(int x=x_coord;x<x_coord+this.m_wr;x++)
        {
         //--- Restore the next image pixel from the array and increase the array index
         this.m_element.GetCanvasObj().PixelSet(x,y,this.m_array[n]);
         n++;
        }
     }
   return true;
  }
//+------------------------------------------------------------------+

The only thing that has been (temporarily) changed here is the fact that I have commented out the code strings that should copy the entire form image saved previously. The error has been made here causing the background to be copied directly from the graphical resource rather than from the form object array. The graphical resource contains all the changes applied to the form background image. To fix this, I will need to save the form appearance to a separate array featuring the copy of the original form image. I already have such an array but I still need to create the methods for saving the original form appearance right after its creation. Till then, I have commented out these strings. The background with the size of the entire form (rather than of its part) will be restored in the loop of restoring the part of the form background (i.e. not by copying one array to another but rather by filling the form background element by element from the array storing the saved copy of the part of the form background image).

Next, after the pixel copier class listing, write the body of the animation frame object class:

//+------------------------------------------------------------------+
//| Single animation frame class                                     |
//+------------------------------------------------------------------+
class CFrame : public CPixelCopier
  {
protected:
   ENUM_ANIMATION_FRAME_TYPE m_frame_figure_type;           // Type of the figure drawn by the frame
   ENUM_TEXT_ANCHOR  m_anchor_last;                         // Last frame anchor point
   double            m_x_last;                              // X coordinate of the upper left corner of the last frame
   double            m_y_last;                              // Y coordinate of the upper left corner of the last frame
   int               m_shift_x_prev;                        // Offset of the X coordinate of the last frame upper left corner
   int               m_shift_y_prev;                        // Offset of the Y coordinate of the last frame upper left corner
public:
//--- Return the last (1) anchor point, (2) X and (3) Y coordinate,
//--- previous offset by (4) X and (5) Y, (6) type of the figure drawn by the frame
   ENUM_TEXT_ANCHOR  LastAnchor(void)                 const { return this.m_anchor_last;        }
   double            LastX(void)                      const { return this.m_x_last;             }
   double            LastY(void)                      const { return this.m_y_last;             }
   int               LastShiftX(void)                 const { return this.m_shift_x_prev;       }
   int               LastShiftY(void)                 const { return this.m_shift_y_prev;       }
   ENUM_ANIMATION_FRAME_TYPE FrameFigureType(void)    const { return this.m_frame_figure_type;  }
   
//--- Default constructor
                     CFrame();
protected:
//--- Text frame constructor
                     CFrame(const int id,
                            const int x,
                            const int y,
                            const string text,
                            CGCnvElement *element);
//--- Rectangle frame constructor
                     CFrame(const int id,
                            const int x,
                            const int y,
                            const int w,
                            const int h,
                            CGCnvElement *element);
  };
//+------------------------------------------------------------------+

The class is derived from the pixel copier object class, so, in fact, it IS the pixel copier object class.

All variables and methods declared in the class are described in the comments. Since the class is basic for other animation frame classes, all properties and methods common to the descendants are set here.

The variables and methods returning the last coordinates, offsets and anchor points are necessary so that we are able to define the coordinates of the previous saved part of the image when restoring it. These coordinates are to be used for placing the saved background that has been erased by the image drawn over it.

The class features three constructors:

  1. default public constructor,
  2. protected text frame object constructor,
  3. protected rectangle frame object constructor.

Let's consider the implementation of protected constructors.

Constructor of rectangle frames:

//+------------------------------------------------------------------+
//| Constructor of rectangle frames                                  |
//+------------------------------------------------------------------+
CFrame::CFrame(const int id,const int x,const int y,const int w,const int h,CGCnvElement *element) : CPixelCopier(id,x,y,w,h,element)
  {
   this.m_frame_figure_type=ANIMATION_FRAME_TYPE_QUAD;
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=x;
   this.m_y_last=y;
   this.m_shift_x_prev=0;
   this.m_shift_y_prev=0;
  }
//+------------------------------------------------------------------+

The constructor receives the ID of the created rectangle frame object, its X and Y coordinates, frame width and height, as well as the pointer to the graphical element object the new object is created of. Since the class is a descendant of the pixel copier object, pass all the necessary parameters to the base class constructor in the constructor initialization list. These parameters are all the properties passed to the constructor arguments.
Set the default parameters to all class member variables in the class body.

The constructor of text frames:

//+------------------------------------------------------------------+
//| The constructor of text frames                                   |
//+------------------------------------------------------------------+
CFrame::CFrame(const int id,
               const int x,
               const int y,
               const string text,
               CGCnvElement *element)
  {
   int w=0,h=0;
   this.m_element=element;
   this.m_element.GetCanvasObj().TextSize(text,w,h);
   this.m_anchor_last=this.m_element.TextAnchor();
   this.m_frame_figure_type=ANIMATION_FRAME_TYPE_TEXT;
   this.m_x_last=x;
   this.m_y_last=y;
   this.m_shift_x_prev=0;
   this.m_shift_y_prev=0;
   CPixelCopier::SetID(id);
   CPixelCopier::SetCoordX(x);
   CPixelCopier::SetCoordY(y);
   CPixelCopier::SetWidth(w);
   CPixelCopier::SetHeight(h);
  }
//+------------------------------------------------------------------+

The constructor receives the ID of the created text frame object, its X and Y coordinates, the text and the pointer to the graphical element object the new object is created of.
In the class body, first define the text size, then set the default values of class member variables and set the ID of the created object, its coordinates and text size to the parent pixel copier object.

Create the classes of objects of animation frame object class descendants.

Text animation frame class

In \MQL5\Include\DoEasy\Objects\Graph\Animations\, create the new file FrameText.mqh of the CFrameText class.

The file of the animation frame class should be included into the file, while the class itself should be its descendant:

//+------------------------------------------------------------------+
//|                                                    FrameText.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 "Frame.mqh"
//+------------------------------------------------------------------+
//| Single text animation frame class                                |
//+------------------------------------------------------------------+
class CFrameText : public CFrame
  {
private:

public:
//--- Display the text on the background while saving and restoring the background
   bool              TextOnBG(const string text,const int x,const int y,const ENUM_TEXT_ANCHOR anchor,const color clr,const uchar opacity,bool redraw=false);

//--- Constructors
                     CFrameText() {;}
                     CFrameText(const int id,CGCnvElement *element) : CFrame(id,0,0,"",element) {}
  };
//+------------------------------------------------------------------+

Here we can see one public method for drawing the text on the background of the form object and two constructors — default and parametric ones.

The parametric constructor receives the ID of the created text animation frame object and the pointer to the graphical element the object is created of. In the initialization list, the parent class receives the ID passed in the constructor arguments, default values for coordinates and a text, as well as the pointer to the graphical element also passed in the constructor arguments.

The method displaying a text on the background, while saving and restoring the background:

//+-------------------------------------------------------------------------------+
//| Display the text on the background, while saving and restoring the background |
//+-------------------------------------------------------------------------------+
bool CFrameText::TextOnBG(const string text,const int x,const int y,const ENUM_TEXT_ANCHOR anchor,const color clr,const uchar opacity,bool redraw=false)
  {
//--- Find out the width and height of the text outlining the rectangle (to be used as the size of the saved area)
   int w=0,h=0;
   this.m_element.TextSize(text,w,h);
//--- Calculate coordinate offsets for the saved area depending on the text anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(w,h,anchor,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the text has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If a background area with calculated coordinates and size under the future text is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(x+shift_x,y+shift_y,w,h))
      return false;
//--- Draw the text and update the element
   this.m_element.Text(x,y,text,clr,opacity,anchor);
   this.m_element.Update(redraw);
   this.m_anchor_last=anchor;
   this.m_x_last=x;
   this.m_y_last=y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

The method logic is described in detail in the code comments. I have already considered it in the previous article during the test (a similar logic was set in the OnChartEvent() handler of the test EA), so, I believe, all is clear here. After the text has been drawn on the form, its anchor points, X and Y coordinates, as well as offset values relative to the anchor point are set in the variables of the parent class. Their values will be used to restore the form image background overwritten by the text.

Now let's create the second descendant class of the animation frame object.

Rectangle animation frame class

In \MQL5\Include\DoEasy\Objects\Graph\Animations\, create the new file FrameQuad.mqh of the CFrameQuad class.

The parent class file should be included into (and derived from) the class file:

//+------------------------------------------------------------------+
//|                                                    FrameQuad.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 "Frame.mqh"
//+------------------------------------------------------------------+
//| Single sprite animation frame class                              |
//+------------------------------------------------------------------+
class CFrameQuad : public CFrame
  {
private:
   double            m_quad_x;                                 // X coordinate of the rectangle enclosing the shape
   double            m_quad_y;                                 // Y coordinate of the rectangle enclosing the shape
   uint              m_quad_width;                             // Width of the rectangle enclosing the shape
   uint              m_quad_height;                            // Height of the rectangle enclosing the shape
   
public:

//--- Constructors
                     CFrameQuad() {;}
                     CFrameQuad(const int id,CGCnvElement *element) : CFrame(id,0,0,0,0,element) { this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;   }

//+------------------------------------------------------------------+

In the private section of the class, declare the class member variables storing coordinates and size of the rectangle enclosing the drawn shape — these are the coordinates and size of the saved background part image area overwritten by the drawn shape.

The parametric constructor receives the ID of the created object and the pointer to the graphical element the object is created of. The ID passed in the method arguments, default coordinate and frame size parameters and the pointer to the graphical element are passed to the parent class constructor in the constructor initialization list. In the constructor body, set the anchor point of the drawn figure as "top left". This is necessary to calculate the offset of the copied area. With this value, the anchor points of X and Y coordinate offsets are equal to zero.

Since we have plenty of drawing methods in the CCanvas class, all appropriate methods for drawing shapes on the background of the form object are declared in the public section of the class followed by restoring the background:

public:

//--- Constructors
                     CFrameQuad() {;}
                     CFrameQuad(const int id,CGCnvElement *element) : CFrame(id,0,0,0,0,element) { this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;   }

//+------------------------------------------------------------------+
//| Drawing primitives while saving and restoring the background     |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Methods of drawing primitives without smoothing                  |
//+------------------------------------------------------------------+
//--- Set the color of the dot with the specified coordinates
   bool              SetPixelOnBG(const int x,const int y,const color clr,const uchar opacity=255,const bool redraw=false);
                       
//--- Draw a segment of a vertical line
   bool              DrawLineVerticalOnBG(const int x,                  // X coordinate of the segment
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a segment of a horizontal line
   bool              DrawLineHorizontalOnBG(const int x1,               // X coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y,                            // Segment Y coordinate
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a segment of a freehand line
   bool              DrawLineOnBG(const int x1,                         // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a polyline
   bool              DrawPolylineOnBG(int &array_x[],                   // Array with the X coordinates of polyline points
                              int         &array_y[],                   // Array with the Y coordinates of polyline points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a polygon
   bool              DrawPolygonOnBG(int  &array_x[],                   // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a rectangle using two points
   bool              DrawRectangleOnBG(const int x1,                    // X coordinate of the first point defining the rectangle
                              const int   y1,                           // Y coordinate of the first point defining the rectangle
                              const int   x2,                           // X coordinate of the second point defining the rectangle
                              const int   y2,                           // Y coordinate of the second point defining the rectangle
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a circle
   bool              DrawCircleOnBG(const int x,                        // X coordinate of the circle center
                              const int   y,                            // Y coordinate of the circle center
                              const int   r,                            // Circle radius
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a triangle
   bool              DrawTriangleOnBG(const int x1,                     // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw an ellipse using two points
   bool              DrawEllipseOnBG(const int x1,                      // X coordinate of the first point defining the ellipse
                              const int   y1,                           // Y coordinate of the first point defining the ellipse
                              const int   x2,                           // X coordinate of the second point defining the ellipse
                              const int   y2,                           // Y coordinate of the second point defining the ellipse
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw an arc of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2).
//--- The arc boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4)
   bool              DrawArcOnBG(const int x1,                          // X coordinate of the top left corner forming the rectangle
                              const int   y1,                           // Y coordinate of the top left corner forming the rectangle
                              const int   x2,                           // X coordinate of the bottom right corner forming the rectangle
                              const int   y2,                           // Y coordinate of the bottom right corner forming the rectangle
                              const int   x3,                           // X coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const int   y3,                           // Y coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const int   x4,                           // X coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const int   y4,                           // Y coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a filled sector of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2).
//--- The sector boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4)
   bool              DrawPieOnBG(const int x1,                          // X coordinate of the upper left corner of the rectangle
                              const int   y1,                           // Y coordinate of the upper left corner of the rectangle
                              const int   x2,                           // X coordinate of the bottom right corner of the rectangle
                              const int   y2,                           // Y coordinate of the bottom right corner of the rectangle
                              const int   x3,                           // X coordinate of the first point to find the arc boundaries
                              const int   y3,                           // Y coordinate of the first point to find the arc boundaries
                              const int   x4,                           // X coordinate of the second point to find the arc boundaries
                              const int   y4,                           // Y coordinate of the second point to find the arc boundaries
                              const color clr,                          // Line color
                              const color fill_clr,                     // Fill color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//+------------------------------------------------------------------+
//| Methods of drawing filled primitives without smoothing           |
//+------------------------------------------------------------------+
//--- Fill in the area
   bool              FillOnBG(const int   x,                            // X coordinate of the filling start point
                              const int   y,                            // Y coordinate of the filling start point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const uint  threshould=0,                 // Threshold
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a filled rectangle
   bool              DrawRectangleFillOnBG(const int x1,                // X coordinate of the first point defining the rectangle
                              const int   y1,                           // Y coordinate of the first point defining the rectangle
                              const int   x2,                           // X coordinate of the second point defining the rectangle
                              const int   y2,                           // Y coordinate of the second point defining the rectangle
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag

//--- Draw a filled circle
   bool              DrawCircleFillOnBG(const int x,                    // X coordinate of the circle center
                              const int   y,                            // Y coordinate of the circle center
                              const int   r,                            // Circle radius
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a filled triangle
   bool              DrawTriangleFillOnBG(const int x1,                 // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a filled polygon
   bool              DrawPolygonFillOnBG(int &array_x[],                // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a filled ellipse inscribed in a rectangle with the specified coordinates
   bool              DrawEllipseFillOnBG(const int x1,                  // X coordinate of the top left corner forming the rectangle
                              const int   y1,                           // Y coordinate of the top left corner forming the rectangle
                              const int   x2,                           // X coordinate of the bottom right corner forming the rectangle
                              const int   y2,                           // Y coordinate of the bottom right corner forming the rectangle
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false);                // Chart redraw flag
                       
//+------------------------------------------------------------------+
//| Methods of drawing primitives using smoothing                    |
//+------------------------------------------------------------------+
//--- Draw a point using AntiAliasing algorithm
   bool              SetPixelAAOnBG(const double x,                     // Point X coordinate
                              const double y,                           // Point Y coordinate
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   redraw=false);               // Chart redraw flag
                       
//--- Draw a segment of a freehand line using AntiAliasing algorithm
   bool              DrawLineAAOnBG(const int x1,                       // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a segment of a freehand line using Wu algorithm
   bool              DrawLineWuOnBG(const int x1,                       // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draws a segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration
   bool              DrawLineThickOnBG(const int x1,                    // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const int   size,                         // Line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              ENUM_LINE_END end_style=LINE_END_ROUND);  // Line style is one of the ENUM_LINE_END enumeration's values
 
//--- Draw a vertical segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration
   bool              DrawLineThickVerticalOnBG(const int x,             // X coordinate of the segment
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   y2,                           // Y coordinate of the segment second point
                              const int   size,                         // line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values
                       
//--- Draw a horizontal segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration
   bool              DrawLineThickHorizontalOnBG(const int x1,          // X coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y,                            // Segment Y coordinate
                              const int   size,                         // line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values

//--- Draws a polyline using AntiAliasing algorithm
   bool              DrawPolylineAAOnBG(int &array_x[],                 // Array with the X coordinates of polyline points
                              int         &array_y[],                   // Array with the Y coordinates of polyline points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draws a polyline using Wu algorithm
   bool              DrawPolylineWuOnBG(int &array_x[],                 // Array with the X coordinates of polyline points
                              int         &array_y[],                   // Array with the Y coordinates of polyline points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a polyline with a specified width consecutively using two antialiasing algorithms.
//--- First, individual line segments are smoothed based on Bezier curves.
//--- Then, the raster antialiasing algorithm is applied to the polyline built from these segments to improve the rendering quality
   bool              DrawPolylineSmoothOnBG(const int &array_x[],       // Array with the X coordinates of polyline points
                              const int    &array_y[],                  // Array with the Y coordinates of polyline points
                              const int    size,                        // Line width
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const double tension=0.5,                 // Smoothing parameter value
                              const double step=10,                     // Approximation step
                              const bool   redraw=false,                // Chart redraw flag
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END   end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values
                       
//--- Draw a polyline having a specified width using smoothing algorithm with the preliminary filtration
   bool              DrawPolylineThickOnBG(const int &array_x[],        // Array with the X coordinates of polyline points
                              const int      &array_y[],                // Array with the Y coordinates of polyline points
                              const int      size,                      // Line width
                              const color    clr,                       // Color
                              const uchar    opacity=255,               // Opacity
                              const bool     redraw=false,              // Chart redraw flag
                              const uint     style=STYLE_SOLID,         // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              ENUM_LINE_END  end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values
                       
//--- Draw a polygon using AntiAliasing algorithm
   bool              DrawPolygonAAOnBG(int &array_x[],                  // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a polygon using Wu algorithm
   bool              DrawPolygonWuOnBG(int &array_x[],                  // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a polygon with a specified width consecutively using two smoothing algorithms.
//--- First, individual segments are smoothed based on Bezier curves.
//--- Then, the raster smoothing algorithm is applied to the polygon built from these segments to improve the rendering quality. 
   bool              DrawPolygonSmoothOnBG(int &array_x[],              // Array with the X coordinates of polyline points
                              int          &array_y[],                  // Array with the Y coordinates of polyline points
                              const int    size,                        // Line width
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const double tension=0.5,                 // Smoothing parameter value
                              const double step=10,                     // Approximation step
                              const bool   redraw=false,                // Chart redraw flag
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END   end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values
                       
//--- Draw a polygon having a specified width using smoothing algorithm with the preliminary filtration
   bool              DrawPolygonThickOnBG(const int &array_x[],         // array with the X coordinates of polygon points
                              const int   &array_y[],                   // array with the Y coordinates of polygon points
                              const int   size,                         // line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // line style
                              ENUM_LINE_END end_style=LINE_END_ROUND);  // line ends style
                       
//--- Draw a triangle using AntiAliasing algorithm
   bool              DrawTriangleAAOnBG(const int x1,                   // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a triangle using Wu algorithm
   bool              DrawTriangleWuOnBG(const int x1,                   // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a circle using AntiAliasing algorithm
   bool              DrawCircleAAOnBG(const int x,                      // X coordinate of the circle center
                              const int    y,                           // Y coordinate of the circle center
                              const double r,                           // Circle radius
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   redraw=false,                // Chart redraw flag
                              const uint   style=UINT_MAX);             // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a circle using Wu algorithm
   bool              DrawCircleWuOnBG(const int x,                      // X coordinate of the circle center
                              const int    y,                           // Y coordinate of the circle center
                              const double r,                           // Circle radius
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   redraw=false,                // Chart redraw flag
                              const uint   style=UINT_MAX);             // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw an ellipse by two points using AntiAliasing algorithm
   bool              DrawEllipseAAOnBG(const double x1,                 // X coordinate of the first point defining the ellipse
                              const double y1,                          // Y coordinate of the first point defining the ellipse
                              const double x2,                          // X coordinate of the second point defining the ellipse
                              const double y2,                          // Y coordinate of the second point defining the ellipse
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   redraw=false,                // Chart redraw flag
                              const uint   style=UINT_MAX);             // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw an ellipse by two points using Wu algorithm
   bool              DrawEllipseWuOnBG(const int x1,                    // X coordinate of the first point defining the ellipse
                              const int   y1,                           // Y coordinate of the first point defining the ellipse
                              const int   x2,                           // X coordinate of the second point defining the ellipse
                              const int   y2,                           // Y coordinate of the second point defining the ellipse
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  };
//+------------------------------------------------------------------+

Implementation of each of these methods is similar to the implementation of similar drawing methods. However, almost all of them have their nuances inherent in its drawing method (the size of the saved area of two similar drawing methods may be different due to individual features of each of them).

Let's have a look at the implementation of these methods.

The method setting the color of the point with specified coordinates:

//+------------------------------------------------------------------+
//| Set the color of the dot with the specified coordinates          |
//+------------------------------------------------------------------+
bool CFrameQuad::SetPixelOnBG(const int x,const int y,const color clr,const uchar opacity=255,const bool redraw=false)
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=x;
   this.m_quad_y=y;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=1;
   this.m_quad_height=1;
   
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If a background area with calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.SetPixel(x,y,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

The logic of the method is commented in sufficient detail in the code. Let's consider this more thoroughly. Here we first set X and Y coordinates of the upper left edge of the background rectangle area to be saved in the array for subsequent background restoration under the drawn point. Since this is only a dot (one pixel image), the coordinates of the saved area match the coordinates of the drawn dot and the size matches the size of a single pixel, i.e. 1 x 1.

Next we check whether the background has been previously saved (by the non-zero array size the background is saved into). If yes, restore the previously saved form object background (the coordinates and the size of the restored area are already set in the class variables). After the background is successfully restored, save the form background with the dot new coordinates and draw the dot. Save the new coordinates, as well as the size of the saved area and the shift, in the class variables for subsequent restoration of the background erased by the newly drawn dot.

The method drawing a segment of a vertical line:

//+------------------------------------------------------------------+
//| Draw a segment of a vertical line                                |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineVerticalOnBG(const int   x,              // X coordinate of the segment
                                      const int   y1,             // Y coordinate of the segment first point
                                      const int   y2,             // Y coordinate of the segment second point
                                      const color clr,            // Color
                                      const uchar opacity=255,    // Opacity
                                      const bool  redraw=false)   // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=x;
   this.m_quad_y=::fmin(y1,y2);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawLineVertical(x,y1,y2,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

Here the calculation of the coordinates and the size of the rectangle outlining the shape are different from the calculation in the previous method. This is natural since we draw a vertical line with the width of one pixel. The height of the line should be calculated as a difference between the maximum and minimum values of two Y coordinates of the line. The Y coordinate of the saved area should correspond to the minimum value of the two Y coordinates (the upper point of the drawn line).

The method drawing a segment of a horizontal line:

//+------------------------------------------------------------------+
//| Draw a segment of a horizontal line                              |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineHorizontalOnBG(const int   x1,           // X coordinate of the segment first point
                                        const int   x2,           // X coordinate of the segment second point
                                        const int   y,            // Segment Y coordinate
                                        const color clr,          // Color
                                        const uchar opacity=255,  // Opacity
                                        const bool  redraw=false) // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=y;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawLineHorizontal(x1,x2,y,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

Here the calculation of the coordinates and the size of the saved area are similar to the same calculation in the previous method, except that this is a horizontal line and the height here is equal to one pixel, while the width and the X coordinate of the saved area should be calculated.

The method drawing a segment of a freehand line:

//+------------------------------------------------------------------+
//| Draw a segment of a freehand line                                |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineOnBG(const int   x1,            // X coordinate of the segment first point
                              const int   y1,            // Y coordinate of the segment first point
                              const int   x2,            // X coordinate of the segment second point
                              const int   y2,            // Y coordinate of the segment second point
                              const color clr,           // Color
                              const uchar opacity=255,   // Opacity
                              const bool  redraw=false)  // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawLine(x1,y1,x2,y2,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

Here the coordinates and the size of the saved area are calculated based on the coordinates of the drawn line.

The method drawing a polyline:

//+------------------------------------------------------------------+
//| Draw a polyline                                                  |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolylineOnBG(int         &array_x[],   // Array with the X coordinates of polyline points
                                  int         &array_y[],   // Array with the Y coordinates of polyline points
                                  const color clr,          // Color
                                  const uchar opacity=255,  // Opacity
                                  const bool  redraw=false) // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   int x=0,y=0;
   if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y))
      return false;
   this.m_quad_x=x;
   this.m_quad_y=y;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   int max_x_value=0,min_x_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value))
      return false;
   int max_y_value=0,min_y_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value))
      return false;
   this.m_quad_width=(max_x_value-min_x_value)+1;
   this.m_quad_height=(max_y_value-min_y_value)+1;

//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawPolyline(array_x,array_y,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

Here the idea behind the calculation of the coordinates and the size of the saved area is the same as the one behind the methods considered above. However, the execution is different since in case of a polyline (as well as many other shapes), the coordinates are passed in arrays rather than in the form of variables as it is impossible to know the number of line bends or the number of coordinates to be passed in the method arguments beforehand. This is why before calling the method, we should fill in two arrays with X coordinates and the appropriate Y coordinates of each line bend dot.
In the method, we receive the maximum and minimum values from the arrays using the previously considered function returning the minimum or maximum value from the array passed to the function. The obtained values are used for calculating the coordinates and the size of the saved form background area.

The remaining shape drawing methods without smoothing (just pay attention to the calculation of the coordinates and the size of the saved area):

//+------------------------------------------------------------------+
//| Draw the rectangle                                               |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonOnBG(int         &array_x[],    // Array with the X coordinates of polygon points
                                 int         &array_y[],    // Array with the Y coordinates of polygon points
                                 const color clr,           // Color
                                 const uchar opacity=255,   // Opacity
                                 const bool  redraw=false)  // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   int x=0,y=0;
   if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y))
      return false;
   this.m_quad_x=x;
   this.m_quad_y=y;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   int max_x_value=0,min_x_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value))
      return false;
   int max_y_value=0,min_y_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value))
      return false;
   this.m_quad_width=(max_x_value-min_x_value)+1;
   if(this.m_quad_width==0)
      this.m_quad_width=1;
   this.m_quad_height=(max_y_value-min_y_value)+1;
   if(this.m_quad_height==0)
      this.m_quad_height=1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawPolygon(array_x,array_y,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a rectangle using two points                                |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawRectangleOnBG(const int   x1,             // X coordinate of the first point defining the rectangle
                                   const int   y1,             // Y coordinate of the first point defining the rectangle
                                   const int   x2,             // X coordinate of the second point defining the rectangle
                                   const int   y2,             // Y coordinate of the second point defining the rectangle
                                   const color clr,            // Color
                                   const uchar opacity=255,    // Opacity
                                   const bool  redraw=false)   // Chart redraw flag
     {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawRectangle(x1,y1,x2,y2,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw the circle                                                  |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawCircleOnBG(const int   x,              // X coordinate of the circle center
                                const int   y,              // Y coordinate of the circle center
                                const int   r,              // Circle radius
                                const color clr,            // Color
                                const uchar opacity=255,    // Opacity
                                const bool  redraw=false)   // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   int rd=(r>0 ? r : 1);
   this.m_quad_x=x-rd;
   this.m_quad_y=y-rd;
   double x2=x+rd;
   double y2=y+rd;
   if(this.m_quad_x<0)
      this.m_quad_x=0;
   if(this.m_quad_y<0)
      this.m_quad_y=0;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1);
   this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1);
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawCircle(x,y,rd,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_CENTER;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a triangle                                                  |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawTriangleOnBG(const int   x1,           // X coordinate of the triangle first vertex
                                  const int   y1,           // Y coordinate of the triangle first vertex
                                  const int   x2,           // X coordinate of the triangle second vertex
                                  const int   y2,           // Y coordinate of the triangle second vertex
                                  const int   x3,           // X coordinate of the triangle third vertex
                                  const int   y3,           // Y coordinate of the triangle third vertex
                                  const color clr,          // Color
                                  const uchar opacity=255,  // Opacity
                                  const bool  redraw=false) // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(::fmin(x1,x2),x3);
   this.m_quad_y=::fmin(::fmin(y1,y2),y3);
   int max_x=::fmax(::fmax(x1,x2),x3);
   int max_y=::fmax(::fmax(y1,y2),y3);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=int(max_x-this.m_quad_x)+1;
   this.m_quad_height=int(max_y-this.m_quad_y)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawTriangle(x1,y1,x2,y2,x3,y3,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw an ellipse using two points                                 |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawEllipseOnBG(const int   x1,            // X coordinate of the first point defining the ellipse
                                 const int   y1,            // Y coordinate of the first point defining the ellipse
                                 const int   x2,            // X coordinate of the second point defining the ellipse
                                 const int   y2,            // Y coordinate of the second point defining the ellipse
                                 const color clr,           // Color
                                 const uchar opacity=255,   // Opacity
                                 const bool  redraw=false)  // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawEllipse(x1,y1,x2,y2,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw an arc of an ellipse inscribed in a rectangle               |
//| with the corners in (x1,y1) and (x2,y2).                         |
//| The arc boundaries are cropped from the ellipse center           |
//| moving to two points with the coordinates of (x3,y3) and (x4,y4) |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawArcOnBG(const int   x1,             // X coordinate of the top left corner forming the rectangle
                             const int   y1,             // Y coordinate of the top left corner forming the rectangle
                             const int   x2,             // X coordinate of the bottom right corner forming the rectangle
                             const int   y2,             // Y coordinate of the bottom right corner forming the rectangle
                             const int   x3,             // X coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                             const int   y3,             // Y coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                             const int   x4,             // X coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                             const int   y4,             // Y coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                             const color clr,            // Color
                             const uchar opacity=255,    // Opacity
                             const bool  redraw=false)   // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2)-1;
   this.m_quad_y=::fmin(y1,y2)-1;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+2;
   this.m_quad_height=::fabs(y2-y1)+2;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawArc(x1,y1,x2,y2,x3,y3,x4,y4,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a filled sector of an ellipse inscribed in a rectangle      |
//| with the corners in (x1,y1) and (x2,y2).                         |
//| The sector boundaries are cropped from the ellipse center,       |
//| moving to two points with the coordinates of (x3,y3) and (x4,y4) |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPieOnBG(const int   x1,             // X coordinate of the upper left corner of the rectangle
                             const int   y1,             // Y coordinate of the upper left corner of the rectangle
                             const int   x2,             // X coordinate of the bottom right corner of the rectangle
                             const int   y2,             // Y coordinate of the bottom right corner of the rectangle
                             const int   x3,             // X coordinate of the first point to find the arc boundaries
                             const int   y3,             // Y coordinate of the first point to find the arc boundaries
                             const int   x4,             // X coordinate of the second point to find the arc boundaries
                             const int   y4,             // Y coordinate of the second point to find the arc boundaries
                             const color clr,            // Color
                             const color fill_clr,       // Fill color
                             const uchar opacity=255,    // Opacity
                             const bool  redraw=false)   // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2)-1;
   this.m_quad_y=::fmin(y1,y2)-1;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+2;
   this.m_quad_height=::fabs(y2-y1)+2;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawPie(x1,y1,x2,y2,x3,y3,x4,y4,clr,fill_clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+


Let's consider the methods of drawing filled primitives without smoothing.

The method filling the area:

//+------------------------------------------------------------------+
//| Fill in the area                                                 |
//+------------------------------------------------------------------+
bool CFrameQuad::FillOnBG(const int   x,              // X coordinate of the filling start point
                          const int   y,              // Y coordinate of the filling start point
                          const color clr,            // Color
                          const uchar opacity=255,    // Opacity
                          const uint  threshould=0,   // Threshold
                          const bool  redraw=false)   // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=0;
   this.m_quad_y=0;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=0;
   this.m_quad_height=0;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.Fill(x,y,clr,opacity,threshould);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

Since the method fills in an arbitrary enclosed area, we cannot know the size of the saved area in advance. Therefore, the entire form should be saved here. To achieve this, let's set the coordinates and the size to zero. In case of these values, the method, which saves the rectangular area of the image, saves the entire form background to the array.

As for the remaining methods of drawing filled primitives, their calculation of coordinates and saved area size matches the calculation of simple non-smoothed primitives considered earlier. Let's have a look at the methods as they are:

//+------------------------------------------------------------------+
//| Draw a filled rectangle                                          |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawRectangleFillOnBG(const int   x1,            // X coordinate of the first point defining the rectangle
                                       const int   y1,            // Y coordinate of the first point defining the rectangle
                                       const int   x2,            // X coordinate of the second point defining the rectangle
                                       const int   y2,            // Y coordinate of the second point defining the rectangle
                                       const color clr,           // Color
                                       const uchar opacity=255,   // Opacity
                                       const bool  redraw=false)  // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawRectangleFill(x1,y1,x2,y2,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a filled circle                                             |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawCircleFillOnBG(const int   x,             // X coordinate of the circle center
                                    const int   y,             // Y coordinate of the circle center
                                    const int   r,             // Circle radius
                                    const color clr,           // Color
                                    const uchar opacity=255,   // Opacity
                                    const bool  redraw=false)  // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   int rd=(r>0 ? r : 1);
   this.m_quad_x=x-rd;
   this.m_quad_y=y-rd;
   double x2=x+rd;
   double y2=y+rd;
   if(this.m_quad_x<0)
      this.m_quad_x=0;
   if(this.m_quad_y<0)
      this.m_quad_y=0;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1);
   this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1);
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawCircleFill(x,y,rd,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a filled triangle                                           |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawTriangleFillOnBG(const int   x1,             // X coordinate of the triangle first vertex
                                      const int   y1,             // Y coordinate of the triangle first vertex
                                      const int   x2,             // X coordinate of the triangle second vertex
                                      const int   y2,             // Y coordinate of the triangle second vertex
                                      const int   x3,             // X coordinate of the triangle third vertex
                                      const int   y3,             // Y coordinate of the triangle third vertex
                                      const color clr,            // Color
                                      const uchar opacity=255,    // Opacity
                                      const bool  redraw=false)   // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(::fmin(x1,x2),x3)-1;
   this.m_quad_y=::fmin(::fmin(y1,y2),y3)-1;
   int max_x=::fmax(::fmax(x1,x2),x3)+1;
   int max_y=::fmax(::fmax(y1,y2),y3)+1;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=int(max_x-this.m_quad_x)+1;
   this.m_quad_height=int(max_y-this.m_quad_y)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawTriangleFill(x1,y1,x2,y2,x3,y3,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a filled polygon                                            |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonFillOnBG(int         &array_x[],   // Array with the X coordinates of polygon points
                                     int         &array_y[],   // Array with the Y coordinates of polygon points
                                     const color clr,          // Color
                                     const uchar opacity=255,  // Opacity
                                     const bool  redraw=false) // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   int x=0,y=0;
   if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y))
      return false;
   this.m_quad_x=x;
   this.m_quad_y=y;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   int max_x_value=0,min_x_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value))
      return false;
   int max_y_value=0,min_y_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value))
      return false;
   this.m_quad_width=(max_x_value-min_x_value)+1;
   this.m_quad_height=(max_y_value-min_y_value)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawPolygonFill(array_x,array_y,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a filled ellipse inscribed in a rectangle                   |
//| with the given coordinates                                       |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawEllipseFillOnBG(const int   x1,           // X coordinate of the top left corner forming the rectangle
                                     const int   y1,           // Y coordinate of the top left corner forming the rectangle
                                     const int   x2,           // X coordinate of the bottom right corner forming the rectangle
                                     const int   y2,           // Y coordinate of the bottom right corner forming the rectangle
                                     const color clr,          // Color
                                     const uchar opacity=255,  // Opacity
                                     const bool  redraw=false) // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawEllipseFill(x1,y1,x2,y2,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+


The methods of drawing primitives with smoothing.

The method drawing a point using AntiAliasing algorithm:

//+------------------------------------------------------------------+
//| Draw a point using AntiAliasing algorithm                        |
//+------------------------------------------------------------------+
bool CFrameQuad::SetPixelAAOnBG(const double x,             // Point X coordinate
                                const double y,             // Point Y coordinate
                                const color  clr,           // Color
                                const uchar  opacity=255,   // Opacity
                                const bool   redraw=false)  // Chart redraw flag
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=x-1;
   if(this.m_quad_x<0)
      this.m_quad_x=0;
   this.m_quad_y=y-1;
   if(this.m_quad_y<0)
      this.m_quad_y=0;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=3;
   this.m_quad_height=3;
   
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If a background area with calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.SetPixelAA(x,y,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

Here, the calculation of saved area coordinates and size are different from the same calculation in the point drawing method without smoothing. A smoothed point can be located on three adjacent pixels (9 in total, that is 3 x 3 pixels), therefore the dimensions of the saved area should be three pixels high and three pixels wide. The X and Y coordinates, respectively, should be one pixel to the left and one pixel above the coordinates of the point itself. Thus, the saved area rectangle outlining the point will have a margin of one pixel on all sides of the drawn point in case the latter is blurred by the smoothing algorithm and drawn on more than one pixel. This will allow us to get rid of the incomplete restoration of the background erased by a drawn point with smoothing.

The method drawing a segment of a freehand line using AntiAliasing algorithm:

//+------------------------------------------------------------------+
//| Draw a segment of a freehand line                                |
//| using AntiAliasing algorithm                                     |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineAAOnBG(const int   x1,             // X coordinate of the segment first point
                                const int   y1,             // Y coordinate of the segment first point
                                const int   x2,             // X coordinate of the segment second point
                                const int   y2,             // Y coordinate of the segment second point
                                const color clr,            // Color
                                const uchar opacity=255,    // Opacity
                                const bool  redraw=false,   // Chart redraw flag
                                const uint  style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;

//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;

//--- Draw the shape and update the element
   this.m_element.DrawLineAA(x1,y1,x2,y2,clr,opacity,style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

Testing the method revealed that the edges of the drawn line are not blurry, therefore the calculation of the saved area size matches the calculation in the line drawing method without smoothing.

The method drawing a segment of a freehand line using Wu algorithm:

//+------------------------------------------------------------------+
//| Draw a segment of a freehand line using the                      |
//| Wu algorithm                                                     |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineWuOnBG(const int   x1,             // X coordinate of the segment first point
                                const int   y1,             // Y coordinate of the segment first point
                                const int   x2,             // X coordinate of the segment second point
                                const int   y2,             // Y coordinate of the segment second point
                                const color clr,            // Color
                                const uchar opacity=255,    // Opacity
                                const bool  redraw=false,   // Chart redraw flag
                                const uint  style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawLineWu(x1,y1,x2,y2,clr,opacity,style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

Here the calculation is similar to the previous method for the same reason.

The method drawing a segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration:

//+------------------------------------------------------------------+
//| Draw a  segment of a freehand line having a specified width      |
//| using a smoothing algorithm                                      |
//| with the preliminary sorting                                     |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineThickOnBG(const int   x1,                         // X coordinate of the segment first point
                                   const int   y1,                         // Y coordinate of the segment first point
                                   const int   x2,                         // X coordinate of the segment second point
                                   const int   y2,                         // Y coordinate of the segment second point
                                   const int   size,                       // Line width
                                   const color clr,                        // Color
                                   const uchar opacity=255,                // Opacity
                                   const bool  redraw=false,               // Chart redraw flag
                                   const uint  style=STYLE_SOLID,          // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                                   ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values
  {
//--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size
   int correct=int(::ceil((double)size/2.0))+1;
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2)-correct;
   this.m_quad_y=::fmin(y1,y2)-correct;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+1+correct*2;
   this.m_quad_height=::fabs(y2-y1)+1+correct*2;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawLineThick(x1,y1,x2,y2,size,clr,opacity,style,end_style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

In this method, calculation of a saved area is different from the ones considered above. Since a line with such a smoothing algorithm features an editable value and an appearance of its ends, the width of the saved area should consider the size (width) of the line and its edges (the line edges can be rounded, therefore the line size (length) increases by two rounding radii, i.e. by the value set as a line width).

The method drawing a vertical segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration:

//+---------------------------------------------------------------------+
//| Draw a vertical segment of a freehand line having a specified width |
//| using a smoothing algorithm                                         |
//| with the preliminary sorting                                        |
//+---------------------------------------------------------------------+
bool CFrameQuad::DrawLineThickVerticalOnBG(const int   x,                              // X coordinate of the segment
                                           const int   y1,                             // Y coordinate of the segment first point
                                           const int   y2,                             // Y coordinate of the segment second point
                                           const int   size,                           // line width
                                           const color clr,                            // Color
                                           const uchar opacity=255,                    // Opacity
                                           const bool  redraw=false,                   // Chart redraw flag
                                           const uint  style=STYLE_SOLID,              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                                           const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values
  {
//--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size and the type of its ends
   int correct_x=(int)::ceil((double)size/2.0);
   int correct_y=(end_style==LINE_END_BUTT ? 0 : correct_x);
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=x-correct_x;
   this.m_quad_y=::fmin(y1,y2)-correct_y;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=size;
   this.m_quad_height=::fabs(y2-y1)+1+correct_y*2;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawLineThickVertical(x,y1,y2,size,clr,opacity,style,end_style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

Here the calculation is the same as described for the previous method.

The remaining methods of drawing smoothed and other primitives:

//+-----------------------------------------------------------------------+
//| Draws a horizontal segment of a freehand line having a specified width|
//| using a smoothing algorithm                                           |
//| with the preliminary sorting                                          |
//+-----------------------------------------------------------------------+
bool CFrameQuad::DrawLineThickHorizontalOnBG(const int   x1,                              // X coordinate of the segment first point
                                             const int   x2,                              // X coordinate of the segment second point
                                             const int   y,                               // Segment Y coordinate
                                             const int   size,                            // line width
                                             const color clr,                             // Color
                                             const uchar opacity=255,                     // Opacity
                                             const bool  redraw=false,                    // Chart redraw flag
                                             const uint  style=STYLE_SOLID,               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                                             const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values
  {
//--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size and the type of its ends
   int correct_y=(int)::ceil((double)size/2.0);
   int correct_x=(end_style==LINE_END_BUTT ? 0 : correct_y);
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2)-correct_x;
   this.m_quad_y=y-correct_y;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+1+correct_x*2;
   this.m_quad_height=size;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawLineThickHorizontal(x1,x2,y,size,clr,opacity,style,end_style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a polyline using                                            |
//| AntiAliasing algorithm                                           |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolylineAAOnBG(int         &array_x[],       // Array with the X coordinates of polyline points
                                    int         &array_y[],       // Array with the Y coordinates of polyline points
                                    const color clr,              // Color
                                    const uchar opacity=255,      // Opacity
                                    const bool  redraw=false,     // Chart redraw flag
                                    const uint  style=UINT_MAX)   // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   int x=0,y=0;
   if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y))
      return false;
   this.m_quad_x=x;
   this.m_quad_y=y;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   int max_x_value=0,min_x_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value))
      return false;
   int max_y_value=0,min_y_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value))
      return false;
   this.m_quad_width=(max_x_value-min_x_value)+1;
   this.m_quad_height=(max_y_value-min_y_value)+1;

//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawPolylineAA(array_x,array_y,clr,opacity,style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draws a polyline using Wu algorithm                              |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolylineWuOnBG(int         &array_x[],       // Array with the X coordinates of polyline points
                                    int         &array_y[],       // Array with the Y coordinates of polyline points
                                    const color clr,              // Color
                                    const uchar opacity=255,      // Opacity
                                    const bool  redraw=false,     // Chart redraw flag
                                    const uint  style=UINT_MAX)   // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   int x=0,y=0;
   if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y))
      return false;
   this.m_quad_x=x;
   this.m_quad_y=y;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   int max_x_value=0,min_x_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value))
      return false;
   int max_y_value=0,min_y_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value))
      return false;
   this.m_quad_width=(max_x_value-min_x_value)+1;
   this.m_quad_height=(max_y_value-min_y_value)+1;

//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawPolylineWu(array_x,array_y,clr,opacity,style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a polyline with a specified width using                     |
//| two smoothing algorithms in series.                              |
//| First, individual segments are smoothed                          |
//| based on Bezier curves.                                          |
//| Then, to improve the rendering quality,                          |
//| a raster smoothing algorithm is applied                          |
//| made of the polyline segments                                    |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolylineSmoothOnBG(const int    &array_x[],                    // Array with the X coordinates of polyline points
                                        const int    &array_y[],                    // Array with the Y coordinates of polyline points
                                        const int    size,                          // Line width
                                        const color  clr,                           // Color
                                        const uchar  opacity=255,                   // Chart redraw flag
                                        const double tension=0.5,                   // Smoothing parameter value
                                        const double step=10,                       // Approximation step
                                        const bool   redraw=false,                  // Chart redraw flag
                                        const ENUM_LINE_STYLE style=STYLE_SOLID,    // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                                        const ENUM_LINE_END   end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=0;
   this.m_quad_y=0;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=this.m_element.Width();
   this.m_quad_height=this.m_element.Height();
   
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }

//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;

//--- Draw the shape and update the element
   this.m_element.DrawPolylineSmooth(array_x,array_y,size,clr,opacity,tension,step,style,end_style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a polyline with a specified width using                     |
//| a smoothing algorithm with the preliminary sorting               |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolylineThickOnBG(const int   &array_x[],                // Array with the X coordinates of polyline points
                                       const int   &array_y[],                // Array with the Y coordinates of polyline points
                                       const int   size,                      // Line width
                                       const color clr,                       // Color
                                       const uchar opacity=255,               // Opacity
                                       const bool  redraw=false,              // Chart redraw flag
                                       const uint  style=STYLE_SOLID,         // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                                       ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values
  {
//--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size
   int correct=int(::ceil((double)size/2.0))+1;
//--- Set the coordinates of the outlining rectangle
   int x=0,y=0;
   if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y))
      return false;
   this.m_quad_x=x-correct;
   this.m_quad_y=y-correct;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   int max_x_value=0,min_x_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value))
      return false;
   int max_y_value=0,min_y_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value))
      return false;
   this.m_quad_width=(max_x_value-min_x_value)+1+correct*2;
   this.m_quad_height=(max_y_value-min_y_value)+1+correct*2;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawPolylineThick(array_x,array_y,size,clr,opacity,style,end_style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a polygon using                                             |
//| AntiAliasing algorithm                                           |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonAAOnBG(int         &array_x[],     // Array with the X coordinates of polygon points
                                   int         &array_y[],     // Array with the Y coordinates of polygon points
                                   const color clr,            // Color
                                   const uchar opacity=255,    // Opacity
                                   const bool  redraw=false,   // Chart redraw flag
                                   const uint  style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   int x=0,y=0;
   if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y))
      return false;
   this.m_quad_x=x;
   this.m_quad_y=y;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   int max_x_value=0,min_x_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value))
      return false;
   int max_y_value=0,min_y_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value))
      return false;
   this.m_quad_width=(max_x_value-min_x_value)+1;
   if(this.m_quad_width==0)
      this.m_quad_width=1;
   this.m_quad_height=(max_y_value-min_y_value)+1;
   if(this.m_quad_height==0)
      this.m_quad_height=1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawPolygonAA(array_x,array_y,clr,opacity,style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a polygon using Wu algorithm                                |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonWuOnBG(int         &array_x[],     // Array with the X coordinates of polygon points
                                   int         &array_y[],     // Array with the Y coordinates of polygon points
                                   const color clr,            // Color
                                   const uchar opacity=255,    // Opacity
                                   const bool  redraw=false,   // Chart redraw flag
                                   const uint  style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   int x=0,y=0;
   if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y))
      return false;
   this.m_quad_x=x;
   this.m_quad_y=y;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   int max_x_value=0,min_x_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value))
      return false;
   int max_y_value=0,min_y_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value))
      return false;
   this.m_quad_width=(max_x_value-min_x_value)+1;
   if(this.m_quad_width==0)
      this.m_quad_width=1;
   this.m_quad_height=(max_y_value-min_y_value)+1;
   if(this.m_quad_height==0)
      this.m_quad_height=1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawPolygonWu(array_x,array_y,clr,opacity,style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a polygon with a specified width using                      |
//| two smoothing algorithms in series.                              |
//| First, individual segments are smoothed based on Bezier curves.  |
//| Then, to improve the rendering quality,                          |
//| a raster smoothing algorithm is applied                          |
//| made of the polyline segments.                                   |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonSmoothOnBG(int          &array_x[],                  // Array with the X coordinates of polyline points
                                       int          &array_y[],                  // Array with the Y coordinates of polyline points
                                       const int    size,                        // Line width
                                       const color  clr,                         // Color
                                       const uchar  opacity=255,                 // Chart redraw flag
                                       const double tension=0.5,                 // Smoothing parameter value
                                       const double step=10,                     // Approximation step
                                       const bool   redraw=false,                // Chart redraw flag
                                       const ENUM_LINE_STYLE style=STYLE_SOLID,  // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                                       const ENUM_LINE_END   end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=0;
   this.m_quad_y=0;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=this.m_element.Width();
   this.m_quad_height=this.m_element.Height();
   
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }

//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;

//--- Draw the shape and update the element
   this.m_element.DrawPolygonSmooth(array_x,array_y,size,clr,opacity,tension,step,style,end_style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a polygon with a specified width using                      |
//| a smoothing algorithm with the preliminary sorting               |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonThickOnBG(const int   &array_x[],                 // array with the X coordinates of polygon points
                                      const int   &array_y[],                 // array with the Y coordinates of polygon points
                                      const int   size,                       // line width
                                      const color clr,                        // Color
                                      const uchar opacity=255,                // Opacity
                                      const bool  redraw=false,               // Chart redraw flag
                                      const uint  style=STYLE_SOLID,          // line style
                                      ENUM_LINE_END end_style=LINE_END_ROUND) // line ends style
  {
//--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size
   int correct=int(::ceil((double)size/2.0))+1;
//--- Set the coordinates of the outlining rectangle
   int x=0,y=0;
   if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y))
      return false;
   this.m_quad_x=x-correct;
   this.m_quad_y=y-correct;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   int max_x_value=0,min_x_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value))
      return false;
   int max_y_value=0,min_y_value=0;
   if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value))
      return false;
   this.m_quad_width=(max_x_value-min_x_value)+1+correct*2;
   this.m_quad_height=(max_y_value-min_y_value)+1+correct*2;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawPolygonThick(array_x,array_y,size,clr,opacity,style,end_style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a triangle using                                            |
//| AntiAliasing algorithm                                           |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawTriangleAAOnBG(const int   x1,               // X coordinate of the triangle first vertex
                                    const int   y1,               // Y coordinate of the triangle first vertex
                                    const int   x2,               // X coordinate of the triangle second vertex
                                    const int   y2,               // Y coordinate of the triangle second vertex
                                    const int   x3,               // X coordinate of the triangle third vertex
                                    const int   y3,               // Y coordinate of the triangle third vertex
                                    const color clr,              // Color
                                    const uchar opacity=255,      // Opacity
                                    const bool  redraw=false,     // Chart redraw flag
                                    const uint  style=UINT_MAX)   // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(::fmin(x1,x2),x3);
   this.m_quad_y=::fmin(::fmin(y1,y2),y3);
   int max_x=::fmax(::fmax(x1,x2),x3);
   int max_y=::fmax(::fmax(y1,y2),y3);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=int(max_x-this.m_quad_x)+1;
   this.m_quad_height=int(max_y-this.m_quad_y)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawTriangleAA(x1,y1,x2,y2,x3,y3,clr,opacity,style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a triangle using Wu algorithm                               |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawTriangleWuOnBG(const int   x1,               // X coordinate of the triangle first vertex
                                    const int   y1,               // Y coordinate of the triangle first vertex
                                    const int   x2,               // X coordinate of the triangle second vertex
                                    const int   y2,               // Y coordinate of the triangle second vertex
                                    const int   x3,               // X coordinate of the triangle third vertex
                                    const int   y3,               // Y coordinate of the triangle third vertex
                                    const color clr,              // Color
                                    const uchar opacity=255,      // Opacity
                                    const bool  redraw=false,     // Chart redraw flag
                                    const uint  style=UINT_MAX)   // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(::fmin(x1,x2),x3);
   this.m_quad_y=::fmin(::fmin(y1,y2),y3);
   int max_x=::fmax(::fmax(x1,x2),x3);
   int max_y=::fmax(::fmax(y1,y2),y3);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=int(max_x-this.m_quad_x)+1;
   this.m_quad_height=int(max_y-this.m_quad_y)+1;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawTriangleWu(x1,y1,x2,y2,x3,y3,clr,opacity,style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a circle using                                              |
//| AntiAliasing algorithm                                           |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawCircleAAOnBG(const int    x,              // X coordinate of the circle center
                                  const int    y,              // Y coordinate of the circle center
                                  const double r,              // Circle radius
                                  const color  clr,            // Color
                                  const uchar  opacity=255,    // Opacity
                                  const bool   redraw=false,   // Chart redraw flag
                                  const uint   style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   double rd=(r>0 ? r : 1);
   this.m_quad_x=x-rd;
   this.m_quad_y=y-rd;
   double x2=x+rd;
   double y2=y+rd;
   if(this.m_quad_x<0)
      this.m_quad_x=0;
   if(this.m_quad_y<0)
      this.m_quad_y=0;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1);
   this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1);
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawCircleAA(x,y,rd,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw a circle using Wu algorithm                                 |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawCircleWuOnBG(const int    x,              // X coordinate of the circle center
                                  const int    y,              // Y coordinate of the circle center
                                  const double r,              // Circle radius
                                  const color  clr,            // Color
                                  const uchar  opacity=255,    // Opacity
                                  const bool   redraw=false,   // Chart redraw flag
                                  const uint   style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   double rd=(r>0 ? r : 1);
   this.m_quad_x=x-rd;
   this.m_quad_y=y-rd;
   double x2=x+rd;
   double y2=y+rd;
   if(this.m_quad_x<0)
      this.m_quad_x=0;
   if(this.m_quad_y<0)
      this.m_quad_y=0;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1);
   this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1);
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawCircleWu(x,y,rd,clr,opacity);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw an ellipse using two points while applying                  |
//| AntiAliasing algorithm                                           |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawEllipseAAOnBG(const double x1,               // X coordinate of the first point defining the ellipse
                                   const double y1,               // Y coordinate of the first point defining the ellipse
                                   const double x2,               // X coordinate of the second point defining the ellipse
                                   const double y2,               // Y coordinate of the second point defining the ellipse
                                   const color  clr,              // Color
                                   const uchar  opacity=255,      // Opacity
                                   const bool   redraw=false,     // Chart redraw flag
                                   const uint   style=UINT_MAX)   // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2)-1;
   this.m_quad_y=::fmin(y1,y2)-1;
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=int(::ceil(::fabs(x2-x1)))+1;
   this.m_quad_height=int(::ceil(::fabs(y2-y1)))+1;
   
   if(this.m_quad_width<3)
      this.m_quad_width=3;
   if(this.m_quad_height<3)
      this.m_quad_height=3;
      
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawEllipseAA(x1,y1,x2,y2,clr,opacity,style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+
//| Draw an ellipse using two points while applying                  |
//| Wu algorithm                                                     |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawEllipseWuOnBG(const int   x1,             // X coordinate of the first point defining the ellipse
                                   const int   y1,             // Y coordinate of the first point defining the ellipse
                                   const int   x2,             // X coordinate of the second point defining the ellipse
                                   const int   y2,             // Y coordinate of the second point defining the ellipse
                                   const color clr,            // Color
                                   const uchar opacity=255,    // Opacity
                                   const bool  redraw=false,   // Chart redraw flag
                                   const uint  style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
//--- Set the coordinates of the outlining rectangle
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area)
   this.m_quad_width=::fabs(x2-x1)+1;
   if(this.m_quad_width<3)
      this.m_quad_width=3;
   this.m_quad_height=::fabs(y2-y1)+1;
   if(this.m_quad_height<3)
      this.m_quad_height=3;
   
//--- Calculate coordinate offsets for the saved area depending on the anchor point
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y);
//--- If the pixel array is not empty, the background under the image has already been saved -
//--- restore the previously saved background (by the previous coordinates and offsets)
   if(::ArraySize(this.m_array)>0)
     {
      if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev)))
         return false;
     }
//--- If the background area with the calculated coordinates and size under the future image is successfully saved
   if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height))
      return false;
//--- Draw the shape and update the element
   this.m_element.DrawEllipseWu(x1,y1,x2,y2,clr,opacity,style);
   this.m_element.Update(redraw);
   this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;
   this.m_x_last=this.m_quad_x;
   this.m_y_last=this.m_quad_y;
   this.m_shift_x_prev=shift_x;
   this.m_shift_y_prev=shift_y;
   return true;
  }
//+------------------------------------------------------------------+

Here, the saved background area calculation algorithms of all methods are approximately identical to the calculation algorithms in the methods considered above.

In the ellipse drawing methods (DrawEllipseAAOnBG and DrawEllipseWuOnBG), if the rectangle the ellipse is drawn within is less than three pixels, the shape is not drawn. Therefore, the calculations here contain the check for the size less than three pixels. I have not decided yet, whether this is my bug or a feature of the CCanvas class methods. I hope to clarify this later.

I have developed all classes of the animation frame objects that I currently need.

Now it is time to create a class to store, access and manage created animation frame objects.

The class is to contain two (for now) lists for storing created animation frame objects (text and rectangle ones), as well as to have the methods of creating and managing new objects. Subsequently, the class is to store all animation objects belonging to one form. Thus, each form is to feature its own set of animation objects that can be dynamically created and added to the list of form animations.

Form animation class

In \MQL5\Include\DoEasy\Objects\Graph\Animations\, create a new Animations.mqh file of the CAnimations class.

Only newly created descendant class files of the base animation frame object should be included into the class file, while the class itself should be a descendant of the base object of the CObject standard library:

//+------------------------------------------------------------------+
//|                                                   Animations.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 "FrameText.mqh"
#include "FrameQuad.mqh"
//+------------------------------------------------------------------+
//| Pixel copier class                                               |
//+------------------------------------------------------------------+
class CAnimations : public CObject
  {
  }

In the private section of the class, declare the pointer to the graphical element object animation objects are to be created from, two lists for storing two types of animation frame objects and the methods for returning the flag indicating the presence of a specified object in the list, as well as the methods returning the pointer to the existing animation frame object or preliminarily creating it if it is not in the list:

//+------------------------------------------------------------------+
//| Pixel copier class                                               |
//+------------------------------------------------------------------+
class CAnimations : public CObject
  {
private:
   CGCnvElement     *m_element;                             // Pointer to the graphical element
   CArrayObj         m_list_frames_text;                    // List of text animation frames
   CArrayObj         m_list_frames_quad;                    // List of rectangle animation frames

//--- Return the flag indicating the presence of the frame object with the specified ID in the list
   bool              IsPresentFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id);
//--- Return or create a new animation frame object
   CFrame           *GetOrCreateFrame(const string soutce,const int id,const ENUM_ANIMATION_FRAME_TYPE frame_type,const bool create_new);

public:

All methods are considered below.

In the public section of the class, declare the methods for creating and working with objects in the lists and the methods of drawing primitives, while saving and restoring the background:

public:
                     CAnimations(CGCnvElement *element);
                     CAnimations(){;}

//--- Create a new (1) rectangle and (2) text animation frame object
   CFrame           *CreateNewFrameText(const int id);
   CFrame           *CreateNewFrameQuad(const int id);
//--- Return the animation frame objects by ID
   CFrame           *GetFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id);
//--- Return the list of (1) text and (2) rectangle animation frames
   CArrayObj        *GetListFramesText(void)                { return &this.m_list_frames_text;  }
   CArrayObj        *GetListFramesQuad(void)                { return &this.m_list_frames_quad;  }

//+------------------------------------------------------------------+
//| The methods of drawing, while saving and restoring the background|
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Display a text on the background                                 |
//+------------------------------------------------------------------+
   bool              TextOnBG(const int id,
                              const string text,
                              const int x,
                              const int y,
                              const ENUM_TEXT_ANCHOR anchor,
                              const color clr,
                              const uchar opacity,
                              const bool create_new=true,
                              const bool redraw=false);
//+------------------------------------------------------------------+
//| Methods of drawing primitives without smoothing                  |
//+------------------------------------------------------------------+
//--- Set the color of the dot with the specified coordinates
   bool              SetPixelOnBG(const int id,const int x,const int y,const color clr,const uchar opacity=255,const bool create_new=true,const bool redraw=false);
                       
//--- Draw a segment of a vertical line
   bool              DrawLineVerticalOnBG(const int id,                 // Frame ID
                              const int   x,                            // Segment X coordinate
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a segment of a horizontal line
   bool              DrawLineHorizontalOnBG(const int id,               // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y,                            // Segment Y coordinate
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a segment of a freehand line
   bool              DrawLineOnBG(const int id,                         // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a polyline
   bool              DrawPolylineOnBG(const int id,                     // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polyline points
                              int         &array_y[],                   // Array with the Y coordinates of polyline points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a polygon
   bool              DrawPolygonOnBG(const int id,                      // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a rectangle using two points
   bool              DrawRectangleOnBG(const int id,                    // Frame ID
                              const int   x1,                           // X coordinate of the first point defining the rectangle
                              const int   y1,                           // Y coordinate of the first point defining the rectangle
                              const int   x2,                           // X coordinate of the second point defining the rectangle
                              const int   y2,                           // Y coordinate of the second point defining the rectangle
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a circle
   bool              DrawCircleOnBG(const int id,                       // Frame ID
                              const int   x,                            // X coordinate of the circle center
                              const int   y,                            // Y coordinate of the circle center
                              const int   r,                            // Circle radius
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a triangle
   bool              DrawTriangleOnBG(const int id,                     // Frame ID
                              const int   x1,                           // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw an ellipse using two points
   bool              DrawEllipseOnBG(const int id,                      // Frame ID
                              const int   x1,                           // X coordinate of the first point defining the ellipse
                              const int   y1,                           // Y coordinate of the first point defining the ellipse
                              const int   x2,                           // X coordinate of the second point defining the ellipse
                              const int   y2,                           // Y coordinate of the second point defining the ellipse
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw an arc of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2).
//--- The arc boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4)
   bool              DrawArcOnBG(const int id,                          // Frame ID
                              const int   x1,                           // X coordinate of the top left corner forming the rectangle
                              const int   y1,                           // Y coordinate of the top left corner forming the rectangle
                              const int   x2,                           // X coordinate of the bottom right corner forming the rectangle
                              const int   y2,                           // Y coordinate of the bottom right corner forming the rectangle
                              const int   x3,                           // X coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const int   y3,                           // Y coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const int   x4,                           // X coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const int   y4,                           // Y coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a filled sector of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2).
//--- The sector boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4)
   bool              DrawPieOnBG(const int id,                          // Frame ID
                              const int   x1,                           // X coordinate of the upper left corner of the rectangle
                              const int   y1,                           // Y coordinate of the upper left corner of the rectangle
                              const int   x2,                           // X coordinate of the bottom right corner of the rectangle
                              const int   y2,                           // Y coordinate of the bottom right corner of the rectangle
                              const int   x3,                           // X coordinate of the first point to find the arc boundaries
                              const int   y3,                           // Y coordinate of the first point to find the arc boundaries
                              const int   x4,                           // X coordinate of the second point to find the arc boundaries
                              const int   y4,                           // Y coordinate of the second point to find the arc boundaries
                              const color clr,                          // Color
                              const color fill_clr,                     // Fill color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//+------------------------------------------------------------------+
//| Methods of drawing filled primitives without smoothing           |
//+------------------------------------------------------------------+
//--- Fill in the area
   bool              FillOnBG(const int   id,                           // Frame ID
                              const int   x,                            // X coordinate of the filling start point
                              const int   y,                            // Y coordinate of the filling start point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const uint  threshould=0,                 // Threshold
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a filled rectangle
   bool              DrawRectangleFillOnBG(const int id,                // Frame ID
                              const int   x1,                           // X coordinate of the first point defining the rectangle
                              const int   y1,                           // Y coordinate of the first point defining the rectangle
                              const int   x2,                           // X coordinate of the second point defining the rectangle
                              const int   y2,                           // Y coordinate of the second point defining the rectangle
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag

//--- Draw a filled circle
   bool              DrawCircleFillOnBG(const int id,                   // Frame ID
                              const int   x,                            // X coordinate of the circle center
                              const int   y,                            // Y coordinate of the circle center
                              const int   r,                            // Circle radius
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a filled triangle
   bool              DrawTriangleFillOnBG(const int id,                 // Frame ID
                              const int   x1,                           // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a filled polygon
   bool              DrawPolygonFillOnBG(const int id,                  // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//--- Draw a filled ellipse inscribed in a rectangle with the specified coordinates
   bool              DrawEllipseFillOnBG(const int id,                  // Frame ID
                              const int   x1,                           // X coordinate of the top left corner forming the rectangle
                              const int   y1,                           // Y coordinate of the top left corner forming the rectangle
                              const int   x2,                           // X coordinate of the bottom right corner forming the rectangle
                              const int   y2,                           // Y coordinate of the bottom right corner forming the rectangle
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false);                // Chart redraw flag
                       
//+------------------------------------------------------------------+
//| Methods of drawing primitives using smoothing                    |
//+------------------------------------------------------------------+
//--- Draw a point using AntiAliasing algorithm
   bool              SetPixelAAOnBG(const int id,                       // Frame ID
                              const double x,                           // Point X coordinate
                              const double y,                           // Point Y coordinate
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false);               // Chart redraw flag
                       
//--- Draw a segment of a freehand line using AntiAliasing algorithm
   bool              DrawLineAAOnBG(const int id,                       // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a segment of a freehand line using Wu algorithm
   bool              DrawLineWuOnBG(const int id,                       // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draws a segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration
   bool              DrawLineThickOnBG(const int id,                    // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const int   size,                         // Line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              ENUM_LINE_END end_style=LINE_END_ROUND);  // Line style is one of the ENUM_LINE_END enumeration's values
 
//--- Draw a vertical segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration
   bool              DrawLineThickVerticalOnBG(const int id,            // Frame ID
                              const int   x,                            // Segment X coordinate
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   y2,                           // Y coordinate of the segment second point
                              const int   size,                         // line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values
                       
//--- Draw a horizontal segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration
   bool              DrawLineThickHorizontalOnBG(const int id,          // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y,                            // Segment Y coordinate
                              const int   size,                         // line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values

//--- Draws a polyline using AntiAliasing algorithm
   bool              DrawPolylineAAOnBG(const int id,                   // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polyline points
                              int         &array_y[],                   // Array with the Y coordinates of polyline points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draws a polyline using Wu algorithm
   bool              DrawPolylineWuOnBG(const int id,                   // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polyline points
                              int         &array_y[],                   // Array with the Y coordinates of polyline points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a polyline with a specified width consecutively using two antialiasing algorithms.
//--- First, individual line segments are smoothed based on Bezier curves.
//--- Then, the raster antialiasing algorithm is applied to the polyline built from these segments to improve the rendering quality
   bool              DrawPolylineSmoothOnBG(const int id,               // Frame ID
                              const int    &array_x[],                  // Array with the X coordinates of polyline points
                              const int    &array_y[],                  // Array with the Y coordinates of polyline points
                              const int    size,                        // Line width
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const double tension=0.5,                 // Smoothing parameter value
                              const double step=10,                     // Approximation step
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false,                // Chart redraw flag
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values
                       
//--- Draw a polyline having a specified width using smoothing algorithm with the preliminary filtration
   bool              DrawPolylineThickOnBG(const int id,                // Frame ID
                              const int     &array_x[],                 // Array with the X coordinates of polyline points
                              const int     &array_y[],                 // Array with the Y coordinates of polyline points
                              const int     size,                       // Line width
                              const color   clr,                        // Color
                              const uchar   opacity=255,                // Opacity
                              const bool    create_new=true,            // New object creation flag
                              const bool    redraw=false,               // Chart redraw flag
                              const uint    style=STYLE_SOLID,          // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              ENUM_LINE_END end_style=LINE_END_ROUND);  // Line style is one of the ENUM_LINE_END enumeration's values
                       
//--- Draw a polygon using AntiAliasing algorithm
   bool              DrawPolygonAAOnBG(const int id,                    // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a polygon using Wu algorithm
   bool              DrawPolygonWuOnBG(const int id,                    // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a polygon with a specified width consecutively using two smoothing algorithms.
//--- First, individual segments are smoothed based on Bezier curves.
//--- Then, the raster smoothing algorithm is applied to the polygon built from these segments to improve the rendering quality. 
   bool              DrawPolygonSmoothOnBG(const int id,                // Frame ID
                              int          &array_x[],                  // Array with the X coordinates of polyline points
                              int          &array_y[],                  // Array with the Y coordinates of polyline points
                              const int    size,                        // Line width
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const double tension=0.5,                 // Smoothing parameter value
                              const double step=10,                     // Approximation step
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false,                // Chart redraw flag
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values
                       
//--- Draw a polygon having a specified width using smoothing algorithm with the preliminary filtration
   bool              DrawPolygonThickOnBG(const int id,                 // Frame ID
                              const int   &array_x[],                   // array with the X coordinates of polygon points
                              const int   &array_y[],                   // array with the Y coordinates of polygon points
                              const int   size,                         // line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // line style
                              ENUM_LINE_END end_style=LINE_END_ROUND);  // line ends style
                       
//--- Draw a triangle using AntiAliasing algorithm
   bool              DrawTriangleAAOnBG(const int id,                   // Frame ID
                              const int   x1,                           // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a triangle using Wu algorithm
   bool              DrawTriangleWuOnBG(const int id,                   // Frame ID
                              const int   x1,                           // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a circle using AntiAliasing algorithm
   bool              DrawCircleAAOnBG(const int id,                     // Frame ID
                              const int    x,                           // X coordinate of the circle center
                              const int    y,                           // Y coordinate of the circle center
                              const double r,                           // Circle radius
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false,                // Chart redraw flag
                              const uint   style=UINT_MAX);             // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw a circle using Wu algorithm
   bool              DrawCircleWuOnBG(const int id,                     // Frame ID
                              const int    x,                           // X coordinate of the circle center
                              const int    y,                           // Y coordinate of the circle center
                              const double r,                           // Circle radius
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false,                // Chart redraw flag
                              const uint   style=UINT_MAX);             // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw an ellipse by two points using AntiAliasing algorithm
   bool              DrawEllipseAAOnBG(const int id,                    // Frame ID
                              const double x1,                          // X coordinate of the first point defining the ellipse
                              const double y1,                          // Y coordinate of the first point defining the ellipse
                              const double x2,                          // X coordinate of the second point defining the ellipse
                              const double y2,                          // Y coordinate of the second point defining the ellipse
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false,                // Chart redraw flag
                              const uint   style=UINT_MAX);             // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       
//--- Draw an ellipse by two points using Wu algorithm
   bool              DrawEllipseWuOnBG(const int id,                    // Frame ID
                              const int   x1,                           // X coordinate of the first point defining the ellipse
                              const int   y1,                           // Y coordinate of the first point defining the ellipse
                              const int   x2,                           // X coordinate of the second point defining the ellipse
                              const int   y2,                           // Y coordinate of the second point defining the ellipse
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX);              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  };
//+------------------------------------------------------------------+


Let's consider the implementation of the declared methods.

The parametric constructor:

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CAnimations::CAnimations(CGCnvElement *element)
  {
   this.m_element=element;
  }
//+------------------------------------------------------------------+

The value of the pointer to the graphical element object passed in the arguments is set for m_element pointer.

The method returning the pointer to the animation frame object by type and ID:

//+------------------------------------------------------------------+
//| Return the animation frame objects by type and ID                |
//+------------------------------------------------------------------+
CFrame *CAnimations::GetFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id)
  {
//--- Declare the pointer to the animation frame object
   CFrame *frame=NULL;
//--- Depending on the necessary object type, receive their number in the appropriate list
   int total=
     (
      frame_type==ANIMATION_FRAME_TYPE_TEXT ? this.m_list_frames_text.Total() : 
      frame_type==ANIMATION_FRAME_TYPE_QUAD ? this.m_list_frames_quad.Total() : 0
     );
//--- Get the next object in the loop ...
   for(int i=0;i<total;i++)
     {
      //--- ... by the list corresponding to the animation frame type
      switch(frame_type)
        {
         case ANIMATION_FRAME_TYPE_TEXT : frame=this.m_list_frames_text.At(i); break;
         case ANIMATION_FRAME_TYPE_QUAD : frame=this.m_list_frames_quad.At(i); break;
         default: break;
        }
      //--- if failed to get the pointer, move on to the next one
      if(frame==NULL)
         continue;
      //--- If the object ID correspond to the required one,
      //--- return the pointer to the detected object
      if(frame.ID()==id)
         return frame;
     }
//--- Nothing is found - return NULL
   return NULL;
  }
//+------------------------------------------------------------------+

The method logic is described in details in the code comments and requires no explanations.

The method returning the flag indicating the presence of the frame object with the specified type and ID in the list:

//+-----------------------------------------------------------------------+
//| Return the flag indicating the presence of the animation frame object |
//| with the specified type and ID                                        |
//+-----------------------------------------------------------------------+
bool CAnimations::IsPresentFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id)
  {
   return(this.GetFrame(frame_type,id)!=NULL);
  }
//+------------------------------------------------------------------+

The method returns the bool result of calling the GetFrame() method considered above. If the GetFrame() method returns a non-NULL result (the required object is present in the list), the method returns true, otherwise — false.

The method creating a new text animation frame object:

//+------------------------------------------------------------------+
//| Create a new text animation frame object                         |
//+------------------------------------------------------------------+
CFrame *CAnimations::CreateNewFrameText(const int id)
  {
//--- If the object with such an ID is already present, inform of that in the journal and return NULL
   if(this.IsPresentFrame(ANIMATION_FRAME_TYPE_TEXT,id))
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST),(string)id);
      return NULL;
     }
//--- Create a new text animation frame object with the specified ID
   CFrame *frame=new CFrameText(id,this.m_element);
//--- If failed to create an object, inform of that and return NULL
   if(frame==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME));
      return NULL;
     }
//--- If failed to add the created object to the list, inform of that, remove the object and return NULL
   if(!this.m_list_frames_text.Add(frame))
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST)," ID: ",id);
      delete frame;
      return NULL;
     }
//--- Return the pointer to a newly created object
   return frame;
  }
//+------------------------------------------------------------------+

The method logic is fully described in the code comments.

The method creating a new rectangle animation frame object:

//+------------------------------------------------------------------+
//| Create a new rectangle animation frame object                    |
//+------------------------------------------------------------------+
CFrame *CAnimations::CreateNewFrameQuad(const int id)
  {
//--- If the object with such an ID is already present, inform of that in the journal and return NULL
   if(this.IsPresentFrame(ANIMATION_FRAME_TYPE_QUAD,id))
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST),(string)id);
      return NULL;
     }
//--- Create a new rectangle animation frame object with the specified ID
   CFrame *frame=new CFrameQuad(id,this.m_element);
//--- If failed to create an object, inform of that and return NULL
   if(frame==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME));
      return NULL;
     }
//--- If failed to add the created object to the list, inform of that, remove the object and return NULL
   if(!this.m_list_frames_quad.Add(frame))
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST)," ID: ",id);
      delete frame;
      return NULL;
     }
//--- Return the pointer to a newly created object
   return frame;
  }
//+------------------------------------------------------------------+

The method is identical to the one considered above.

The method returning the pointer or creating a new animation frame object:

//+------------------------------------------------------------------+
//| Return or create a new animation frame object                    |
//+------------------------------------------------------------------+
CFrame *CAnimations::GetOrCreateFrame(const string source,const int id,const ENUM_ANIMATION_FRAME_TYPE frame_type,const bool create_new)
  {
   //--- Declare null pointers to objects
   CFrameQuad *frame_q=NULL;
   CFrameText *frame_t=NULL;
   //--- Depending on the required object type
   switch(frame_type)
     {
      //--- If this is a text animation frame,
      case ANIMATION_FRAME_TYPE_TEXT :
        //--- get the pointer to an object with a specified ID
        frame_t=this.GetFrame(ANIMATION_FRAME_TYPE_TEXT,id);
        //--- If the pointer is obtained, return it
        if(frame_t!=NULL)
           return frame_t;
        //--- If the flag of creating a new object is not set, report an error and return NULL
        if(!create_new)
          {
           ::Print(source,CMessage::Text(MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST),(string)id);
           return NULL;
          }
        //--- Return the result of creating a new text animation frame object (pointer to the created object)
        return this.CreateNewFrameText(id);
      
      //--- If this is a rectangle animation frame
      case ANIMATION_FRAME_TYPE_QUAD :
        //--- get the pointer to an object with a specified ID
        frame_q=this.GetFrame(ANIMATION_FRAME_TYPE_QUAD,id);
        //--- If the pointer is obtained, return it
        if(frame_q!=NULL)
           return frame_q;
        //--- If the flag of creating a new object is not set, report an error and return NULL
        if(!create_new)
          {
           ::Print(source,CMessage::Text(MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST),(string)id);
           return NULL;
          }
        //--- Return the result of creating a new rectangle animation frame object (pointer to the created object)
        return this.CreateNewFrameQuad(id);
      //--- In the remaining cases, return NULL
      default:
        return NULL;
     }
  }
//+------------------------------------------------------------------+

The method logic is described in the code comments. If we need to work with an animation frame, we can create it beforehand, get the pointer to it and manage the obtained object. If we need to dynamically create objects, this method allows us to first create a new object (provided that an object with a specified ID is absent) and return the pointer to it. Thus, it is possible to arrange dynamic creation of an object as appropriate, get the pointer to it right away and manage it.

The methods of working with animation frame objects.

The method displaying a text on the background, while saving and restoring the background:

//+--------------------------------------------------------------------------------+
//| Display the text on the background, while saving and restoring the background  |
//+--------------------------------------------------------------------------------+
bool CAnimations::TextOnBG(const int id,
                           const string text,
                           const int x,
                           const int y,
                           const ENUM_TEXT_ANCHOR anchor,
                           const color clr,
                           const uchar opacity,
                           const bool create_new=true,
                           const bool redraw=false)
  {
   CFrameText *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_TEXT,create_new);
   if(frame==NULL)
      return false;
   return frame.TextOnBG(text,x,y,anchor,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+

The method receives the object ID, displayed text parameters (the text itself, X and Y coordinates, anchor point, color and opacity), the flag indicating the need to create a new object with the specified ID, in case the object with such an ID is not present in the list, and the chart redraw flag.
Next, get the pointer to the required object (or create the object if it is absent). If failed to get the pointer, return false.
If the pointer is received, return the result of the TextOnBG() method of the obtained text animation frame object.

The method setting the color of the point with specified coordinates:

//+------------------------------------------------------------------+
//| Set the color of the dot with the specified coordinates          |
//+------------------------------------------------------------------+
bool CAnimations::SetPixelOnBG(const int id,const int x,const int y,const color clr,const uchar opacity=255,const bool create_new=true,const bool redraw=false)
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.SetPixelOnBG(x,y,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+

The method logic is identical to the one of the method considered above. The method receives the object ID, drawn shape X and Y coordinates, its color and opacity, the flag indicating the need to create a new object with the specified ID, in case the object with such an ID is not present in the list, and the chart redraw flag.
Next, get the pointer to the required object (or create the object if it is absent). If failed to get the pointer, return false.
If the pointer is received, return the result of the SetPixelOnBG() method of the obtained animation rectangle frame object.

Other methods of drawing primitives.

The logic of the remaining shape drawing methods is identical to the logic of the methods considered above. Let's have a look at their listing:

//+------------------------------------------------------------------+
//| Draw a segment of a vertical line                                |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineVerticalOnBG(const int id,                 // Frame ID
                           const int   x,                            // Segment X coordinate
                           const int   y1,                           // Y coordinate of the segment first point
                           const int   y2,                           // Y coordinate of the segment second point
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawLineVerticalOnBG(x,y1,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a segment of a horizontal line                              |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineHorizontalOnBG(const int id,               // Frame ID
                           const int   x1,                           // X coordinate of the segment first point
                           const int   x2,                           // X coordinate of the segment second point
                           const int   y,                            // Segment Y coordinate
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawLineHorizontalOnBG(x1,x2,y,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a segment of a freehand line                                |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineOnBG(const int id,                         // Frame ID
                           const int   x1,                           // X coordinate of the segment first point
                           const int   y1,                           // Y coordinate of the segment first point
                           const int   x2,                           // X coordinate of the segment second point
                           const int   y2,                           // Y coordinate of the segment second point
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawLineOnBG(x1,y1,x2,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a polyline                                                  |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolylineOnBG(const int id,                     // Frame ID
                           int         &array_x[],                   // Array with the X coordinates of polyline points
                           int         &array_y[],                   // Array with the Y coordinates of polyline points
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPolylineOnBG(array_x,array_y,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw the rectangle                                               |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolygonOnBG(const int id,                      // Frame ID
                           int         &array_x[],                   // Array with the X coordinates of polygon points
                           int         &array_y[],                   // Array with the Y coordinates of polygon points
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPolygonOnBG(array_x,array_y,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a rectangle using two points                                |
//+------------------------------------------------------------------+
bool CAnimations::DrawRectangleOnBG(const int id,                    // Frame ID
                           const int   x1,                           // X coordinate of the first point defining the rectangle
                           const int   y1,                           // Y coordinate of the first point defining the rectangle
                           const int   x2,                           // X coordinate of the second point defining the rectangle
                           const int   y2,                           // Y coordinate of the second point defining the rectangle
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawRectangleOnBG(x1,y1,x2,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw the circle                                                  |
//+------------------------------------------------------------------+
bool CAnimations::DrawCircleOnBG(const int id,                       // Frame ID
                           const int   x,                            // X coordinate of the circle center
                           const int   y,                            // Y coordinate of the circle center
                           const int   r,                            // Circle radius
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawCircleOnBG(x,y,r,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a triangle                                                  |
//+------------------------------------------------------------------+
bool CAnimations::DrawTriangleOnBG(const int id,                     // Frame ID
                           const int   x1,                           // X coordinate of the triangle first vertex
                           const int   y1,                           // Y coordinate of the triangle first vertex
                           const int   x2,                           // X coordinate of the triangle second vertex
                           const int   y2,                           // Y coordinate of the triangle second vertex
                           const int   x3,                           // X coordinate of the triangle third vertex
                           const int   y3,                           // Y coordinate of the triangle third vertex
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawTriangleOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw an ellipse using two points                                 |
//+------------------------------------------------------------------+
bool CAnimations::DrawEllipseOnBG(const int id,                      // Frame ID
                           const int   x1,                           // X coordinate of the first point defining the ellipse
                           const int   y1,                           // Y coordinate of the first point defining the ellipse
                           const int   x2,                           // X coordinate of the second point defining the ellipse
                           const int   y2,                           // Y coordinate of the second point defining the ellipse
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawEllipseOnBG(x1,y1,x2,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw an arc of an ellipse inscribed in a rectangle               |
//| with the corners in (x1,y1) and (x2,y2).                         |
//| The arc boundaries are cropped from the ellipse center           |
//| moving to two points with the coordinates of (x3,y3) and (x4,y4) |
//+------------------------------------------------------------------+
bool CAnimations::DrawArcOnBG(const int id,                          // Frame ID
                           const int   x1,                           // X coordinate of the top left corner forming the rectangle
                           const int   y1,                           // Y coordinate of the top left corner forming the rectangle
                           const int   x2,                           // X coordinate of the bottom right corner forming the rectangle
                           const int   y2,                           // Y coordinate of the bottom right corner forming the rectangle
                           const int   x3,                           // X coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                           const int   y3,                           // Y coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                           const int   x4,                           // X coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                           const int   y4,                           // Y coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawArcOnBG(x1,y1,x2,y2,x3,y3,x4,y4,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a filled sector of an ellipse inscribed in a rectangle      |
//| with the corners in (x1,y1) and (x2,y2).                         |
//| The sector boundaries are cropped from the ellipse center,       |
//| moving to two points with the coordinates of (x3,y3) and (x4,y4) |
//+------------------------------------------------------------------+
bool CAnimations::DrawPieOnBG(const int id,                          // Frame ID
                           const int   x1,                           // X coordinate of the upper left corner of the rectangle
                           const int   y1,                           // Y coordinate of the upper left corner of the rectangle
                           const int   x2,                           // X coordinate of the bottom right corner of the rectangle
                           const int   y2,                           // Y coordinate of the bottom right corner of the rectangle
                           const int   x3,                           // X coordinate of the first point to find the arc boundaries
                           const int   y3,                           // Y coordinate of the first point to find the arc boundaries
                           const int   x4,                           // X coordinate of the second point to find the arc boundaries
                           const int   y4,                           // Y coordinate of the second point to find the arc boundaries
                           const color clr,                          // Color
                           const color fill_clr,                     // Fill color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPieOnBG(x1,y1,x2,y2,x3,y3,x4,y4,clr,fill_clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Fill in the area                                                 |
//+------------------------------------------------------------------+
bool CAnimations::FillOnBG(const int   id,                           // Frame ID
                           const int   x,                            // X coordinate of the filling start point
                           const int   y,                            // Y coordinate of the filling start point
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const uint  threshould=0,                 // Threshold
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.FillOnBG(x,y,clr,opacity,threshould,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a filled rectangle                                          |
//+------------------------------------------------------------------+
bool CAnimations::DrawRectangleFillOnBG(const int id,                // Frame ID
                           const int   x1,                           // X coordinate of the first point defining the rectangle
                           const int   y1,                           // Y coordinate of the first point defining the rectangle
                           const int   x2,                           // X coordinate of the second point defining the rectangle
                           const int   y2,                           // Y coordinate of the second point defining the rectangle
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawRectangleFillOnBG(x1,y1,x2,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a filled circle                                             |
//+------------------------------------------------------------------+
bool CAnimations::DrawCircleFillOnBG(const int id,                   // Frame ID
                           const int   x,                            // X coordinate of the circle center
                           const int   y,                            // Y coordinate of the circle center
                           const int   r,                            // Circle radius
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawCircleFillOnBG(x,y,r,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a filled triangle                                           |
//+------------------------------------------------------------------+
bool CAnimations::DrawTriangleFillOnBG(const int id,                 // Frame ID
                           const int   x1,                           // X coordinate of the triangle first vertex
                           const int   y1,                           // Y coordinate of the triangle first vertex
                           const int   x2,                           // X coordinate of the triangle second vertex
                           const int   y2,                           // Y coordinate of the triangle second vertex
                           const int   x3,                           // X coordinate of the triangle third vertex
                           const int   y3,                           // Y coordinate of the triangle third vertex
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawTriangleFillOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a filled polygon                                            |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolygonFillOnBG(const int id,                  // Frame ID
                           int         &array_x[],                   // Array with the X coordinates of polygon points
                           int         &array_y[],                   // Array with the Y coordinates of polygon points
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPolygonFillOnBG(array_x,array_y,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a filled ellipse inscribed in a rectangle                   |
//| with the given coordinates                                       |
//+------------------------------------------------------------------+
bool CAnimations::DrawEllipseFillOnBG(const int id,                  // Frame ID
                           const int   x1,                           // X coordinate of the top left corner forming the rectangle
                           const int   y1,                           // Y coordinate of the top left corner forming the rectangle
                           const int   x2,                           // X coordinate of the bottom right corner forming the rectangle
                           const int   y2,                           // Y coordinate of the bottom right corner forming the rectangle
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false)                 // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawEllipseFillOnBG(x1,y1,x2,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a point using AntiAliasing algorithm                        |
//+------------------------------------------------------------------+
bool CAnimations::SetPixelAAOnBG(const int id,                       // Frame ID
                           const double x,                           // Point X coordinate
                           const double y,                           // Point Y coordinate
                           const color  clr,                         // Color
                           const uchar  opacity=255,                 // Opacity
                           const bool   create_new=true,             // New object creation flag
                           const bool   redraw=false)                // Chart redraw flag
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.SetPixelAAOnBG(x,y,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Draw a segment of a freehand line using the                      |
//| AntiAliasing algorithm                                           |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineAAOnBG(const int id,                       // Frame ID
                           const int   x1,                           // X coordinate of the segment first point
                           const int   y1,                           // Y coordinate of the segment first point
                           const int   x2,                           // X coordinate of the segment second point
                           const int   y2,                           // Y coordinate of the segment second point
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawLineAAOnBG(x1,y1,x2,y2,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+
//| Draw a segment of a freehand line using the                      |
//| Wu algorithm                                                     |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineWuOnBG(const int id,                       // Frame ID
                           const int   x1,                           // X coordinate of the segment first point
                           const int   y1,                           // Y coordinate of the segment first point
                           const int   x2,                           // X coordinate of the segment second point
                           const int   y2,                           // Y coordinate of the segment second point
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawLineWuOnBG(x1,y1,x2,y2,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+
//| Draw a  segment of a freehand line having a specified width      |
//| using a smoothing algorithm                                      |
//| with the preliminary sorting                                     |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineThickOnBG(const int id,                    // Frame ID
                           const int   x1,                           // X coordinate of the segment first point
                           const int   y1,                           // Y coordinate of the segment first point
                           const int   x2,                           // X coordinate of the segment second point
                           const int   y2,                           // Y coordinate of the segment second point
                           const int   size,                         // Line width
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                           ENUM_LINE_END end_style=LINE_END_ROUND)   // Line style is one of the ENUM_LINE_END enumeration's values
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawLineThickOnBG(x1,y1,x2,y2,size,clr,opacity,redraw,style,end_style);
  }
//+---------------------------------------------------------------------+
//| Draw a vertical segment of a freehand line having a specified width |
//| using a smoothing algorithm                                         |
//| with the preliminary sorting                                        |
//+---------------------------------------------------------------------+
bool CAnimations::DrawLineThickVerticalOnBG(const int id,            // Frame ID
                           const int   x,                            // Segment X coordinate
                           const int   y1,                           // Y coordinate of the segment first point
                           const int   y2,                           // Y coordinate of the segment second point
                           const int   size,                         // line width
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                           const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawLineThickVerticalOnBG(x,y1,y2,size,clr,opacity,redraw,style,end_style);
  }
//+-----------------------------------------------------------------------+
//| Draws a horizontal segment of a freehand line having a specified width|
//| using a smoothing algorithm                                           |
//| with the preliminary sorting                                          |
//+-----------------------------------------------------------------------+
bool CAnimations::DrawLineThickHorizontalOnBG(const int id,          // Frame ID
                           const int   x1,                           // X coordinate of the segment first point
                           const int   x2,                           // X coordinate of the segment second point
                           const int   y,                            // Segment Y coordinate
                           const int   size,                         // line width
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                           const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawLineThickHorizontalOnBG(x1,x2,y,size,clr,opacity,redraw,style,end_style);
  }
//+------------------------------------------------------------------+
//| Draw a polyline using                                            |
//| AntiAliasing algorithm                                           |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolylineAAOnBG(const int id,                   // Frame ID
                           int         &array_x[],                   // Array with the X coordinates of polyline points
                           int         &array_y[],                   // Array with the Y coordinates of polyline points
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPolylineAAOnBG(array_x,array_y,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+
//| Draws a polyline using Wu algorithm                              |
//+------------------------------------------------------------------+
//--- 
bool CAnimations::DrawPolylineWuOnBG(const int id,                   // Frame ID
                           int         &array_x[],                   // Array with the X coordinates of polyline points
                           int         &array_y[],                   // Array with the Y coordinates of polyline points
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPolylineWuOnBG(array_x,array_y,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+
//| Draw a polyline with a specified width using                     |
//| two smoothing algorithms in series.                              |
//| First, individual segments are smoothed                          |
//| based on Bezier curves.                                          |
//| Then, to improve the rendering quality,                          |
//| a raster smoothing algorithm                                     |
//| made of the polyline segments is applied                                                              |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolylineSmoothOnBG(const int id,               // Frame ID
                           const int    &array_x[],                  // Array with the X coordinates of polyline points
                           const int    &array_y[],                  // Array with the Y coordinates of polyline points
                           const int    size,                        // Line width
                           const color  clr,                         // Color
                           const uchar  opacity=255,                 // Opacity
                           const double tension=0.5,                 // Smoothing parameter value
                           const double step=10,                     // Approximation step
                           const bool   create_new=true,             // New object creation flag
                           const bool   redraw=false,                // Chart redraw flag
                           const ENUM_LINE_STYLE style=STYLE_SOLID,  // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                           const ENUM_LINE_END   end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPolylineSmoothOnBG(array_x,array_y,size,clr,opacity,tension,step,redraw,style,end_style);
  }
//+------------------------------------------------------------------+
//| Draw a polyline with a specified width using                     |
//| a smoothing algorithm with the preliminary sorting               |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolylineThickOnBG(const int id,                // Frame ID
                           const int      &array_x[],                // Array with the X coordinates of polyline points
                           const int      &array_y[],                // Array with the Y coordinates of polyline points
                           const int      size,                      // Line width
                           const color    clr,                       // Color
                           const uchar    opacity=255,               // Opacity
                           const bool     create_new=true,           // New object creation flag
                           const bool     redraw=false,              // Chart redraw flag
                           const uint     style=STYLE_SOLID,         // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                           ENUM_LINE_END  end_style=LINE_END_ROUND)  // Line style is one of the ENUM_LINE_END enumeration's values
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPolylineThickOnBG(array_x,array_y,size,clr,opacity,redraw,style,end_style);
  }
//+------------------------------------------------------------------+
//| Draw a polygon using                                             |
//| AntiAliasing algorithm                                           |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolygonAAOnBG(const int id,                    // Frame ID
                           int         &array_x[],                   // Array with the X coordinates of polygon points
                           int         &array_y[],                   // Array with the Y coordinates of polygon points
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPolygonAAOnBG(array_x,array_y,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+
//| Draw a polygon using Wu algorithm                                |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolygonWuOnBG(const int id,                    // Frame ID
                           int         &array_x[],                   // Array with the X coordinates of polygon points
                           int         &array_y[],                   // Array with the Y coordinates of polygon points
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPolygonWuOnBG(array_x,array_y,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+
//| Draw a polygon with a specified width using                      |
//| two smoothing algorithms in series.                              |
//| First, individual segments are smoothed based on Bezier curves.  |
//| Then, to improve the rendering quality,                          |
//| a raster smoothing algorithm is applied                          |
//| made of the polyline segments.                                   |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolygonSmoothOnBG(const int id,                // Frame ID
                           int          &array_x[],                  // Array with the X coordinates of polyline points
                           int          &array_y[],                  // Array with the Y coordinates of polyline points
                           const int    size,                        // Line width
                           const color  clr,                         // Color
                           const uchar  opacity=255,                 // Opacity
                           const double tension=0.5,                 // Smoothing parameter value
                           const double step=10,                     // Approximation step
                           const bool   create_new=true,             // New object creation flag
                           const bool   redraw=false,                // Chart redraw flag
                           const ENUM_LINE_STYLE style=STYLE_SOLID,  // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                           const ENUM_LINE_END   end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPolygonSmoothOnBG(array_x,array_y,size,clr,opacity,tension,step,redraw,style,end_style);
  }
//+------------------------------------------------------------------+
//| Draw a polygon with a specified width using                      |
//| a smoothing algorithm with the preliminary sorting               |
//+------------------------------------------------------------------+
//--- Draw a polygon having a specified width using smoothing algorithm with the preliminary filtration
bool CAnimations::DrawPolygonThickOnBG(const int id,                 // Frame ID
                           const int   &array_x[],                   // array with the X coordinates of polygon points
                           const int   &array_y[],                   // array with the Y coordinates of polygon points
                           const int   size,                         // line width
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=STYLE_SOLID,            // line style

                           ENUM_LINE_END end_style=LINE_END_ROUND)   // line ends style
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawPolygonThickOnBG(array_x,array_y,size,clr,opacity,redraw,style,end_style);
  }
//+------------------------------------------------------------------+
//| Draw a triangle using                                            |
//| AntiAliasing algorithm                                           |
//+------------------------------------------------------------------+
bool CAnimations::DrawTriangleAAOnBG(const int id,                   // Frame ID
                           const int   x1,                           // X coordinate of the triangle first vertex
                           const int   y1,                           // Y coordinate of the triangle first vertex
                           const int   x2,                           // X coordinate of the triangle second vertex
                           const int   y2,                           // Y coordinate of the triangle second vertex
                           const int   x3,                           // X coordinate of the triangle third vertex
                           const int   y3,                           // Y coordinate of the triangle third vertex
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawTriangleAAOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+
//| Draw a triangle using Wu algorithm                               |
//+------------------------------------------------------------------+
bool CAnimations::DrawTriangleWuOnBG(const int id,                   // Frame ID
                           const int   x1,                           // X coordinate of the triangle first vertex
                           const int   y1,                           // Y coordinate of the triangle first vertex
                           const int   x2,                           // X coordinate of the triangle second vertex
                           const int   y2,                           // Y coordinate of the triangle second vertex
                           const int   x3,                           // X coordinate of the triangle third vertex
                           const int   y3,                           // Y coordinate of the triangle third vertex
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawTriangleWuOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+
//| Draw a circle using                                              |
//| AntiAliasing algorithm                                           |
//+------------------------------------------------------------------+
bool CAnimations::DrawCircleAAOnBG(const int id,                     // Frame ID
                           const int    x,                           // X coordinate of the circle center
                           const int    y,                           // Y coordinate of the circle center
                           const double r,                           // Circle radius
                           const color  clr,                         // Color
                           const uchar  opacity=255,                 // Opacity
                           const bool   create_new=true,             // New object creation flag
                           const bool   redraw=false,                // Chart redraw flag
                           const uint   style=UINT_MAX)              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawCircleAAOnBG(x,y,r,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+
//| Draw a circle using Wu algorithm                                 |
//+------------------------------------------------------------------+
bool CAnimations::DrawCircleWuOnBG(const int id,                     // Frame ID
                           const int    x,                           // X coordinate of the circle center
                           const int    y,                           // Y coordinate of the circle center
                           const double r,                           // Circle radius
                           const color  clr,                         // Color
                           const uchar  opacity=255,                 // Opacity
                           const bool   create_new=true,             // New object creation flag
                           const bool   redraw=false,                // Chart redraw flag
                           const uint   style=UINT_MAX)              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawCircleWuOnBG(x,y,r,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+
//| Draw an ellipse using two points while applying                  |
//| AntiAliasing algorithm                                           |
//+------------------------------------------------------------------+
bool CAnimations::DrawEllipseAAOnBG(const int id,                    // Frame ID
                           const double x1,                          // X coordinate of the first point defining the ellipse
                           const double y1,                          // Y coordinate of the first point defining the ellipse
                           const double x2,                          // X coordinate of the second point defining the ellipse
                           const double y2,                          // Y coordinate of the second point defining the ellipse
                           const color  clr,                         // Color
                           const uchar  opacity=255,                 // Opacity
                           const bool   create_new=true,             // New object creation flag
                           const bool   redraw=false,                // Chart redraw flag
                           const uint   style=UINT_MAX)              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawEllipseAAOnBG(x1,y1,x2,y2,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+
//| Draw an ellipse using two points                                 |
//| using Wu algorithm                     |
//+------------------------------------------------------------------+
bool CAnimations::DrawEllipseWuOnBG(const int id,                    // Frame ID
                           const int   x1,                           // X coordinate of the first point defining the ellipse
                           const int   y1,                           // Y coordinate of the first point defining the ellipse
                           const int   x2,                           // X coordinate of the second point defining the ellipse
                           const int   y2,                           // Y coordinate of the second point defining the ellipse
                           const color clr,                          // Color
                           const uchar opacity=255,                  // Opacity
                           const bool  create_new=true,              // New object creation flag
                           const bool  redraw=false,                 // Chart redraw flag
                           const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
  {
   CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new);
   if(frame==NULL)
      return false;
   return frame.DrawEllipseWuOnBG(x1,y1,x2,y2,clr,opacity,redraw,style);
  }
//+------------------------------------------------------------------+


The newly created class of animation objects should be an integral part of the form object. Thus, each form is to have its own methods of creating images.

Open the file of the form object class \MQL5\Include\DoEasy\Objects\Graph\Form.mqh and add the necessary improvements.

Include the file of the animation object class:

//+------------------------------------------------------------------+
//|                                                         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"
#include "Animations\Animations.mqh"
//+------------------------------------------------------------------+

Remove the pixel copier object class from the listing (I have moved it to another file):

//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "GCnvElement.mqh"
#include "ShadowObj.mqh"
#include "Animations\Animations.mqh"
//+------------------------------------------------------------------+
//| Pixel copier class                                               |
//+------------------------------------------------------------------+
class CPixelCopier : public CObject
  {
private:
...
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Form object class                                                |
//+------------------------------------------------------------------+

In the private section of the class, instead of the pixel copier list

CArrayObj         m_list_pc_obj;                            // List of pixel copier objects

declare the pointer to the animation class object:

//+------------------------------------------------------------------+
//|                                                         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"
#include "Animations\Animations.mqh"
//+------------------------------------------------------------------+
//| Form object class                                                |
//+------------------------------------------------------------------+
class CForm : public CGCnvElement
  {
private:
   CArrayObj         m_list_elements;                          // List of attached elements
   CAnimations      *m_animations;                             // Pointer to the animation object
   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:

Remove the declaration of the already unnecessary IsPresentPC() method from the private section, as well as its implementation from the code listing:

//--- Create a shadow object
   void              CreateShadowObj(const color colour,const uchar opacity);
   
//--- Return the flag indicating the presence of the copier object with the specified ID in the list
   bool              IsPresentPC(const int id);

public:

Remove the already unnecessary method from the public section of the class:

//--- Return (1) itself, the list of (2) attached objects, (3) pixel copier objects and (4) the shadow object
   CForm            *GetObject(void)                                          { return &this;                  }
   CArrayObj        *GetList(void)                                            { return &this.m_list_elements;  }
   CArrayObj        *GetListPC(void)                                          { return &this.m_list_pc_obj;    }
   CGCnvElement     *GetShadowObj(void)                                       { return this.m_shadow_obj;      }

and add the new methods returning the pointers to the animation object and the lists of text and rectangle animation frames:

   CGCnvElement     *GetShadowObj(void)                                       { return this.m_shadow_obj;      }
//--- Return the pointer to (1) the animation object, the list of (2) text and (3) rectangle animation frames
   CAnimations      *GetAnimationsObj(void)                                   { return this.m_animations;      }
   CArrayObj        *GetListFramesText(void)
                       { return(this.m_animations!=NULL ? this.m_animations.GetListFramesText() : NULL);       }
   CArrayObj        *GetListFramesQuad(void)
                       { return(this.m_animations!=NULL ? this.m_animations.GetListFramesQuad() : NULL);       }
   
//--- Set the form (1) color scheme and (2) style

Remove the declaration of the method for creating a new pixel copier object:

//--- Create a new pixel copier object
   CPixelCopier     *CreateNewPixelCopier(const int id,const int x_coord,const int y_coord,const int width,const int height);

//--- Draw an object shadow

The implementation of the method written outside the class body is removed as well.

In the block of methods for working with image pixels in the public section of the class, write the new methods for creating animation frame objects, returning the pointers to created objects and drawing methods that save and restore the background:

//+------------------------------------------------------------------+
//| Methods of working with image pixels                             |
//+------------------------------------------------------------------+
//--- Create a new (1) rectangle and (2) text animation frame object
   bool              CreateNewFrameText(const int id,const int x_coord,const int y_coord,const string text)
                       { return(this.m_animations!=NULL ? this.m_animations.CreateNewFrameText(id)!=NULL : false);            }
                       
   bool              CreateNewFrameQuad(const int id,const int x_coord,const int y_coord,const int width,const int height)
                       { return(this.m_animations!=NULL ? this.m_animations.CreateNewFrameQuad(id)!=NULL : false);            }
                       
//--- Return the frame object of the (1) text and (2) rectangle animation by ID
   CFrame           *GetFrameText(const int id)
                       { return(this.m_animations!=NULL ? this.m_animations.GetFrame(ANIMATION_FRAME_TYPE_TEXT,id) : NULL);   }
                       
   CFrame           *GetFrameQuad(const int id)
                       { return(this.m_animations!=NULL ? this.m_animations.GetFrame(ANIMATION_FRAME_TYPE_QUAD,id) : NULL);   }
                       
//--- Display the text on the background while saving and restoring the background
   bool              TextOnBG(const int id,
                              const string text,
                              const int x,
                              const int y,
                              const ENUM_TEXT_ANCHOR anchor,
                              const color clr,
                              const uchar opacity=255,
                              const bool create_new=true,
                              const bool redraw=false)
                       { return(this.m_animations!=NULL ? this.m_animations.TextOnBG(id,text,x,y,anchor,clr,opacity,create_new,redraw) : false);  }

//--- Set the color of the point with the specified coordinates while saving and restoring the background
   bool              SetPixelOnBG(const int id,const int x,const int y,const color clr,const uchar opacity=255,const bool create_new=true,const bool redraw=false)
                       { return(this.m_animations!=NULL ? this.m_animations.SetPixelOnBG(id,x,y,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a segment of a vertical line
   bool              DrawLineVerticalOnBG(const int id,                 // Frame ID
                              const int   x,                            // Segment X coordinate
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineVerticalOnBG(id,x,y1,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a segment of a horizontal line while saving and restoring the background
   bool              DrawLineHorizontalOnBG(const int id,               // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y,                            // Segment Y coordinate
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineHorizontalOnBG(id,x1,x2,y,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a segment of a freehand line while saving and restoring the background
   bool              DrawLineOnBG(const int id,                         // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a polyline while saving and restoring the background
   bool              DrawPolylineOnBG(const int id,                     // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polyline points
                              int         &array_y[],                   // Array with the Y coordinates of polyline points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a polygon while saving and restoring the background
   bool              DrawPolygonOnBG(const int id,                      // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a rectangle by two points while saving and restoring the background
   bool              DrawRectangleOnBG(const int id,                    // Frame ID
                              const int   x1,                           // X coordinate of the first point defining the rectangle
                              const int   y1,                           // Y coordinate of the first point defining the rectangle
                              const int   x2,                           // X coordinate of the second point defining the rectangle
                              const int   y2,                           // Y coordinate of the second point defining the rectangle
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawRectangleOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a circle while saving and restoring the background
   bool              DrawCircleOnBG(const int id,                       // Frame ID
                              const int   x,                            // X coordinate of the circle center
                              const int   y,                            // Y coordinate of the circle center
                              const int   r,                            // Circle radius
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawCircleOnBG(id,x,y,r,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a triangle while saving and restoring the background
   bool              DrawTriangleOnBG(const int id,                     // Frame ID
                              const int   x1,                           // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw an ellipse by two points while saving and restoring the background
   bool              DrawEllipseOnBG(const int id,                      // Frame ID
                              const int   x1,                           // X coordinate of the first point defining the ellipse
                              const int   y1,                           // Y coordinate of the first point defining the ellipse
                              const int   x2,                           // X coordinate of the second point defining the ellipse
                              const int   y2,                           // Y coordinate of the second point defining the ellipse
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw an arc of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2) while saving and restoring the background.
//--- The arc boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4)
   bool              DrawArcOnBG(const int id,                          // Frame ID
                              const int   x1,                           // X coordinate of the top left corner forming the rectangle
                              const int   y1,                           // Y coordinate of the top left corner forming the rectangle
                              const int   x2,                           // X coordinate of the bottom right corner forming the rectangle
                              const int   y2,                           // Y coordinate of the bottom right corner forming the rectangle
                              const int   x3,                           // X coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const int   y3,                           // Y coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const int   x4,                           // X coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const int   y4,                           // Y coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawArcOnBG(id,x1,y1,x2,y2,x3,y3,x4,y4,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a filled sector of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2) while saving and restoring the background.
//--- The sector boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4)
   bool              DrawPieOnBG(const int id,                          // Frame ID
                              const int   x1,                           // X coordinate of the upper left corner of the rectangle
                              const int   y1,                           // Y coordinate of the upper left corner of the rectangle
                              const int   x2,                           // X coordinate of the bottom right corner of the rectangle
                              const int   y2,                           // Y coordinate of the bottom right corner of the rectangle
                              const int   x3,                           // X coordinate of the first point to find the arc boundaries
                              const int   y3,                           // Y coordinate of the first point to find the arc boundaries
                              const int   x4,                           // X coordinate of the second point to find the arc boundaries
                              const int   y4,                           // Y coordinate of the second point to find the arc boundaries
                              const color clr,                          // Color
                              const color fill_clr,                     // Fill color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPieOnBG(id,x1,y1,x2,y2,x3,y3,x4,y4,clr,fill_clr,opacity,create_new,redraw) : false);  }
                       
//--- Fill the area while saving and restoring the background
   bool              FillOnBG(const int   id,                           // Frame ID
                              const int   x,                            // X coordinate of the filling start point
                              const int   y,                            // Y coordinate of the filling start point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const uint  threshould=0,                 // Threshold
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.FillOnBG(id,x,y,clr,opacity,threshould,create_new,redraw) : false);  }
                       
//--- Draw a filled rectangle while saving and restoring the background
   bool              DrawRectangleFillOnBG(const int id,                // Frame ID
                              const int   x1,                           // X coordinate of the first point defining the rectangle
                              const int   y1,                           // Y coordinate of the first point defining the rectangle
                              const int   x2,                           // X coordinate of the second point defining the rectangle
                              const int   y2,                           // Y coordinate of the second point defining the rectangle
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawRectangleFillOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a filled circle while saving and restoring the background
   bool              DrawCircleFillOnBG(const int id,                   // Frame ID
                              const int   x,                            // X coordinate of the circle center
                              const int   y,                            // Y coordinate of the circle center
                              const int   r,                            // Circle radius
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawCircleFillOnBG(id,x,y,r,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a filled triangle while saving and restoring the background
   bool              DrawTriangleFillOnBG(const int id,                 // Frame ID
                              const int   x1,                           // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleFillOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a filled polygon while saving and restoring the background
   bool              DrawPolygonFillOnBG(const int id,                  // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonFillOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a filled ellipse inscribed in a rectangle with the specified coordinates while saving and restoring the background
   bool              DrawEllipseFillOnBG(const int id,                  // Frame ID
                              const int   x1,                           // X coordinate of the top left corner forming the rectangle
                              const int   y1,                           // Y coordinate of the top left corner forming the rectangle
                              const int   x2,                           // X coordinate of the bottom right corner forming the rectangle
                              const int   y2,                           // Y coordinate of the bottom right corner forming the rectangle
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false)                 // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseFillOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a point using AntiAliasing algorithm while saving and restoring the background
   bool              SetPixelAAOnBG(const int id,                       // Frame ID
                              const double x,                           // Point X coordinate
                              const double y,                           // Point Y coordinate
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false)                // Chart redraw flag
                       { return(this.m_animations!=NULL ? this.m_animations.SetPixelAAOnBG(id,x,y,clr,opacity,create_new,redraw) : false);  }
                       
//--- Draw a segment of a freehand line using AntiAliasing algorithm while saving and restoring the background
   bool              DrawLineAAOnBG(const int id,                       // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineAAOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Draw a segment of a freehand line using Wu algorithm while saving and restoring the background
   bool              DrawLineWuOnBG(const int id,                       // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineWuOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Draw a segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background
   bool              DrawLineThickOnBG(const int id,                    // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y2,                           // Y coordinate of the segment second point
                              const int   size,                         // Line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              ENUM_LINE_END end_style=LINE_END_ROUND)   // Line style is one of the ENUM_LINE_END enumeration's values
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickOnBG(id,x1,y1,x2,y2,size,clr,opacity,create_new,redraw,style,end_style) : false);  }
                       
//--- Draw a vertical segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background
   bool              DrawLineThickVerticalOnBG(const int id,            // Frame ID
                              const int   x,                            // Segment X coordinate
                              const int   y1,                           // Y coordinate of the segment first point
                              const int   y2,                           // Y coordinate of the segment second point
                              const int   size,                         // line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickVerticalOnBG(id,x,y1,y2,size,clr,opacity,create_new,redraw,style,end_style) : false);  }
                       
//--- Draw a horizontal segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background
   bool              DrawLineThickHorizontalOnBG(const int id,          // Frame ID
                              const int   x1,                           // X coordinate of the segment first point
                              const int   x2,                           // X coordinate of the segment second point
                              const int   y,                            // Segment Y coordinate
                              const int   size,                         // line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickHorizontalOnBG(id,x1,x2,y,size,clr,opacity,create_new,redraw,style,end_style) : false);  }
                       
//--- Draw a polyline using AntiAliasing algorithm while saving and restoring the background
   bool              DrawPolylineAAOnBG(const int id,                   // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polyline points
                              int         &array_y[],                   // Array with the Y coordinates of polyline points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineAAOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Draw a polyline using Wu algorithm while saving and restoring the background
   bool              DrawPolylineWuOnBG(const int id,                   // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polyline points
                              int         &array_y[],                   // Array with the Y coordinates of polyline points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineWuOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Draw a polyline with a specified width consecutively using two smoothing algorithms while saving and restoring the background.
//--- First, individual line segments are smoothed based on Bezier curves.
//--- Then, the raster antialiasing algorithm is applied to the polyline built from these segments to improve the rendering quality
   bool              DrawPolylineSmoothOnBG(const int id,               // Frame ID
                              const int    &array_x[],                  // Array with the X coordinates of polyline points
                              const int    &array_y[],                  // Array with the Y coordinates of polyline points
                              const int    size,                        // Line width
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const double tension=0.5,                 // Smoothing parameter value
                              const double step=10,                     // Approximation step
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false,                // Chart redraw flag
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineSmoothOnBG(id,array_x,array_y,size,clr,opacity,tension,step,create_new,redraw,style,end_style) : false);  }
                       
//--- Draw a polyline having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background
   bool              DrawPolylineThickOnBG(const int id,                // Frame ID
                              const int     &array_x[],                 // Array with the X coordinates of polyline points
                              const int     &array_y[],                 // Array with the Y coordinates of polyline points
                              const int     size,                       // Line width
                              const color   clr,                        // Color
                              const uchar   opacity=255,                // Opacity
                              const bool    create_new=true,            // New object creation flag
                              const bool    redraw=false,               // Chart redraw flag
                              const uint    style=STYLE_SOLID,          // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              ENUM_LINE_END end_style=LINE_END_ROUND)   // Line style is one of the ENUM_LINE_END enumeration's values
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineThickOnBG(id,array_x,array_y,size,clr,opacity,create_new,redraw,style,end_style) : false);  }
                       
//--- Draw a polygon using AntiAliasing algorithm while saving and restoring the background
   bool              DrawPolygonAAOnBG(const int id,                    // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonAAOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Draw a polygon using Wu algorithm while saving and restoring the background
   bool              DrawPolygonWuOnBG(const int id,                    // Frame ID
                              int         &array_x[],                   // Array with the X coordinates of polygon points
                              int         &array_y[],                   // Array with the Y coordinates of polygon points
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonWuOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Draw a polygon with a specified width consecutively using two smoothing algorithms while saving and restoring the background.
//--- First, individual segments are smoothed based on Bezier curves.
//--- Then, the raster smoothing algorithm is applied to the polygon built from these segments to improve the rendering quality. 
   bool              DrawPolygonSmoothOnBG(const int id,                // Frame ID
                              int          &array_x[],                  // Array with the X coordinates of polyline points
                              int          &array_y[],                  // Array with the Y coordinates of polyline points
                              const int    size,                        // Line width
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const double tension=0.5,                 // Smoothing parameter value
                              const double step=10,                     // Approximation step
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false,                // Chart redraw flag
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                              const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonSmoothOnBG(id,array_x,array_y,size,clr,opacity,tension,step,create_new,redraw,style,end_style) : false);  }
                       
//--- Draw a polygon of a specified width using a smoothing algorithm with the preliminary filtration while saving and restoring the background
   bool              DrawPolygonThickOnBG(const int id,                 // Frame ID
                              const int   &array_x[],                   // array with the X coordinates of polygon points
                              const int   &array_y[],                   // array with the Y coordinates of polygon points
                              const int   size,                         // line width
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=STYLE_SOLID,            // line style
                              ENUM_LINE_END end_style=LINE_END_ROUND)   // line ends style
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonThickOnBG(id,array_x,array_y,size,clr,opacity,create_new,redraw,style,end_style) : false);  }
                       
//--- Draw a triangle using AntiAliasing algorithm while saving and restoring the background
   bool              DrawTriangleAAOnBG(const int id,                   // Frame ID
                              const int   x1,                           // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleAAOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Draw a triangle using Wu algorithm while saving and restoring the background
   bool              DrawTriangleWuOnBG(const int id,                   // Frame ID
                              const int   x1,                           // X coordinate of the triangle first vertex
                              const int   y1,                           // Y coordinate of the triangle first vertex
                              const int   x2,                           // X coordinate of the triangle second vertex
                              const int   y2,                           // Y coordinate of the triangle second vertex
                              const int   x3,                           // X coordinate of the triangle third vertex
                              const int   y3,                           // Y coordinate of the triangle third vertex
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleWuOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Draw a circle using AntiAliasing algorithm while saving and restoring the background
   bool              DrawCircleAAOnBG(const int id,                     // Frame ID
                              const int    x,                           // X coordinate of the circle center
                              const int    y,                           // Y coordinate of the circle center
                              const double r,                           // Circle radius
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false,                // Chart redraw flag
                              const uint   style=UINT_MAX)              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawCircleAAOnBG(id,x,y,r,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Draw a circle using Wu algorithm while saving and restoring the background
   bool              DrawCircleWuOnBG(const int id,                     // Frame ID
                              const int    x,                           // X coordinate of the circle center
                              const int    y,                           // Y coordinate of the circle center
                              const double r,                           // Circle radius

                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false,                // Chart redraw flag
                              const uint   style=UINT_MAX)              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawCircleWuOnBG(id,x,y,r,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Draw an ellipse by two points using AntiAliasing algorithm while saving and restoring the background
   bool              DrawEllipseAAOnBG(const int id,                    // Frame ID
                              const double x1,                          // X coordinate of the first point defining the ellipse
                              const double y1,                          // Y coordinate of the first point defining the ellipse
                              const double x2,                          // X coordinate of the second point defining the ellipse
                              const double y2,                          // Y coordinate of the second point defining the ellipse
                              const color  clr,                         // Color
                              const uchar  opacity=255,                 // Opacity
                              const bool   create_new=true,             // New object creation flag
                              const bool   redraw=false,                // Chart redraw flag
                              const uint   style=UINT_MAX)              // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseAAOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Draw an ellipse by two points using Wu algorithm while saving and restoring the background
   bool              DrawEllipseWuOnBG(const int id,                    // Frame ID
                              const int   x1,                           // X coordinate of the first point defining the ellipse
                              const int   y1,                           // Y coordinate of the first point defining the ellipse
                              const int   x2,                           // X coordinate of the second point defining the ellipse
                              const int   y2,                           // Y coordinate of the second point defining the ellipse
                              const color clr,                          // Color
                              const uchar opacity=255,                  // Opacity
                              const bool  create_new=true,              // New object creation flag
                              const bool  redraw=false,                 // Chart redraw flag
                              const uint  style=UINT_MAX)               // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value
                       { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseWuOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false);  }
                       
//+------------------------------------------------------------------+

All methods return the results of the appropriate methods from the CAnimations animation object created above.

In the class destructor, remove the animation object:

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CForm::~CForm()
  {
   if(this.m_shadow_obj!=NULL)
      delete this.m_shadow_obj;
   if(this.m_animations!=NULL)
      delete this.m_animations;
  }
//+------------------------------------------------------------------+

In the initialization method, create a new animation object:

//+------------------------------------------------------------------+
//| 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;
   this.m_animations=new CAnimations(CGCnvElement::GetObject());
  }
//+------------------------------------------------------------------+

Now a new animation object is created automatically when creating a new form object. We can dynamically add new animation frames to the animation object or create the predefined forms. Upon the completion of the program run, the animation object is destroyed to avoid memory leaks.

We are ready to test the created classes.

We have a test EA, in which four forms are drawn. When we click the fourth (bottom) form, the H-Gradient label moves (H - for horizontal filling type). This label will now be created and moved as a text animation frame object. The third form (the vertical filling) is to be used for displaying various drawn shapes. Before drawing a shape, we first display a form text as a text animation frame. Shapes are drawn above it. Switching the types of drawn figures is done by pressing the keys, while the text displays the selected drawn figure. Each mouse click on the shape changes the coordinates of the drawn shape points.

Test

To perform the test, let's use the EA from the previous article and save it in \MQL5\Experts\TestDoEasy\Part79\ as TestDoEasyPart79.mq5.

In the area of global variables, enter macro substitutions for specifying initial coordinates of drawn shapes and declare the variables for storing coordinates of different points of drawn shapes (five points are to be used in total) and their change values:

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart79.mq5 |
//|                                  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"
//--- includes
#include <Arrays\ArrayObj.mqh>
#include <DoEasy\Services\Select.mqh>
#include <DoEasy\Objects\Graph\Form.mqh>
//--- defines
#define        FORMS_TOTAL (4)   // Number of created forms
#define        START_X     (4)   // Initial X coordinate of the shape
#define        START_Y     (4)   // Initial Y coordinate of the shape
//--- input parameters
sinput   bool              InpMovable     =  true;          // Movable forms flag
sinput   ENUM_INPUT_YES_NO InpUseColorBG  =  INPUT_YES;     // Use chart background color to calculate shadow color
sinput   color             InpColorForm3  =  clrCadetBlue;  // Third form shadow color (if not background color) 
//--- global variables
CArrayObj      list_forms;  
color          array_clr[];
int nx1=0, ny1=0, nx2=0, ny2=0, nx3=0, ny3=0, nx4=0, ny4=0, nx5=0, ny5=0;
int coordX1=START_X+nx1;
int coordY1=START_Y+ny1;
int coordX2=START_X+nx2*2;
int coordY2=START_Y+ny2*2;
int coordX3=START_X+nx3*3;
int coordY3=START_Y+ny3*3;
int coordX4=START_X+nx4*4;
int coordY4=START_Y+ny4*4;
int coordX5=START_X+nx5*5;
int coordY5=START_Y+ny5*5;
double RD=1;
//+------------------------------------------------------------------+

In the blocks of creating two last forms of the OnInit() handler, the text is created using text animation objects:

      //--- If this is the third form
      if(i==2)
        {
         //--- Set the opacity of 200
         form.SetOpacity(200);
         //--- The form background color is set as the first color from the color array
         form.SetColorBackground(array_clr[0]);
         //--- Form outlining frame color
         form.SetColorFrame(clrDarkBlue);
         //--- Draw the shadow drawing flag
         form.SetShadow(true);
         //--- Calculate the shadow color as the chart background color converted to the monochrome one
         color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100);
         //--- If the settings specify the usage of the chart background color, replace the monochrome color with 20 units
         //--- Otherwise, use the color specified in the settings for drawing the shadow
         color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3);
         //--- Draw the form shadow with the right-downwards offset from the form by three pixels along all axes
         //--- Set the shadow opacity to 200, while the blur radius is equal to 4
         form.DrawShadow(3,3,clr,200,4);
         //--- Fill the form background with a vertical gradient
         form.Erase(array_clr,form.Opacity());
         //--- Draw an outlining rectangle at the edges of the form
         form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity());
         
         //--- Display the text describing the gradient type and update the form
         //--- Text parameters: the text coordinates and the anchor point in the form center
         //--- Create a new text animation frame with the ID of 0 and display the text on the form
         form.TextOnBG(0,TextByLanguage("V-Градиент","V-Gradient"),form.Width()/2,form.Height()/2,TEXT_ANCHOR_CENTER,C'211,233,149',255,true,false);
        }
      //--- If this is the fourth (bottom) form
      if(i==3)
        {
         //--- Set the opacity of 200
         form.SetOpacity(200);
         //--- The form background color is set as the first color from the color array
         form.SetColorBackground(array_clr[0]);
         //--- Form outlining frame color
         form.SetColorFrame(clrDarkBlue);
         //--- Draw the shadow drawing flag
         form.SetShadow(true);
         //--- Calculate the shadow color as the chart background color converted to the monochrome one
         color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100);
         //--- If the settings specify the usage of the chart background color, replace the monochrome color with 20 units
         //--- Otherwise, use the color specified in the settings for drawing the shadow
         color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3);
         //--- Draw the form shadow with the right-downwards offset from the form by three pixels along all axes
         //--- Set the shadow opacity to 200, while the blur radius is equal to 4
         form.DrawShadow(3,3,clr,200,4);
         //--- Fill the form background with a horizontal gradient
         form.Erase(array_clr,form.Opacity(),false);
         //--- Draw an outlining rectangle at the edges of the form
         form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity());
         
         //--- Display the text describing the gradient type and update the form
         //--- Text parameters: the text coordinates and the anchor point in the form center
         //--- Create a new text animation frame with the ID of 0 and display the text on the form
         form.TextOnBG(0,TextByLanguage("H-Градиент","H-Gradient"),form.Width()/2,form.Height()/2,TEXT_ANCHOR_CENTER,C'211,233,149',255,true,true);
        }
      //--- Add objects to the list

I have created these text objects here beforehand. Drawn shapes are to be created dynamically — upon clicking in the form area.

To handle keystrokes, add the following code block to the OnChartEvent() handler:

//--- Drawing mode depending on the pressed key
   static ENUM_FIGURE_TYPE figure_type_prev=WRONG_VALUE;
   static ENUM_FIGURE_TYPE figure_type=figure_type_prev;
   string figure=FigureTypeDescription(figure_type);
//--- If a key is pressed
   if(id==CHARTEVENT_KEYDOWN)
     {
      //--- Get a drawn shape type depending on a pressed key
      figure_type=FigureType(lparam);
      //--- If the shape type has changed
      if(figure_type!=figure_type_prev)
        {
         //--- Get the text of the drawn shape type description
         figure=FigureTypeDescription(figure_type);
         //--- In the loop by all forms, 
         for(int i=0;i<list_forms.Total();i++)
           {
            //--- get the pointer to the next form object
            CForm *form=list_forms.At(i);
            if(form==NULL)
               continue;
            //--- If the form ID is 2,
            if(form.ID()==2)
              {
               //--- Reset all coordinate shifts to zero and display the text describing the drawn shape type
               nx1=ny1=nx2=ny2=nx3=ny3=nx4=ny4=nx5=ny5=0;
               form.TextOnBG(0,figure,form.TextLastX(),form.TextLastY(),form.TextAnchor(),C'211,233,149',255,false,true);
              }
           }
         //--- Write the new shape type
         figure_type_prev=figure_type;
        }
     }
  
//--- If clicking an object

Slightly change the code in the click handling block by forms — now the text will be displayed using text animation objects of the form being clicked:

//--- If clicking an object
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- If the clicked object belongs to the EA
      if(StringFind(sparam,MQLInfoString(MQL_PROGRAM_NAME))==0)
        {
         //--- Get the object ID from it
         int form_id=(int)StringToInteger(StringSubstr(sparam,StringLen(sparam)-1))-1;
         //--- Find this form object in the loop by all forms created in the EA
         for(int i=0;i<list_forms.Total();i++)
           {
            CForm *form=list_forms.At(i);
            if(form==NULL)
               continue;
            //--- If the clicked object has the ID of 2 and the form has the same ID
            if(form_id==2 && form.ID()==2)
              {
               //--- Handle clicking the form - draw the corresponding shape
               FigureProcessing(form,figure_type);
              }
            
            //--- If the clicked object has the ID of 3 and the form has the same ID
            if(form_id==3 && form.ID()==3)
              {
               ////--- Get the anchor point of the last drawn text
               ENUM_TEXT_ANCHOR anchor=form.TextAnchor();
               ////--- Get the coordinates of the last drawn text
               int text_x=form.TextLastX();
               int text_y=form.TextLastY();
               //--- Set the text anchor initial point (0 = LEFT_TOP) out of nine possible ones
               static int n=0;
               //--- Depending on the n variable, set the new text anchor point
               switch(n)
                 {
                  case 0 : anchor=TEXT_ANCHOR_LEFT_TOP;     text_x=1;               text_y=1;               break;
                  case 1 : anchor=TEXT_ANCHOR_CENTER_TOP;   text_x=form.Width()/2;  text_y=1;               break;
                  case 2 : anchor=TEXT_ANCHOR_RIGHT_TOP;    text_x=form.Width()-2;  text_y=1;               break;
                  case 3 : anchor=TEXT_ANCHOR_LEFT_CENTER;  text_x=1;               text_y=form.Height()/2; break;
                  case 4 : anchor=TEXT_ANCHOR_CENTER;       text_x=form.Width()/2;  text_y=form.Height()/2; break;
                  case 5 : anchor=TEXT_ANCHOR_RIGHT_CENTER; text_x=form.Width()-2;  text_y=form.Height()/2; break;
                  case 6 : anchor=TEXT_ANCHOR_LEFT_BOTTOM;  text_x=1;               text_y=form.Height()-2; break;
                  case 7 : anchor=TEXT_ANCHOR_CENTER_BOTTOM;text_x=form.Width()/2;  text_y=form.Height()-2; break;
                  case 8 : anchor=TEXT_ANCHOR_RIGHT_BOTTOM; text_x=form.Width()-2;  text_y=form.Height()-2; break;
                  default: anchor=TEXT_ANCHOR_CENTER;       text_x=form.Width()/2;  text_y=form.Height()/2; break;
                 }
               form.TextOnBG(0,TextByLanguage("H-Градиент","H-Gradient"),text_x,text_y,anchor,C'211,233,149',255,true,true);
               //--- Increase the object click counter (and also the pointer to the text anchor point),
               //--- and if the value exceeds 8, reset the value to zero (from 0 to 8 = nine anchor points)
               n++;
               if(n>8) n=0;
              }
           }
        }
     }

Clicking the third form (the ID of 2) is to be handled in the FigureProcessing() function. Clicking the fourth form (the ID of 3) allows us to define the text anchor angle depending on n and display the text. But the text is now displayed using the text animation frame object class.

The auxiliary function returning the shape type depending on the pressed key:

//+------------------------------------------------------------------+
//| Return the shape depending on the pressed key                    |
//+------------------------------------------------------------------+
ENUM_FIGURE_TYPE FigureType(const long key_code)
  {
   switch((int)key_code)
     {
      //--- "1" = Dot
      case 49  :  return FIGURE_TYPE_PIXEL;
      
      //--- "2" = Dot with AntiAlliasing
      case 50  :  return FIGURE_TYPE_PIXEL_AA;
      
      //--- "3" = Vertical line
      case 51  :  return FIGURE_TYPE_LINE_VERTICAL;
      
      //--- "4" = Vertical segment of a freehand line having a specified width using a smoothing algorithm
      case 52  :  return FIGURE_TYPE_LINE_VERTICAL_THICK;
      
      //--- "5" = Horizontal line
      case 53  :  return FIGURE_TYPE_LINE_HORIZONTAL;
      
      //--- "6" = Horizontal segment of a freehand line having a specified width using a smoothing algorithm
      case 54  :  return FIGURE_TYPE_LINE_HORIZONTAL_THICK;
      
      //--- "7" = Freehand line
      case 55  :  return FIGURE_TYPE_LINE;
      
      //--- "8" = Line with AntiAlliasing
      case 56  :  return FIGURE_TYPE_LINE_AA;
      
      //--- "9" = Line with WU
      case 57  :  return FIGURE_TYPE_LINE_WU;
      
      //--- "0" = Segment of a freehand line having a specified width using a smoothing algorithm
      case 48  :  return FIGURE_TYPE_LINE_THICK;
      
      //--- "q" = Polyline
      case 81  :  return FIGURE_TYPE_POLYLINE;
      
      //--- "w" = Polyline with AntiAlliasing
      case 87  :  return FIGURE_TYPE_POLYLINE_AA;
      
      //--- "e" = Polyline with WU
      case 69  :  return FIGURE_TYPE_POLYLINE_WU;
      
      //--- "r" = Polyline with a specified width using two smoothing algorithms
      case 82  :  return FIGURE_TYPE_POLYLINE_SMOOTH;
      
      //--- "t" = Polyline with a specified width using a smoothing algorithm
      case 84  :  return FIGURE_TYPE_POLYLINE_THICK;
      
      //--- "y" = Polygon
      case 89  :  return FIGURE_TYPE_POLYGON;
      
      //--- "u" = Filled polygon
      case 85  :  return FIGURE_TYPE_POLYGON_FILL;
      
      //--- "i" = Polygon with AntiAlliasing
      case 73  :  return FIGURE_TYPE_POLYGON_AA;
      
      //--- "o" = Polygon with WU
      case 79  :  return FIGURE_TYPE_POLYGON_WU;
      
      //--- "p" = Polygon with a specified width using two smoothing algorithms
      case 80  :  return FIGURE_TYPE_POLYGON_SMOOTH;
      
      //--- "a" = Polygon with a specified width using a smoothing algorithm
      case 65  :  return FIGURE_TYPE_POLYGON_THICK;
      
      //--- "s" = Rectangle
      case 83  :  return FIGURE_TYPE_RECTANGLE;
      
      //--- "d" = Filled rectangle
      case 68  :  return FIGURE_TYPE_RECTANGLE_FILL;
      
      //--- "f" = Circle
      case 70  :  return FIGURE_TYPE_CIRCLE;
      
      //--- "g" = Filled circle
      case 71  :  return FIGURE_TYPE_CIRCLE_FILL;
      
      //--- "h" = Circle with AntiAlliasing
      case 72  :  return FIGURE_TYPE_CIRCLE_AA;
      
      //--- "j" = Circle with WU
      case 74  :  return FIGURE_TYPE_CIRCLE_WU;
      
      //--- "k" = Triangle
      case 75  :  return FIGURE_TYPE_TRIANGLE;
      
      //--- "l" = Filled triangle
      case 76  :  return FIGURE_TYPE_TRIANGLE_FILL;
      
      //--- "z" = Triangle with AntiAlliasing
      case 90  :  return FIGURE_TYPE_TRIANGLE_AA;
      
      //--- "x" = Triangle with WU
      case 88  :  return FIGURE_TYPE_TRIANGLE_WU;
      
      //--- "c" = Ellipse
      case 67  :  return FIGURE_TYPE_ELLIPSE;
      
      //--- "v" = Filled ellipse
      case 86  :  return FIGURE_TYPE_ELLIPSE_FILL;
      
      //--- "b" = Ellipse with AntiAlliasing
      case 66  :  return FIGURE_TYPE_ELLIPSE_AA;
      
      //--- "n" = Ellipse with WU
      case 78  :  return FIGURE_TYPE_ELLIPSE_WU;
      
      //--- "m" = Ellipse arc
      case 77  :  return FIGURE_TYPE_ARC;
      
      //--- "," = Ellipse sector
      case 188 :  return FIGURE_TYPE_PIE;
      
      //--- Default = Dot
      default  :  return FIGURE_TYPE_PIXEL;
     }
  }
//+------------------------------------------------------------------+

The function handling the click on the form object is quite bulky. However, it is simple as it features the switch operator handling each pressed button the drawn form corresponds to. The handling is simple — set the initial coordinates, check them for being out of the acceptable value range, draw a figure with these parameters and increase the shifts of the parameter values. The next time we click the form, the previous shape is overwritten by the restored background and a new one is drawn using the new coordinates of its points.

//+------------------------------------------------------------------+
//| Handle the selected shape                                        |
//+------------------------------------------------------------------+
void FigureProcessing(CForm *form,const ENUM_FIGURE_TYPE figure_type)
  {
   int array_x[5]={0,0,0,0,0};
   int array_y[5]={0,0,0,0,0};
   switch(figure_type)
     {
   //--- "1" = Dot
      case FIGURE_TYPE_PIXEL  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         form.SetPixelOnBG(0,coordX1,coordY1,clrWheat);
         nx1++;
         ny1++;
         break;
      
   //--- "2" = Dot with AntiAlliasing
      case FIGURE_TYPE_PIXEL_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         form.SetPixelAAOnBG(0,coordX1,coordY1,clrWheat);
         nx1++;
         ny1++;
         break;
      
   //--- "3" = Vertical line
      case FIGURE_TYPE_LINE_VERTICAL  :
         coordX1=START_X+nx1;
         coordY1=START_Y;
         coordY2=form.Height()-START_Y-1;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         form.DrawLineVerticalOnBG(0,coordX1,coordY1,coordY2,clrWheat);
         nx1++;
         break;
      
   //--- "4" = Vertical segment of a freehand line having a specified width using a smoothing algorithm
      case FIGURE_TYPE_LINE_VERTICAL_THICK  :
         coordX1=START_X+nx1;
         coordY1=START_Y;
         coordY2=form.Height()-START_Y-1;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         form.DrawLineThickVerticalOnBG(0,coordX1,coordY1,coordY2,5,clrWheat,255,true,false,STYLE_SOLID,LINE_END_SQUARE);
         nx1++;
         break;
      
   //--- "5" = Horizontal line
      case FIGURE_TYPE_LINE_HORIZONTAL :
         coordX1=START_X;
         coordX2=form.Width()-START_X-1;
         coordY1=START_Y+ny1;
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         form.DrawLineHorizontalOnBG(0,coordX1,coordX2,coordY1,clrWheat);
         ny1++;
         break;
         
   //--- "6" = Horizontal segment of a freehand line having a specified width using a smoothing algorithm
      case FIGURE_TYPE_LINE_HORIZONTAL_THICK  :
         coordX1=START_X;
         coordX2=form.Width()-START_X-1;
         coordY1=START_Y+ny1;
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         form.DrawLineThickHorizontalOnBG(0,coordX1,coordX2,coordY1,5,clrWheat,255,true,false,STYLE_SOLID,LINE_END_ROUND);
         ny1++;
         break;
      
   //--- "7" = Freehand line
      case FIGURE_TYPE_LINE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawLineOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- "8" = Line with AntiAlliasing
      case FIGURE_TYPE_LINE_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawLineAAOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- "9" = Line with WU
      case FIGURE_TYPE_LINE_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawLineWuOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- "0" = Segment of a freehand line having a specified width using a smoothing algorithm
      case FIGURE_TYPE_LINE_THICK  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawLineThickOnBG(0,coordX1,coordY1,coordX2,coordY2,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_SQUARE);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- "q" = Polyline
      case FIGURE_TYPE_POLYLINE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Fill in the arrays with coordinate values
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- check x1 and y1 coordinates for being outside the form
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- check x2 and y2 coordinates for being outside the form
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- check x3 and y3 coordinates for being outside the form
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- check x4 and y4 coordinates for being outside the form
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- check x5 and y5 coordinates for being outside the form
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Draw a shape
         form.DrawPolylineOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- "w" = Polyline with AntiAlliasing
      case FIGURE_TYPE_POLYLINE_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Fill in the arrays with coordinate values
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- check x1 and y1 coordinates for being outside the form
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- check x2 and y2 coordinates for being outside the form
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- check x3 and y3 coordinates for being outside the form
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- check x4 and y4 coordinates for being outside the form
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- check x5 and y5 coordinates for being outside the form
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Draw a shape
         form.DrawPolylineAAOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- "e" = Polyline with WU
      case FIGURE_TYPE_POLYLINE_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Fill in the arrays with coordinate values
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- check x1 and y1 coordinates for being outside the form
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- check x2 and y2 coordinates for being outside the form
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- check x3 and y3 coordinates for being outside the form
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- check x4 and y4 coordinates for being outside the form
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- check x5 and y5 coordinates for being outside the form
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Draw a shape
         form.DrawPolylineWuOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- "r" = Polyline with a specified width using two smoothing algorithms
      case FIGURE_TYPE_POLYLINE_SMOOTH  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Fill in the arrays with coordinate values
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- check x1 and y1 coordinates for being outside the form
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- check x2 and y2 coordinates for being outside the form
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- check x3 and y3 coordinates for being outside the form
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- check x4 and y4 coordinates for being outside the form
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- check x5 and y5 coordinates for being outside the form
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Draw a shape
         form.DrawPolylineSmoothOnBG(0,array_x,array_y,1,clrWheat,255,0.5,30.0,true,false,STYLE_SOLID,LINE_END_BUTT);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- "t" = Polyline with a specified width using a smoothing algorithm
      case FIGURE_TYPE_POLYLINE_THICK  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Fill in the arrays with coordinate values
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- check x1 and y1 coordinates for being outside the form
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- check x2 and y2 coordinates for being outside the form
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- check x3 and y3 coordinates for being outside the form
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- check x4 and y4 coordinates for being outside the form
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- check x5 and y5 coordinates for being outside the form
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Draw a shape
         form.DrawPolylineThickOnBG(0,array_x,array_y,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_BUTT);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- "y" = Polygon
      case FIGURE_TYPE_POLYGON  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Fill in the arrays with coordinate values
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- check x1 and y1 coordinates for being outside the form
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- check x2 and y2 coordinates for being outside the form
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- check x3 and y3 coordinates for being outside the form
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- check x4 and y4 coordinates for being outside the form
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- check x5 and y5 coordinates for being outside the form
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Draw a shape
         form.DrawPolygonOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- "u" = Filled polygon
      case FIGURE_TYPE_POLYGON_FILL  :
         return;
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*4;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         //--- Fill in the arrays with coordinate values
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- check x1 and y1 coordinates for being outside the form
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- check x2 and y2 coordinates for being outside the form
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- check x3 and y3 coordinates for being outside the form
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- check x4 and y4 coordinates for being outside the form
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- Draw a shape
         form.DrawPolygonFillOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         break;
      
   //--- "i" = Polygon with AntiAlliasing
      case FIGURE_TYPE_POLYGON_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Fill in the arrays with coordinate values
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- check x1 and y1 coordinates for being outside the form
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- check x2 and y2 coordinates for being outside the form
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- check x3 and y3 coordinates for being outside the form
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- check x4 and y4 coordinates for being outside the form
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- check x5 and y5 coordinates for being outside the form
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Draw a shape
         form.DrawPolygonAAOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- "o" = Polygon with WU
      case FIGURE_TYPE_POLYGON_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Fill in the arrays with coordinate values
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- check x1 and y1 coordinates for being outside the form
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- check x2 and y2 coordinates for being outside the form
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- check x3 and y3 coordinates for being outside the form
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- check x4 and y4 coordinates for being outside the form
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- check x5 and y5 coordinates for being outside the form
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Draw a shape
         form.DrawPolygonWuOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- "p" = Polygon with a specified width using two smoothing algorithms
      case FIGURE_TYPE_POLYGON_SMOOTH  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Fill in the arrays with coordinate values
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- check x1 and y1 coordinates for being outside the form
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- check x2 and y2 coordinates for being outside the form
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- check x3 and y3 coordinates for being outside the form
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- check x4 and y4 coordinates for being outside the form
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- check x5 and y5 coordinates for being outside the form
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Draw a shape
         form.DrawPolygonSmoothOnBG(0,array_x,array_y,3,clrWheat,255,0.5,10.0,true,false,STYLE_SOLID,LINE_END_BUTT);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- "a" = Polygon with a specified width using a smoothing algorithm
      case FIGURE_TYPE_POLYGON_THICK  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Fill in the arrays with coordinate values
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- check x1 and y1 coordinates for being outside the form
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- check x2 and y2 coordinates for being outside the form
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- check x3 and y3 coordinates for being outside the form
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- check x4 and y4 coordinates for being outside the form
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- check x5 and y5 coordinates for being outside the form
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Draw a shape
         form.DrawPolygonThickOnBG(0,array_x,array_y,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_BUTT);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- "s" = Rectangle
      case FIGURE_TYPE_RECTANGLE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawRectangleOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- "d" = Filled rectangle
      case FIGURE_TYPE_RECTANGLE_FILL  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawRectangleFillOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- "f" = Circle
      case FIGURE_TYPE_CIRCLE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         RD=nx2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(RD>form.Height()/2)
           {
            nx2=0;
            RD=1;
           }
         form.DrawCircleOnBG(0,coordX1,coordY1,(int)RD,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         break;
      
   //--- "g" = Filled circle
      case FIGURE_TYPE_CIRCLE_FILL  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         RD=nx2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(RD>form.Height()/2)
           {
            nx2=0;
            RD=1;
           }
         form.DrawCircleFillOnBG(0,coordX1,coordY1,(int)RD,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         break;
      
   //--- "h" = Circle with AntiAlliasing
      case FIGURE_TYPE_CIRCLE_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         RD=nx2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(RD>form.Height()/2)
           {
            nx2=0;
            RD=1;
           }
         form.DrawCircleAAOnBG(0,coordX1,coordY1,RD,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         break;
      
   //--- "j" = Circle with WU
      case FIGURE_TYPE_CIRCLE_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         RD=nx2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(RD>form.Height()/2)
           {
            nx2=0;
            RD=1;
           }
         form.DrawCircleWuOnBG(0,coordX1,coordY1,RD,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         break;
      
   //--- "k" = Triangle
      case FIGURE_TYPE_TRIANGLE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*4;
         coordY2=START_Y+ny2*2;
         coordX3=coordX1+nx3*2;
         coordY3=coordY2+ny3*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
           
         if(coordX3>form.Width()-START_X-1)
           {
            nx3=0;
            coordX3=START_X;
           }
         if(coordY3>form.Height()-START_Y-1)
           {
            ny3=0;
            coordY3=START_Y;
           }
         form.DrawTriangleOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         break;
      
   //--- "l" = Filled triangle
      case FIGURE_TYPE_TRIANGLE_FILL  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*4;
         coordY2=START_Y+ny2*2;
         coordX3=coordX1+nx3*2;
         coordY3=coordY2+ny3*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
           
         if(coordX3>form.Width()-START_X-1)
           {
            nx3=0;
            coordX3=START_X;
           }
         if(coordY3>form.Height()-START_Y-1)
           {
            ny3=0;
            coordY3=START_Y;
           }
         form.DrawTriangleFillOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         break;
      
   //--- "z" = Triangle with AntiAlliasing
      case FIGURE_TYPE_TRIANGLE_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*4;
         coordY2=START_Y+ny2*2;
         coordX3=coordX1+nx3*2;
         coordY3=coordY2+ny3*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
           
         if(coordX3>form.Width()-START_X-1)
           {
            nx3=0;
            coordX3=START_X;
           }
         if(coordY3>form.Height()-START_Y-1)
           {
            ny3=0;
            coordY3=START_Y;
           }
         form.DrawTriangleAAOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         break;
      
   //--- "x" = Triangle with WU
      case FIGURE_TYPE_TRIANGLE_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*4;
         coordY2=START_Y+ny2*2;
         coordX3=coordX1+nx3*2;
         coordY3=coordY2+ny3*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
           
         if(coordX3>form.Width()-START_X-1)
           {
            nx3=0;
            coordX3=START_X;
           }
         if(coordY3>form.Height()-START_Y-1)
           {
            ny3=0;
            coordY3=START_Y;
           }
         form.DrawTriangleWuOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         break;
      
   //--- "c" = Ellipse
      case FIGURE_TYPE_ELLIPSE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawEllipseOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- "v" = Filled ellipse
      case FIGURE_TYPE_ELLIPSE_FILL  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawEllipseFillOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- "b" = Ellipse with AntiAlliasing
      case FIGURE_TYPE_ELLIPSE_AA  :
         return;
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*2;
         coordY2=coordY1+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawEllipseAAOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- "n" = Ellipse with WU
      case FIGURE_TYPE_ELLIPSE_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*2;
         coordY2=coordY1+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawEllipseWuOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- "m" = Ellipse arc
      case FIGURE_TYPE_ARC  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=form.Width()-START_X-1-nx2;
         coordY2=form.Height()-START_Y-1-ny2;
         
         coordX3=coordX1;
         coordY3=coordY1;
         coordX4=coordX2;
         coordY4=coordY2;
         
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX3=coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY3=coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX4=coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY4=coordY2=START_Y;
           }
         form.DrawArcOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,coordX4,coordY4,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- "," = Ellipse sector
      case FIGURE_TYPE_PIE :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=form.Width()-START_X-1-nx2;
         coordY2=form.Height()-START_Y-1-ny2;
         
         coordX3=coordX1;
         coordY3=coordY1;
         coordX4=coordX2;
         coordY4=coordY1;
         
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX3=coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY3=coordY4=coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX4=coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawPieOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,coordX4,coordY4,clrWheat,clrLightSteelBlue);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Default = Nothing
      default  :
         
         break;
     }
  }
//+------------------------------------------------------------------+

I believe, the function code is simple and easy to understand. In any case, you are welcome to use the comments section.

I have not performed a general handling of identical parameters for a simple test. It is much easier and faster to write everything explicitly in the 'switch' operator cases. The code repetitiveness is not important. It is more important for us to simply check the functionality of the created classes.

Compile the EA and launch it on the chart. After the launch, press a few keys to make sure the drawing mode changes and is displayed in the label on the third form. When clicking the fourth form, the text is moved the same way as in the past EA from the previous article. Only now this text is rendered through the animation text frame object class.

If, after selecting the required drawing mode, we start clicking the third form (the label with a description of the drawing mode is displayed on), the selected shape is drawn above the label and the entire form with the shape points coordinates changing each time.


Not all drawing methods seem to work smoothly. For example, the FillPolygon() method of the CCanvas class simply falls into an infinite loop in case of the specified initial parameters in the object click, while the EllipseAA() method generates a zero divide error. This method features potential points where this may happen:

//+------------------------------------------------------------------+
//| Draw ellipse with antialiasing                                   |
//+------------------------------------------------------------------+
void CCanvas::EllipseAA(const double x1,const double y1,const double x2,const double y2,const uint clr,const uint style=UINT_MAX)
  {
   double rx = (x2-x1)/2;
   double ry = (y2-y1)/2;
//--- preliminary calculations
   double x=(x2>x1) ? x1+rx : x2+rx;
   double y=(y2>y1) ? y1+ry : y2+ry;
   double rx2=rx*rx;
   double ry2=ry*ry;
//--- set the line style
   uint prev_style=m_style;
   if(style!=UINT_MAX)
      LineStyleSet(style);
   uint mask=1<<m_style_idx;
//--- draw
   double quarter=round(rx2/sqrt(rx2+ry2));
   for(double dx=0; dx<=quarter; dx++)
     {
      double dy=ry*sqrt(1-dx*dx/rx2);
      if((m_style&mask)==mask)
         PixelSet4AA(x,y,dx,dy,clr);
      mask<<=1;
      if(mask==0x1000000)
         mask=1;
     }
   quarter=round(ry2/sqrt(rx2+ry2));
   for(double dy=0; dy<=quarter; dy++)
     {
      double dx=rx*sqrt(1-dy*dy/ry2);
      if((m_style&mask)==mask)
         PixelSet4AA(x,y,dx,dy,clr);
      mask<<=1;
      if(mask==0x1000000)
         mask=1;
     }
//--- set the previous line style
   if(style!=UINT_MAX)
      m_style=prev_style;
  }
//+------------------------------------------------------------------+

I reported this issue in the profile thread. Till I have a response from the developers, I will try to bypass such errors in subsequent articles.

Regarding this, some drawing methods are not called in the handler of mouse clicks on the form object. Instead, the function simply makes a return. Anyway, this will be fixed later. But now we see that the background under the drawn shapes is restored and everything is displayed as intended. There is a problem with switching drawing modes — after switching, the background is not restored. This happens due to the absence of the method for removing an image with the background restoration. I will do this in subsequent articles. Here, for testing purposes, I have simply switched the timeframe to completely restore the background before displaying another shape on the form.


What's next?

In the next article, I will continue the development of the animation classes.

All files of the current version of the library are attached below together with the test EA file for MQL5 for you to test and download.
Leave your questions and suggestions in the comments.

Back to contents

*Previous articles within the series:

Graphics in DoEasy library (Part 73): Form object of a graphical element
Graphics in DoEasy library (Part 74): Basic graphical element powered by the CCanvas class
Graphics in DoEasy library (Part 75): Methods of handling primitives and text in the basic graphical element
Graphics in DoEasy library (Part 76): Form object and predefined color themes
Graphics in DoEasy library (Part 77): Shadow object class
Graphics in DoEasy library (Part 78): Animation principles in the library. Image slicing

Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/9652

Attached files |
MQL5.zip (4076.37 KB)
Bid/Ask spread analysis in MetaTrader 5 Bid/Ask spread analysis in MetaTrader 5
An indicator to report your brokers Bid/Ask spread levels. Now we can use MT5s tick data to analyze what the historic true average Bid/Ask spread actually have recently been. You shouldn't need to look at the current spread because that is available if you show both bid and ask price lines.
Combinatorics and probability theory for trading (Part I): The basics Combinatorics and probability theory for trading (Part I): The basics
In this series of article, we will try to find a practical application of probability theory to describe trading and pricing processes. In the first article, we will look into the basics of combinatorics and probability, and will analyze the first example of how to apply fractals in the framework of the probability theory.
Exploring options for creating multicolored candlesticks Exploring options for creating multicolored candlesticks
In this article I will address the possibilities of creating customized indicators with candlesticks, pointing out their advantages and disadvantages.
Better Programmer (Part 04): How to become a faster developer Better Programmer (Part 04): How to become a faster developer
Every developer wants to be able to write code faster, and being able to code faster and effective is not some kind of special ability that only a few people are born with. It's a skill that can be learned by every coder, regardless of years of experience on the keyboard.