English 中文 Español Deutsch 日本語 Português
Графика в библиотеке DoEasy (Часть 79): Класс объекта "Кадр анимации" и его объекты-наследники

Графика в библиотеке DoEasy (Часть 79): Класс объекта "Кадр анимации" и его объекты-наследники

MetaTrader 5Примеры | 15 июля 2021, 12:39
2 997 0
Artyom Trishkin
Artyom Trishkin

Содержание


Концепция

В прошлой статье мы создали класс для сохранения и последующего восстановления части фона, находящегося под рисуемой фигурой. Сегодня продолжим эту концепцию и на её основе создадим несколько классов: базовый класс одного кадра анимации и его наследников — класс кадра текстовой анимации и класс прямоугольного кадра анимации.

Базовый класс будет содержать в себе общий набор свойств одного кадра анимации, в то время как его наследники будут иметь свои, присущие только им, методы для рисования фигур. Класс текстовой анимации будет позволять работать именно с текстами, а класс прямоугольного кадра анимации будет позволять создать один кадр анимации и рисовать в нём различные фигуры при помощи методов рисования, основанных на таких методах класса CCanvas.

Каждый созданный объект-форма будет иметь набор методов для рисования на своём холсте, что позволит оперативно создавать новые изображения на форме и управлять ими. Для того, чтобы мы могли удобно использовать инструментарий рисования в каждой форме, создадим общий класс, в котором будут находиться списки всех создаваемых текстовых и фигурных рисунков на этой форме (впоследствии будем добавлять новые методы анимации, и их списки тоже будут находиться в этом общем классе). Такая концепция позволит нам динамически создавать новые изображения и сохранять их в соответствующие их типу списки, а затем их можно будет быстро находить из объекта-формы и выводить на его фон. При этом такие объекты будут автоматически сохранять находящийся под ними фон формы, а при их удалении, изменении или перемещении — восстанавливать сохранённый фон.

Таким образом, сегодня мы немного переработаем созданные в предыдущих статьях классы рисования, разработаем класс базового объекта-кадра анимации и разработаем два класса его наследников — класс кадра текстовой анимации и класс прямоугольного кадра анимации. Создадим класс для хранения списков этих объектов-кадров и дадим возможность работы с ними из объекта-формы.


Доработка классов библиотеки

Для начала доработаем ранее созданные классы библиотеки. В файл \MQL5\Include\DoEasy\Defines.mqh впишем список типов кадров анимации и список типов рисуемых фигур в классе прямоугольного кадра анимации:

//+------------------------------------------------------------------+
//| Данные для работы с анимацией графических элементов              |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Список  типов кадров анимации                                    |
//+------------------------------------------------------------------+
enum ENUM_ANIMATION_FRAME_TYPE
  {
   ANIMATION_FRAME_TYPE_TEXT,                         // Текстовый кадр анимации
   ANIMATION_FRAME_TYPE_QUAD,                         // Прямоугольный кадр анимации
  };
//+------------------------------------------------------------------+
//| Список типов рисуемых фигур                                      |
//+------------------------------------------------------------------+
enum ENUM_FIGURE_TYPE
  {
   FIGURE_TYPE_PIXEL,                                 // Точка
   FIGURE_TYPE_PIXEL_AA,                              // Точка со сглаживанием AntiAlliasing
   
   FIGURE_TYPE_LINE_VERTICAL,                         // Вертикальная линия
   FIGURE_TYPE_LINE_VERTICAL_THICK,                   // Вертикальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания
   
   FIGURE_TYPE_LINE_HORIZONTAL,                       // Горизонтальная линия
   FIGURE_TYPE_LINE_HORIZONTAL_THICK,                 // Горизонтальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания
   
   FIGURE_TYPE_LINE,                                  // Произвольная линия
   FIGURE_TYPE_LINE_AA,                               // Линия со сглаживанием AntiAlliasing
   FIGURE_TYPE_LINE_WU,                               // Линия со сглаживанием WU
   FIGURE_TYPE_LINE_THICK,                            // Отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания
   
   FIGURE_TYPE_POLYLINE,                              // Ломаная линия
   FIGURE_TYPE_POLYLINE_AA,                           // Ломаная линия со сглаживанием AntiAlliasing
   FIGURE_TYPE_POLYLINE_WU,                           // Ломаная линия со сглаживанием WU
   FIGURE_TYPE_POLYLINE_SMOOTH,                       // Ломаная линия заданной толщины с использованием двух алгоритмов сглаживания
   FIGURE_TYPE_POLYLINE_THICK,                        // Ломаная линия заданной толщины с использованием алгоритма сглаживания    
   
   FIGURE_TYPE_POLYGON,                               // Многоугольник
   FIGURE_TYPE_POLYGON_FILL,                          // Закрашенный многоугольник
   FIGURE_TYPE_POLYGON_AA,                            // Многоугольник со сглаживанием AntiAlliasing
   FIGURE_TYPE_POLYGON_WU,                            // Многоугольник со сглаживанием WU
   FIGURE_TYPE_POLYGON_SMOOTH,                        // Многоугольник заданной толщины с использованием двух алгоритмов сглаживания
   FIGURE_TYPE_POLYGON_THICK,                         // Многоугольник заданной толщины с использованием алгоритма сглаживания
   
   FIGURE_TYPE_RECTANGLE,                             // Прямоугольник
   FIGURE_TYPE_RECTANGLE_FILL,                        // Закрашенный прямоугольник
   
   FIGURE_TYPE_CIRCLE,                                // Окружность
   FIGURE_TYPE_CIRCLE_FILL,                           // Закрашенный круг
   FIGURE_TYPE_CIRCLE_AA,                             // Окружность со сглаживанием AntiAlliasing
   FIGURE_TYPE_CIRCLE_WU,                             // Окружность со сглаживанием WU
   
   FIGURE_TYPE_TRIANGLE,                              // Треугольник
   FIGURE_TYPE_TRIANGLE_FILL,                         // Закрашенный треугольник
   FIGURE_TYPE_TRIANGLE_AA,                           // Треугольник со сглаживанием AntiAlliasing
   FIGURE_TYPE_TRIANGLE_WU,                           // Треугольник со сглаживанием WU
   
   FIGURE_TYPE_ELLIPSE,                               // Эллипс
   FIGURE_TYPE_ELLIPSE_FILL,                          // Закрашенный эллипс
   FIGURE_TYPE_ELLIPSE_AA,                            // Эллипс со сглаживанием AntiAlliasing
   FIGURE_TYPE_ELLIPSE_WU,                            // Эллипс со сглаживанием WU
   
   FIGURE_TYPE_ARC,                                   // Дуга эллипса
   FIGURE_TYPE_PIE,                                   // Сектор эллипса
   
  };
//+------------------------------------------------------------------+

Типы кадров анимации будем использовать для идентификации объектов-кадров анимации (текст ли это, рисуемая ли фигура, либо какой-то иной тип кадра анимации, которые далее будем делать в последующих статьях). Типы рисуемых фигур будут указывать нам на то, что именно рисуется в одном кадре прямоугольной анимации. Эти типы соответствуют имеющимся методам рисования в классе CCanvas (разделы "Доступ к данным", "Рисование примитивов", "Рисование закрашенных примитивов" и "Рисование примитивов с использованием сглаживания" в таблице методов класса).

В файле \MQL5\Include\DoEasy\Data.mqh впишем индексы новых сообщений:

//--- CForm
   MSG_FORM_OBJECT_TEXT_NO_SHADOW_OBJ_FIRST_CREATE_IT,// Отсутствует объект тени. Необходимо сначала его создать при помощи метода CreateShadowObj()
   MSG_FORM_OBJECT_ERR_FAILED_CREATE_SHADOW_OBJ,      // Не удалось создать новый объект для тени
   MSG_FORM_OBJECT_ERR_FAILED_CREATE_PC_OBJ,          // Не удалось создать новый объект-копировщик пикселей
   MSG_FORM_OBJECT_PC_OBJ_ALREADY_IN_LIST,            // В списке уже есть объект-копировщик пикселей с идентификатором 
   MSG_FORM_OBJECT_PC_OBJ_NOT_EXIST_LIST,             // В списке нет объекта-копировщика пикселей с идентификатором 

//--- CFrame
   MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME,           // Не удалось создать новый объект-кадр анимации
   MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST,             // В списке уже есть объект-кадр анимации с идентификатором 
   MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST,              // В списке нет объекта-кадра анимации с идентификатором 

//--- CShadowObj
   MSG_SHADOW_OBJ_IMG_SMALL_BLUR_LARGE,               // Ошибка! Размер изображения очень маленький или очень большое размытие

и тексты сообщений, соответствующие вновь добавленным индексам:

//--- 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 впишем функции, возвращающие максимальное и минимальное значение в массиве:

//+------------------------------------------------------------------+
//| Возвращает максимальное значение в массиве                       |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+
//| Возвращает минимальное значение в массиве                        |
//+------------------------------------------------------------------+
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 в функцию передаётся название метода, из которого была вызвана эта функция, что позволит при ошибке вывести название того метода, из которого была вызвана эта функция, и текст сообщения об ошибке.

Туда же впишем функцию, возвращающую описание типа рисуемой фигуры:

//+------------------------------------------------------------------+
//| Возвращает описание типа рисуемой фигуры                         |
//+------------------------------------------------------------------+
string FigureTypeDescription(const ENUM_FIGURE_TYPE figure_type)
  {
   return(StringSubstr(EnumToString(figure_type),12));
  }
//+------------------------------------------------------------------+

Здесь переданный в функцию в формате перечисления тип преобразуется в строковое описание и уже из текстового представления типа извлекается подстрока с позиции 12-го символа для обрезания ненужного текста. Таким образом, например, тип фигуры FIGURE_TYPE_TRIANGLE будет преобразован в текст "FIGURE_TYPE_TRIANGLE" и из этого текста будет извлечена нужная подстрока, начинающаяся с 12-го символа "FIGURE_TYPE_TRIANGLE". В результате будет возвращена строка "TRIANGLE".

В прошлой статье, при создании методов копирования части фона в массив, мы определяли размер и координаты копируемого прямоугольника фона по размеру текста, который выводили на форму. Сегодня мы будем выводить не только тексты, но и рисунки. А их размеры уже не будут определяться по размеру текста. Поэтому нам нужно создать метод, определяющий координаты и размер копируемого прямоугольника части фона.

В файле \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh класса графического элемента переименуем метод

//--- Возвращает смещения координат относительно точки привязки текста
   void              TextGetShiftXY(const string text,            // Текст для расчёта размера его очерчивающего прямоугольника
                                    const ENUM_TEXT_ANCHOR anchor,// Точка привязки текста, относительно которой будут рассчитаны смещения
                                    int &shift_x,                 // Сюда будет записана X-координата верхнего левого угла прямоугольника
                                    int &shift_y);                // Сюда будет записана Y-координата верхнего левого угла прямоугольника

Теперь этот метод будет называться GetShiftXYbyText() и объявим новый метод, возвращающий координаты и размер копируемой части изображения по указанному размеру относительно точки привязки объекта:

//--- Возвращает смещения координат относительно точки привязки текста по тексту
   void              GetShiftXYbyText(const string text,             // Текст для расчёта размера его очерчивающего прямоугольника
                                      const ENUM_TEXT_ANCHOR anchor, // Точка привязки текста, относительно которой будут рассчитаны смещения
                                      int &shift_x,                  // Сюда будет записана X-координата верхнего левого угла прямоугольника
                                      int &shift_y);                 // Сюда будет записана Y-координата верхнего левого угла прямоугольника
//--- Возвращает смещения координат относительно точки привязки прямоугольника по размеру
   void              GetShiftXYbySize(const int width,               //Размер прямоугольника по ширине
                                      const int height,              //Размер прямоугольника по высоте
                                      const ENUM_TEXT_ANCHOR anchor, // Точка привязки прямоугольника, относительно которой будут рассчитаны смещения
                                      int &shift_x,                  // Сюда будет записана X-координата верхнего левого угла прямоугольника
                                      int &shift_y);                 // Сюда будет записана Y-координата верхнего левого угла прямоугольника

В конце листинга класса напишем их реализацию.

Метод, возвращающий смещения координат относительно точки привязки прямоугольника по размеру:

//+------------------------------------------------------------------+
//| Возвращает смещения координат относительно точки привязки        |
//| прямоугольника по размеру                                        |
//+------------------------------------------------------------------+
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;
     }
  }
//+------------------------------------------------------------------+

Здесь: в зависимости от ширины и высоты копируемой области, а также в зависимости от переданной в метод точки привязки, рассчитываем смещения координат относительно точки привязки и записываем их в переменные, переданные по ссылке в метод.

Метод, возвращающий смещения координат относительно точки привязки текста:

//+------------------------------------------------------------------+
//| Возвращает смещения координат относительно точки привязки текста |
//+------------------------------------------------------------------+
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\, а в ней — новый файл Frame.mqh класса CFrame.

К файлу класса должен быть подключен файл класса объекта-графического элемента:

//+------------------------------------------------------------------+
//|                                                        Frame.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "..\GCnvElement.mqh"
//+------------------------------------------------------------------+

Далее разместим удалённый из файла класса объекта-формы класс объекта-копировщика пикселей (его мы рассматривали в прошлой статье):

//+------------------------------------------------------------------+
//|                                                        Frame.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "..\GCnvElement.mqh"
//+------------------------------------------------------------------+
//| Класс копировщика пикселей                                       |
//+------------------------------------------------------------------+
class CPixelCopier : public CObject
  {
protected:
   CGCnvElement     *m_element;                             // Указатель на графический элемент
   uint              m_array[];                             // Массив пикселей
   int               m_id;                                  // Идентификатор
   int               m_x;                                   // Координата X верхнего левого угла
   int               m_y;                                   // Координата Y верхнего левого угла
   int               m_w;                                   // Ширина копируемого изображения
   int               m_h;                                   // Высота копируемого изображения
   int               m_wr;                                  // Рассчитываемая ширина копируемого изображения
   int               m_hr;                                  // Рассчитываемая высота копируемого изображения
public:
//--- Сравнивает объекты CPixelCopier между собой по указанному свойству (для сортировки списка по свойству объекта)
   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);
                       }
   
//--- Установка свойств
   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;          }
//--- Получение свойств
   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;        }

//--- Копирует часть или всё изображение в массив
   bool              CopyImgDataToArray(const uint x_coord,const uint y_coord,uint width,uint height);
//--- Копирует часть или всё изображение из массива на канвас
   bool              CopyImgDataToCanvas(const int x_coord,const int y_coord);

//--- Конструкторы
                     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){;}
  };
//+------------------------------------------------------------------+
//| Копирует часть или всё изображение в массив                      |
//+------------------------------------------------------------------+
bool CPixelCopier::CopyImgDataToArray(const uint x_coord,const uint y_coord,uint width,uint height)
  {
//--- Присваиваем переменным значения координат, переданных в метод
   int x1=(int)x_coord;
   int y1=(int)y_coord;
//--- Если X-координата выходит за пределы формы справа, или Y-координата выходит за пределы снизу,
//--- то копировать нечего - копируемая область за пределами формы - возвращаем false
   if(x1>this.m_element.Width()-1 || y1>this.m_element.Height()-1)
      return false;
//--- Присваиваем переменным значения ширины и высоты копируемой области
//--- Если переданные ширина и высота равны нулю - присваиваем им значения ширины и высоты формы
   this.m_wr=int(width==0  ? this.m_element.Width()  : width);
   this.m_hr=int(height==0 ? this.m_element.Height() : height);

//--- Если координаты X и Y равны нулю (это верхний левый угол формы) и ширина и высота равны ширине и высоте формы,
//--- Значит копируемая область равна всей площади формы - копируем (с возвратом из метода) всю форму целиком при помощи метода ImageCopy()
   //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);

//--- Рассчитываем правую координату X и нижнюю координату Y прямоугольной области
   int x2=int(x1+this.m_wr-1);
   int y2=int(y1+this.m_hr-1);
//--- Если рассчитанная координата X выхоит за пределы формы, то этой координатой будет правый край формы
   if(x2>=this.m_element.Width()-1)
      x2=this.m_element.Width()-1;
//--- Если рассчитанная координата Y выхоит за пределы формы, то этой координатой будет нижний край формы
   if(y2>=this.m_element.Height()-1)
      y2=this.m_element.Height()-1;
//--- Рассчитываем копируемые ширину и высоту
   this.m_wr=x2-x1+1;
   this.m_hr=y2-y1+1;
//--- Определяем необходимый размер массива, в который должны поместиться все пиксели изображения с рассчитанными шириной и высотой
   int size=this.m_wr*this.m_hr;
//--- Если размер массива установить не удалось - сообщаем об этом и возвращаем false
   if(::ArrayResize(this.m_array,size)!=size)
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE,true);
      return false;
     }
//--- Устанавливаем индекс в массиве для записи пикселя изображения
   int n=0;
//--- В цикле по рассчитанной высоте копируемой области, начиная от указанной координаты Y
   for(int y=y1;y<y1+this.m_hr;y++)
     {
      //--- в цикле по рассчитанной ширине копируемой области, начиная от указанной координаты X
      for(int x=x1;x<x1+this.m_wr;x++)
        {
         //--- Копируем очередной пиксель изображения в массив и увеличиваем индекс массива
         this.m_array[n]=this.m_element.GetCanvasObj().PixelGet(x,y);
         n++;
        }
     }
//--- Успешно - возвращаем true
   return true;
  }
//+------------------------------------------------------------------+
//| Копирует часть или всё изображение из массива на канвас          |
//+------------------------------------------------------------------+
bool CPixelCopier::CopyImgDataToCanvas(const int x_coord,const int y_coord)
  {
//--- Если массив сохранённых пикселей пустой - сообщаем об этом и возвращаем false
   int size=::ArraySize(this.m_array);
   if(size==0)
     {
      CMessage::ToLog(DFUN,MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY,true);
      return false;
     }
//--- Устанавливаем индекс массива для чтения пикселя изображения
   int n=0;
//--- В цикле по ранее рассчитанной высоте скопированной области, начиная от указанной координаты Y
   for(int y=y_coord;y<y_coord+this.m_hr;y++)
     {
      //--- в цикле по ранее рассчитанной ширине скопированной области, начиная от указанной координаты X
      for(int x=x_coord;x<x_coord+this.m_wr;x++)
        {
         //--- Восстанавливаем очередной пиксель изображения из массива и увеличиваем индекс массива
         this.m_element.GetCanvasObj().PixelSet(x,y,this.m_array[n]);
         n++;
        }
     }
   return true;
  }
//+------------------------------------------------------------------+

Единственное, что здесь (временно) изменено, это то, что мы закомментировали строки кода, которые должны копировать полностью весь ранее сохранённый рисунок формы. Здесь была допущена ошибка, и копировался фон не из массива объекта-формы, а прямо из графического ресурса, а там содержатся как раз все изменения, производимые с изображением фона формы. Для исправления ошибки нам необходимо будет после окночательного создания внешнего вида формы, сохранять его в специально-созданный для этого массив, в котором будет храниться копия оригинального изображения формы. Массив такой у нас есть, но пока ещё не созданы методы для сохранения изначального внешнего вида формы сразу после её создания. Для этого необходимо будет продумать и написать такие методы. Поэтому, пока таких методов у нас нет, мы закомментировали эти строки, и восстановление фона, имеющего размеры всей формы (а не её части), будет производиться в цикле восстановления части фона формы (т.е., не копированием одного массива в другой, а поэлементым заполнением фона формы из массива, в котором хранится сохранённая копия части изображения фона формы).

Далее — после листинга класса-копировщика пикселей, напишем тело класса объекта-кадра анимации:

//+------------------------------------------------------------------+
//| Класс одного кадра анимации                                      |
//+------------------------------------------------------------------+
class CFrame : public CPixelCopier
  {
protected:
   ENUM_ANIMATION_FRAME_TYPE m_frame_figure_type;           // Тип фигуры, рисуемой кадром
   ENUM_TEXT_ANCHOR  m_anchor_last;                         // Точка привязки последнего кадра
   double            m_x_last;                              // Координата X верхнего левого угла последнего кадра
   double            m_y_last;                              // Координата Y верхнего левого угла последнего кадра
   int               m_shift_x_prev;                        // Смещение координаты X верхнего левого угла последнего кадра
   int               m_shift_y_prev;                        // Смещение координаты Y верхнего левого угла последнего кадра
public:
//--- Возвращает последнюю (1) точку привязки, координату (2) X, (3) Y,
//--- предыдущее смещение по (4) X и (5) Y, (6) тип фигуры, рисуемой кадром
   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;  }
   
//--- Конструктор по умолчанию
                     CFrame();
protected:
//--- Конструктор текстового кадра
                     CFrame(const int id,
                            const int x,
                            const int y,
                            const string text,
                            CGCnvElement *element);
//--- Конструктор прямоугольного кадра
                     CFrame(const int id,
                            const int x,
                            const int y,
                            const int w,
                            const int h,
                            CGCnvElement *element);
  };
//+------------------------------------------------------------------+

Класс унаследован от класса объекта-копировщика пикселей, т.е., по сути — является им.

Все переменные и методы, объявленные в классе, описаны в комментариях. Так как этот класс будет базовым для других классов-кадров анимации, то здесь прописаны только все общие для наследников свойства и методы.

Переменные и методы, возвращающие последние координаты, смещения и точки привязки нужны для того, чтобы при восстановлении ранее сохранённой части изображения фона формы мы могли знать, в каких координатах находилась прошлая сохранённая часть изображения, — чтобы в эти же координаты с этими же смещениями относительно точки привязки разместить сохранённый фон, который был затёрт нарисованным поверх него изображением.

Класс имеет три конструктора:

  1. публичный конструктор по умолчанию,
  2. защищённый конструктор объекта-текстового кадра,
  3. защищённый конструктор объекта-прямоугольного кадра.

Рассмотрим реализацию защищённых конструкторов.

