DoEasy 函数库中的图形(第七十九部分):“动画框”对象类及其衍生对象

27 九月 2021, 09:16
Artyom Trishkin
0
479

内容


概述

在上一篇文章中,我已创建了类,来保存和之后恢复位于所绘制造型的下层背景部分。 在此,我将重启这个概念的探究,并基于它创建若干个类:单个动画框、及其衍生类 — 文本动画框和矩形动画框类。

基类包含单个动画框的一套通用属性,而其衍生类将拥有自己固有的绘制造型的方法。 文本动画类能够操控文本,而矩形动画框能够创建单个动画框,并利用基于诸如 CCanvas 类的绘制方法在其内绘制各种造型。

每个所创建交互窗对象都有一套在画布上绘图的自定义方法,这令我们可在交互窗上快速创建和管理新的图像。 为了能够在每个交互窗中方便地运用绘图工具,我将创建一个通用类来显示交互窗上所有已创建文本和形状图像的列表。 稍后,我还会添加新的动画方法,它们的清单也将放置到通用类之中。 这样的概念允许我们动态创建新图像,并将它们保存到相应的列表当中。 接下来,可以从交互窗对象中快速恢复它们,并显示在其背景之上。 在这种情况下,该类对象会自动将交互窗的背景保存在它们之下。 如果对象被删除、更改或移动,则恢复所保存的背景。

因此,在本篇文章中,我将略微修改前几篇文章里创建的绘制框的代码,开发基本动画框对象类,并开发两个衍生类 — 文本动画框和矩形动画框类。 我们来创建存储这些框对象列表的类,并提供从交互窗对象中操控它们的能力。


改进库类

首先,我们改进之前创建的库类。 在 \MQL5\Include\DoEasy\Defines.mqh 里,在矩形动画框类中添加动画框列表所绘制造型类型列表

//+------------------------------------------------------------------+
//| 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
   
  };
//+------------------------------------------------------------------+

我将用动画框类型来识别动画框对象(无论是文本、绘制的造型、还是我将在后续文章中引入的任何其它动画框类型)。 绘制造型的类型可准确指示单个矩形动画框中的绘制内容。 这些类型对应于 CCanvas 类中现有的绘制方法(在类方法表格中的数据访问”、“绘制图元”、“绘制填充图元" 和 "运用抗锯齿绘制图元 ”部分)。

在 \MQL5\Include\DoEasy\Data.mqh 里,加入新的消息索引:

//--- 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

与新添加的索引相对应的消息文本:

//--- 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"},


在函数库服务函数文件 \MQL5\Include\DoEasy\Services\DELib.mqh中,添加返回数组中最大值和最小值的函数:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

这些函数依据所传递的引用,返回位于数组中的最大值或最小值。 因为位于数组单元格中的数值可能是“无效”的,故函数的任何返回值都是 bool 类型。 例如,如果从数组收到的数据返回 -1(就像在许多函数中所做的那样),则这样的值可以是数组中设置的数值之一。 当返回有效值 (-1) 时,我们的程序假定这是一个错误。 这是不正确的。 因此,如果出现错误,我们将返回 false,而在数组中找到的最大值或最小值则赋值给通过引用传递给函数的变量。 如果函数返回 true,则变量里存储所需的数值。 source 变量接收所调用函数的方法名称。 如若发生错误,这可以令我们查看调用该函数的方法名称,以及错误消息。

该变量还接收函数返回的绘制造型类型的描述:

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

在此,以枚举格式传递给函数的类型被转换为字符串描述。 从第 12 个字符位置开始的子字符串是从类型文本表达中提取出来的,以便裁剪不必要的文本。 例如,FIGURE_TYPE_TRIANGLE 图形类型转换为 "FIGURE_TYPE_TRIANGLE",且必要子串 就是从这个文本 "FIGURE_TYPE_TRIANGLE" 中第 12 个字符开始提取出来的。 字符串 “TRIANGLE” 就是返回的结果。

在前一篇文章中,当创建把一部分背景复制到数组的方法时,我是通过交互窗上显示的文本大小来定义索要复制的背景矩形的大小和坐标。 在此,我会显示图像。 它们的大小不再由文本大小定义。 因此,我们需要创建一个方法来定义背景部分需复制矩形的坐标和大小。