Конструктор прямоугольных кадров:

//+------------------------------------------------------------------+
//| Конструктор прямоугольных кадров                                 |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

В конструктор передаются: идентификатор создаваемого объекта-прямоугольного кадра, его координаты X и Y, ширина и высота кадра, а также в конструктор передаётся указатель на объект-графический элемент, из которого создаётся этот новый объект. Так как класс является наследником объекта-копировщика пикселей, то в списке инициализации конструктора передаём все необходимые параметры в конструктор базового класса, а ими как раз являются все свойства, передаваемые в аргументах конструктора.
В теле класса всем переменным-членам класса задаём параметры по умолчанию.

Конструктор текстовых кадров:

//+------------------------------------------------------------------+
//| Конструктор текстовых кадров                                     |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+

В конструктор передаются: идентификатор создаваемого объекта-текстового кадра, его координаты X и Y, текст и указатель на объект-графический элемент, из которого создаётся этот новый объект.
В теле класса сначала определяем размеры текста, затем устанавливаем значения по умолчанию переменным-членам класса и устанавливаем в родительский объект-копировщих пикселей идентификатор создаваемого объекта, его координаты и размер текста.

Создадим классы объектов-наследников класса объекта-кадра анимации.

Класс текстового кадра анимации

В папке \MQL5\Include\DoEasy\Objects\Graph\Animations\ создадим новый файл FrameText.mqh класса CFrameText.

К файлу должен быть подключен файл класса кадра анимации, а сам класс должен быть его наследником:

//+------------------------------------------------------------------+
//|                                                    FrameText.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "Frame.mqh"
//+------------------------------------------------------------------+
//| Класс одного кадра текстовой анимации                            |
//+------------------------------------------------------------------+
class CFrameText : public CFrame
  {
private:

public:
//--- Выводит текст на фон с сохранением и восстановлением фона
   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);

//--- Конструкторы
                     CFrameText() {;}
                     CFrameText(const int id,CGCnvElement *element) : CFrame(id,0,0,"",element) {}
  };
//+------------------------------------------------------------------+

Здесь мы видим один публичный метод для рисования текста на фоне объекта-формы и два конструктора — по умолчанию и параметрический.

В параметрический конструктор передаём идентификатор создаваемого объекта-кадра текстовой анимации и указатель на объект-графический элемент, из которого создаётся этот объект. В списке инициализации в родительский класс передаём идентификатор, переданный в аргументах конструктора, значения по умолчанию для координат и текста и указатель на графический элемент, тоже переданный в аргументах конструктора.

Метод, выводящий текст на фон с сохранением и восстановлением фона:

//+------------------------------------------------------------------+
//| Выводит текст на фон с сохранением и восстановлением фона        |
//+------------------------------------------------------------------+
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)
  {
//--- Узнаем ширину и высоту очерчивающего прямоугольника текста (это и будет размером сохраняемой области)
   int w=0,h=0;
   this.m_element.TextSize(text,w,h);
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки текста
   int shift_x=0,shift_y=0;
   this.m_element.GetShiftXYbySize(w,h,anchor,shift_x,shift_y);
//--- Если массив пикселей не пустой - значит уже сохраняли фон под текстом -
//--- восстановим фон, который ранее был сохранён (по прошлым координатам и смещениям)
   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(!CPixelCopier::CopyImgDataToArray(x+shift_x,y+shift_y,w,h))
      return false;
//--- Нарисуем текст и обновим элемент
   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;
  }
//+------------------------------------------------------------------+

Логика метода подробно расписана в комментариях к коду, ранее нами уже рассматривалась в прошлой статье при тестировании (аналогичная логика была прописана в обработчике OnChartEvent() тестового советника) и, надеюсь, здесь вопросов не возникнет. После того, как текст на форме нарисован, его точка привязки, координаты X и Y и размеры смещения относительно точки привязки записываются в переменные родительского класса — их значения будут использоваться для восстановления затёртого текстом фона изображения формы.

Теперь создадим второй класс-наследник объекта-кадра анимации.

Класс прямоугольного кадра анимации

В папке \MQL5\Include\DoEasy\Objects\Graph\Animations\ создадим новый файл FrameQuad.mqh класса CFrameQuad.

К файлу класса должен быть подключен файл родительского класса, и от него же он должен быть унаследован:

//+------------------------------------------------------------------+
//|                                                    FrameQuad.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "Frame.mqh"
//+------------------------------------------------------------------+
//| Класс одного кадра спрайтовой анимации                           |
//+------------------------------------------------------------------+
class CFrameQuad : public CFrame
  {
private:
   double            m_quad_x;                                 // X-координата охватывающего фигуру прямоугольника
   double            m_quad_y;                                 // Y-координата охватывающего фигуру прямоугольника
   uint              m_quad_width;                             // Ширина охватывающего фигуру прямоугольника
   uint              m_quad_height;                            // Высота охватывающего фигуру прямоугольника
   
public:

//--- Конструкторы
                     CFrameQuad() {;}
                     CFrameQuad(const int id,CGCnvElement *element) : CFrame(id,0,0,0,0,element) { this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;   }

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

В приватной секции класса объявим переменные-члены класса, в которых будем хранить координаты и размеры охватывающего нарисованную фигуру прямоугольника, — это как раз координаты и размер сохраняемой области рисунка части фона, затираемой рисуемой фигурой.

В параметрическом конструкторе передаются идентификатор создаваемого объекта и указатель на графический элемент, из которого создаётся этот объект. В списке инициализации конструктора в конструктор ролительского класса передаётся идентификатор, переданный в аргументах метода, параметры по умолчанию координат и размеров кадра и указатель на графический элемент. В теле конструктора устанавливаем точку привязки рисуемой фигуры как "сверху-слева" — это необходимо будет для расчёта смещения копируемой области. При таком значении точки привязки смещения координат по X и Y будут нулевыми.

Так как методов рисования в классе CCanvas достаточно много, то у нас в этом классе, в его публичной секции будут объявлены все соответствующие методы для рисования фигур на фоне объекта-формы с последующим восстановлением фона:

public:

//--- Конструкторы
                     CFrameQuad() {;}
                     CFrameQuad(const int id,CGCnvElement *element) : CFrame(id,0,0,0,0,element) { this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP;   }

//+------------------------------------------------------------------+
//| Рисование примитивов с сохранением и восстановлением фона        |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы рисования примитивов без сглаживания                      |
//+------------------------------------------------------------------+
//--- Устанавливает цвет точки с указанными координатами
   bool              SetPixelOnBG(const int x,const int y,const color clr,const uchar opacity=255,const bool redraw=false);
                       
//--- Рисует отрезок вертикальной линии
   bool              DrawLineVerticalOnBG(const int x,                  // Координата X отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует отрезок горизонтальной линии
   bool              DrawLineHorizontalOnBG(const int x1,               // Координата X первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y,                            // Координата Y отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует отрезок произвольной линии
   bool              DrawLineOnBG(const int x1,                         // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует ломаную линию
   bool              DrawPolylineOnBG(int &array_x[],                   // Массив координат X точек ломаной линии
                              int         &array_y[],                   // Массив координат Y точек ломаной линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует многоугольник
   bool              DrawPolygonOnBG(int  &array_x[],                   // Массив координат X точек многоугольника
                              int         &array_y[],                   // Массив координат Y точек многоугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует прямоугольник по двум точкам
   bool              DrawRectangleOnBG(const int x1,                    // Координата X первой точки, определяющей прямоугольник
                              const int   y1,                           // Координата Y первой точки, определяющей прямоугольник
                              const int   x2,                           // Координата X второй точки, определяющей прямоугольник
                              const int   y2,                           // Координата Y второй точки, определяющей прямоугольник
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует окружность
   bool              DrawCircleOnBG(const int x,                        // Координата X центра окружности
                              const int   y,                            // Координата Y центра окружности
                              const int   r,                            // Радиус окружности
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует треугольник
   bool              DrawTriangleOnBG(const int x1,                     // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата Y третьей вершины треугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует эллипс по двум точкам
   bool              DrawEllipseOnBG(const int x1,                      // Координата X первой точки, определяющей эллипс
                              const int   y1,                           // Координата Y первой точки, определяющей эллипс
                              const int   x2,                           // Координата X второй точки, определяющей эллипс
                              const int   y2,                           // Координата Y второй точки, определяющей эллипс
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует дугу эллипса, вписанного в прямоугольник с углами в (x1,y1) и (x2,y2).
//--- Границы дуги отсекаются линиями из центра эллипса, идущими к двум точкам с координатами (x3,y3) и (x4,y4)
   bool              DrawArcOnBG(const int x1,                          // Координата X левого верхнего угла, определяющего прямоугольник
                              const int   y1,                           // Координата Y левого верхнего угла, определяющего прямоугольник
                              const int   x2,                           // Координата X правого нижнего угла, определяющего прямоугольник
                              const int   y2,                           // Координата Y правого нижнего угла, определяющего прямоугольник
                              const int   x3,                           // Координата X первой точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                              const int   y3,                           // Координата Y первой точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                              const int   x4,                           // Координата X второй точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                              const int   y4,                           // Координата Y второй точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует закрашенный сектор эллипса, вписанного в прямоугольник с углами в (x1,y1) и (x2,y2).
//--- Границы сектора отсекаются линиями из центра эллипса, идущими к двум точкам с координатами (x3,y3) и (x4,y4)
   bool              DrawPieOnBG(const int x1,                          // координата X верхнего левого угла прямоугольника
                              const int   y1,                           // координата Y верхнего левого угла прямоугольника
                              const int   x2,                           // координата X нижнего правого угла прямоугольника
                              const int   y2,                           // координата Y нижнего правого угла прямоугольника
                              const int   x3,                           // координата X первой точки для нахождения границы дуги
                              const int   y3,                           // координата Y первой точки для нахождения границы дуги
                              const int   x4,                           // координата X второй точки для нахождения границы дуги
                              const int   y4,                           // координата Y второй точки для нахождения границы дуги
                              const color clr,                          // Цвет линии
                              const color fill_clr,                     // Цвет заливки
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//+------------------------------------------------------------------+
//| Методы рисования закрашенных примитивов без сглаживания          |
//+------------------------------------------------------------------+
//--- Закрашивает область
   bool              FillOnBG(const int   x,                            // Координата X точки начала закрашивания
                              const int   y,                            // Координата Y точки начала закрашивания
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const uint  threshould=0,                 // Порог
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует закрашенный прямоугольник
   bool              DrawRectangleFillOnBG(const int x1,                // Координата X первой точки, определяющей прямоугольник
                              const int   y1,                           // Координата Y первой точки, определяющей прямоугольник
                              const int   x2,                           // Координата X второй точки, определяющей прямоугольник
                              const int   y2,                           // Координата Y второй точки, определяющей прямоугольник
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта

//--- Рисует закрашенный круг
   bool              DrawCircleFillOnBG(const int x,                    // Координата X центра круга
                              const int   y,                            // Координата Y центра круга
                              const int   r,                            // Радиус круга
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует закрашенный треугольник
   bool              DrawTriangleFillOnBG(const int x1,                 // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата Y третьей вершины треугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует закрашенный многоугольник
   bool              DrawPolygonFillOnBG(int &array_x[],                // Массив, содержащий координаты X точек многоугольника
                              int         &array_y[],                   // Массив, содержащий координаты Y точек многоугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует закрашенный эллипс, вписанный в прямоугольник с заданными координатами
   bool              DrawEllipseFillOnBG(const int x1,                  // Координата X левого верхнего угла, определяющего прямоугольник
                              const int   y1,                           // Координата Y левого верхнего угла, определяющего прямоугольник
                              const int   x2,                           // Координата X правого нижнего угла, определяющего прямоугольник
                              const int   y2,                           // Координата Y правого нижнего угла, определяющего прямоугольник
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//+------------------------------------------------------------------+
//| Методы рисования примитивов с использованием сглаживания         |
//+------------------------------------------------------------------+
//--- Рисует точку с использованием алгоритма сглаживания AntiAliasing
   bool              SetPixelAAOnBG(const double x,                     // Координата X точки
                              const double y,                           // Координата Y точки
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const bool   redraw=false);               // Флаг перерисовки чарта
                       
//--- Рисует отрезок произвольной линии с использованием алгоритма сглаживания AntiAliasing
   bool              DrawLineAAOnBG(const int x1,                       // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует отрезок произвольной линии с использованием алгоритма сглаживания Wu
   bool              DrawLineWuOnBG(const int x1,                       // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией
   bool              DrawLineThickOnBG(const int x1,                    // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const int   size,                         // Толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              ENUM_LINE_END end_style=LINE_END_ROUND);  // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
 
//--- Рисует вертикальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией
   bool              DrawLineThickVerticalOnBG(const int x,             // Координата X отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const int   size,                         // толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END end_style=LINE_END_ROUND); // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       
//--- Рисует горизонтальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией
   bool              DrawLineThickHorizontalOnBG(const int x1,          // Координата X первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y,                            // Координата Y отрезка
                              const int   size,                         // толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END end_style=LINE_END_ROUND); // Стиль концов линии — одно из значений перечисления ENUM_LINE_END

//--- Рисует ломаную линию с использованием алгоритма сглаживания AntiAliasing
   bool              DrawPolylineAAOnBG(int &array_x[],                 // Массив координат X точек ломаной линии
                              int         &array_y[],                   // Массив координат Y точек ломаной линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует ломаную линию с использованием алгоритма сглаживания Wu
   bool              DrawPolylineWuOnBG(int &array_x[],                 // Массив координат X точек ломаной линии
                              int         &array_y[],                   // Массив координат Y точек ломаной линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует ломаную линию заданной толщины с использованием двух алгоритмов сглаживания последовательно.
//--- Сначала на основе кривых Безье сглаживаются отдельные отрезки линии.
//--- Затем для повышения качества отрисовки к построенной из этих отрезков ломаной линии применяется растровый алгоритм сглаживания
   bool              DrawPolylineSmoothOnBG(const int &array_x[],       // Массив координат X точек ломаной линии
                              const int    &array_y[],                  // Массив координат Y точек ломаной линии
                              const int    size,                        // Толщина линии
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const double tension=0.5,                 // Значение параметра сглаживания
                              const double step=10,                     // Шаг аппроксимации
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END   end_style=LINE_END_ROUND);// Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       
//--- Рисует ломаную линию заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией
   bool              DrawPolylineThickOnBG(const int &array_x[],        // Массив координат X точек ломаной линии
                              const int      &array_y[],                // Массив координат Y точек ломаной линии
                              const int      size,                      // Толщина линии
                              const color    clr,                       // Цвет
                              const uchar    opacity=255,               // Непрозрачность
                              const bool     redraw=false,              // Флаг перерисовки чарта
                              const uint     style=STYLE_SOLID,         // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              ENUM_LINE_END  end_style=LINE_END_ROUND); // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       
//--- Рисует многоугольник с использованием алгоритма сглаживания AntiAliasing
   bool              DrawPolygonAAOnBG(int &array_x[],                  // Массив координат X точек многоугольника
                              int         &array_y[],                   // Массив координат Y точек многоугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует многоугольник с использованием алгоритма сглаживания Wu
   bool              DrawPolygonWuOnBG(int &array_x[],                  // Массив координат X точек многоугольника
                              int         &array_y[],                   // Массив координат Y точек многоугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует  многоугольник заданной толщины с использованием двух алгоритмов сглаживания последовательно.
//--- Сначала на основе кривых Безье сглаживаются отдельные отрезки.
//--- Затем для повышения качества отрисовки к построенному из этих отрезков многоугольнику применяется растровый алгоритм сглаживания. 
   bool              DrawPolygonSmoothOnBG(int &array_x[],              // Массив координат X точек ломаной линии
                              int          &array_y[],                  // Массив координат Y точек ломаной линии
                              const int    size,                        // Толщина линии
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const double tension=0.5,                 // Значение параметра сглаживания
                              const double step=10,                     // Шаг аппроксимации
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END   end_style=LINE_END_ROUND);// Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       
//--- Рисует многоугольник заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией
   bool              DrawPolygonThickOnBG(const int &array_x[],         // массив координат X точек многоугольника
                              const int   &array_y[],                   // массив координат Y точек многоугольника
                              const int   size,                         // толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // стиль линии
                              ENUM_LINE_END end_style=LINE_END_ROUND);  // стиль концов линии
                       
//--- Рисует треугольник с использованием алгоритма сглаживания AntiAliasing
   bool              DrawTriangleAAOnBG(const int x1,                   // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата Y третьей вершины треугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует треугольник с использованием алгоритма сглаживания Wu
   bool              DrawTriangleWuOnBG(const int x1,                   // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата Y третьей вершины треугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует окружность с использованием алгоритма сглаживания AntiAliasing
   bool              DrawCircleAAOnBG(const int x,                      // Координата X центра окружности
                              const int    y,                           // Координата Y центра окружности
                              const double r,                           // Радиус окружности
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const uint   style=UINT_MAX);             // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует окружность с использованием алгоритма сглаживания Wu
   bool              DrawCircleWuOnBG(const int x,                      // Координата X центра окружности
                              const int    y,                           // Координата Y центра окружности
                              const double r,                           // Радиус окружности
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const uint   style=UINT_MAX);             // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует эллипс по двум точкам с использованием алгоритма сглаживания AntiAliasing
   bool              DrawEllipseAAOnBG(const double x1,                 // Координата X первой точки, определяющей эллипс
                              const double y1,                          // Координата Y первой точки, определяющей эллипс
                              const double x2,                          // Координата X второй точки, определяющей эллипс
                              const double y2,                          // Координата Y второй точки, определяющей эллипс
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const uint   style=UINT_MAX);             // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует эллипс по двум точкам с использованием алгоритма сглаживания Wu
   bool              DrawEllipseWuOnBG(const int x1,                    // Координата X первой точки, определяющей эллипс
                              const int   y1,                           // Координата Y первой точки, определяющей эллипс
                              const int   x2,                           // Координата X второй точки, определяющей эллипс
                              const int   y2,                           // Координата Y второй точки, определяющей эллипс
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  };
//+------------------------------------------------------------------+

Реализация всех этих методов, каждого по отдельности, будет похожа на реализацию других таких же методов рисования, но практически каждый из них будет иметь свои нюансы, присущие его методу рисования (размеры сохраняемой области могут отличаться в двух похожих методах рисования из-за особенностей каждого отдельного метода рисования).

Рассмотрим реализацию этих методов.

Метод, устанавливающий цвет точки с указанными координатами:

//+------------------------------------------------------------------+
//| Устанавливает цвет точки с указанными координатами               |
//+------------------------------------------------------------------+
bool CFrameQuad::SetPixelOnBG(const int x,const int y,const color clr,const uchar opacity=255,const bool redraw=false)
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=x;
   this.m_quad_y=y;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=1;
   this.m_quad_height=1;
   
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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.

Далее мы сначала проверяем, был ли ранее сохранён фон (по ненулевому размеру массива, в который этот фон сохраняется), и если фон ранее сохранялся, то сначала восстанавливаем ранее сохранённый фон объекта-формы (при этом координаты и размер восстанавливаемой области уже записаны в переменные класса). После успешного восстановления ранее сохранённого фона, сохраняем фон формы в новых координатах, в которых будет нарисована точка, и рисуем её. После чего сохраняем в переменных класса новые координаты, размеры сохраняемой области и смещения — для последующего восстановления фона, затёртого только что нарисованной точкой.

Метод, рисующий отрезок вертикальной линии:

//+------------------------------------------------------------------+
//| Рисует отрезок вертикальной линии                                |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineVerticalOnBG(const int   x,              // Координата X отрезка
                                      const int   y1,             // Координата Y первой точки отрезка
                                      const int   y2,             // Координата Y второй точки отрезка
                                      const color clr,            // Цвет
                                      const uchar opacity=255,    // Непрозрачность
                                      const bool  redraw=false)   // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=x;
   this.m_quad_y=::fmin(y1,y2);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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-координат (самая верхняя точка рисуемой линии).

Метод, рисующий отрезок горизонтальной линии:

//+------------------------------------------------------------------+
//| Рисует отрезок горизонтальной линии                              |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineHorizontalOnBG(const int   x1,           // Координата X первой точки отрезка
                                        const int   x2,           // Координата X второй точки отрезка
                                        const int   y,            // Координата Y отрезка
                                        const color clr,          // Цвет
                                        const uchar opacity=255,  // Непрозрачность
                                        const bool  redraw=false) // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=y;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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 сохраняемой области должны быть рассчитаны.

Метод, рисующий отрезок произвольной линии:

//+------------------------------------------------------------------+
//| Рисует отрезок произвольной линии                                |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineOnBG(const int   x1,            // Координата X первой точки отрезка
                              const int   y1,            // Координата Y первой точки отрезка
                              const int   x2,            // Координата X второй точки отрезка
                              const int   y2,            // Координата Y второй точки отрезка
                              const color clr,           // Цвет
                              const uchar opacity=255,   // Непрозрачность
                              const bool  redraw=false)  // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+

Здесь уже координаты и размер сохраняемой области рассчитываются от координат рисуемой линии.

Метод, рисующий ломаную линию:

//+------------------------------------------------------------------+
//| Рисует ломаную линию                                             |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolylineOnBG(int         &array_x[],   // Массив координат X точек ломаной линии
                                  int         &array_y[],   // Массив координат Y точек ломаной линии
                                  const color clr,          // Цвет
                                  const uchar opacity=255,  // Непрозрачность
                                  const bool  redraw=false) // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   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;

//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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 каждой точки излома линии.
В методе же мы получаем максимальные и минимальные значения из этих массивов при помощи ранее рассмотренной функции, возвращающей из переданного в неё массива минимальное или максимальное значение, записанное в массиве. И полученные значения используем для расчёта координат и размеров сохраняемой области фона формы.

Остальные методы рисования фигур без сглаживания (просто обратите внимание на расчёты координат и размеров сохраняемой области):

//+------------------------------------------------------------------+
//| Рисует многоугольник                                             |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonOnBG(int         &array_x[],    // Массив координат X точек многоугольника
                                 int         &array_y[],    // Массив координат Y точек многоугольника
                                 const color clr,           // Цвет
                                 const uchar opacity=255,   // Непрозрачность
                                 const bool  redraw=false)  // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   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;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует прямоугольник по двум точкам                              |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawRectangleOnBG(const int   x1,             // Координата X первой точки, определяющей прямоугольник
                                   const int   y1,             // Координата Y первой точки, определяющей прямоугольник
                                   const int   x2,             // Координата X второй точки, определяющей прямоугольник
                                   const int   y2,             // Координата Y второй точки, определяющей прямоугольник
                                   const color clr,            // Цвет
                                   const uchar opacity=255,    // Непрозрачность
                                   const bool  redraw=false)   // Флаг перерисовки чарта
     {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует окружность                                                |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawCircleOnBG(const int   x,              // Координата X центра окружности
                                const int   y,              // Координата Y центра окружности
                                const int   r,              // Радиус окружности
                                const color clr,            // Цвет
                                const uchar opacity=255,    // Непрозрачность
                                const bool  redraw=false)   // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1);
   this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1);
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует треугольник                                               |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawTriangleOnBG(const int   x1,           // Координата X первой вершины треугольника
                                  const int   y1,           // Координата Y первой вершины треугольника
                                  const int   x2,           // Координата X второй вершины треугольника
                                  const int   y2,           // Координата Y второй вершины треугольника
                                  const int   x3,           // Координата X третьей вершины треугольника
                                  const int   y3,           // Координата Y третьей вершины треугольника
                                  const color clr,          // Цвет
                                  const uchar opacity=255,  // Непрозрачность
                                  const bool  redraw=false) // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   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);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=int(max_x-this.m_quad_x)+1;
   this.m_quad_height=int(max_y-this.m_quad_y)+1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует эллипс по двум точкам                                     |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawEllipseOnBG(const int   x1,            // Координата X первой точки, определяющей эллипс
                                 const int   y1,            // Координата Y первой точки, определяющей эллипс
                                 const int   x2,            // Координата X второй точки, определяющей эллипс
                                 const int   y2,            // Координата Y второй точки, определяющей эллипс
                                 const color clr,           // Цвет
                                 const uchar opacity=255,   // Непрозрачность
                                 const bool  redraw=false)  // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует дугу эллипса, вписанного в прямоугольник                  |
//| с углами в (x1,y1) и (x2,y2).                                    |
//| Границы дуги отсекаются линиями из центра эллипса,               |
//| идущими к двум точкам с координатами (x3,y3) и (x4,y4)           |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawArcOnBG(const int   x1,             // Координата X левого верхнего угла, определяющего прямоугольник
                             const int   y1,             // Координата Y левого верхнего угла, определяющего прямоугольник
                             const int   x2,             // Координата X правого нижнего угла, определяющего прямоугольник
                             const int   y2,             // Координата Y правого нижнего угла, определяющего прямоугольник
                             const int   x3,             // Координата X первой точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                             const int   y3,             // Координата Y первой точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                             const int   x4,             // Координата X второй точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                             const int   y4,             // Координата Y второй точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                             const color clr,            // Цвет
                             const uchar opacity=255,    // Непрозрачность
                             const bool  redraw=false)   // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2)-1;
   this.m_quad_y=::fmin(y1,y2)-1;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+2;
   this.m_quad_height=::fabs(y2-y1)+2;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный сектор эллипса, вписанного в прямоугольник    |
//| с углами в (x1,y1) и (x2,y2).                                    |
//| Границы сектора отсекаются линиями из центра эллипса,            |
//| идущими к двум точкам с координатами (x3,y3) и (x4,y4)           |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPieOnBG(const int   x1,             // координата X верхнего левого угла прямоугольника
                             const int   y1,             // координата Y верхнего левого угла прямоугольника
                             const int   x2,             // координата X нижнего правого угла прямоугольника
                             const int   y2,             // координата Y нижнего правого угла прямоугольника
                             const int   x3,             // координата X первой точки для нахождения границы дуги
                             const int   y3,             // координата Y первой точки для нахождения границы дуги
                             const int   x4,             // координата X второй точки для нахождения границы дуги
                             const int   y4,             // координата Y второй точки для нахождения границы дуги
                             const color clr,            // Цвет
                             const color fill_clr,       // Цвет заливки
                             const uchar opacity=255,    // Непрозрачность
                             const bool  redraw=false)   // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2)-1;
   this.m_quad_y=::fmin(y1,y2)-1;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+2;
   this.m_quad_height=::fabs(y2-y1)+2;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+


Рассмотрим методы рисования закрашенных примитивов без сглаживания.

Метод, закрашивающий область:

//+------------------------------------------------------------------+
//| Закрашивает область                                              |
//+------------------------------------------------------------------+
bool CFrameQuad::FillOnBG(const int   x,              // Координата X точки начала закрашивания
                          const int   y,              // Координата Y точки начала закрашивания
                          const color clr,            // Цвет
                          const uchar opacity=255,    // Непрозрачность
                          const uint  threshould=0,   // Порог
                          const bool  redraw=false)   // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=0;
   this.m_quad_y=0;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=0;
   this.m_quad_height=0;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+

Так как метод закрашивает произвольную замкнутую область, то размеры сохраняемой области заранее не узнать. Поэтому здесь должна быть сохранена вся форма. Для этого устанавливаем координаты и размеры в ноль. При таких значениях метод, сохраняющий прямоугольную область изображения, сохраняет в массив всё изображение фона формы.

Остальные методы рисования закрашенных примитивов — их расчёт координат и размеров сохраняемой области, совпадает с расчётом в аналогичных методах рисования простых несглаженных примитивов, рассмотренных нами выше. Просто посмотрим методы как есть:

//+------------------------------------------------------------------+
//| Рисует закрашенный прямоугольник                                 |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawRectangleFillOnBG(const int   x1,            // Координата X первой точки, определяющей прямоугольник
                                       const int   y1,            // Координата Y первой точки, определяющей прямоугольник
                                       const int   x2,            // Координата X второй точки, определяющей прямоугольник
                                       const int   y2,            // Координата Y второй точки, определяющей прямоугольник
                                       const color clr,           // Цвет
                                       const uchar opacity=255,   // Непрозрачность
                                       const bool  redraw=false)  // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный круг                                          |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawCircleFillOnBG(const int   x,             // Координата X центра круга
                                    const int   y,             // Координата Y центра круга
                                    const int   r,             // Радиус круга
                                    const color clr,           // Цвет
                                    const uchar opacity=255,   // Непрозрачность
                                    const bool  redraw=false)  // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1);
   this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1);
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный треугольник                                   |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawTriangleFillOnBG(const int   x1,             // Координата X первой вершины треугольника
                                      const int   y1,             // Координата Y первой вершины треугольника
                                      const int   x2,             // Координата X второй вершины треугольника
                                      const int   y2,             // Координата Y второй вершины треугольника
                                      const int   x3,             // Координата X третьей вершины треугольника
                                      const int   y3,             // Координата Y третьей вершины треугольника
                                      const color clr,            // Цвет
                                      const uchar opacity=255,    // Непрозрачность
                                      const bool  redraw=false)   // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=int(max_x-this.m_quad_x)+1;
   this.m_quad_height=int(max_y-this.m_quad_y)+1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный многоугольник                                 |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonFillOnBG(int         &array_x[],   // Массив, содержащий координаты X точек многоугольника
                                     int         &array_y[],   // Массив, содержащий координаты Y точек многоугольника
                                     const color clr,          // Цвет
                                     const uchar opacity=255,  // Непрозрачность
                                     const bool  redraw=false) // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   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;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный эллипс, вписанный в прямоугольник             |
//| с заданными координатами                                         |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawEllipseFillOnBG(const int   x1,           // Координата X левого верхнего угла, определяющего прямоугольник
                                     const int   y1,           // Координата Y левого верхнего угла, определяющего прямоугольник
                                     const int   x2,           // Координата X правого нижнего угла, определяющего прямоугольник
                                     const int   y2,           // Координата Y правого нижнего угла, определяющего прямоугольник
                                     const color clr,          // Цвет
                                     const uchar opacity=255,  // Непрозрачность
                                     const bool  redraw=false) // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+


Методы рисования примитивов со сглаживанием.

Метод, рисующий точку с использованием алгоритма сглаживания AntiAliasing:

//+------------------------------------------------------------------+
//| Рисует точку с использованием алгоритма сглаживания AntiAliasing |
//+------------------------------------------------------------------+
bool CFrameQuad::SetPixelAAOnBG(const double x,             // Координата X точки
                                const double y,             // Координата Y точки
                                const color  clr,           // Цвет
                                const uchar  opacity=255,   // Непрозрачность
                                const bool   redraw=false)  // Флаг перерисовки чарта
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=3;
   this.m_quad_height=3;
   
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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 пикселя), поэтому и размеры сохраняемой области должны иметь по три пикселя в высоту и ширину. Координаты X и Y, соответственно, должны быть на один пиксель левее и выше координат самой точки. Таким образом, очерчивающий точку прямоугольник сохраняемой области будет иметь запас в один пиксель со всех сторон от рисуемой точки для случая, если нарисованная точка будет размыта алгоритмом сглаживания и нарисована не на одном пикселе. Тем самым мы избавимся от неполного восстановления фона, затёртого нарисованной точкой со сглаживанием.

Метод, рисующий отрезок произвольной линии с использованием алгоритма сглаживания AntiAliasing:

//+------------------------------------------------------------------+
//| Рисует отрезок произвольной линии                                |
//| с использованием алгоритма сглаживания AntiAliasing              |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineAAOnBG(const int   x1,             // Координата X первой точки отрезка
                                const int   y1,             // Координата Y первой точки отрезка
                                const int   x2,             // Координата X второй точки отрезка
                                const int   y2,             // Координата Y второй точки отрезка
                                const color clr,            // Цвет
                                const uchar opacity=255,    // Непрозрачность
                                const bool  redraw=false,   // Флаг перерисовки чарта
                                const uint  style=UINT_MAX) // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;

//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;

//--- Нарисуем фигуру и обновим элемент
   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:

//+------------------------------------------------------------------+
//| Рисует отрезок произвольной линии с использованием               |
//| алгоритма сглаживания Wu                                         |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineWuOnBG(const int   x1,             // Координата X первой точки отрезка
                                const int   y1,             // Координата Y первой точки отрезка
                                const int   x2,             // Координата X второй точки отрезка
                                const int   y2,             // Координата Y второй точки отрезка
                                const color clr,            // Цвет
                                const uchar opacity=255,    // Непрозрачность
                                const bool  redraw=false,   // Флаг перерисовки чарта
                                const uint  style=UINT_MAX) // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+1;
   this.m_quad_height=::fabs(y2-y1)+1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+

Здесь расчёт аналогичен предыдущему методу по той же причине.

Метод, рисующий отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией:

//+------------------------------------------------------------------+
//| Рисует отрезок произвольной линии заданной толщины               |
//| с использованием алгоритма сглаживания                           |
//| с предварительной фильтрацией                                    |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineThickOnBG(const int   x1,                         // Координата X первой точки отрезка
                                   const int   y1,                         // Координата Y первой точки отрезка
                                   const int   x2,                         // Координата X второй точки отрезка
                                   const int   y2,                         // Координата Y второй точки отрезка
                                   const int   size,                       // Толщина линии
                                   const color clr,                        // Цвет
                                   const uchar opacity=255,                // Непрозрачность
                                   const bool  redraw=false,               // Флаг перерисовки чарта
                                   const uint  style=STYLE_SOLID,          // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                                   ENUM_LINE_END end_style=LINE_END_ROUND) // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
//--- Рассчитаем корректировку координат очерчивающего прямоугольника в зависимости от размера линии
   int correct=int(::ceil((double)size/2.0))+1;
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2)-correct;
   this.m_quad_y=::fmin(y1,y2)-correct;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+1+correct*2;
   this.m_quad_height=::fabs(y2-y1)+1+correct*2;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+

В этом методе расчёт сохраняемой области уже отличается от всех вышерассмотренных. Так как линия с таким алгоритмом сглаживания имеет задаваемую ширину и внешний вид её окончаний, то и ширина сохраняемой области должна учитывать размер (толщину) линии и её краёв (края линии могут быть закругленными, поэтому размер (длина) линии увеличивается на два радиуса закругления, т.е. на величину, заданную как толщина линии).

Метод, рисующий вертикальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией:

//+------------------------------------------------------------------+
//| Рисует вертикальный отрезок произвольной линии заданной толщины  |
//| с использованием алгоритма сглаживания                           |
//| с предварительной фильтрацией                                    |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineThickVerticalOnBG(const int   x,                              // Координата X отрезка
                                           const int   y1,                             // Координата Y первой точки отрезка
                                           const int   y2,                             // Координата Y второй точки отрезка
                                           const int   size,                           // толщина линии
                                           const color clr,                            // Цвет
                                           const uchar opacity=255,                    // Непрозрачность
                                           const bool  redraw=false,                   // Флаг перерисовки чарта
                                           const uint  style=STYLE_SOLID,              // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                                           const ENUM_LINE_END end_style=LINE_END_ROUND)// Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
//--- Рассчитаем корректировку координат очерчивающего прямоугольника в зависимости от размера линии и типа её окончаний
   int correct_x=(int)::ceil((double)size/2.0);
   int correct_y=(end_style==LINE_END_BUTT ? 0 : correct_x);
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=x-correct_x;
   this.m_quad_y=::fmin(y1,y2)-correct_y;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=size;
   this.m_quad_height=::fabs(y2-y1)+1+correct_y*2;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+

Здесь расчёт такой же, как описано для предыдущего метода.

Остальные методы рисования сглаженных и других примитивов:

//+------------------------------------------------------------------+
//| Рисует горизонтальный отрезок произвольной линии заданной толщины|
//| с использованием алгоритма сглаживания                           |
//| с предварительной фильтрацией                                    |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawLineThickHorizontalOnBG(const int   x1,                              // Координата X первой точки отрезка
                                             const int   x2,                              // Координата X второй точки отрезка
                                             const int   y,                               // Координата Y отрезка
                                             const int   size,                            // толщина линии
                                             const color clr,                             // Цвет
                                             const uchar opacity=255,                     // Непрозрачность
                                             const bool  redraw=false,                    // Флаг перерисовки чарта
                                             const uint  style=STYLE_SOLID,               // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                                             const ENUM_LINE_END end_style=LINE_END_ROUND)// Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
//--- Рассчитаем корректировку координат очерчивающего прямоугольника в зависимости от размера линии и типа её окончаний
   int correct_y=(int)::ceil((double)size/2.0);
   int correct_x=(end_style==LINE_END_BUTT ? 0 : correct_y);
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2)-correct_x;
   this.m_quad_y=y-correct_y;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=::fabs(x2-x1)+1+correct_x*2;
   this.m_quad_height=size;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует ломаную линию с использованием                            |
//| алгоритма сглаживания AntiAliasing                               |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolylineAAOnBG(int         &array_x[],       // Массив координат X точек ломаной линии
                                    int         &array_y[],       // Массив координат Y точек ломаной линии
                                    const color clr,              // Цвет
                                    const uchar opacity=255,      // Непрозрачность
                                    const bool  redraw=false,     // Флаг перерисовки чарта
                                    const uint  style=UINT_MAX)   // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   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;

//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует ломаную линию с использованием алгоритма сглаживания Wu   |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolylineWuOnBG(int         &array_x[],       // Массив координат X точек ломаной линии
                                    int         &array_y[],       // Массив координат Y точек ломаной линии
                                    const color clr,              // Цвет
                                    const uchar opacity=255,      // Непрозрачность
                                    const bool  redraw=false,     // Флаг перерисовки чарта
                                    const uint  style=UINT_MAX)   // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   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;

//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует ломаную линию заданной толщины с использованием           |
//| двух алгоритмов сглаживания последовательно.                     |
//| Сначала на основе кривых Безье сглаживаются                      |
//| отдельные отрезки линии.                                         |
//| Затем для повышения качества отрисовки к построенной             |
//| из этих отрезков ломаной линии                                   |
//| применяется растровый алгоритм сглаживания                       |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolylineSmoothOnBG(const int    &array_x[],                    // Массив координат X точек ломаной линии
                                        const int    &array_y[],                    // Массив координат Y точек ломаной линии
                                        const int    size,                          // Толщина линии
                                        const color  clr,                           // Цвет
                                        const uchar  opacity=255,                   // Флаг перерисовки чарта
                                        const double tension=0.5,                   // Значение параметра сглаживания
                                        const double step=10,                       // Шаг аппроксимации
                                        const bool   redraw=false,                  // Флаг перерисовки чарта
                                        const ENUM_LINE_STYLE style=STYLE_SOLID,    // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                                        const ENUM_LINE_END   end_style=LINE_END_ROUND)// Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=0;
   this.m_quad_y=0;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=this.m_element.Width();
   this.m_quad_height=this.m_element.Height();
   
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;

//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует ломаную линию заданной толщины с использованием           |
//| алгоритма сглаживания с предварительной фильтрацией              |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolylineThickOnBG(const int   &array_x[],                // Массив координат X точек ломаной линии
                                       const int   &array_y[],                // Массив координат Y точек ломаной линии
                                       const int   size,                      // Толщина линии
                                       const color clr,                       // Цвет
                                       const uchar opacity=255,               // Непрозрачность
                                       const bool  redraw=false,              // Флаг перерисовки чарта
                                       const uint  style=STYLE_SOLID,         // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                                       ENUM_LINE_END end_style=LINE_END_ROUND)// Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
//--- Рассчитаем корректировку координат очерчивающего прямоугольника в зависимости от размера линии
   int correct=int(::ceil((double)size/2.0))+1;
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   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;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует многоугольник с использованием                            |
//| алгоритма сглаживания AntiAliasing                               |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonAAOnBG(int         &array_x[],     // Массив координат X точек многоугольника
                                   int         &array_y[],     // Массив координат Y точек многоугольника
                                   const color clr,            // Цвет
                                   const uchar opacity=255,    // Непрозрачность
                                   const bool  redraw=false,   // Флаг перерисовки чарта
                                   const uint  style=UINT_MAX) // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   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;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует многоугольник с использованием алгоритма сглаживания Wu   |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonWuOnBG(int         &array_x[],     // Массив координат X точек многоугольника
                                   int         &array_y[],     // Массив координат Y точек многоугольника
                                   const color clr,            // Цвет
                                   const uchar opacity=255,    // Непрозрачность
                                   const bool  redraw=false,   // Флаг перерисовки чарта
                                   const uint  style=UINT_MAX) // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   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;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует  многоугольник заданной толщины с использованием          |
//| двух алгоритмов сглаживания последовательно.                     |
//| Сначала на основе кривых Безье сглаживаются отдельные отрезки.   |
//| Затем для повышения качества отрисовки к построенному            |
//| из этих отрезков многоугольнику применяется                      |
//| растровый алгоритм сглаживания.                                  |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonSmoothOnBG(int          &array_x[],                  // Массив координат X точек ломаной линии
                                       int          &array_y[],                  // Массив координат Y точек ломаной линии
                                       const int    size,                        // Толщина линии
                                       const color  clr,                         // Цвет
                                       const uchar  opacity=255,                 // Флаг перерисовки чарта
                                       const double tension=0.5,                 // Значение параметра сглаживания
                                       const double step=10,                     // Шаг аппроксимации
                                       const bool   redraw=false,                // Флаг перерисовки чарта
                                       const ENUM_LINE_STYLE style=STYLE_SOLID,  // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                                       const ENUM_LINE_END   end_style=LINE_END_ROUND)// Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=0;
   this.m_quad_y=0;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=this.m_element.Width();
   this.m_quad_height=this.m_element.Height();
   
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;

//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует многоугольник заданной толщины с использованием           |
//| алгоритма сглаживания с предварительной фильтрацией              |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawPolygonThickOnBG(const int   &array_x[],                 // массив координат X точек многоугольника
                                      const int   &array_y[],                 // массив координат Y точек многоугольника
                                      const int   size,                       // толщина линии
                                      const color clr,                        // Цвет
                                      const uchar opacity=255,                // Непрозрачность
                                      const bool  redraw=false,               // Флаг перерисовки чарта
                                      const uint  style=STYLE_SOLID,          // стиль линии
                                      ENUM_LINE_END end_style=LINE_END_ROUND) // стиль концов линии
  {
//--- Рассчитаем корректировку координат очерчивающего прямоугольника в зависимости от размера линии
   int correct=int(::ceil((double)size/2.0))+1;
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   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;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует треугольник с использованием                              |
//| алгоритма сглаживания AntiAliasing                               |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawTriangleAAOnBG(const int   x1,               // Координата X первой вершины треугольника
                                    const int   y1,               // Координата Y первой вершины треугольника
                                    const int   x2,               // Координата X второй вершины треугольника
                                    const int   y2,               // Координата Y второй вершины треугольника
                                    const int   x3,               // Координата X третьей вершины треугольника
                                    const int   y3,               // Координата Y третьей вершины треугольника
                                    const color clr,              // Цвет
                                    const uchar opacity=255,      // Непрозрачность
                                    const bool  redraw=false,     // Флаг перерисовки чарта
                                    const uint  style=UINT_MAX)   // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   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);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=int(max_x-this.m_quad_x)+1;
   this.m_quad_height=int(max_y-this.m_quad_y)+1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует треугольник с использованием алгоритма сглаживания Wu     |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawTriangleWuOnBG(const int   x1,               // Координата X первой вершины треугольника
                                    const int   y1,               // Координата Y первой вершины треугольника
                                    const int   x2,               // Координата X второй вершины треугольника
                                    const int   y2,               // Координата Y второй вершины треугольника
                                    const int   x3,               // Координата X третьей вершины треугольника
                                    const int   y3,               // Координата Y третьей вершины треугольника
                                    const color clr,              // Цвет
                                    const uchar opacity=255,      // Непрозрачность
                                    const bool  redraw=false,     // Флаг перерисовки чарта
                                    const uint  style=UINT_MAX)   // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   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);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=int(max_x-this.m_quad_x)+1;
   this.m_quad_height=int(max_y-this.m_quad_y)+1;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует окружность с использованием                               |
//| алгоритма сглаживания AntiAliasing                               |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawCircleAAOnBG(const int    x,              // Координата X центра окружности
                                  const int    y,              // Координата Y центра окружности
                                  const double r,              // Радиус окружности
                                  const color  clr,            // Цвет
                                  const uchar  opacity=255,    // Непрозрачность
                                  const bool   redraw=false,   // Флаг перерисовки чарта
                                  const uint   style=UINT_MAX) // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1);
   this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1);
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует окружность с использованием алгоритма сглаживания Wu      |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawCircleWuOnBG(const int    x,              // Координата X центра окружности
                                  const int    y,              // Координата Y центра окружности
                                  const double r,              // Радиус окружности
                                  const color  clr,            // Цвет
                                  const uchar  opacity=255,    // Непрозрачность
                                  const bool   redraw=false,   // Флаг перерисовки чарта
                                  const uint   style=UINT_MAX) // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   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;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1);
   this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1);
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует эллипс по двум точкам с использованием                    |
//| алгоритма сглаживания AntiAliasing                               |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawEllipseAAOnBG(const double x1,               // Координата X первой точки, определяющей эллипс
                                   const double y1,               // Координата Y первой точки, определяющей эллипс
                                   const double x2,               // Координата X второй точки, определяющей эллипс
                                   const double y2,               // Координата Y второй точки, определяющей эллипс
                                   const color  clr,              // Цвет
                                   const uchar  opacity=255,      // Непрозрачность
                                   const bool   redraw=false,     // Флаг перерисовки чарта
                                   const uint   style=UINT_MAX)   // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2)-1;
   this.m_quad_y=::fmin(y1,y2)-1;
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   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;
      
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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;
  }
//+------------------------------------------------------------------+
//| Рисует эллипс по двум точкам с использованием                    |
//| алгоритма сглаживания Wu                                         |
//+------------------------------------------------------------------+
bool CFrameQuad::DrawEllipseWuOnBG(const int   x1,             // Координата X первой точки, определяющей эллипс
                                   const int   y1,             // Координата Y первой точки, определяющей эллипс
                                   const int   x2,             // Координата X второй точки, определяющей эллипс
                                   const int   y2,             // Координата Y второй точки, определяющей эллипс
                                   const color clr,            // Цвет
                                   const uchar opacity=255,    // Непрозрачность
                                   const bool  redraw=false,   // Флаг перерисовки чарта
                                   const uint  style=UINT_MAX) // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
//--- Установим координаты очерчивающего прямоугольника
   this.m_quad_x=::fmin(x1,x2);
   this.m_quad_y=::fmin(y1,y2);
//--- Установим ширину и высоту очерчивающего прямоугольника рисунка (это и будет размером сохраняемой области)
   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;
   
//--- Рассчитаем смещения координат для сохраняемой области в зависимости от точки привязки
   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(::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(!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;
//--- Нарисуем фигуру и обновим элемент
   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\ создадим новый файл Animations.mqh класса CAnimations.

К файлу класса должны быть подключены только что созданные файлы классов-наследников базового объекта-кадра анимации, а сам класс должен быть наследником базового объекта стандартной библиотеки CObject:

//+------------------------------------------------------------------+
//|                                                   Animations.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "FrameText.mqh"
#include "FrameQuad.mqh"
//+------------------------------------------------------------------+
//| Класс копировщика пикселей                                       |
//+------------------------------------------------------------------+
class CAnimations : public CObject
  {
  }

В приватной секции класса объявим указатель на объект-графический элемент, из которого будут создаваться анимационные объекты, два списка для хранения двух типов объектов-кадров анимации и методы для возврата флага присутствия в списке указанного объекта и для возврата указателя на существующий объект-кадр анимации, либо предварительно его создающий при его отсутствии в списке:

//+------------------------------------------------------------------+
//| Класс копировщика пикселей                                       |
//+------------------------------------------------------------------+
class CAnimations : public CObject
  {
private:
   CGCnvElement     *m_element;                             // Указатель на графический элемент
   CArrayObj         m_list_frames_text;                    // Список текстовых кадров анимаций
   CArrayObj         m_list_frames_quad;                    // Список прямоугольных кадров анимаций

//--- Возвращает флаг присутствия в списке объекта-кадра с указанным идентификатором
   bool              IsPresentFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id);
//--- Возвращает или создаёт новый объект-кадр анимации
   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(){;}

//--- Создаёт новый (1) прямоугольный, (2) текстовый объект-кадр анимации
   CFrame           *CreateNewFrameText(const int id);
   CFrame           *CreateNewFrameQuad(const int id);
//--- Возвращает объект-кадр анимации по идентификатору
   CFrame           *GetFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id);
//--- Возвращает список (1) текстовых, (2) прямоугольных кадров анимаций
   CArrayObj        *GetListFramesText(void)                { return &this.m_list_frames_text;  }
   CArrayObj        *GetListFramesQuad(void)                { return &this.m_list_frames_quad;  }

//+------------------------------------------------------------------+
//| Методы рисования с сохранением и восстановлением фона            |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Выводит текст на фон                                             |
//+------------------------------------------------------------------+
   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);
//+------------------------------------------------------------------+
//| Методы рисования примитивов без сглаживания                      |
//+------------------------------------------------------------------+
//--- Устанавливает цвет точки с указанными координатами
   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);
                       
//--- Рисует отрезок вертикальной линии
   bool              DrawLineVerticalOnBG(const int id,                 // Идентификатор кадра
                              const int   x,                            // Координата X отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует отрезок горизонтальной линии
   bool              DrawLineHorizontalOnBG(const int id,               // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y,                            // Координата Y отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует отрезок произвольной линии
   bool              DrawLineOnBG(const int id,                         // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует ломаную линию
   bool              DrawPolylineOnBG(const int id,                     // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек ломаной линии
                              int         &array_y[],                   // Массив координат Y точек ломаной линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует многоугольник
   bool              DrawPolygonOnBG(const int id,                      // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек многоугольника
                              int         &array_y[],                   // Массив координат Y точек многоугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует прямоугольник по двум точкам
   bool              DrawRectangleOnBG(const int id,                    // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки, определяющей прямоугольник
                              const int   y1,                           // Координата Y первой точки, определяющей прямоугольник
                              const int   x2,                           // Координата X второй точки, определяющей прямоугольник
                              const int   y2,                           // Координата Y второй точки, определяющей прямоугольник
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует окружность
   bool              DrawCircleOnBG(const int id,                       // Идентификатор кадра
                              const int   x,                            // Координата X центра окружности
                              const int   y,                            // Координата Y центра окружности
                              const int   r,                            // Радиус окружности
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует треугольник
   bool              DrawTriangleOnBG(const int id,                     // Идентификатор кадра
                              const int   x1,                           // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата Y третьей вершины треугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует эллипс по двум точкам
   bool              DrawEllipseOnBG(const int id,                      // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки, определяющей эллипс
                              const int   y1,                           // Координата Y первой точки, определяющей эллипс
                              const int   x2,                           // Координата X второй точки, определяющей эллипс
                              const int   y2,                           // Координата Y второй точки, определяющей эллипс
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует дугу эллипса, вписанного в прямоугольник с углами в (x1,y1) и (x2,y2).
//--- Границы дуги отсекаются линиями из центра эллипса, идущими к двум точкам с координатами (x3,y3) и (x4,y4)
   bool              DrawArcOnBG(const int id,                          // Идентификатор кадра
                              const int   x1,                           // Координата X левого верхнего угла, определяющего прямоугольник
                              const int   y1,                           // Координата Y левого верхнего угла, определяющего прямоугольник
                              const int   x2,                           // Координата X правого нижнего угла, определяющего прямоугольник
                              const int   y2,                           // Координата Y правого нижнего угла, определяющего прямоугольник
                              const int   x3,                           // Координата X первой точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                              const int   y3,                           // Координата Y первой точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                              const int   x4,                           // Координата X второй точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                              const int   y4,                           // Координата Y второй точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует закрашенный сектор эллипса, вписанного в прямоугольник с углами в (x1,y1) и (x2,y2).
//--- Границы сектора отсекаются линиями из центра эллипса, идущими к двум точкам с координатами (x3,y3) и (x4,y4)
   bool              DrawPieOnBG(const int id,                          // Идентификатор кадра
                              const int   x1,                           // координата X верхнего левого угла прямоугольника
                              const int   y1,                           // координата Y верхнего левого угла прямоугольника
                              const int   x2,                           // координата X нижнего правого угла прямоугольника
                              const int   y2,                           // координата Y нижнего правого угла прямоугольника
                              const int   x3,                           // координата X первой точки для нахождения границы дуги
                              const int   y3,                           // координата Y первой точки для нахождения границы дуги
                              const int   x4,                           // координата X второй точки для нахождения границы дуги
                              const int   y4,                           // координата Y второй точки для нахождения границы дуги
                              const color clr,                          // Цвет
                              const color fill_clr,                     // Цвет заливки
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//+------------------------------------------------------------------+
//| Методы рисования закрашенных примитивов без сглаживания          |
//+------------------------------------------------------------------+
//--- Закрашивает область
   bool              FillOnBG(const int   id,                           // Идентификатор кадра
                              const int   x,                            // Координата X точки начала закрашивания
                              const int   y,                            // Координата Y точки начала закрашивания
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const uint  threshould=0,                 // Порог
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует закрашенный прямоугольник
   bool              DrawRectangleFillOnBG(const int id,                // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки, определяющей прямоугольник
                              const int   y1,                           // Координата Y первой точки, определяющей прямоугольник
                              const int   x2,                           // Координата X второй точки, определяющей прямоугольник
                              const int   y2,                           // Координата Y второй точки, определяющей прямоугольник
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта

//--- Рисует закрашенный круг
   bool              DrawCircleFillOnBG(const int id,                   // Идентификатор кадра
                              const int   x,                            // Координата X центра круга
                              const int   y,                            // Координата Y центра круга
                              const int   r,                            // Радиус круга
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует закрашенный треугольник
   bool              DrawTriangleFillOnBG(const int id,                 // Идентификатор кадра
                              const int   x1,                           // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата Y третьей вершины треугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует закрашенный многоугольник
   bool              DrawPolygonFillOnBG(const int id,                  // Идентификатор кадра
                              int         &array_x[],                   // Массив, содержащий координаты X точек многоугольника
                              int         &array_y[],                   // Массив, содержащий координаты Y точек многоугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//--- Рисует закрашенный эллипс, вписанный в прямоугольник с заданными координатами
   bool              DrawEllipseFillOnBG(const int id,                  // Идентификатор кадра
                              const int   x1,                           // Координата X левого верхнего угла, определяющего прямоугольник
                              const int   y1,                           // Координата Y левого верхнего угла, определяющего прямоугольник
                              const int   x2,                           // Координата X правого нижнего угла, определяющего прямоугольник
                              const int   y2,                           // Координата Y правого нижнего угла, определяющего прямоугольник
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false);                // Флаг перерисовки чарта
                       
//+------------------------------------------------------------------+
//| Методы рисования примитивов с использованием сглаживания         |
//+------------------------------------------------------------------+
//--- Рисует точку с использованием алгоритма сглаживания AntiAliasing
   bool              SetPixelAAOnBG(const int id,                       // Идентификатор кадра
                              const double x,                           // Координата X точки
                              const double y,                           // Координата Y точки
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const bool   create_new=true,             // Флаг создания нового объекта
                              const bool   redraw=false);               // Флаг перерисовки чарта
                       
//--- Рисует отрезок произвольной линии с использованием алгоритма сглаживания AntiAliasing
   bool              DrawLineAAOnBG(const int id,                       // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует отрезок произвольной линии с использованием алгоритма сглаживания Wu
   bool              DrawLineWuOnBG(const int id,                       // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией
   bool              DrawLineThickOnBG(const int id,                    // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const int   size,                         // Толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              ENUM_LINE_END end_style=LINE_END_ROUND);  // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
 
//--- Рисует вертикальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией
   bool              DrawLineThickVerticalOnBG(const int id,            // Идентификатор кадра
                              const int   x,                            // Координата X отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const int   size,                         // толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END end_style=LINE_END_ROUND); // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       
//--- Рисует горизонтальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией
   bool              DrawLineThickHorizontalOnBG(const int id,          // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y,                            // Координата Y отрезка
                              const int   size,                         // толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END end_style=LINE_END_ROUND); // Стиль концов линии — одно из значений перечисления ENUM_LINE_END

//--- Рисует ломаную линию с использованием алгоритма сглаживания AntiAliasing
   bool              DrawPolylineAAOnBG(const int id,                   // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек ломаной линии
                              int         &array_y[],                   // Массив координат Y точек ломаной линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует ломаную линию с использованием алгоритма сглаживания Wu
   bool              DrawPolylineWuOnBG(const int id,                   // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек ломаной линии
                              int         &array_y[],                   // Массив координат Y точек ломаной линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует ломаную линию заданной толщины с использованием двух алгоритмов сглаживания последовательно.
//--- Сначала на основе кривых Безье сглаживаются отдельные отрезки линии.
//--- Затем для повышения качества отрисовки к построенной из этих отрезков ломаной линии применяется растровый алгоритм сглаживания
   bool              DrawPolylineSmoothOnBG(const int id,               // Идентификатор кадра
                              const int    &array_x[],                  // Массив координат X точек ломаной линии
                              const int    &array_y[],                  // Массив координат Y точек ломаной линии
                              const int    size,                        // Толщина линии
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const double tension=0.5,                 // Значение параметра сглаживания
                              const double step=10,                     // Шаг аппроксимации
                              const bool   create_new=true,             // Флаг создания нового объекта
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END end_style=LINE_END_ROUND);// Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       
//--- Рисует ломаную линию заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией
   bool              DrawPolylineThickOnBG(const int id,                // Идентификатор кадра
                              const int     &array_x[],                 // Массив координат X точек ломаной линии
                              const int     &array_y[],                 // Массив координат Y точек ломаной линии
                              const int     size,                       // Толщина линии
                              const color   clr,                        // Цвет
                              const uchar   opacity=255,                // Непрозрачность
                              const bool    create_new=true,            // Флаг создания нового объекта
                              const bool    redraw=false,               // Флаг перерисовки чарта
                              const uint    style=STYLE_SOLID,          // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              ENUM_LINE_END end_style=LINE_END_ROUND);  // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       
//--- Рисует многоугольник с использованием алгоритма сглаживания AntiAliasing
   bool              DrawPolygonAAOnBG(const int id,                    // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек многоугольника
                              int         &array_y[],                   // Массив координат Y точек многоугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует многоугольник с использованием алгоритма сглаживания Wu
   bool              DrawPolygonWuOnBG(const int id,                    // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек многоугольника
                              int         &array_y[],                   // Массив координат Y точек многоугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует  многоугольник заданной толщины с использованием двух алгоритмов сглаживания последовательно.
//--- Сначала на основе кривых Безье сглаживаются отдельные отрезки.
//--- Затем для повышения качества отрисовки к построенному из этих отрезков многоугольнику применяется растровый алгоритм сглаживания. 
   bool              DrawPolygonSmoothOnBG(const int id,                // Идентификатор кадра
                              int          &array_x[],                  // Массив координат X точек ломаной линии
                              int          &array_y[],                  // Массив координат Y точек ломаной линии
                              const int    size,                        // Толщина линии
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const double tension=0.5,                 // Значение параметра сглаживания
                              const double step=10,                     // Шаг аппроксимации
                              const bool   create_new=true,             // Флаг создания нового объекта
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END end_style=LINE_END_ROUND);// Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       
//--- Рисует многоугольник заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией
   bool              DrawPolygonThickOnBG(const int id,                 // Идентификатор кадра
                              const int   &array_x[],                   // массив координат X точек многоугольника
                              const int   &array_y[],                   // массив координат Y точек многоугольника
                              const int   size,                         // толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // стиль линии
                              ENUM_LINE_END end_style=LINE_END_ROUND);  // стиль концов линии
                       
//--- Рисует треугольник с использованием алгоритма сглаживания AntiAliasing
   bool              DrawTriangleAAOnBG(const int id,                   // Идентификатор кадра
                              const int   x1,                           // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата Y третьей вершины треугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует треугольник с использованием алгоритма сглаживания Wu
   bool              DrawTriangleWuOnBG(const int id,                   // Идентификатор кадра
                              const int   x1,                           // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата Y третьей вершины треугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует окружность с использованием алгоритма сглаживания AntiAliasing
   bool              DrawCircleAAOnBG(const int id,                     // Идентификатор кадра
                              const int    x,                           // Координата X центра окружности
                              const int    y,                           // Координата Y центра окружности
                              const double r,                           // Радиус окружности
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const bool   create_new=true,             // Флаг создания нового объекта
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const uint   style=UINT_MAX);             // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует окружность с использованием алгоритма сглаживания Wu
   bool              DrawCircleWuOnBG(const int id,                     // Идентификатор кадра
                              const int    x,                           // Координата X центра окружности
                              const int    y,                           // Координата Y центра окружности
                              const double r,                           // Радиус окружности
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const bool   create_new=true,             // Флаг создания нового объекта
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const uint   style=UINT_MAX);             // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует эллипс по двум точкам с использованием алгоритма сглаживания AntiAliasing
   bool              DrawEllipseAAOnBG(const int id,                    // Идентификатор кадра
                              const double x1,                          // Координата X первой точки, определяющей эллипс
                              const double y1,                          // Координата Y первой точки, определяющей эллипс
                              const double x2,                          // Координата X второй точки, определяющей эллипс
                              const double y2,                          // Координата Y второй точки, определяющей эллипс
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const bool   create_new=true,             // Флаг создания нового объекта
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const uint   style=UINT_MAX);             // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       
//--- Рисует эллипс по двум точкам с использованием алгоритма сглаживания Wu
   bool              DrawEllipseWuOnBG(const int id,                    // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки, определяющей эллипс
                              const int   y1,                           // Координата Y первой точки, определяющей эллипс
                              const int   x2,                           // Координата X второй точки, определяющей эллипс
                              const int   y2,                           // Координата Y второй точки, определяющей эллипс
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX);              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  };
//+------------------------------------------------------------------+


Рассмотрим реализацию объявленных методов.

Параметрический конструктор:

//+------------------------------------------------------------------+
//| Параметрический конструктор                                      |
//+------------------------------------------------------------------+
CAnimations::CAnimations(CGCnvElement *element)
  {
   this.m_element=element;
  }
//+------------------------------------------------------------------+

Здесь устанавливаем указателю m_element переданное в аргументах значение указателя на объект-графический элемент.

Метод, возвращающий указатель на объект-кадр анимации по типу и идентификатору:

//+------------------------------------------------------------------+
//| Возвращает объект-кадр анимации по типу и идентификатору         |
//+------------------------------------------------------------------+
CFrame *CAnimations::GetFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id)
  {
//--- Объявляем указатель на объект-кадр анимации
   CFrame *frame=NULL;
//--- В зависимости от типа нужного объекта получаем их количество в соответствующем списке
   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
     );
//--- В цикле ...
   for(int i=0;i<total;i++)
     {
      //--- ... по списку, соответствующему типу кадра анимации получаем очередной объект
      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(frame==NULL)
         continue;
      //--- Если идентификатор объекта соответствует искомому -
      //--- возвращаем указатель на найденный объект
      if(frame.ID()==id)
         return frame;
     }
//--- Ничего не нашли - возвращаем NULL
   return NULL;
  }
//+------------------------------------------------------------------+

Логика метода полностью расписана в комментариях к коду и в дополнительных пояснениях не нуждается.

Метод, возвращающий флаг присутствия в списке объекта-кадра анимации с указанным типом и идентификатором:

//+------------------------------------------------------------------+
//| Возвращает флаг присутствия в списке объекта-кадра анимации      |
//| с указанным типом и идентификатором                              |
//+------------------------------------------------------------------+
bool CAnimations::IsPresentFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id)
  {
   return(this.GetFrame(frame_type,id)!=NULL);
  }
//+------------------------------------------------------------------+

Метод возвращает bool-результат вызова вышерассмотренного метода GetFrame(). Если метод GetFrame() вернул результат не NULL (т.е., искомый объект есть в списке), то метод вернёт true, иначе — false.

Метод, создающий новый текстовый объект-кадр анимации:

//+------------------------------------------------------------------+
//| Создаёт новый текстовый объект-кадр анимации                     |
//+------------------------------------------------------------------+
CFrame *CAnimations::CreateNewFrameText(const int id)
  {
//--- Если объект с таким идентификатором уже есть - сообщаем об этом в журнал и возвращаем NULL
   if(this.IsPresentFrame(ANIMATION_FRAME_TYPE_TEXT,id))
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST),(string)id);
      return NULL;
     }
//--- Создаём новый текстовый объект-кадр анимации с указанным идентификатором
   CFrame *frame=new CFrameText(id,this.m_element);
//--- Если объект создать не удалось - сообщаем об этом и возвращаем NULL
   if(frame==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME));
      return NULL;
     }
//--- Если успешно созданный объект не удалось добавить в список - сообщаем об этом, удаляем объект и возвращаем 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 frame;
  }
//+------------------------------------------------------------------+

Логика метода полностью расписана в комментариях к коду.

Метод, создающий новый прямоугольный объект-кадр анимации:

//+------------------------------------------------------------------+
//| Создаёт новый прямоугольный объект-кадр анимации                 |
//+------------------------------------------------------------------+
CFrame *CAnimations::CreateNewFrameQuad(const int id)
  {
//--- Если объект с таким идентификатором уже есть - сообщаем об этом в журнал и возвращаем NULL
   if(this.IsPresentFrame(ANIMATION_FRAME_TYPE_QUAD,id))
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST),(string)id);
      return NULL;
     }
//--- Создаём новый прямоугольный объект-кадр анимации с указанным идентификатором
   CFrame *frame=new CFrameQuad(id,this.m_element);
//--- Если объект создать не удалось - сообщаем об этом и возвращаем NULL
   if(frame==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME));
      return NULL;
     }
//--- Если успешно созданный объект не удалось добавить в список - сообщаем об этом, удаляем объект и возвращаем 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 frame;
  }
//+------------------------------------------------------------------+

Метод идентичен вышерассмотренному, так же полностью прокомментирован и в дополнительных пояснениях не нуждается.

Метод, возвращающий указатель или создающий новый объект-кадр анимации:

//+------------------------------------------------------------------+
//| Возвращает или создаёт новый объект-кадр анимации                |
//+------------------------------------------------------------------+
CFrame *CAnimations::GetOrCreateFrame(const string source,const int id,const ENUM_ANIMATION_FRAME_TYPE frame_type,const bool create_new)
  {
   //--- Объявляем нулевые указатели на объекты
   CFrameQuad *frame_q=NULL;
   CFrameText *frame_t=NULL;
   //--- В зависимости от типа требуемого объекта
   switch(frame_type)
     {
      //--- Если это текстовый анимационный кадр
      case ANIMATION_FRAME_TYPE_TEXT :
        //--- получим указатель на объект с указанным идентификатором
        frame_t=this.GetFrame(ANIMATION_FRAME_TYPE_TEXT,id);
        //--- Если указатель получен - вернём его
        if(frame_t!=NULL)
           return frame_t;
        //--- Если не установлен флаг создания нового объекта - сообщим об ошибке и вернём NULL
        if(!create_new)
          {
           ::Print(source,CMessage::Text(MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST),(string)id);
           return NULL;
          }
        //--- Вернём результат создания нового объекта-кадра текстовой анимации (указатель на созданный объект)
        return this.CreateNewFrameText(id);
      
      //--- Если это прямоугольный анимационный кадр
      case ANIMATION_FRAME_TYPE_QUAD :
        //--- получим указатель на объект с указанным идентификатором
        frame_q=this.GetFrame(ANIMATION_FRAME_TYPE_QUAD,id);
        //--- Если указатель получен - вернём его
        if(frame_q!=NULL)
           return frame_q;
        //--- Если не установлен флаг создания нового объекта - сообщим об ошибке и вернём NULL
        if(!create_new)
          {
           ::Print(source,CMessage::Text(MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST),(string)id);
           return NULL;
          }
        //--- Вернём результат создания нового объекта-прямоугольного кадра анимации (указатель на созданный объект)
        return this.CreateNewFrameQuad(id);
      //--- Остальные случаи - возвращаем NULL
      default:
        return NULL;
     }
  }
//+------------------------------------------------------------------+

Логика метода расписана в комментариях к коду. Если нам необходимо работать с кадром анимации, то мы можем заранее его создать, получить на него указатель и управлять полученным объектом. Но если нам нужно динамически создавать объекты, то этот метод позволит при отсутствии объекта с указанным идентификатором сначала создать новый объект, а затем уже вернуть на него указатель. Таким образом можно организовать динамическое создание объектов "по ситуации", сразу же получить на него указатель и работать с ним.

Методы работы с объектами-кадрами анимаций.

Метод, выводящий текст на фон с сохранением и восстановлением фона:

//+------------------------------------------------------------------+
//| Выводит текст на фон с сохранением и восстановлением фона        |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+

В метод передаются идентификатор объекта, параметры выводимого текста (сам текст, координаты X и Y, точка привязки, цвет и непрозрачность), флаг необхоимости создать новый объект с указанным идентификатором в случае, если объекта с таким идентификатором нет в списке, и флаг перерисовки чарта.
Далее получаем указатель на требуемый объект (или создаём объект при его отсутствии). Если указатель получить не удалось, возвращаем false.
Если указатель получен, возвращаем результат работы метода TextOnBG() полученного объекта-кадра текстовой анимации.

Метод, устанавливающий цвет точки с указанными координатами:

//+------------------------------------------------------------------+
//| Устанавливает цвет точки с указанными координатами               |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+

Логика метода идентична логике вышерассмотренного метода. В метод передаются идентификатор объекта, координаты X и Y рисуемой фигуры, её цвет и непрозрачность, флаг необходимости создать новый объект с указанным идентификатором в случае, если объекта с таким идентификатором нет в списке, и флаг перерисовки чарта.
Далее получаем указатель на требуемый объект (или создаём объект при его отсутствии). Если указатель получить не удалось, возвращаем false.
Если указатель получен, возвращаем результат работы метода SetPixelOnBG() полученного объекта-прямоугольного кадра анимации.

Остальные методы рисования примитивов.

Логика остальных методов рисования фигур идентична логике вышерассмотренных методов. Просто посмотрим их листинг:

//+------------------------------------------------------------------+
//| Рисует отрезок вертикальной линии                                |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineVerticalOnBG(const int id,                 // Идентификатор кадра
                           const int   x,                            // Координата X отрезка
                           const int   y1,                           // Координата Y первой точки отрезка
                           const int   y2,                           // Координата 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.DrawLineVerticalOnBG(x,y1,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует отрезок горизонтальной линии                              |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineHorizontalOnBG(const int id,               // Идентификатор кадра
                           const int   x1,                           // Координата X первой точки отрезка
                           const int   x2,                           // Координата X второй точки отрезка
                           const int   y,                            // Координата 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.DrawLineHorizontalOnBG(x1,x2,y,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует отрезок произвольной линии                                |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineOnBG(const int id,                         // Идентификатор кадра
                           const int   x1,                           // Координата X первой точки отрезка
                           const int   y1,                           // Координата Y первой точки отрезка
                           const int   x2,                           // Координата X второй точки отрезка
                           const int   y2,                           // Координата 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.DrawLineOnBG(x1,y1,x2,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует ломаную линию                                             |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolylineOnBG(const int id,                     // Идентификатор кадра
                           int         &array_x[],                   // Массив координат X точек ломаной линии
                           int         &array_y[],                   // Массив координат 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.DrawPolylineOnBG(array_x,array_y,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует многоугольник                                             |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolygonOnBG(const int id,                      // Идентификатор кадра
                           int         &array_x[],                   // Массив координат X точек многоугольника
                           int         &array_y[],                   // Массив координат 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.DrawPolygonOnBG(array_x,array_y,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует прямоугольник по двум точкам                              |
//+------------------------------------------------------------------+
bool CAnimations::DrawRectangleOnBG(const int id,                    // Идентификатор кадра
                           const int   x1,                           // Координата X первой точки, определяющей прямоугольник
                           const int   y1,                           // Координата Y первой точки, определяющей прямоугольник
                           const int   x2,                           // Координата X второй точки, определяющей прямоугольник
                           const int   y2,                           // Координата 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.DrawRectangleOnBG(x1,y1,x2,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует окружность                                                |
//+------------------------------------------------------------------+
bool CAnimations::DrawCircleOnBG(const int id,                       // Идентификатор кадра
                           const int   x,                            // Координата X центра окружности
                           const int   y,                            // Координата Y центра окружности
                           const int   r,                            // Радиус окружности
                           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.DrawCircleOnBG(x,y,r,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует треугольник                                               |
//+------------------------------------------------------------------+
bool CAnimations::DrawTriangleOnBG(const int id,                     // Идентификатор кадра
                           const int   x1,                           // Координата X первой вершины треугольника
                           const int   y1,                           // Координата Y первой вершины треугольника
                           const int   x2,                           // Координата X второй вершины треугольника
                           const int   y2,                           // Координата Y второй вершины треугольника
                           const int   x3,                           // Координата X третьей вершины треугольника
                           const int   y3,                           // Координата 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.DrawTriangleOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует эллипс по двум точкам                                     |
//+------------------------------------------------------------------+
bool CAnimations::DrawEllipseOnBG(const int id,                      // Идентификатор кадра
                           const int   x1,                           // Координата X первой точки, определяющей эллипс
                           const int   y1,                           // Координата Y первой точки, определяющей эллипс
                           const int   x2,                           // Координата X второй точки, определяющей эллипс
                           const int   y2,                           // Координата 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.DrawEllipseOnBG(x1,y1,x2,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует дугу эллипса, вписанного в прямоугольник                  |
//| с углами в (x1,y1) и (x2,y2).                                    |
//| Границы дуги отсекаются линиями из центра эллипса,               |
//| идущими к двум точкам с координатами (x3,y3) и (x4,y4)           |
//+------------------------------------------------------------------+
bool CAnimations::DrawArcOnBG(const int id,                          // Идентификатор кадра
                           const int   x1,                           // Координата X левого верхнего угла, определяющего прямоугольник
                           const int   y1,                           // Координата Y левого верхнего угла, определяющего прямоугольник
                           const int   x2,                           // Координата X правого нижнего угла, определяющего прямоугольник
                           const int   y2,                           // Координата Y правого нижнего угла, определяющего прямоугольник
                           const int   x3,                           // Координата X первой точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                           const int   y3,                           // Координата Y первой точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                           const int   x4,                           // Координата X второй точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                           const int   y4,                           // Координата 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.DrawArcOnBG(x1,y1,x2,y2,x3,y3,x4,y4,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный сектор эллипса, вписанного в прямоугольник    |
//| с углами в (x1,y1) и (x2,y2).                                    |
//| Границы сектора отсекаются линиями из центра эллипса,            |
//| идущими к двум точкам с координатами (x3,y3) и (x4,y4)           |
//+------------------------------------------------------------------+
bool CAnimations::DrawPieOnBG(const int id,                          // Идентификатор кадра
                           const int   x1,                           // координата X верхнего левого угла прямоугольника
                           const int   y1,                           // координата Y верхнего левого угла прямоугольника
                           const int   x2,                           // координата X нижнего правого угла прямоугольника
                           const int   y2,                           // координата Y нижнего правого угла прямоугольника
                           const int   x3,                           // координата X первой точки для нахождения границы дуги
                           const int   y3,                           // координата Y первой точки для нахождения границы дуги
                           const int   x4,                           // координата X второй точки для нахождения границы дуги
                           const int   y4,                           // координата Y второй точки для нахождения границы дуги
                           const color clr,                          // Цвет
                           const color fill_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.DrawPieOnBG(x1,y1,x2,y2,x3,y3,x4,y4,clr,fill_clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Закрашивает область                                              |
//+------------------------------------------------------------------+
bool CAnimations::FillOnBG(const int   id,                           // Идентификатор кадра
                           const int   x,                            // Координата X точки начала закрашивания
                           const int   y,                            // Координата Y точки начала закрашивания
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const uint  threshould=0,                 // Порог
                           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.FillOnBG(x,y,clr,opacity,threshould,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный прямоугольник                                 |
//+------------------------------------------------------------------+
bool CAnimations::DrawRectangleFillOnBG(const int id,                // Идентификатор кадра
                           const int   x1,                           // Координата X первой точки, определяющей прямоугольник
                           const int   y1,                           // Координата Y первой точки, определяющей прямоугольник
                           const int   x2,                           // Координата X второй точки, определяющей прямоугольник
                           const int   y2,                           // Координата 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.DrawRectangleFillOnBG(x1,y1,x2,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный круг                                          |
//+------------------------------------------------------------------+
bool CAnimations::DrawCircleFillOnBG(const int id,                   // Идентификатор кадра
                           const int   x,                            // Координата X центра круга
                           const int   y,                            // Координата Y центра круга
                           const int   r,                            // Радиус круга
                           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.DrawCircleFillOnBG(x,y,r,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный треугольник                                   |
//+------------------------------------------------------------------+
bool CAnimations::DrawTriangleFillOnBG(const int id,                 // Идентификатор кадра
                           const int   x1,                           // Координата X первой вершины треугольника
                           const int   y1,                           // Координата Y первой вершины треугольника
                           const int   x2,                           // Координата X второй вершины треугольника
                           const int   y2,                           // Координата Y второй вершины треугольника
                           const int   x3,                           // Координата X третьей вершины треугольника
                           const int   y3,                           // Координата 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.DrawTriangleFillOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный многоугольник                                 |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolygonFillOnBG(const int id,                  // Идентификатор кадра
                           int         &array_x[],                   // Массив, содержащий координаты X точек многоугольника
                           int         &array_y[],                   // Массив, содержащий координаты 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.DrawPolygonFillOnBG(array_x,array_y,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный эллипс, вписанный в прямоугольник             |
//| с заданными координатами                                         |
//+------------------------------------------------------------------+
bool CAnimations::DrawEllipseFillOnBG(const int id,                  // Идентификатор кадра
                           const int   x1,                           // Координата X левого верхнего угла, определяющего прямоугольник
                           const int   y1,                           // Координата Y левого верхнего угла, определяющего прямоугольник
                           const int   x2,                           // Координата X правого нижнего угла, определяющего прямоугольник
                           const int   y2,                           // Координата 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.DrawEllipseFillOnBG(x1,y1,x2,y2,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует точку с использованием алгоритма сглаживания AntiAliasing |
//+------------------------------------------------------------------+
bool CAnimations::SetPixelAAOnBG(const int id,                       // Идентификатор кадра
                           const double x,                           // Координата X точки
                           const double y,                           // Координата 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.SetPixelAAOnBG(x,y,clr,opacity,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует отрезок произвольной линии с использованием               |
//| алгоритма сглаживания AntiAliasing                               |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineAAOnBG(const int id,                       // Идентификатор кадра
                           const int   x1,                           // Координата X первой точки отрезка
                           const int   y1,                           // Координата Y первой точки отрезка
                           const int   x2,                           // Координата X второй точки отрезка
                           const int   y2,                           // Координата Y второй точки отрезка
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует отрезок произвольной линии с использованием               |
//| алгоритма сглаживания Wu                                         |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineWuOnBG(const int id,                       // Идентификатор кадра
                           const int   x1,                           // Координата X первой точки отрезка
                           const int   y1,                           // Координата Y первой точки отрезка
                           const int   x2,                           // Координата X второй точки отрезка
                           const int   y2,                           // Координата Y второй точки отрезка
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует отрезок произвольной линии заданной толщины               |
//| с использованием алгоритма сглаживания                           |
//| с предварительной фильтрацией                                    |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineThickOnBG(const int id,                    // Идентификатор кадра
                           const int   x1,                           // Координата X первой точки отрезка
                           const int   y1,                           // Координата Y первой точки отрезка
                           const int   x2,                           // Координата X второй точки отрезка
                           const int   y2,                           // Координата Y второй точки отрезка
                           const int   size,                         // Толщина линии
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                           ENUM_LINE_END end_style=LINE_END_ROUND)   // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует вертикальный отрезок произвольной линии заданной толщины  |
//| с использованием алгоритма сглаживания                           |
//| с предварительной фильтрацией                                    |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineThickVerticalOnBG(const int id,            // Идентификатор кадра
                           const int   x,                            // Координата X отрезка
                           const int   y1,                           // Координата Y первой точки отрезка
                           const int   y2,                           // Координата Y второй точки отрезка
                           const int   size,                         // толщина линии
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                           const ENUM_LINE_END end_style=LINE_END_ROUND) // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует горизонтальный отрезок произвольной линии заданной толщины|
//| с использованием алгоритма сглаживания                           |
//| с предварительной фильтрацией                                    |
//+------------------------------------------------------------------+
bool CAnimations::DrawLineThickHorizontalOnBG(const int id,          // Идентификатор кадра
                           const int   x1,                           // Координата X первой точки отрезка
                           const int   x2,                           // Координата X второй точки отрезка
                           const int   y,                            // Координата Y отрезка
                           const int   size,                         // толщина линии
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                           const ENUM_LINE_END end_style=LINE_END_ROUND) // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует ломаную линию с использованием                            |
//| алгоритма сглаживания AntiAliasing                               |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolylineAAOnBG(const int id,                   // Идентификатор кадра
                           int         &array_x[],                   // Массив координат X точек ломаной линии
                           int         &array_y[],                   // Массив координат Y точек ломаной линии
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует ломаную линию с использованием алгоритма сглаживания Wu   |
//+------------------------------------------------------------------+
//--- 
bool CAnimations::DrawPolylineWuOnBG(const int id,                   // Идентификатор кадра
                           int         &array_x[],                   // Массив координат X точек ломаной линии
                           int         &array_y[],                   // Массив координат Y точек ломаной линии
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует ломаную линию заданной толщины с использованием           |
//| двух алгоритмов сглаживания последовательно.                     |
//| Сначала на основе кривых Безье сглаживаются                      |
//| отдельные отрезки линии.                                         |
//| Затем для повышения качества отрисовки к построенной             |
//| из этих отрезков ломаной линии применяется                       |
//| растровый алгоритм сглаживания                                   |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolylineSmoothOnBG(const int id,               // Идентификатор кадра
                           const int    &array_x[],                  // Массив координат X точек ломаной линии
                           const int    &array_y[],                  // Массив координат Y точек ломаной линии
                           const int    size,                        // Толщина линии
                           const color  clr,                         // Цвет
                           const uchar  opacity=255,                 // Непрозрачность
                           const double tension=0.5,                 // Значение параметра сглаживания
                           const double step=10,                     // Шаг аппроксимации
                           const bool   create_new=true,             // Флаг создания нового объекта
                           const bool   redraw=false,                // Флаг перерисовки чарта
                           const ENUM_LINE_STYLE style=STYLE_SOLID,  // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                           const ENUM_LINE_END   end_style=LINE_END_ROUND) // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует ломаную линию заданной толщины с использованием           |
//| алгоритма сглаживания с предварительной фильтрацией              |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolylineThickOnBG(const int id,                // Идентификатор кадра
                           const int      &array_x[],                // Массив координат X точек ломаной линии
                           const int      &array_y[],                // Массив координат Y точек ломаной линии
                           const int      size,                      // Толщина линии
                           const color    clr,                       // Цвет
                           const uchar    opacity=255,               // Непрозрачность
                           const bool     create_new=true,           // Флаг создания нового объекта
                           const bool     redraw=false,              // Флаг перерисовки чарта
                           const uint     style=STYLE_SOLID,         // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                           ENUM_LINE_END  end_style=LINE_END_ROUND)  // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует многоугольник с использованием                            |
//| алгоритма сглаживания AntiAliasing                               |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolygonAAOnBG(const int id,                    // Идентификатор кадра
                           int         &array_x[],                   // Массив координат X точек многоугольника
                           int         &array_y[],                   // Массив координат Y точек многоугольника
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует многоугольник с использованием алгоритма сглаживания Wu   |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolygonWuOnBG(const int id,                    // Идентификатор кадра
                           int         &array_x[],                   // Массив координат X точек многоугольника
                           int         &array_y[],                   // Массив координат Y точек многоугольника
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует  многоугольник заданной толщины с использованием          |
//| двух алгоритмов сглаживания последовательно.                     |
//| Сначала на основе кривых Безье сглаживаются отдельные отрезки.   |
//| Затем для повышения качества отрисовки к построенному            |
//| из этих отрезков многоугольнику применяется                      |
//| растровый алгоритм сглаживания.                                  |
//+------------------------------------------------------------------+
bool CAnimations::DrawPolygonSmoothOnBG(const int id,                // Идентификатор кадра
                           int          &array_x[],                  // Массив координат X точек ломаной линии
                           int          &array_y[],                  // Массив координат Y точек ломаной линии
                           const int    size,                        // Толщина линии
                           const color  clr,                         // Цвет
                           const uchar  opacity=255,                 // Непрозрачность
                           const double tension=0.5,                 // Значение параметра сглаживания
                           const double step=10,                     // Шаг аппроксимации
                           const bool   create_new=true,             // Флаг создания нового объекта
                           const bool   redraw=false,                // Флаг перерисовки чарта
                           const ENUM_LINE_STYLE style=STYLE_SOLID,  // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                           const ENUM_LINE_END   end_style=LINE_END_ROUND) // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует многоугольник заданной толщины с использованием           |
//| алгоритма сглаживания с предварительной фильтрацией              |
//+------------------------------------------------------------------+
//--- Рисует многоугольник заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией
bool CAnimations::DrawPolygonThickOnBG(const int id,                 // Идентификатор кадра
                           const int   &array_x[],                   // массив координат X точек многоугольника
                           const int   &array_y[],                   // массив координат Y точек многоугольника
                           const int   size,                         // толщина линии
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=STYLE_SOLID,            // стиль линии

                           ENUM_LINE_END end_style=LINE_END_ROUND)   // стиль концов линии
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует треугольник с использованием                              |
//| алгоритма сглаживания AntiAliasing                               |
//+------------------------------------------------------------------+
bool CAnimations::DrawTriangleAAOnBG(const int id,                   // Идентификатор кадра
                           const int   x1,                           // Координата X первой вершины треугольника
                           const int   y1,                           // Координата Y первой вершины треугольника
                           const int   x2,                           // Координата X второй вершины треугольника
                           const int   y2,                           // Координата Y второй вершины треугольника
                           const int   x3,                           // Координата X третьей вершины треугольника
                           const int   y3,                           // Координата Y третьей вершины треугольника
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует треугольник с использованием алгоритма сглаживания Wu     |
//+------------------------------------------------------------------+
bool CAnimations::DrawTriangleWuOnBG(const int id,                   // Идентификатор кадра
                           const int   x1,                           // Координата X первой вершины треугольника
                           const int   y1,                           // Координата Y первой вершины треугольника
                           const int   x2,                           // Координата X второй вершины треугольника
                           const int   y2,                           // Координата Y второй вершины треугольника
                           const int   x3,                           // Координата X третьей вершины треугольника
                           const int   y3,                           // Координата Y третьей вершины треугольника
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует окружность с использованием                               |
//| алгоритма сглаживания AntiAliasing                               |
//+------------------------------------------------------------------+
bool CAnimations::DrawCircleAAOnBG(const int id,                     // Идентификатор кадра
                           const int    x,                           // Координата X центра окружности
                           const int    y,                           // Координата Y центра окружности
                           const double r,                           // Радиус окружности
                           const color  clr,                         // Цвет
                           const uchar  opacity=255,                 // Непрозрачность
                           const bool   create_new=true,             // Флаг создания нового объекта
                           const bool   redraw=false,                // Флаг перерисовки чарта
                           const uint   style=UINT_MAX)              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует окружность с использованием алгоритма сглаживания Wu      |
//+------------------------------------------------------------------+
bool CAnimations::DrawCircleWuOnBG(const int id,                     // Идентификатор кадра
                           const int    x,                           // Координата X центра окружности
                           const int    y,                           // Координата Y центра окружности
                           const double r,                           // Радиус окружности
                           const color  clr,                         // Цвет
                           const uchar  opacity=255,                 // Непрозрачность
                           const bool   create_new=true,             // Флаг создания нового объекта
                           const bool   redraw=false,                // Флаг перерисовки чарта
                           const uint   style=UINT_MAX)              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует эллипс по двум точкам с использованием                    |
//| алгоритма сглаживания AntiAliasing                               |
//+------------------------------------------------------------------+
bool CAnimations::DrawEllipseAAOnBG(const int id,                    // Идентификатор кадра
                           const double x1,                          // Координата X первой точки, определяющей эллипс
                           const double y1,                          // Координата Y первой точки, определяющей эллипс
                           const double x2,                          // Координата X второй точки, определяющей эллипс
                           const double y2,                          // Координата Y второй точки, определяющей эллипс
                           const color  clr,                         // Цвет
                           const uchar  opacity=255,                 // Непрозрачность
                           const bool   create_new=true,             // Флаг создания нового объекта
                           const bool   redraw=false,                // Флаг перерисовки чарта
                           const uint   style=UINT_MAX)              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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);
  }
//+------------------------------------------------------------------+
//| Рисует эллипс по двум точкам                                     |
//| с использованием алгоритма сглаживания Wu                        |
//+------------------------------------------------------------------+
bool CAnimations::DrawEllipseWuOnBG(const int id,                    // Идентификатор кадра
                           const int   x1,                           // Координата X первой точки, определяющей эллипс
                           const int   y1,                           // Координата Y первой точки, определяющей эллипс
                           const int   x2,                           // Координата X второй точки, определяющей эллипс
                           const int   y2,                           // Координата Y второй точки, определяющей эллипс
                           const color clr,                          // Цвет
                           const uchar opacity=255,                  // Непрозрачность
                           const bool  create_new=true,              // Флаг создания нового объекта
                           const bool  redraw=false,                 // Флаг перерисовки чарта
                           const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
  {
   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/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "GCnvElement.mqh"
#include "ShadowObj.mqh"
#include "Animations\Animations.mqh"
//+------------------------------------------------------------------+

Удалим из листинга класс объекта-копировщика пикселей (его мы перенесли в другой файл):

//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "GCnvElement.mqh"
#include "ShadowObj.mqh"
#include "Animations\Animations.mqh"
//+------------------------------------------------------------------+
//| Класс копировщика пикселей                                       |
//+------------------------------------------------------------------+
class CPixelCopier : public CObject
  {
private:
...
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс объекта "форма"                                            |
//+------------------------------------------------------------------+

В приватной секции класса вместо списка копировщиков-пикселей

CArrayObj         m_list_pc_obj;                            // Список объектов-копировщиков пикселей

объявим указатель на объект класса анимаций:

//+------------------------------------------------------------------+
//|                                                         Form.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "GCnvElement.mqh"
#include "ShadowObj.mqh"
#include "Animations\Animations.mqh"
//+------------------------------------------------------------------+
//| Класс объекта "форма"                                            |
//+------------------------------------------------------------------+
class CForm : public CGCnvElement
  {
private:
   CArrayObj         m_list_elements;                          // Список присоединённых элементов
   CAnimations      *m_animations;                             // Указатель на объект анимаций
   CShadowObj       *m_shadow_obj;                             // Указатель на объект тени
   color             m_color_frame;                            // Цвет рамки формы
   int               m_frame_width_left;                       // Ширина рамки формы слева
   int               m_frame_width_right;                      // Ширина рамки формы справа
   int               m_frame_width_top;                        // Ширина рамки формы сверху
   int               m_frame_width_bottom;                     // Ширина рамки формы снизу

//--- Инициализирует переменные
   void              Initialize(void);
//--- Возвращает имя зависимого объекта
   string            CreateNameDependentObject(const string base_name)  const
                       { return ::StringSubstr(this.NameObj(),::StringLen(::MQLInfoString(MQL_PROGRAM_NAME))+1)+"_"+base_name;   }
   
//--- Создаёт новый графический объект
   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);

//--- Создаёт объект для тени
   void              CreateShadowObj(const color colour,const uchar opacity);
   
public:

Также из приватной секции удалим объявление уже ненужного метода IsPresentPC(), а из листинга кода — его реализацию:

//--- Создаёт объект для тени
   void              CreateShadowObj(const color colour,const uchar opacity);
   
//--- Возвращает флаг присутствия в списке объекта-копировщика с указанным идентификатором
   bool              IsPresentPC(const int id);

public:

Из публичной секции класса удалим уже не нужный метод:

//--- Возвращает (1) себя, список (2) присоединённых объектов, (3) объектов-копировщиков пикселей, (4) объект тени
   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;      }
//--- Возвращает указатель на (1) объект анимаций, список (2) текстовых, (3) прямоугольных кадров анимаций
   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);       }
   
//--- Устанавливает (1) цветовую схему, (2) стиль формы

Удалим объявление метода для создания нового объекта-копировщика пикселей:

//--- Создаёт новый объект-копировщик пикселей
   CPixelCopier     *CreateNewPixelCopier(const int id,const int x_coord,const int y_coord,const int width,const int height);

//--- Рисует тень объекта

Реализацию этого метода, написанную за пределами тела класса, тоже удалим.

В публичной секции класса, в блоке методов для работы с пикселями изображения, напишем новые методы для создания объектов-кадров анимаций, возврата указателей на созданные объекты и методы рисования с сохранением и восстановлением фона:

//+------------------------------------------------------------------+
//| Методы работы с пикселями изображения                            |
//+------------------------------------------------------------------+
//--- Создаёт новый (1) прямоугольный, (2) текстовый объект-кадр анимации
   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);            }
                       
//--- Возвращает объект-кадр (1) текстовой, (2) прямоугольной анимации по идентификатору
   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);   }
                       
//--- Выводит текст на фон с сохранением и восстановлением фона
   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);  }

//--- Устанавливает цвет точки с указанными координатами с сохранением и восстановлением фона
   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);  }
                       
//--- Рисует отрезок вертикальной линии
   bool              DrawLineVerticalOnBG(const int id,                 // Идентификатор кадра
                              const int   x,                            // Координата X отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   y2,                           // Координата 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.DrawLineVerticalOnBG(id,x,y1,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует отрезок горизонтальной линии с сохранением и восстановлением фона
   bool              DrawLineHorizontalOnBG(const int id,               // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y,                            // Координата 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.DrawLineHorizontalOnBG(id,x1,x2,y,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует отрезок произвольной линии с сохранением и восстановлением фона
   bool              DrawLineOnBG(const int id,                         // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата 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.DrawLineOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует ломаную линию с сохранением и восстановлением фона
   bool              DrawPolylineOnBG(const int id,                     // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек ломаной линии
                              int         &array_y[],                   // Массив координат 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.DrawPolylineOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует многоугольник с сохранением и восстановлением фона
   bool              DrawPolygonOnBG(const int id,                      // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек многоугольника
                              int         &array_y[],                   // Массив координат 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.DrawPolygonOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует прямоугольник по двум точкам с сохранением и восстановлением фона
   bool              DrawRectangleOnBG(const int id,                    // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки, определяющей прямоугольник
                              const int   y1,                           // Координата Y первой точки, определяющей прямоугольник
                              const int   x2,                           // Координата X второй точки, определяющей прямоугольник
                              const int   y2,                           // Координата 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.DrawRectangleOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует окружность с сохранением и восстановлением фона
   bool              DrawCircleOnBG(const int id,                       // Идентификатор кадра
                              const int   x,                            // Координата X центра окружности
                              const int   y,                            // Координата Y центра окружности
                              const int   r,                            // Радиус окружности
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false)                 // Флаг перерисовки чарта
                       { return(this.m_animations!=NULL ? this.m_animations.DrawCircleOnBG(id,x,y,r,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует треугольник с сохранением и восстановлением фона
   bool              DrawTriangleOnBG(const int id,                     // Идентификатор кадра
                              const int   x1,                           // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата 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.DrawTriangleOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует эллипс по двум точкам с сохранением и восстановлением фона
   bool              DrawEllipseOnBG(const int id,                      // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки, определяющей эллипс
                              const int   y1,                           // Координата Y первой точки, определяющей эллипс
                              const int   x2,                           // Координата X второй точки, определяющей эллипс
                              const int   y2,                           // Координата 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.DrawEllipseOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует дугу эллипса, вписанного в прямоугольник с углами в (x1,y1) и (x2,y2)  с сохранением и восстановлением фона.
//--- Границы дуги отсекаются линиями из центра эллипса, идущими к двум точкам с координатами (x3,y3) и (x4,y4)
   bool              DrawArcOnBG(const int id,                          // Идентификатор кадра
                              const int   x1,                           // Координата X левого верхнего угла, определяющего прямоугольник
                              const int   y1,                           // Координата Y левого верхнего угла, определяющего прямоугольник
                              const int   x2,                           // Координата X правого нижнего угла, определяющего прямоугольник
                              const int   y2,                           // Координата Y правого нижнего угла, определяющего прямоугольник
                              const int   x3,                           // Координата X первой точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                              const int   y3,                           // Координата Y первой точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                              const int   x4,                           // Координата X второй точки, к которой проведена линия из центра прямоугольника для получения границы дуги
                              const int   y4,                           // Координата 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.DrawArcOnBG(id,x1,y1,x2,y2,x3,y3,x4,y4,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует закрашенный сектор эллипса, вписанного в прямоугольник с углами в (x1,y1) и (x2,y2)  с сохранением и восстановлением фона.
//--- Границы сектора отсекаются линиями из центра эллипса, идущими к двум точкам с координатами (x3,y3) и (x4,y4)
   bool              DrawPieOnBG(const int id,                          // Идентификатор кадра
                              const int   x1,                           // координата X верхнего левого угла прямоугольника
                              const int   y1,                           // координата Y верхнего левого угла прямоугольника
                              const int   x2,                           // координата X нижнего правого угла прямоугольника
                              const int   y2,                           // координата Y нижнего правого угла прямоугольника
                              const int   x3,                           // координата X первой точки для нахождения границы дуги
                              const int   y3,                           // координата Y первой точки для нахождения границы дуги
                              const int   x4,                           // координата X второй точки для нахождения границы дуги
                              const int   y4,                           // координата Y второй точки для нахождения границы дуги
                              const color clr,                          // Цвет
                              const color fill_clr,                     // Цвет заливки
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false)                 // Флаг перерисовки чарта
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPieOnBG(id,x1,y1,x2,y2,x3,y3,x4,y4,clr,fill_clr,opacity,create_new,redraw) : false);  }
                       
//--- Закрашивает область с сохранением и восстановлением фона
   bool              FillOnBG(const int   id,                           // Идентификатор кадра
                              const int   x,                            // Координата X точки начала закрашивания
                              const int   y,                            // Координата Y точки начала закрашивания
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const uint  threshould=0,                 // Порог
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false)                 // Флаг перерисовки чарта
                       { return(this.m_animations!=NULL ? this.m_animations.FillOnBG(id,x,y,clr,opacity,threshould,create_new,redraw) : false);  }
                       
//--- Рисует закрашенный прямоугольник с сохранением и восстановлением фона
   bool              DrawRectangleFillOnBG(const int id,                // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки, определяющей прямоугольник
                              const int   y1,                           // Координата Y первой точки, определяющей прямоугольник
                              const int   x2,                           // Координата X второй точки, определяющей прямоугольник
                              const int   y2,                           // Координата 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.DrawRectangleFillOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует закрашенный круг с сохранением и восстановлением фона
   bool              DrawCircleFillOnBG(const int id,                   // Идентификатор кадра
                              const int   x,                            // Координата X центра круга
                              const int   y,                            // Координата Y центра круга
                              const int   r,                            // Радиус круга
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false)                 // Флаг перерисовки чарта
                       { return(this.m_animations!=NULL ? this.m_animations.DrawCircleFillOnBG(id,x,y,r,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует закрашенный треугольник с сохранением и восстановлением фона
   bool              DrawTriangleFillOnBG(const int id,                 // Идентификатор кадра
                              const int   x1,                           // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата 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.DrawTriangleFillOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует закрашенный многоугольник с сохранением и восстановлением фона
   bool              DrawPolygonFillOnBG(const int id,                  // Идентификатор кадра
                              int         &array_x[],                   // Массив, содержащий координаты X точек многоугольника
                              int         &array_y[],                   // Массив, содержащий координаты 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.DrawPolygonFillOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует закрашенный эллипс, вписанный в прямоугольник с заданными координатами с сохранением и восстановлением фона
   bool              DrawEllipseFillOnBG(const int id,                  // Идентификатор кадра
                              const int   x1,                           // Координата X левого верхнего угла, определяющего прямоугольник
                              const int   y1,                           // Координата Y левого верхнего угла, определяющего прямоугольник
                              const int   x2,                           // Координата X правого нижнего угла, определяющего прямоугольник
                              const int   y2,                           // Координата 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.DrawEllipseFillOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует точку с использованием алгоритма сглаживания AntiAliasing с сохранением и восстановлением фона
   bool              SetPixelAAOnBG(const int id,                       // Идентификатор кадра
                              const double x,                           // Координата X точки
                              const double y,                           // Координата 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.SetPixelAAOnBG(id,x,y,clr,opacity,create_new,redraw) : false);  }
                       
//--- Рисует отрезок произвольной линии с использованием алгоритма сглаживания AntiAliasing с сохранением и восстановлением фона
   bool              DrawLineAAOnBG(const int id,                       // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineAAOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Рисует отрезок произвольной линии с использованием алгоритма сглаживания Wu с сохранением и восстановлением фона
   bool              DrawLineWuOnBG(const int id,                       // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineWuOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Рисует отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией с сохранением и восстановлением фона
   bool              DrawLineThickOnBG(const int id,                    // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const int   size,                         // Толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              ENUM_LINE_END end_style=LINE_END_ROUND)   // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickOnBG(id,x1,y1,x2,y2,size,clr,opacity,create_new,redraw,style,end_style) : false);  }
                       
//--- Рисует вертикальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией с сохранением и восстановлением фона
   bool              DrawLineThickVerticalOnBG(const int id,            // Идентификатор кадра
                              const int   x,                            // Координата X отрезка
                              const int   y1,                           // Координата Y первой точки отрезка
                              const int   y2,                           // Координата Y второй точки отрезка
                              const int   size,                         // толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END end_style=LINE_END_ROUND) // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickVerticalOnBG(id,x,y1,y2,size,clr,opacity,create_new,redraw,style,end_style) : false);  }
                       
//--- Рисует горизонтальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией с сохранением и восстановлением фона
   bool              DrawLineThickHorizontalOnBG(const int id,          // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки отрезка
                              const int   x2,                           // Координата X второй точки отрезка
                              const int   y,                            // Координата Y отрезка
                              const int   size,                         // толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END end_style=LINE_END_ROUND) // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickHorizontalOnBG(id,x1,x2,y,size,clr,opacity,create_new,redraw,style,end_style) : false);  }
                       
//--- Рисует ломаную линию с использованием алгоритма сглаживания AntiAliasing с сохранением и восстановлением фона
   bool              DrawPolylineAAOnBG(const int id,                   // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек ломаной линии
                              int         &array_y[],                   // Массив координат Y точек ломаной линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineAAOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Рисует ломаную линию с использованием алгоритма сглаживания Wu с сохранением и восстановлением фона
   bool              DrawPolylineWuOnBG(const int id,                   // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек ломаной линии
                              int         &array_y[],                   // Массив координат Y точек ломаной линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineWuOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Рисует ломаную линию заданной толщины с использованием двух алгоритмов сглаживания последовательно с сохранением и восстановлением фона.
//--- Сначала на основе кривых Безье сглаживаются отдельные отрезки линии.
//--- Затем для повышения качества отрисовки к построенной из этих отрезков ломаной линии применяется растровый алгоритм сглаживания
   bool              DrawPolylineSmoothOnBG(const int id,               // Идентификатор кадра
                              const int    &array_x[],                  // Массив координат X точек ломаной линии
                              const int    &array_y[],                  // Массив координат Y точек ломаной линии
                              const int    size,                        // Толщина линии
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const double tension=0.5,                 // Значение параметра сглаживания
                              const double step=10,                     // Шаг аппроксимации
                              const bool   create_new=true,             // Флаг создания нового объекта
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END end_style=LINE_END_ROUND)// Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineSmoothOnBG(id,array_x,array_y,size,clr,opacity,tension,step,create_new,redraw,style,end_style) : false);  }
                       
//--- Рисует ломаную линию заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией с сохранением и восстановлением фона
   bool              DrawPolylineThickOnBG(const int id,                // Идентификатор кадра
                              const int     &array_x[],                 // Массив координат X точек ломаной линии
                              const int     &array_y[],                 // Массив координат Y точек ломаной линии
                              const int     size,                       // Толщина линии
                              const color   clr,                        // Цвет
                              const uchar   opacity=255,                // Непрозрачность
                              const bool    create_new=true,            // Флаг создания нового объекта
                              const bool    redraw=false,               // Флаг перерисовки чарта
                              const uint    style=STYLE_SOLID,          // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              ENUM_LINE_END end_style=LINE_END_ROUND)   // Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineThickOnBG(id,array_x,array_y,size,clr,opacity,create_new,redraw,style,end_style) : false);  }
                       
//--- Рисует многоугольник с использованием алгоритма сглаживания AntiAliasing с сохранением и восстановлением фона
   bool              DrawPolygonAAOnBG(const int id,                    // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек многоугольника
                              int         &array_y[],                   // Массив координат Y точек многоугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonAAOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Рисует многоугольник с использованием алгоритма сглаживания Wu с сохранением и восстановлением фона
   bool              DrawPolygonWuOnBG(const int id,                    // Идентификатор кадра
                              int         &array_x[],                   // Массив координат X точек многоугольника
                              int         &array_y[],                   // Массив координат Y точек многоугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonWuOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Рисует  многоугольник заданной толщины с использованием двух алгоритмов сглаживания последовательно с сохранением и восстановлением фона.
//--- Сначала на основе кривых Безье сглаживаются отдельные отрезки.
//--- Затем для повышения качества отрисовки к построенному из этих отрезков многоугольнику применяется растровый алгоритм сглаживания. 
   bool              DrawPolygonSmoothOnBG(const int id,                // Идентификатор кадра
                              int          &array_x[],                  // Массив координат X точек ломаной линии
                              int          &array_y[],                  // Массив координат Y точек ломаной линии
                              const int    size,                        // Толщина линии
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const double tension=0.5,                 // Значение параметра сглаживания
                              const double step=10,                     // Шаг аппроксимации
                              const bool   create_new=true,             // Флаг создания нового объекта
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const ENUM_LINE_STYLE style=STYLE_SOLID,  // Стиль линии — одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                              const ENUM_LINE_END end_style=LINE_END_ROUND)// Стиль концов линии — одно из значений перечисления ENUM_LINE_END
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonSmoothOnBG(id,array_x,array_y,size,clr,opacity,tension,step,create_new,redraw,style,end_style) : false);  }
                       
//--- Рисует многоугольник заданной толщины с использованием алгоритма сглаживания с предварительной фильтрацией с сохранением и восстановлением фона
   bool              DrawPolygonThickOnBG(const int id,                 // Идентификатор кадра
                              const int   &array_x[],                   // массив координат X точек многоугольника
                              const int   &array_y[],                   // массив координат Y точек многоугольника
                              const int   size,                         // толщина линии
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=STYLE_SOLID,            // стиль линии
                              ENUM_LINE_END end_style=LINE_END_ROUND)   // стиль концов линии
                       { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonThickOnBG(id,array_x,array_y,size,clr,opacity,create_new,redraw,style,end_style) : false);  }
                       
//--- Рисует треугольник с использованием алгоритма сглаживания AntiAliasing с сохранением и восстановлением фона
   bool              DrawTriangleAAOnBG(const int id,                   // Идентификатор кадра
                              const int   x1,                           // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата Y третьей вершины треугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleAAOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Рисует треугольник с использованием алгоритма сглаживания Wu с сохранением и восстановлением фона
   bool              DrawTriangleWuOnBG(const int id,                   // Идентификатор кадра
                              const int   x1,                           // Координата X первой вершины треугольника
                              const int   y1,                           // Координата Y первой вершины треугольника
                              const int   x2,                           // Координата X второй вершины треугольника
                              const int   y2,                           // Координата Y второй вершины треугольника
                              const int   x3,                           // Координата X третьей вершины треугольника
                              const int   y3,                           // Координата Y третьей вершины треугольника
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleWuOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Рисует окружность с использованием алгоритма сглаживания AntiAliasing с сохранением и восстановлением фона
   bool              DrawCircleAAOnBG(const int id,                     // Идентификатор кадра
                              const int    x,                           // Координата X центра окружности
                              const int    y,                           // Координата Y центра окружности
                              const double r,                           // Радиус окружности
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const bool   create_new=true,             // Флаг создания нового объекта
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const uint   style=UINT_MAX)              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawCircleAAOnBG(id,x,y,r,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Рисует окружность с использованием алгоритма сглаживания Wu с сохранением и восстановлением фона
   bool              DrawCircleWuOnBG(const int id,                     // Идентификатор кадра
                              const int    x,                           // Координата X центра окружности
                              const int    y,                           // Координата Y центра окружности
                              const double r,                           // Радиус окружности

                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const bool   create_new=true,             // Флаг создания нового объекта
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const uint   style=UINT_MAX)              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawCircleWuOnBG(id,x,y,r,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Рисует эллипс по двум точкам с использованием алгоритма сглаживания AntiAliasing с сохранением и восстановлением фона
   bool              DrawEllipseAAOnBG(const int id,                    // Идентификатор кадра
                              const double x1,                          // Координата X первой точки, определяющей эллипс
                              const double y1,                          // Координата Y первой точки, определяющей эллипс
                              const double x2,                          // Координата X второй точки, определяющей эллипс
                              const double y2,                          // Координата Y второй точки, определяющей эллипс
                              const color  clr,                         // Цвет
                              const uchar  opacity=255,                 // Непрозрачность
                              const bool   create_new=true,             // Флаг создания нового объекта
                              const bool   redraw=false,                // Флаг перерисовки чарта
                              const uint   style=UINT_MAX)              // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseAAOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false);  }
                       
//--- Рисует эллипс по двум точкам с использованием алгоритма сглаживания Wu с сохранением и восстановлением фона
   bool              DrawEllipseWuOnBG(const int id,                    // Идентификатор кадра
                              const int   x1,                           // Координата X первой точки, определяющей эллипс
                              const int   y1,                           // Координата Y первой точки, определяющей эллипс
                              const int   x2,                           // Координата X второй точки, определяющей эллипс
                              const int   y2,                           // Координата Y второй точки, определяющей эллипс
                              const color clr,                          // Цвет
                              const uchar opacity=255,                  // Непрозрачность
                              const bool  create_new=true,              // Флаг создания нового объекта
                              const bool  redraw=false,                 // Флаг перерисовки чарта
                              const uint  style=UINT_MAX)               // Стиль линии - одно из значений перечисления ENUM_LINE_STYLE или пользовательское значение
                       { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseWuOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false);  }
                       
//+------------------------------------------------------------------+

Все методы возвращают результат работы соответствующих методов из объекта анимаций CAnimations, созданного нами выше.

В деструкторе класса удалим объект анимаций:

//+------------------------------------------------------------------+
//| Деструктор                                                       |
//+------------------------------------------------------------------+
CForm::~CForm()
  {
   if(this.m_shadow_obj!=NULL)
      delete this.m_shadow_obj;
   if(this.m_animations!=NULL)
      delete this.m_animations;
  }
//+------------------------------------------------------------------+

В методе инициализации создадим новый объект анимациий:

//+------------------------------------------------------------------+
//| Инициализирует переменные                                        |
//+------------------------------------------------------------------+
void CForm::Initialize(void)
  {
   this.m_list_elements.Clear();
   this.m_list_elements.Sort();
   this.m_shadow_obj=NULL;
   this.m_shadow=false;
   this.m_frame_width_right=2;
   this.m_frame_width_left=2;
   this.m_frame_width_top=2;
   this.m_frame_width_bottom=2;
   this.m_animations=new CAnimations(CGCnvElement::GetObject());
  }
//+------------------------------------------------------------------+

Теперь при создании нового объекта-формы, для неё будет автоматически создаваться и объект анимаций, в который можно будет динамически добавлять новые кадры анимаций, либо создавать предопределённые при создании формы. По окончании работы программы, объект анимаций будет уничтожаться для избежания утечек памяти.

У нас всё готово для тестирования созданных классов.

Что и как будем тестировать. У нас есть тестовый советник, в котором рисуются четыре формы. В четвёртой — нижней форме при щелчке на ней у нас перемещается надпись "H-Gradient", указывающая на способ заливки (горизонтальная). Эту надпись мы теперь будем создавать и перемещать как объект-кадр текстовой анимации. Третья форма — с вертикальной заливкой — у нас будет использоваться для вывода различных рисуемых фигур. Но перед тем, как рисовать фигуру, мы сначала выведем на форму текст в виде текстового кадра анимации. Поверх него будем рисовать фигуры. Переключение типов рисуемых фигур организуем путём нажатия на клавиши клавиатуры, а текст будет отображать выбранную рисуемую фигуру. Каждый щелчок мышки по форме будет изменять координаты точек рисуемой фигуры.

Тестирование

Для тестирования возьмём советник из прошлой статьи и сохраним его в новой папке \MQL5\Experts\TestDoEasy\Part79\ под новым именем TestDoEasyPart79.mq5.

В области глобальных переменных впишем макроподстановки для указания начальных координат рисуемых фигур и объявим переменные для хранения координат разных точек рисуемых фигур (всего будем использовать пять точек) и величин их изменения:

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart79.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
//--- includes
#include <Arrays\ArrayObj.mqh>
#include <DoEasy\Services\Select.mqh>
#include <DoEasy\Objects\Graph\Form.mqh>
//--- defines
#define        FORMS_TOTAL (4)   // Количество создаваемых форм
#define        START_X     (4)   // Начальная координата X фигуры
#define        START_Y     (4)   // Начальная координата Y фигуры
//--- input parameters
sinput   bool              InpMovable     =  true;          // Movable forms flag
sinput   ENUM_INPUT_YES_NO InpUseColorBG  =  INPUT_YES;     // Use chart background color to calculate shadow color
sinput   color             InpColorForm3  =  clrCadetBlue;  // Third form shadow color (if not background color) 
//--- global variables
CArrayObj      list_forms;  
color          array_clr[];
int nx1=0, ny1=0, nx2=0, ny2=0, nx3=0, ny3=0, nx4=0, ny4=0, nx5=0, ny5=0;
int coordX1=START_X+nx1;
int coordY1=START_Y+ny1;
int coordX2=START_X+nx2*2;
int coordY2=START_Y+ny2*2;
int coordX3=START_X+nx3*3;
int coordY3=START_Y+ny3*3;
int coordX4=START_X+nx4*4;
int coordY4=START_Y+ny4*4;
int coordX5=START_X+nx5*5;
int coordY5=START_Y+ny5*5;
double RD=1;
//+------------------------------------------------------------------+

В обработчике OnInit() в блоках создания двух последних форм теперь текст создавать будем при помощи объектов-текстовых анимаций:

      //--- Если это третья форма
      if(i==2)
        {
         //--- Установим непрозрачность 200
         form.SetOpacity(200);
         //--- Цвет фона формы зададим как первый цвет из массива цветов
         form.SetColorBackground(array_clr[0]);
         //--- Цвет очерчивающей рамки формы
         form.SetColorFrame(clrDarkBlue);
         //--- Установим флаг рисования тени
         form.SetShadow(true);
         //--- Рассчитаем цвет тени как цвет фона графика, преобразованный в монохромный
         color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100);
         //--- Если в настройках задано использовать цвет фона графика, то затемним монохромный цвет на 20 единиц
         //--- Иначе - будем использовать для рисования тени заданный в настройках цвет
         color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3);
         //--- Нарисуем тень формы со смещением от формы вправо-вниз на три пикселя по всем осям
         //--- Непрозрачность тени при этом установим равной 200, а радиус размытия равный 4
         form.DrawShadow(3,3,clr,200,4);
         //--- Зальём фон формы вертикальным градиентом
         form.Erase(array_clr,form.Opacity());
         //--- Нарисуем очерчивающий прямоугольник по краям формы
         form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity());
         
         //--- Выведем текст с описанием типа градиента и обновим форму
         //--- Параметры текста: координаты текста в центре формы и точка привязки - тоже по центру
         //--- Создаём новый кадр текстовой анимации с идентификатором 0 и выводим текст на форму
         form.TextOnBG(0,TextByLanguage("V-Градиент","V-Gradient"),form.Width()/2,form.Height()/2,TEXT_ANCHOR_CENTER,C'211,233,149',255,true,false);
        }
      //--- Если это четвёртая (нижняя) форма
      if(i==3)
        {
         //--- Установим непрозрачность 200
         form.SetOpacity(200);
         //--- Цвет фона формы зададим как первый цвет из массива цветов
         form.SetColorBackground(array_clr[0]);
         //--- Цвет очерчивающей рамки формы
         form.SetColorFrame(clrDarkBlue);
         //--- Установим флаг рисования тени
         form.SetShadow(true);
         //--- Рассчитаем цвет тени как цвет фона графика, преобразованный в монохромный
         color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100);
         //--- Если в настройках задано использовать цвет фона графика, то заемним монохромный цвет на 20 единиц
         //--- Иначе - будем использовать для рисования тени заданный в настройках цвет
         color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3);
         //--- Нарисуем тень формы со смещением от формы вправо-вниз на три пикселя по всем осям
         //--- Непрозрачность тени при этом установим равной 200, а радиус размытия равный 4
         form.DrawShadow(3,3,clr,200,4);
         //--- Зальём фон формы горизонтальным градиентом
         form.Erase(array_clr,form.Opacity(),false);
         //--- Нарисуем очерчивающий прямоугольник по краям формы
         form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity());
         
         //--- Выведем текст с описанием типа градиента и обновим форму
         //--- Параметры текста: координаты текста в центре формы и точка привязки - тоже по центру
         //--- Создаём новый кадр текстовой анимации с идентификатором 0 и выводим текст на форму
         form.TextOnBG(0,TextByLanguage("H-Градиент","H-Gradient"),form.Width()/2,form.Height()/2,TEXT_ANCHOR_CENTER,C'211,233,149',255,true,true);
        }
      //--- Добавим объекты в список

Эти текстовые объекты здесь мы создали заранее. Рисуемые же фигуры будем создавать динамически — по щелчку мышки в области формы.

Для обработки нажатий на клавиши клавиатуры, добавим в обработчик OnChartEvent() такой блок кода:

//--- Режим рисования в зависимости от нажатой клавиши клавиатуры
   static ENUM_FIGURE_TYPE figure_type_prev=WRONG_VALUE;
   static ENUM_FIGURE_TYPE figure_type=figure_type_prev;
   string figure=FigureTypeDescription(figure_type);
//--- Если нажатие на клавишу клавиатуры
   if(id==CHARTEVENT_KEYDOWN)
     {
      //--- В зависимости от нажатой клавиши получим тип рисуемой фигуры
      figure_type=FigureType(lparam);
      //--- Если тип фигуры сменился
      if(figure_type!=figure_type_prev)
        {
         //--- Получим текст описания типа рисуемой фигуры
         figure=FigureTypeDescription(figure_type);
         //--- В цикле по всем формам 
         for(int i=0;i<list_forms.Total();i++)
           {
            //--- получим указатель на очередной объект-форму
            CForm *form=list_forms.At(i);
            if(form==NULL)
               continue;
            //--- Если идентификатор формы 2
            if(form.ID()==2)
              {
               //--- Сбросим все смещения координат в ноль и выведем текст с описанием типа рисуемой фигуры
               nx1=ny1=nx2=ny2=nx3=ny3=nx4=ny4=nx5=ny5=0;
               form.TextOnBG(0,figure,form.TextLastX(),form.TextLastY(),form.TextAnchor(),C'211,233,149',255,false,true);
              }
           }
         //--- Запишем новый тип фигуры
         figure_type_prev=figure_type;
        }
     }
  
//--- Если щелчок по объекту

Немного изменим код в блоке обработки щелчков по формам — теперь текст будем выводить при помощи объектов-текстовых анимаций той формы, по которой был щелчок:

//--- Если щелчок по объекту
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Если объект, по которому был щелчок, принадлежит советнику
      if(StringFind(sparam,MQLInfoString(MQL_PROGRAM_NAME))==0)
        {
         //--- Получим из его имени идентификатор объекта
         int form_id=(int)StringToInteger(StringSubstr(sparam,StringLen(sparam)-1))-1;
         //--- Найдём этот объект-форму в цикле по всем созданным в советнике формам
         for(int i=0;i<list_forms.Total();i++)
           {
            CForm *form=list_forms.At(i);
            if(form==NULL)
               continue;
            //--- Если объект, по которому был щелчок, имеет идентификатор 2 и форма имеет такой же идентификатор
            if(form_id==2 && form.ID()==2)
              {
               //--- Обработаем щелчок по форме - нарисуем соответствующую фигуру
               FigureProcessing(form,figure_type);
              }
            
            //--- Если объект, по которому был щелчок, имеет идентификатор 3 и форма имеет такой же идентификатор
            if(form_id==3 && form.ID()==3)
              {
               ////--- Возьмём точку привязки у последнего нарисованного текста
               ENUM_TEXT_ANCHOR anchor=form.TextAnchor();
               ////--- Получим координаты последнего нарисованного текста
               int text_x=form.TextLastX();
               int text_y=form.TextLastY();
               //--- Установим стартовую точку привязки текста (0 = LEFT_TOP) из девяти возможных
               static int n=0;
               //--- В зависимости от переменной n установим новую точку привязки текста
               switch(n)
                 {
                  case 0 : anchor=TEXT_ANCHOR_LEFT_TOP;     text_x=1;               text_y=1;               break;
                  case 1 : anchor=TEXT_ANCHOR_CENTER_TOP;   text_x=form.Width()/2;  text_y=1;               break;
                  case 2 : anchor=TEXT_ANCHOR_RIGHT_TOP;    text_x=form.Width()-2;  text_y=1;               break;
                  case 3 : anchor=TEXT_ANCHOR_LEFT_CENTER;  text_x=1;               text_y=form.Height()/2; break;
                  case 4 : anchor=TEXT_ANCHOR_CENTER;       text_x=form.Width()/2;  text_y=form.Height()/2; break;
                  case 5 : anchor=TEXT_ANCHOR_RIGHT_CENTER; text_x=form.Width()-2;  text_y=form.Height()/2; break;
                  case 6 : anchor=TEXT_ANCHOR_LEFT_BOTTOM;  text_x=1;               text_y=form.Height()-2; break;
                  case 7 : anchor=TEXT_ANCHOR_CENTER_BOTTOM;text_x=form.Width()/2;  text_y=form.Height()-2; break;
                  case 8 : anchor=TEXT_ANCHOR_RIGHT_BOTTOM; text_x=form.Width()-2;  text_y=form.Height()-2; break;
                  default: anchor=TEXT_ANCHOR_CENTER;       text_x=form.Width()/2;  text_y=form.Height()/2; break;
                 }
               form.TextOnBG(0,TextByLanguage("H-Градиент","H-Gradient"),text_x,text_y,anchor,C'211,233,149',255,true,true);
               //--- Увеличим счётчик щелчков по объекту (и по совместительству - указатель на точку привязки текста),
               //--- и если значение больше 8, то сбросим значение в ноль (от 0 до 8 = девять точек привязки)
               n++;
               if(n>8) n=0;
              }
           }
        }
     }

Щелчок по третьей форме (с идентификатором 2) будем обрабатывать в функции FigureProcessing(), при щелчке по четвёртой форме (с идентификатором 3), как и ранее, будем определять угол привязки текста в зависимости от значения переменной n и выводить текст. Но текст теперь будем выводить при помощи класса объекта-кадра текстовой анимации.

Вспомогательная функция, возвращающая тип фигуры в зависимости от нажатой кнопки клавиатуры:

//+------------------------------------------------------------------+
//| Возвращает фигуру в зависимости от нажатой кнопки клавиатуры     |
//+------------------------------------------------------------------+
ENUM_FIGURE_TYPE FigureType(const long key_code)
  {
   switch((int)key_code)
     {
      //--- Клавиша "1" = Точка
      case 49  :  return FIGURE_TYPE_PIXEL;
      
      //--- Клавиша "2" = Точка со сглаживанием AntiAlliasing
      case 50  :  return FIGURE_TYPE_PIXEL_AA;
      
      //--- Клавиша "3" = Вертикальная линия
      case 51  :  return FIGURE_TYPE_LINE_VERTICAL;
      
      //--- Клавиша "4" = Вертикальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания
      case 52  :  return FIGURE_TYPE_LINE_VERTICAL_THICK;
      
      //--- Клавиша "5" = Горизонтальная линия
      case 53  :  return FIGURE_TYPE_LINE_HORIZONTAL;
      
      //--- Клавиша "6" = Горизонтальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания
      case 54  :  return FIGURE_TYPE_LINE_HORIZONTAL_THICK;
      
      //--- Клавиша "7" = Произвольная линия
      case 55  :  return FIGURE_TYPE_LINE;
      
      //--- Клавиша "8" = Линия со сглаживанием AntiAlliasing
      case 56  :  return FIGURE_TYPE_LINE_AA;
      
      //--- Клавиша "9" = Линия со сглаживанием WU
      case 57  :  return FIGURE_TYPE_LINE_WU;
      
      //--- Клавиша "0" = Отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания
      case 48  :  return FIGURE_TYPE_LINE_THICK;
      
      //--- Клавиша "q" = Ломаная линия
      case 81  :  return FIGURE_TYPE_POLYLINE;
      
      //--- Клавиша "w" = Ломаная линия со сглаживанием AntiAlliasing
      case 87  :  return FIGURE_TYPE_POLYLINE_AA;
      
      //--- Клавиша "e" = Ломаная линия со сглаживанием WU
      case 69  :  return FIGURE_TYPE_POLYLINE_WU;
      
      //--- Клавиша "r" = Ломаная линия заданной толщины с использованием двух алгоритмов сглаживания
      case 82  :  return FIGURE_TYPE_POLYLINE_SMOOTH;
      
      //--- Клавиша "t" = Ломаная линия заданной толщины с использованием алгоритма сглаживания
      case 84  :  return FIGURE_TYPE_POLYLINE_THICK;
      
      //--- Клавиша "y" = Многоугольник
      case 89  :  return FIGURE_TYPE_POLYGON;
      
      //--- Клавиша "u" = Закрашенный многоугольник
      case 85  :  return FIGURE_TYPE_POLYGON_FILL;
      
      //--- Клавиша "i" = Многоугольник со сглаживанием AntiAlliasing
      case 73  :  return FIGURE_TYPE_POLYGON_AA;
      
      //--- Клавиша "o" = Многоугольник со сглаживанием WU
      case 79  :  return FIGURE_TYPE_POLYGON_WU;
      
      //--- Клавиша "p" = Многоугольник заданной толщины с использованием двух алгоритмов сглаживания
      case 80  :  return FIGURE_TYPE_POLYGON_SMOOTH;
      
      //--- Клавиша "a" = Многоугольник заданной толщины с использованием алгоритма сглаживания
      case 65  :  return FIGURE_TYPE_POLYGON_THICK;
      
      //--- Клавиша "s" = Прямоугольник
      case 83  :  return FIGURE_TYPE_RECTANGLE;
      
      //--- Клавиша "d" = Закрашенный прямоугольник
      case 68  :  return FIGURE_TYPE_RECTANGLE_FILL;
      
      //--- Клавиша "f" = Окружность
      case 70  :  return FIGURE_TYPE_CIRCLE;
      
      //--- Клавиша "g" = Закрашенный круг
      case 71  :  return FIGURE_TYPE_CIRCLE_FILL;
      
      //--- Клавиша "h" = Окружность со сглаживанием AntiAlliasing
      case 72  :  return FIGURE_TYPE_CIRCLE_AA;
      
      //--- Клавиша "j" = Окружность со сглаживанием WU
      case 74  :  return FIGURE_TYPE_CIRCLE_WU;
      
      //--- Клавиша "k" = Треугольник
      case 75  :  return FIGURE_TYPE_TRIANGLE;
      
      //--- Клавиша "l" = Закрашенный треугольник
      case 76  :  return FIGURE_TYPE_TRIANGLE_FILL;
      
      //--- Клавиша "z" = Треугольник со сглаживанием AntiAlliasing
      case 90  :  return FIGURE_TYPE_TRIANGLE_AA;
      
      //--- Клавиша "x" = Треугольник со сглаживанием WU
      case 88  :  return FIGURE_TYPE_TRIANGLE_WU;
      
      //--- Клавиша "c" = Эллипс
      case 67  :  return FIGURE_TYPE_ELLIPSE;
      
      //--- Клавиша "v" = Закрашенный эллипс
      case 86  :  return FIGURE_TYPE_ELLIPSE_FILL;
      
      //--- Клавиша "b" = Эллипс со сглаживанием AntiAlliasing
      case 66  :  return FIGURE_TYPE_ELLIPSE_AA;
      
      //--- Клавиша "n" = Эллипс со сглаживанием WU
      case 78  :  return FIGURE_TYPE_ELLIPSE_WU;
      
      //--- Клавиша "m" = Дуга эллипса
      case 77  :  return FIGURE_TYPE_ARC;
      
      //--- Клавиша "," = Сектор эллипса
      case 188 :  return FIGURE_TYPE_PIE;
      
      //--- По умолчанию = Точка
      default  :  return FIGURE_TYPE_PIXEL;
     }
  }
//+------------------------------------------------------------------+

Функция, в которой обрабатываем щелчок по объекту-форме, достаточно большая. Вернее — простая, но объёмная, потому, что в ней просто в операторе switch обрабатывается каждая нажатая кнопка, которой соответствует рисуемая форма. Обработка простая — задаём начальные координаты, проверяем их на предмет выхода за допустимые рамки значений, рисуем фигуру с этими параметрами и увеличиваем смещения величин параметров. При следующем щелчке по форме прошлая фигура будет затёрта восстановленным фоном и нарисована новая в новых координатах её точек.

//+------------------------------------------------------------------+
//| Обрабатывает выбранную фигуру                                    |
//+------------------------------------------------------------------+
void FigureProcessing(CForm *form,const ENUM_FIGURE_TYPE figure_type)
  {
   int array_x[5]={0,0,0,0,0};
   int array_y[5]={0,0,0,0,0};
   switch(figure_type)
     {
   //--- Клавиша "1" = Точка
      case FIGURE_TYPE_PIXEL  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         form.SetPixelOnBG(0,coordX1,coordY1,clrWheat);
         nx1++;
         ny1++;
         break;
      
   //--- Клавиша "2" = Точка со сглаживанием AntiAlliasing
      case FIGURE_TYPE_PIXEL_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         form.SetPixelAAOnBG(0,coordX1,coordY1,clrWheat);
         nx1++;
         ny1++;
         break;
      
   //--- Клавиша "3" = Вертикальная линия
      case FIGURE_TYPE_LINE_VERTICAL  :
         coordX1=START_X+nx1;
         coordY1=START_Y;
         coordY2=form.Height()-START_Y-1;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         form.DrawLineVerticalOnBG(0,coordX1,coordY1,coordY2,clrWheat);
         nx1++;
         break;
      
   //--- Клавиша "4" = Вертикальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания
      case FIGURE_TYPE_LINE_VERTICAL_THICK  :
         coordX1=START_X+nx1;
         coordY1=START_Y;
         coordY2=form.Height()-START_Y-1;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         form.DrawLineThickVerticalOnBG(0,coordX1,coordY1,coordY2,5,clrWheat,255,true,false,STYLE_SOLID,LINE_END_SQUARE);
         nx1++;
         break;
      
   //--- Клавиша "5" = Горизонтальная линия
      case FIGURE_TYPE_LINE_HORIZONTAL :
         coordX1=START_X;
         coordX2=form.Width()-START_X-1;
         coordY1=START_Y+ny1;
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         form.DrawLineHorizontalOnBG(0,coordX1,coordX2,coordY1,clrWheat);
         ny1++;
         break;
         
   //--- Клавиша "6" = Горизонтальный отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания
      case FIGURE_TYPE_LINE_HORIZONTAL_THICK  :
         coordX1=START_X;
         coordX2=form.Width()-START_X-1;
         coordY1=START_Y+ny1;
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         form.DrawLineThickHorizontalOnBG(0,coordX1,coordX2,coordY1,5,clrWheat,255,true,false,STYLE_SOLID,LINE_END_ROUND);
         ny1++;
         break;
      
   //--- Клавиша "7" = Произвольная линия
      case FIGURE_TYPE_LINE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawLineOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Клавиша "8" = Линия со сглаживанием AntiAlliasing
      case FIGURE_TYPE_LINE_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawLineAAOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Клавиша "9" = Линия со сглаживанием WU
      case FIGURE_TYPE_LINE_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawLineWuOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Клавиша "0" = Отрезок произвольной линии заданной толщины с использованием алгоритма сглаживания
      case FIGURE_TYPE_LINE_THICK  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawLineThickOnBG(0,coordX1,coordY1,coordX2,coordY2,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_SQUARE);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Клавиша "q" = Ломаная линия
      case FIGURE_TYPE_POLYLINE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Заполняем массивы значениями координат
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- проверяем координаты x1, y1 на выход за пределы формы
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- проверяем координаты x2, y2 на выход за пределы формы
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- проверяем координаты x3, y3 на выход за пределы формы
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- проверяем координаты x4, y4 на выход за пределы формы
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- проверяем координаты x5, y5 на выход за пределы формы
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Рисуем фигуру
         form.DrawPolylineOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- Клавиша "w" = Ломаная линия со сглаживанием AntiAlliasing
      case FIGURE_TYPE_POLYLINE_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Заполняем массивы значениями координат
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- проверяем координаты x1, y1 на выход за пределы формы
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- проверяем координаты x2, y2 на выход за пределы формы
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- проверяем координаты x3, y3 на выход за пределы формы
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- проверяем координаты x4, y4 на выход за пределы формы
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- проверяем координаты x5, y5 на выход за пределы формы
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Рисуем фигуру
         form.DrawPolylineAAOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- Клавиша "e" = Ломаная линия со сглаживанием WU
      case FIGURE_TYPE_POLYLINE_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Заполняем массивы значениями координат
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- проверяем координаты x1, y1 на выход за пределы формы
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- проверяем координаты x2, y2 на выход за пределы формы
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- проверяем координаты x3, y3 на выход за пределы формы
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- проверяем координаты x4, y4 на выход за пределы формы
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- проверяем координаты x5, y5 на выход за пределы формы
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Рисуем фигуру
         form.DrawPolylineWuOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- Клавиша "r" = Ломаная линия заданной толщины с использованием двух алгоритмов сглаживания
      case FIGURE_TYPE_POLYLINE_SMOOTH  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Заполняем массивы значениями координат
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- проверяем координаты x1, y1 на выход за пределы формы
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- проверяем координаты x2, y2 на выход за пределы формы
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- проверяем координаты x3, y3 на выход за пределы формы
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- проверяем координаты x4, y4 на выход за пределы формы
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- проверяем координаты x5, y5 на выход за пределы формы
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Рисуем фигуру
         form.DrawPolylineSmoothOnBG(0,array_x,array_y,1,clrWheat,255,0.5,30.0,true,false,STYLE_SOLID,LINE_END_BUTT);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- Клавиша "t" = Ломаная линия заданной толщины с использованием алгоритма сглаживания
      case FIGURE_TYPE_POLYLINE_THICK  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Заполняем массивы значениями координат
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- проверяем координаты x1, y1 на выход за пределы формы
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- проверяем координаты x2, y2 на выход за пределы формы
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- проверяем координаты x3, y3 на выход за пределы формы
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- проверяем координаты x4, y4 на выход за пределы формы
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- проверяем координаты x5, y5 на выход за пределы формы
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Рисуем фигуру
         form.DrawPolylineThickOnBG(0,array_x,array_y,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_BUTT);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- Клавиша "y" = Многоугольник
      case FIGURE_TYPE_POLYGON  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Заполняем массивы значениями координат
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- проверяем координаты x1, y1 на выход за пределы формы
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- проверяем координаты x2, y2 на выход за пределы формы
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- проверяем координаты x3, y3 на выход за пределы формы
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- проверяем координаты x4, y4 на выход за пределы формы
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- проверяем координаты x5, y5 на выход за пределы формы
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Рисуем фигуру
         form.DrawPolygonOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- Клавиша "u" = Закрашенный многоугольник
      case FIGURE_TYPE_POLYGON_FILL  :
         return;
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*4;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         //--- Заполняем массивы значениями координат
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- проверяем координаты x1, y1 на выход за пределы формы
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- проверяем координаты x2, y2 на выход за пределы формы
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- проверяем координаты x3, y3 на выход за пределы формы
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- проверяем координаты x4, y4 на выход за пределы формы
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- Рисуем фигуру
         form.DrawPolygonFillOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         break;
      
   //--- Клавиша "i" = Многоугольник со сглаживанием AntiAlliasing
      case FIGURE_TYPE_POLYGON_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Заполняем массивы значениями координат
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- проверяем координаты x1, y1 на выход за пределы формы
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- проверяем координаты x2, y2 на выход за пределы формы
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- проверяем координаты x3, y3 на выход за пределы формы
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- проверяем координаты x4, y4 на выход за пределы формы
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- проверяем координаты x5, y5 на выход за пределы формы
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Рисуем фигуру
         form.DrawPolygonAAOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- Клавиша "o" = Многоугольник со сглаживанием WU
      case FIGURE_TYPE_POLYGON_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Заполняем массивы значениями координат
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- проверяем координаты x1, y1 на выход за пределы формы
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- проверяем координаты x2, y2 на выход за пределы формы
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- проверяем координаты x3, y3 на выход за пределы формы
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- проверяем координаты x4, y4 на выход за пределы формы
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- проверяем координаты x5, y5 на выход за пределы формы
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Рисуем фигуру
         form.DrawPolygonWuOnBG(0,array_x,array_y,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- Клавиша "p" = Многоугольник заданной толщины с использованием двух алгоритмов сглаживания
      case FIGURE_TYPE_POLYGON_SMOOTH  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Заполняем массивы значениями координат
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- проверяем координаты x1, y1 на выход за пределы формы
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- проверяем координаты x2, y2 на выход за пределы формы
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- проверяем координаты x3, y3 на выход за пределы формы
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- проверяем координаты x4, y4 на выход за пределы формы
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- проверяем координаты x5, y5 на выход за пределы формы
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Рисуем фигуру
         form.DrawPolygonSmoothOnBG(0,array_x,array_y,3,clrWheat,255,0.5,10.0,true,false,STYLE_SOLID,LINE_END_BUTT);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- Клавиша "a" = Многоугольник заданной толщины с использованием алгоритма сглаживания
      case FIGURE_TYPE_POLYGON_THICK  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*8;
         coordY2=coordY1;
         coordX3=coordX2;
         coordY3=coordY2+ny3*2;
         coordX4=coordX1;
         coordY4=coordY3;
         coordX5=coordX1;
         coordY5=coordY1;
         //--- Заполняем массивы значениями координат
         array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5;
         array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5;
         //--- проверяем координаты x1, y1 на выход за пределы формы
         if(array_x[0]>form.Width()-START_X-1)
           {
            nx1=0;
            array_x[0]=START_X;
           }
         if(array_y[0]>form.Height()-START_Y-1)
           {
            ny1=0;
            array_y[0]=START_Y;
           }
         //--- проверяем координаты x2, y2 на выход за пределы формы
         if(array_x[1]>form.Width()-START_X-1)
           {
            nx2=0;
            array_x[1]=START_X;
           }
         if(array_y[1]>form.Height()-START_Y-1)
           {
            ny2=0;
            array_y[1]=array_y[0];
           }
         //--- проверяем координаты x3, y3 на выход за пределы формы
         if(array_x[2]>form.Width()-START_X-1)
           {
            nx3=0;
            array_x[2]=array_x[1];
           }
         if(array_y[2]>form.Height()-START_Y-1)
           {
            ny3=0;
            array_y[2]=array_y[1];
           }
         //--- проверяем координаты x4, y4 на выход за пределы формы
         if(array_x[3]>form.Width()-START_X-1)
           {
            nx4=0;
            array_x[3]=START_X;
           }
         if(array_y[3]>form.Height()-START_Y-1)
           {
            ny4=0;
            array_y[3]=array_y[2];
           }
         //--- проверяем координаты x5, y5 на выход за пределы формы
         if(array_x[4]>form.Height()-START_X-1)
           {
            nx5=0;
            array_x[4]=array_x[0];
           }
         if(array_y[4]>form.Height()-START_Y-1)
           {
            ny5=0;
            array_y[4]=array_y[0];
           }
         //--- Рисуем фигуру
         form.DrawPolygonThickOnBG(0,array_x,array_y,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_BUTT);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         nx4++;
         ny4++;
         nx5++;
         ny5++;
         break;
      
   //--- Клавиша "s" = Прямоугольник
      case FIGURE_TYPE_RECTANGLE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawRectangleOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Клавиша "d" = Закрашенный прямоугольник
      case FIGURE_TYPE_RECTANGLE_FILL  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawRectangleFillOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Клавиша "f" = Окружность
      case FIGURE_TYPE_CIRCLE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         RD=nx2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(RD>form.Height()/2)
           {
            nx2=0;
            RD=1;
           }
         form.DrawCircleOnBG(0,coordX1,coordY1,(int)RD,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         break;
      
   //--- Клавиша "g" = Закрашенный круг
      case FIGURE_TYPE_CIRCLE_FILL  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         RD=nx2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(RD>form.Height()/2)
           {
            nx2=0;
            RD=1;
           }
         form.DrawCircleFillOnBG(0,coordX1,coordY1,(int)RD,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         break;
      
   //--- Клавиша "h" = Окружность со сглаживанием AntiAlliasing
      case FIGURE_TYPE_CIRCLE_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         RD=nx2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(RD>form.Height()/2)
           {
            nx2=0;
            RD=1;
           }
         form.DrawCircleAAOnBG(0,coordX1,coordY1,RD,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         break;
      
   //--- Клавиша "j" = Окружность со сглаживанием WU
      case FIGURE_TYPE_CIRCLE_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         RD=nx2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(RD>form.Height()/2)
           {
            nx2=0;
            RD=1;
           }
         form.DrawCircleWuOnBG(0,coordX1,coordY1,RD,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         break;
      
   //--- Клавиша "k" = Треугольник
      case FIGURE_TYPE_TRIANGLE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*4;
         coordY2=START_Y+ny2*2;
         coordX3=coordX1+nx3*2;
         coordY3=coordY2+ny3*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
           
         if(coordX3>form.Width()-START_X-1)
           {
            nx3=0;
            coordX3=START_X;
           }
         if(coordY3>form.Height()-START_Y-1)
           {
            ny3=0;
            coordY3=START_Y;
           }
         form.DrawTriangleOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         break;
      
   //--- Клавиша "l" = Закрашенный треугольник
      case FIGURE_TYPE_TRIANGLE_FILL  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*4;
         coordY2=START_Y+ny2*2;
         coordX3=coordX1+nx3*2;
         coordY3=coordY2+ny3*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
           
         if(coordX3>form.Width()-START_X-1)
           {
            nx3=0;
            coordX3=START_X;
           }
         if(coordY3>form.Height()-START_Y-1)
           {
            ny3=0;
            coordY3=START_Y;
           }
         form.DrawTriangleFillOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         break;
      
   //--- Клавиша "z" = Треугольник со сглаживанием AntiAlliasing
      case FIGURE_TYPE_TRIANGLE_AA  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*4;
         coordY2=START_Y+ny2*2;
         coordX3=coordX1+nx3*2;
         coordY3=coordY2+ny3*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
           
         if(coordX3>form.Width()-START_X-1)
           {
            nx3=0;
            coordX3=START_X;
           }
         if(coordY3>form.Height()-START_Y-1)
           {
            ny3=0;
            coordY3=START_Y;
           }
         form.DrawTriangleAAOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         break;
      
   //--- Клавиша "x" = Треугольник со сглаживанием WU
      case FIGURE_TYPE_TRIANGLE_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*4;
         coordY2=START_Y+ny2*2;
         coordX3=coordX1+nx3*2;
         coordY3=coordY2+ny3*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
           
         if(coordX3>form.Width()-START_X-1)
           {
            nx3=0;
            coordX3=START_X;
           }
         if(coordY3>form.Height()-START_Y-1)
           {
            ny3=0;
            coordY3=START_Y;
           }
         form.DrawTriangleWuOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         nx3++;
         ny3++;
         break;
      
   //--- Клавиша "c" = Эллипс
      case FIGURE_TYPE_ELLIPSE  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawEllipseOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Клавиша "v" = Закрашенный эллипс
      case FIGURE_TYPE_ELLIPSE_FILL  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=START_X+nx2*2;
         coordY2=START_Y+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawEllipseFillOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Клавиша "b" = Эллипс со сглаживанием AntiAlliasing
      case FIGURE_TYPE_ELLIPSE_AA  :
         return;
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*2;
         coordY2=coordY1+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawEllipseAAOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Клавиша "n" = Эллипс со сглаживанием WU
      case FIGURE_TYPE_ELLIPSE_WU  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=coordX1+nx2*2;
         coordY2=coordY1+ny2*2;
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawEllipseWuOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat,255,true,false,STYLE_SOLID);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Клавиша "m" = Дуга эллипса
      case FIGURE_TYPE_ARC  :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=form.Width()-START_X-1-nx2;
         coordY2=form.Height()-START_Y-1-ny2;
         
         coordX3=coordX1;
         coordY3=coordY1;
         coordX4=coordX2;
         coordY4=coordY2;
         
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX3=coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY3=coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX4=coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY4=coordY2=START_Y;
           }
         form.DrawArcOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,coordX4,coordY4,clrWheat);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- Клавиша "," = Сектор эллипса
      case FIGURE_TYPE_PIE :
         coordX1=START_X+nx1;
         coordY1=START_Y+ny1;
         coordX2=form.Width()-START_X-1-nx2;
         coordY2=form.Height()-START_Y-1-ny2;
         
         coordX3=coordX1;
         coordY3=coordY1;
         coordX4=coordX2;
         coordY4=coordY1;
         
         if(coordX1>form.Width()-START_X-1)
           {
            nx1=0;
            coordX3=coordX1=START_X;
           }
         if(coordY1>form.Height()-START_Y-1)
           {
            ny1=0;
            coordY3=coordY4=coordY1=START_Y;
           }
         if(coordX2>form.Width()-START_X-1)
           {
            nx2=0;
            coordX4=coordX2=START_X;
           }
         if(coordY2>form.Height()-START_Y-1)
           {
            ny2=0;
            coordY2=START_Y;
           }
         form.DrawPieOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,coordX4,coordY4,clrWheat,clrLightSteelBlue);
         nx1++;
         ny1++;
         nx2++;
         ny2++;
         break;
      
   //--- По умолчанию = Ничего
      default  :
         
         break;
     }
  }
//+------------------------------------------------------------------+

Надеюсь, код этой функции прост для понимания и вопросов не вызывает. В любом случае всё можно спросить в обсуждении к статье.

Я не стал для простого теста делать общую обработку идентичных параметров. Проще и быстрее — написать всё "в лоб" прямо в кейсах оператора switch. Нам не важно, что код повторяющийся, нам важнее просто проверить работоспособность созданных классов.

Скомпилируем советник и запустим его на графике. После запуска понажимаем различные кнопки клавиатуры, чтобы убедиться, что режим рисования меняется и отображается в надписи на третьей форме. Если щёлкать по четвёртой форме, то текст будет перемещаться точно так же, как и в прошлом советнике из прошлой статьи. Вот только теперь этот текст выводится посредством класса объекта-текстового кадра анимации.

Если же мы после выбора требуемого режима рисования начнём щёлкать по третьей форме (на которой выводится надпись с описанием режима рисования), то поверх этой надписи, да и самой формы, будет рисоваться выбранная фигура с каждый раз изменяющимися значениями координат её точек.


Не все методы рисования получилось нормально сделать. Например, метод FillPolygon() класса CCanvas при заданных начальных параметрах в нашей функции обработки щелчков по объекту, просто впадает в бесконечный цикл, а метод EllipseAA() выдаёт ошибку деления на ноль. В этом методе есть  потенциальные точки, где такое может произойти:

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

Об этой проблеме я сообщил в профильной ветке. Пока нет ответа разработчиков, мы в последующих статьях попробуем обойти такие ошибки.

Исходя из вышесказанного, в обработчике щелчков мышью на объекте-форме, некоторые методы рисования не вызываются, а просто функция делает возврат. В любом случае, в дальнейшем это будет исправлено. Но сейчас мы видим, что фон под рисуемыми фигурами восстанавливается и всё выводится так, как и задумывалось. Есть проблема с переключением режимов рисования — после его переключения фон не восстанавливается. Но это уже не по причине какой-либо ошибки, а по причине отсутствия метода удаления рисунка с восстановлением фона. Это сделаем в последующих статьях, а здесь — для тестирования и примера — мы просто переключали таймфрейм, чтобы полностью восстановить фон перед выводом другой фигуры на форму.


Что дальше

В следующей статье продолжим развитие классов анимаций.

Ниже прикреплены все файлы текущей версии библиотеки и файл тестового советника для MQL5. Их можно скачать и протестировать всё самостоятельно.
При возникновении вопросов, замечаний и пожеланий, вы можете озвучить их в комментариях к статье.

К содержанию

*Статьи этой серии:

Графика в библиотеке DoEasy (Часть 73): Объект-форма графического элемента
Графика в библиотеке DoEasy (Часть 74): Базовый графический элемент на основе класса CCanvas
Графика в библиотеке DoEasy (Часть 75): Методы работы с примитивами и текстом в базовом графическом элементе
Графика в библиотеке DoEasy (Часть 76): Объект Форма и предопределённые цветовые темы
Графика в библиотеке DoEasy (Часть 77): Класс объекта Тень
Графика в библиотеке DoEasy (Часть 78): Принципы анимации в библиотеке. Нарезка изображений

Прикрепленные файлы |
MQL5.zip (4128.81 KB)
Графика в библиотеке DoEasy (Часть 80): Класс объекта "Кадр геометрической анимации" Графика в библиотеке DoEasy (Часть 80): Класс объекта "Кадр геометрической анимации"
В статье оптимизируем код классов из предыдущих статей и создадим класс объекта кадра геометрической анимации, позволяющего рисовать правильные многоугольники с заданным количеством вершин.
Кластерный анализ (Часть I): Использование наклона индикаторных линий Кластерный анализ (Часть I): Использование наклона индикаторных линий
Кластерный анализ — один из важнейших элементов искусственного интеллекта. В этой статье я пытаюсь применить кластерный анализ наклона индикатора, чтобы получить пороговые значения для определения флэтового или трендового характера рынка.
Комбинаторика и теория вероятностей для трейдинга (Часть III): Первая математическая модель Комбинаторика и теория вероятностей для трейдинга (Часть III): Первая математическая модель
Закономерным продолжением темы стала потребность разработки многофункциональных математических моделей для задач трейдинга. В связи с этим в данной статье я буду описывать весь процесс разработки первой математической модели для описания фракталов с нуля. Данная модель должна стать важным кирпичиком и быть многофункциональной и универсальной, в том числе для того, чтобы нарастить теоретическую базу для дальнейшего развития ветки.
Графика в библиотеке DoEasy (Часть 78): Принципы анимации в библиотеке. Нарезка изображений Графика в библиотеке DoEasy (Часть 78): Принципы анимации в библиотеке. Нарезка изображений
В статье определим принципы анимации, которые будем использовать в некоторых частях библиотеки, разработаем класс для копирования части изображения и вставки его в указанное место объекта-формы с сохранением и восстановлением той части фона формы, на которую будет накладываться рисунок.