在图形元素类的 \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh 文件中,重命名方法

//--- 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

现在该方法称为 GetShiftXYbyText()我们来声明一个新方法,按照相对于对象锚点所的指定大小,返回需复制图像部分的坐标和大小:

//--- 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

在类清单的末尾实现它们。

该方法按大小返回相对于矩形锚点的坐标偏移量:

//+------------------------------------------------------------------+
//| 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;
     }
  }
//+------------------------------------------------------------------+

在此,根据复制区域的宽度和高度,以及传递给方法的锚点,计算相对于锚点的坐标偏移,并将它们赋值给通过引用传递给方法的变量。

该方法返回相对于文本锚点的坐标偏移:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

此处我们首先定义传递给方法文本大小,并调用上面研究过的方法定义保存交互窗背景图片区域的坐标偏移

在前一篇文章中,我曾开发了复制交互窗背景图像一部分,并在之后从数组中恢复它的类。 该类是在交互窗对象类文件中设置的。 现在我从交互窗对象类文件中删除该类,将其重新定位到新创建的框对象类的文件中(我再次发现在单独的文件中编写和存储类更好)。

因此,我们为单个动画框创建一个基类。 该类将包含其所有衍生后代共有的属性。

“动画框”对象类

在 \MQL5\Include\DoEasy\Objects\Graph\ 中,创建新 Animations\ 文件夹,内含 CFrame 类的新 Frame.mqh 文件。

图形元素对象类的文件应该包含到类文件中:

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

接下来,放置从交互窗对象类文件中移除的像素复印机对象类在上一篇文章中已研究过):

//+------------------------------------------------------------------+
//|                                                        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;
  }
//+------------------------------------------------------------------+

此处唯一(暂时)更改的是我把应该在复制之前保存的整个交互窗图像的代码注释掉了。 此处发生的错误导致直接从图形资源复制背景,而非从交互窗对象数组。 图形资源包含应用于交互窗背景图像的所有变化。 为了修复这个问题,我需要将交互窗外观保存到一个单独的数组当中,其中包含原始交互窗图像的副本。 我已经有了一个这样的数组,但我仍然需要创建方法,在原始交互窗外观创建完毕后立即将其保存。 至此,我已经注释掉了这些代码。 含有整个交互窗(而不是其部分)大小的背景,将在循环中恢复交互窗背景部分(即,并非将一个数组复制到另一个数组,而是来自存储在交互窗背景图像部分副本的数组)。

接下来,在像素复制器类清单末尾,编写动画框对象类的主体:

//+------------------------------------------------------------------+
//| 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);
  };
//+------------------------------------------------------------------+

该类派生自像素复印机对象类,所以,实际上就是像素复印机对象类。

类中声明的所有变量和方法都已在注释中讲述。 鉴于该类是其它动画框类的基类,因此所有衍生后代的通用属性和方法都在这里设置。

返回最后坐标、偏移量和锚点的变量和方法是必要的,以便我们能够在恢复图像时确定之前保存的图像部分的坐标。 这些坐标保存的是绘制图像时被擦除的背景。

该类拥有三个构造函数:

  1. 默认的公开构造函数,
  2. 受保护的文本框对象构造函数,
  3. 受保护的矩形框对象构造函数,

我们来研究受保护构造函数的实现。

矩形框的构造函数:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

构造函数接收欲创建矩形框对象的 ID、其 X 和 Y 坐标、框的宽度和高度,以及指向欲创建新对象的图形元素对象的指针。 由于该类是像素复制器对象的衍生后代,因此在构造函数初始化清单中要将所有必要的参数传递给基类的构造函数。 这些参数都是需要传递给构造函数参数的属性。
为类主体中的所有类成员变量设置默认参数。

文本框的构造函数:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

构造函数接收欲创建文本框对象的 ID、其 X 和 Y 坐标、文本和指向欲创建新对象的图形元素对象的指针。
在类主体中,首先定义文本大小,然后设置类成员变量的默认值,并将欲创建对象的 ID、其坐标和文本大小赋值给父类像素复制机对象。

创建动画帧对象类衍生后代的对象类。

文本动画框类

在 \MQL5\Include\DoEasy\Objects\Graph\Animations\ 里,创建 CFrameText 类的新文件 FrameText.mqh

动画框类的文件应该包含在该文件之中,而类本身应该是其衍生后代

//+------------------------------------------------------------------+
//|                                                    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) {}
  };
//+------------------------------------------------------------------+

在此我们可以看到一个在交互窗对象背景上绘制文本的公开方法,和两个构造函数 — 默认和参数型

参数型构造函数接收欲创建文本动画框对象的 ID,和指向欲创建对象的图形元素的指针。 在初始化清单中,父类接收在构造函数参数中传递的 ID、坐标和文本的默认值,以及在构造函数参数中传递的指向图形元素的指针。

在背景上显示文本,同时保存和恢复背景的方法:

//+-------------------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

该方法的逻辑在代码注释中已有详述。 上一篇文章中我已在测试过程中研究过它了(与在测试 EA 部分的 OnChartEvent() 处理程序中设置的逻辑类似),所以,我相信,此处的一切也都很清晰。 在交互窗上绘制文本之后,在父类的变量中设置其锚点、X 和 Y 坐标,以及相对于锚点的偏移值。 它们的值将用于恢复被文本覆盖的交互窗图像背景。

现在,我们来创建动画帧对象的第二个衍生后代类。

矩形动画框类

在 \MQL5\Include\DoEasy\Objects\Graph\Animations\ 里,创建 CFrameQuad 类的新文件 FrameQuad.mqh

父类文件应该包含在(以及派生自)类文件:

//+------------------------------------------------------------------+
//|                                                    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;   }

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

在类的私密部分,声明类成员变量,用于存储围绕所绘制造型的矩形的坐标和大小 — 这些是需保存的,被所绘制造型覆盖的背景部分图像区域的坐标和大小。

参数型构造函数接收欲创建对象的 ID,和指向欲创建对象图形元素的指针。 在方法参数中传递的 ID、默认坐标和帧大小参数、以及指向图形元素的指针,将传递给构造函数初始化清单中的父类构造函数。 在构造函数主体中,将绘制图形的锚点设置为“左上角”。 这是计算复制区域偏移所必需的。 有了这个值,X 和 Y 坐标锚点偏移就等于零。

由于我们在 CCanvas 类中有大量的绘制方法,所有在交互窗对象背景上绘制造型的相应方法都在类的公开部分声明,随后是恢复背景:

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
  };
//+------------------------------------------------------------------+

这些方法的每一个实现,都与类似的绘图方法实现相似。 不过,几乎所有的绘制方法都有其固有的细微差别(两种相似的绘制方法的保存区域的大小可能因它们各自的特点而有所不同)。

我们来看看这些方法的实现。

设置指定坐标点颜色的方法:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

该方法的逻辑已在代码中进行了足够详细的注释。 我们来更通透地研究一下。 此处我们先把背景矩形区域左上边缘的 X、Y坐标保存到数组中,以便后续恢复绘制点之下的背景。 由于这只是一个点(一个像素的图像),保存区域的坐标与绘制点的坐标匹配,大小与单个像素的大小匹配,即 1 x 1。

接下来我们检查背景是否之前已保存(依据保存背景的数组大小非零)。 如果是,则恢复之前保存的交互窗对象背景(恢复区域的坐标和大小已在类变量中设置)。 背景恢复成功后,保存带有新像素点坐标的交互窗背景,并绘制像素点。 在类变量中保存新坐标,以及保存区域的大小和位移,以便后续恢复被新绘制的像素点擦除的背景。

绘制一条垂直线段的方法:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

在此计算勾勒造型的矩形坐标和大小,其与之前方法中的计算不尽相同。 这是很自然的,因为我们绘制的是一条宽度为一个像素的垂直线。 线的高度计算方法是线的两个 Y 坐标的最大值和最小值之间的差值。 保存区域的 Y 坐标则对应两个 Y 坐标的最小值(所绘线的顶点)。

绘制水平线段的方法:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

在此,计算欲保存区域的坐标和大小与前面方法中的计算类似,只是此处是一条水平线,其高度等于一个像素,故只需计算保存区域的宽度和 X 坐标。

绘制手绘线段的方法:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

此处,欲保存区域的坐标和大小是根据所绘制线的坐标计算出来的

绘制折线的方法:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

此处计算欲保存区域坐标和大小背后的思路与上面研究的方法相同。 然而,执行则不同,因为在折线(以及许多其他造型)的情况下,坐标通过数组传递,而非变量的形式,因为不可能预先知道线打弯的数量,或坐标的数量,故无法在方法参数中传递。 这就是为什么在调用该方法之前,我们应该用 X 坐标和每条线打弯点的相应 Y 坐标填充两个数组。
在该方法中,我们用之前研究过的函数从数组中接收最大值和最小值,返回传递给函数的数组中的最小值或最大值。 所获值用于计算欲保存交互窗背景区域的坐标和大小。

其余的造型绘制方法无需平滑(只需关注计算保存区域坐标和大小):

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+


我们来研究无需平滑的情况下绘制填充图元的方法。

区域填充方法:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

由于该方法填充的是任意封闭区域,因此我们无法提前知道保存区域的大小。 因此,整个交互窗都应在此处保存。 为了实现这一点,我们将坐标和大小设置为零。 在这些值的情况下,保存图像矩形区域的方法会把整个交互窗背景保存到数组之中。

至于其余绘制填充图元的方法,它们计算坐标和保存区域大小与之前研究的简单无平滑图元的计算相匹配。 我们来看看这些方法:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+


绘制平滑图元的方法。

运用抗锯齿算法绘制点的方法:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

此处计算欲保存区域坐标和大小与绘制无平滑点方法中的计算有别。 一个平滑点可以位于三个相邻的像素(共 9 个,即 3 x 3 个像素)上,因此保存区域的尺寸应为高 3 像素,宽 3 像素。 X 和 Y 坐标应分别位于点本身坐标左侧和上方 1 个像素的位置。 因此,围绕该点的保存区域矩形将与绘制点的所有边框有一个像素的边距,以防后者被平滑算法模糊,并在多个像素上绘制。 这将令我们能够在恢复因绘制平滑点而擦除的背景时,留有残影。

运用抗锯齿算法绘制手绘线段的方法:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

测试该方法发现绘制线的边缘不会模糊,因此计算欲保存区域大小与绘制无平滑线方法匹配。

使用 Wu 算法绘制一段手绘线段的方法:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

出于同样的原因,此处的计算与之前的方法类似。

使用带有初步过滤的平滑算法绘制具有指定宽度的手绘线段的方法:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

在该方法中,计算欲保存区域与上面研究的不同。 由于采用这种平滑算法的线条具有可编辑的值,以及其末端外观,因此保存区域的宽度应考虑线条及其边缘的大小(宽度)(线条边缘可以倒圆角,因此线条大小 (length) 增加两个圆角半径,即线宽增加的值)。

使用带有初步过滤的平滑算法绘制具有指定宽度的垂直手绘线的方法:

//+---------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

此处计算与之前讲述的方法相同。

其余绘制平滑和其他图元的方法:

//+-----------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

此处,所有方法保存的背景区域算法与上述方法中的算法大致相同。

在椭圆绘制方法(DrawEllipseAAOnBG 和 DrawEllipseWuOnBG)中,如果绘制椭圆的矩形小于三个像素,则不绘制任何造型。 因此,此处的计算包含对小于三个像素大小的检查。 我还未决定,是否是我的错误,还是 CCanvas 类方法的一个特性。 我希望以后能澄清这一点。

我已经开发完毕目前需要的动画框对象的所有类。

现在是时候创建一个类来存储、访问和管理所创建动画框对象了。

该类将包含两个(目前)列表,存储所创建动画框对象(文本和矩形对象),以及创建和管理新对象的方法。 随后,该类将存储属于一个交互窗的所有动画对象。 因此,每个交互窗都有自己的一组动画对象,这些对象可以动态创建,并添加到交互窗动画列表中。

交互窗动画类

在 \MQL5\Include\DoEasy\Objects\Graph\Animations\ 里,创建 CAnimations 类的新 Animations.mqh 文件。

只有新创建的基准动画框对象的衍生后代类文件才可包含在类文件之中,而类本身应该是 CObject 标准库基准对象的衍生后代

//+------------------------------------------------------------------+
//|                                                   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
  {
  }

在类的私密部分,声明指向欲创建动画对象的图形元素对象指针、存储两种类型动画框对象的两个列表、以及用于返回指定对象存在于列表中的标志的方法、以及返回指向现有动画框对象的指针方法、如若它不存在于列表中,则初步创建它:

//+------------------------------------------------------------------+
//| 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:

所有方法均在下面予以研究。

在类的公开部分,声明创建和操控列表中对象的方法,以及绘制图元,同时保存和恢复背景的方法:

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
  };
//+------------------------------------------------------------------+


我们来研究一下所声明方法的实现。

参数型构造函数:

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

在参数中传递的指向图形元素对象的指针值,会赋值给 m_element 指针。

该方法返回按类型和 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;
  }
//+------------------------------------------------------------------+

方法逻辑在代码注释中已有详细讲述,无需赘言。

该方法返回标志,指示列表中是否含有指定类型和 ID 的框对象:

//+-----------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

该方法返回调用上述 GetFrame() 方法的 bool 结果。 如果 GetFrame() 方法返回非 NULL 结果(所需对象存在于列表中),则该方法返回 true,否则 — false

该方法创建一个新的文本动画框对象:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

代码注释中完整描述了方法逻辑。

的方法该建一个新的矩形动画框对象:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

该方法与上面研究过的方法雷同。

该方法返回指针或创建新动画框对象:

//+------------------------------------------------------------------+
//| 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;
     }
  }
//+------------------------------------------------------------------+

方法逻辑已在代码注释中描述。 如果我们需要操控一个动画框,我们可以预先创建它,获取指向它的指针,并管理获取的对象。 如果我们需要动态创建对象,这个方法允许我们先创建一个新对象(前提是没有指定 ID 的对象),并返回指向它的指针。 因此,可相应地安排对象的动态创建,立即获得指向它的指针,并对其进行管理。

操控动画框对象的方法。

在背景上显示文本,同时保存和恢复背景的方法:

//+--------------------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

该方法接收对象 ID、欲显示的文本参数(文本本身、X 和 Y 坐标、锚点、颜色和不透明度)、如果在列表中不存在这个对象的 ID,则指示需要创建含有指定 ID 新对象的标志,以及图表重绘标志。
接下来,获取指向所需对象的指针(如果不存在,则创建该对象)。 如果获取指针失败,则返回 false
如果收到指针,则返回所获取文本动画框对象的 TextOnBG() 方法的结果

设置指定坐标点颜色的方法:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

方法逻辑与上面研究过的方法之一雷同。 该方法接收对象 ID、绘制的形状 X 和 Y 坐标、颜色和不透明度、如若这个 ID 的对象不在列表中,则指示需要创建指定 ID 新对象的标志,以及 图表重绘标志。
接下来,获取指向所需对象的指针(如果不存在,则创建该对象)。 如果获取指针失败,则返回 false
如果收到指针,则返回所获取动画矩形框对象的 SetPixelOnBG() 方法的结果

绘制图元的其它方法。

其余造型绘制方法的逻辑与上面研究的方法的逻辑雷同。 我们来看看它们的清单:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+


新创建的动画对象类应该是交互窗对象的组成部分。 如此,每个交互窗都有自己的创建图像的方法。

打开交互窗对象类 \MQL5\Include\DoEasy\Objects\Graph\Form.mqh 的文件,并添加必要的改进。

包含动画对象类的文件:

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

从清单里删除像素复制器对象类(我已将其移至另一个文件):

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

在类的私密部分,替代像素复制器清单

CArrayObj         m_list_pc_obj;                            // List of pixel copier objects

声明指向动画类对象的指针:

//+------------------------------------------------------------------+
//|                                                         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:

从私密部分移除已经不必要的 IsPresentPC() 方法的声明,以及代码清单中的实现:

//--- 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:

从类的公开部分删除已经不需要的方法

//--- 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;      }

添加返回指向动画对象的指针,以及文本和矩形动画框列表的新方法

   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

删除创建新像素复制对象的方法声明

//--- 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

在类主体之外编写的方法实现也一并被删除。

在类的公开部分中操控图像像素的方法模块中,编写创建动画框对象、返回指向创建对象的指针、以及保存和恢复背景的新方法:

//+------------------------------------------------------------------+
//| 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