English Русский 中文 Deutsch 日本語 Português
Gráficos en la biblioteca DoEasy (Parte 83): Clase de objeto gráfico abstracto estándar

Gráficos en la biblioteca DoEasy (Parte 83): Clase de objeto gráfico abstracto estándar

MetaTrader 5Ejemplos | 12 octubre 2021, 16:52
719 0
Artyom Trishkin
Artyom Trishkin

Contenido


Concepto

Para continuar trabajando con la colección de clases de objetos gráficos que creamos en el último artículo, necesitaremos tener las clases de objeto de todos los objetos gráficos estándar disponibles en el terminal. Después de crear todos estos objetos, tendremos a nuestra disposición las herramientas necesarias para trabajar con cualquier objeto gráfico, ya sea estándar o propio, creado sobre la base de la clase CCanvas, y todos ellos se encontrarán en la lista de la colección de objetos gráficos.

Como la biblioteca podrá tomar bajo su propio control los objetos gráficos creados de forma manual, para implementar tal posibilidad, necesitaremos tener clases de objetos que describan los objetos gráficos estándar creados manualmente. En dicho objeto, se creará un enlace al objeto gráfico creado manualmente, así como los métodos para gestionar sus propiedades. Para asumir el control de un objeto gráfico de este tipo, el usuario de la biblioteca deberá indicar manualmente la necesidad de ejercer dicho control.

Esto se puede hacer, por ejemplo, desde un menú contextual llamado según una cierta condición, es decir, aquí ya necesitaremos crear algún tipo de panel gráfico en el que podremos organizar la selección de las posibles acciones a realizar con un objeto gráfico. Estos paneles se pueden crear usando las clases implementadas sobre la base de CCanvas y los objetos de esta que comenzamos a construir hace varios artículos, y a los que volveremos más adelante, pues suspendimos su desarrollo solo porque necesitábamos crear una colección de objetos gráficos, para lo cual ahora se requiere crear clases para los gráficos estándar (esto es el resultado de un error de planificación de la secuencia de desarrollo, pues tuvimos que comenzar con los gráficos estándar).

Bien. La estructura de los objetos gráficos estándar será exactamente igual a la de todos los objetos de la biblioteca: habrá una clase general de objeto gráfico abstracto que tendrá en su composición las propiedades básicas inherentes a todos los objetos gráficos, y, partiendo de ella, se heredarán las clases que describen cada objeto gráfico estándar donde se concretarán las propiedades que solo tiene este objeto.

Hoy crearemos una clase de un objeto gráfico abstracto y añadiremos los métodos necesarios para trabajar con las propiedades inherentes a absolutamente todos los objetos gráficos; estas serán propiedades de objetos gráficos que podemos obtener con la ayuda de las funciones ObjectGetInteger(), ObjectGetDouble() y ObjectGetString(). Al crear las clases de los objetos herederos de este objeto gráfico abstracto, los métodos que son inherentes solo al objeto heredero que describe un objeto gráfico específico, pero escritos en el objeto básico, serán transferidos del objeto básico al objeto heredado, de forma que estos métodos no estén disponibles para los otros objetos que no tengan tales propiedades.
Para una mejor comprensión, aquí tenemos un ejemplo:

  • en el terminal hay un objeto de icono gráfico "Flecha". Este objeto tiene la propiedad "Código de flecha", pero ninguna propiedad de "Rayo a la derecha";
  • el terminal tiene el objeto gráfico "Línea de tendencia". Este objeto tiene la propiedad "Rayo a la derecha", pero ninguna propiedad "Código de flecha".

Ahora, vamos a escribir estas propiedades y métodos para trabajar con ellos en la clase de objeto gráfico abstracto. Estos métodos estarán disponibles desde cualquier objeto que herede de este objeto básico: el objeto gráfico abstracto.
Además, al crear los objetos herederos (para este ejemplo, hablamos del objeto del icono "Flecha" y el objeto del objeto gráfico "Línea de tendencia"), transferiremos los métodos a cada uno de ellos para que trabajen solo con sus propiedades inherentes:

  • al objeto del icono "Flecha", transmitiremos los métodos para especificar el código de la flecha;
  • al objeto de objeto gráfico "Línea de tendencia", transmitiremos los métodos para indicar la propiedad "Rayo a la derecha" ("Rayo a la izquierda").

Al referirnos a cada uno de estos objetos herederos, tendremos acceso solo para sus propiedades específicas, cuyos métodos de trabajo se establecen solo en estos objetos, junto con los métodos para el manejo de las propiedades que son comunes a todos los objetos inherentes a cualquier objeto gráfico y que están escritos en la clase de objeto gráfico abstracto.

Los objetos gráficos tienen muchas propiedades, y hoy, antes de crear una clase de objeto gráfico abstracto, necesitaremos realizar un trabajo preparatorio extenso: registrar estas propiedades en las enumeraciones de la biblioteca, crear los textos descriptivos para cada propiedad del objeto gráfico y crear funciones que retornen las descripciones de algunas propiedades de los objetos gráficos.


Mejorando las clases de la biblioteca

En la lista de tipos de objetos de biblioteca que creamos en el último artículo, hay tipos de objetos gráficos estándar. Pero necesitamos un tipo más para el objeto gráfico abstracto. En el archivo \MQL5\Include\DoEasy\Defines.mqh, en la enumeración de los tipos de objeto de la biblioteca, escribimos una constante para ello. El cálculo de los valores de las constantes posteriores de los tipos de objeto comenzará a partir del valor de esta nueva constante:

//+------------------------------------------------------------------+
//| List of library object types                                     |
//+------------------------------------------------------------------+
enum ENUM_OBJECT_DE_TYPE
  {
//--- Graphics
   OBJECT_DE_TYPE_GBASE =  COLLECTION_ID_LIST_END+1,              // "Base object of all library graphical objects" object type
   OBJECT_DE_TYPE_GELEMENT,                                       // "Graphical element" object type
   OBJECT_DE_TYPE_GFORM,                                          // Form object type
   OBJECT_DE_TYPE_GSHADOW,                                        // Shadow object type
//--- Animation
   OBJECT_DE_TYPE_GFRAME,                                         // "Single animation frame" object type
   OBJECT_DE_TYPE_GFRAME_TEXT,                                    // "Single text animation frame" object type
   OBJECT_DE_TYPE_GFRAME_QUAD,                                    // "Single rectangular animation frame" object type
   OBJECT_DE_TYPE_GFRAME_GEOMETRY,                                // "Single geometric animation frame" object type
   OBJECT_DE_TYPE_GANIMATIONS,                                    // "Animations" object type
//--- Managing graphical objects
   OBJECT_DE_TYPE_GELEMENT_CONTROL,                               // "Managing graphical objects" object type
//--- Standard graphical objects
   OBJECT_DE_TYPE_GSTD_OBJ,                                       // "Standard graphical object" object type
   OBJECT_DE_TYPE_GSTD_VLINE              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_VLINE,            // "Vertical line" object type
   OBJECT_DE_TYPE_GSTD_HLINE              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_HLINE,            // "Horizontal line" object type
   OBJECT_DE_TYPE_GSTD_TREND              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_TREND,            // "Trend line" object type
   OBJECT_DE_TYPE_GSTD_TRENDBYANGLE       =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_TRENDBYANGLE,     // "Trend line by angle" object type
   OBJECT_DE_TYPE_GSTD_CYCLES             =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_CYCLES,           // "Cyclic lines" object type
   OBJECT_DE_TYPE_GSTD_ARROWED_LINE       =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROWED_LINE,     // "Arrowed line" object type
   OBJECT_DE_TYPE_GSTD_CHANNEL            =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_CHANNEL,          // "Equidistant channel" object type
   OBJECT_DE_TYPE_GSTD_STDDEVCHANNEL      =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_STDDEVCHANNEL,    // "Standard deviation channel" object type
   OBJECT_DE_TYPE_GSTD_REGRESSION         =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_REGRESSION,       // "Linear regression channel" object type
   OBJECT_DE_TYPE_GSTD_PITCHFORK          =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_PITCHFORK,        // "Andrews' pitchfork" object type
   OBJECT_DE_TYPE_GSTD_GANNLINE           =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_GANNLINE,         // "Gann line" object type
   OBJECT_DE_TYPE_GSTD_GANNFAN            =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_GANNFAN,          // "Gann fan" object type
   OBJECT_DE_TYPE_GSTD_GANNGRID           =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_GANNGRID,         // "Gann grid" object type
   OBJECT_DE_TYPE_GSTD_FIBO               =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_FIBO,             // "Fibo levels" object type
   OBJECT_DE_TYPE_GSTD_FIBOTIMES          =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_FIBOTIMES,        // "Fibo time zones" object type
   OBJECT_DE_TYPE_GSTD_FIBOFAN            =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_FIBOFAN,          // "Fibo fan" object type
   OBJECT_DE_TYPE_GSTD_FIBOARC            =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_FIBOARC,          // "Fibo arcs" object type
   OBJECT_DE_TYPE_GSTD_FIBOCHANNEL        =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_FIBOCHANNEL,      // "Fibo channel" object type
   OBJECT_DE_TYPE_GSTD_EXPANSION          =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_EXPANSION,        // "Fibo expansion" object type
   OBJECT_DE_TYPE_GSTD_ELLIOTWAVE5        =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ELLIOTWAVE5,      // "Elliott 5 waves" object type
   OBJECT_DE_TYPE_GSTD_ELLIOTWAVE3        =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ELLIOTWAVE3,      // "Elliott 3 waves" object type
   OBJECT_DE_TYPE_GSTD_RECTANGLE          =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_RECTANGLE,        // "Rectangle" object type
   OBJECT_DE_TYPE_GSTD_TRIANGLE           =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_TRIANGLE,         // "Triangle" object type
   OBJECT_DE_TYPE_GSTD_ELLIPSE            =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ELLIPSE,          // "Ellipse" object type
   OBJECT_DE_TYPE_GSTD_ARROW_THUMB_UP     =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_THUMB_UP,   // "Thumb up" object type
   OBJECT_DE_TYPE_GSTD_ARROW_THUMB_DOWN   =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_THUMB_DOWN, // "Thumb down" object type
   OBJECT_DE_TYPE_GSTD_ARROW_UP           =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_UP,         // "Arrow up" object type
   OBJECT_DE_TYPE_GSTD_ARROW_DOWN         =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_DOWN,       // "Arrow down" object type
   OBJECT_DE_TYPE_GSTD_ARROW_STOP         =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_STOP,       // "Stop sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW_CHECK        =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_CHECK,      // "Check mark" object type
   OBJECT_DE_TYPE_GSTD_ARROW_LEFT_PRICE   =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_LEFT_PRICE, // "Left price label" object type
   OBJECT_DE_TYPE_GSTD_ARROW_RIGHT_PRICE  =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_RIGHT_PRICE,// "Right price label" object type
   OBJECT_DE_TYPE_GSTD_ARROW_BUY          =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_BUY,        // "Buy sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW_SELL         =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_SELL,       // "Sell sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW,            // "Arrow" object type
   OBJECT_DE_TYPE_GSTD_TEXT               =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_TEXT,             // "Text" object type
   OBJECT_DE_TYPE_GSTD_LABEL              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_LABEL,            // "Text label" object type
   OBJECT_DE_TYPE_GSTD_BUTTON             =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_BUTTON,           // "Button" object type
   OBJECT_DE_TYPE_GSTD_CHART              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_CHART,            // "Chart" object type
   OBJECT_DE_TYPE_GSTD_BITMAP             =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_BITMAP,           // "Bitmap" object type
   OBJECT_DE_TYPE_GSTD_BITMAP_LABEL       =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_BITMAP_LABEL,     // "Bitmap label" object type
   OBJECT_DE_TYPE_GSTD_EDIT               =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_EDIT,             // "Input field" object type
   OBJECT_DE_TYPE_GSTD_EVENT              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_EVENT,            // "Event object which corresponds to an event in Economic Calendar" object type
   OBJECT_DE_TYPE_GSTD_RECTANGLE_LABEL    =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_RECTANGLE_LABEL,  // "Rectangle Label object used to create and design the custom graphical interface" object type
   
//--- Objects
   OBJECT_DE_TYPE_BASE  =  OBJECT_DE_TYPE_GSTD_RECTANGLE_LABEL+1, // Base object for all library objects
   OBJECT_DE_TYPE_BASE_EXT,                                       // Extended base object for all library objects
   
   // .......... The constants of other object types are skipped for brevity
   // ..........
   // ..........

  };

En la enumeración de la lista de pertenencia de objetos gráficos, cambiamos la constante GRAPH_OBJ_BELONG_TERMINAL, cuyo nombre indica la pertenencia del objeto gráfico al terminal. La haremos más apropiada: GRAPH_OBJ_BELONG_NO_PROGRAM, ya que el objeto puede no pertenecer al programa ejecutado bajo el control de la biblioteca, y sí a otro programa sin pertenecer al terminal:

//+------------------------------------------------------------------+
//| List of graphical objects affiliations                           |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_OBJ_BELONG
  {
   GRAPH_OBJ_BELONG_PROGRAM,                          // Graphical object belongs to a program
   GRAPH_OBJ_BELONG_NO_PROGRAM,                       // Graphical object does not belong to a program
  };
//+------------------------------------------------------------------+

Añadimos la nueva constante a la enumeración de elementos gráficos:

//+------------------------------------------------------------------+
//| The list of graphical element types                              |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_ELEMENT_TYPE
  {
   GRAPH_ELEMENT_TYPE_STANDART,                       // Standard graphical object
   GRAPH_ELEMENT_TYPE_ELEMENT,                        // Element
   GRAPH_ELEMENT_TYPE_SHADOW_OBJ,                     // Shadow object
   GRAPH_ELEMENT_TYPE_FORM,                           // Form
   GRAPH_ELEMENT_TYPE_WINDOW,                         // Window
  };
//+------------------------------------------------------------------+

Como todos los objetos que describen los objetos gráficos creados en el programa se guardarán en una lista, indicar el tipo de elemento gráfico nos permitirá seleccionar rápidamente solo los elementos gráficos necesarios de la lista completa. Por consiguiente, si seleccionamos "Objeto gráfico estándar" como condición de filtrado para una lista de colección, obtendremos en la salida una lista que constará únicamente de los objetos que describen los objetos gráficos estándar creados.

Para un objeto de la clase de objeto gráfico estándar abstracto, necesitaremos crear tres enumeraciones para todas las propiedades del objeto gráfico (tipos entero, real y string), en las que se escribirán todas las propiedades del objeto gráfico, así como las propiedades adicionales necesarias para trabajar con dichos objetos:

//+------------------------------------------------------------------+
//| Integer properties of a standard graphical object                |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_OBJ_PROP_INTEGER
  {
   //--- Additional properties
   GRAPH_OBJ_PROP_ID = 0,                             // Object ID
   GRAPH_OBJ_PROP_TYPE,                               // Graphical object type (ENUM_OBJECT)
   GRAPH_OBJ_PROP_ELEMENT_TYPE,                       // Graphical element type (ENUM_GRAPH_ELEMENT_TYPE)
   GRAPH_OBJ_PROP_BELONG,                             // Graphical object affiliation
   GRAPH_OBJ_PROP_CHART_ID,                           // Chart ID
   GRAPH_OBJ_PROP_WND_NUM,                            // Chart subwindow index
   GRAPH_OBJ_PROP_NUM,                                // Object index in the list
   //--- Common properties of all graphical objects
   GRAPH_OBJ_PROP_CREATETIME,                         // Object creation time
   GRAPH_OBJ_PROP_TIMEFRAMES,                         // Object visibility on timeframes
   GRAPH_OBJ_PROP_BACK,                               // Background object
   GRAPH_OBJ_PROP_ZORDER,                             // Priority of a graphical object for receiving the event of clicking on a chart
   GRAPH_OBJ_PROP_HIDDEN,                             // Disable displaying the name of a graphical object in the terminal object list
   GRAPH_OBJ_PROP_SELECTED,                           // Object selection
   GRAPH_OBJ_PROP_SELECTABLE,                         // Object availability
//--- Properties belonging to different graphical objects
   GRAPH_OBJ_PROP_TIME,                               // Time coordinate
   GRAPH_OBJ_PROP_COLOR,                              // Color
   GRAPH_OBJ_PROP_STYLE,                              // Style
   GRAPH_OBJ_PROP_WIDTH,                              // Line width
   GRAPH_OBJ_PROP_FILL,                               // Object color filling
   GRAPH_OBJ_PROP_READONLY,                           // Ability to edit text in the Edit object
   GRAPH_OBJ_PROP_LEVELS,                             // Number of levels
   GRAPH_OBJ_PROP_LEVELCOLOR,                         // Level line color
   GRAPH_OBJ_PROP_LEVELSTYLE,                         // Level line style
   GRAPH_OBJ_PROP_LEVELWIDTH,                         // Level line width
   GRAPH_OBJ_PROP_ALIGN,                              // Horizontal text alignment in the Edit object (OBJ_EDIT)
   GRAPH_OBJ_PROP_FONTSIZE,                           // Font size
   GRAPH_OBJ_PROP_RAY_LEFT,                           // Ray goes to the left
   GRAPH_OBJ_PROP_RAY_RIGHT,                          // Ray goes to the right
   GRAPH_OBJ_PROP_RAY,                                // Vertical line goes through all windows of a chart
   GRAPH_OBJ_PROP_ELLIPSE,                            // Display the full ellipse of the Fibonacci Arc object
   GRAPH_OBJ_PROP_ARROWCODE,                          // Arrow code for the "Arrow" object
   GRAPH_OBJ_PROP_ANCHOR,                             // Position of the binding point of the graphical object
   GRAPH_OBJ_PROP_XDISTANCE,                          // Distance from the base corner along the X axis in pixels
   GRAPH_OBJ_PROP_YDISTANCE,                          // Distance from the base corner along the Y axis in pixels
   GRAPH_OBJ_PROP_DIRECTION,                          // Gann object trend
   GRAPH_OBJ_PROP_DEGREE,                             // Elliott wave marking level
   GRAPH_OBJ_PROP_DRAWLINES,                          // Display lines for Elliott wave marking
   GRAPH_OBJ_PROP_STATE,                              // Button state (pressed/released)
   GRAPH_OBJ_PROP_OBJ_CHART_ID,                       // Chart object ID (OBJ_CHART).
   GRAPH_OBJ_PROP_CHART_OBJ_PERIOD,                   // Chart object period
   GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE,               // Time scale display flag for the Chart object
   GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE,              // Price scale display flag for the Chart object
   GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE,              // Chart object scale
   GRAPH_OBJ_PROP_XSIZE,                              // Object width along the X axis in pixels.
   GRAPH_OBJ_PROP_YSIZE,                              // Object height along the Y axis in pixels.
   GRAPH_OBJ_PROP_XOFFSET,                            // X coordinate of the upper-left corner of the visibility area.
   GRAPH_OBJ_PROP_YOFFSET,                            // Y coordinate of the upper-left corner of the visibility area.
   GRAPH_OBJ_PROP_BGCOLOR,                            // Background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL
   GRAPH_OBJ_PROP_CORNER,                             // Chart corner for binding a graphical object
   GRAPH_OBJ_PROP_BORDER_TYPE,                        // Border type for "Rectangle border"
   GRAPH_OBJ_PROP_BORDER_COLOR,                       // Border color for OBJ_EDIT and OBJ_BUTTON
  };
#define GRAPH_OBJ_PROP_INTEGER_TOTAL (51)             // Total number of integer properties
#define GRAPH_OBJ_PROP_INTEGER_SKIP  (0)              // Number of integer properties not used in sorting
//+------------------------------------------------------------------+
//| Real properties of a standard graphical object                   |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_OBJ_PROP_DOUBLE
  {
   GRAPH_OBJ_PROP_PRICE = GRAPH_OBJ_PROP_INTEGER_TOTAL,// Price coordinate
   GRAPH_OBJ_PROP_LEVELVALUE,                         // Level value
   GRAPH_OBJ_PROP_SCALE,                              // Scale
   GRAPH_OBJ_PROP_ANGLE,                              // Angle
   GRAPH_OBJ_PROP_DEVIATION,                          // Deviation of the standard deviation channel
  };
#define GRAPH_OBJ_PROP_DOUBLE_TOTAL  (5)              // Total number of real properties
#define GRAPH_OBJ_PROP_DOUBLE_SKIP   (0)              // Number of real properties not used in sorting
//+------------------------------------------------------------------+
//| String properties of a standard graphical object                 |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_OBJ_PROP_STRING
  {
   GRAPH_OBJ_PROP_NAME = (GRAPH_OBJ_PROP_INTEGER_TOTAL+GRAPH_OBJ_PROP_DOUBLE_TOTAL), // Object name
   GRAPH_OBJ_PROP_TEXT,                               // Object description (text contained in the object)
   GRAPH_OBJ_PROP_TOOLTIP,                            // Tooltip text
   GRAPH_OBJ_PROP_LEVELTEXT,                          // Level description
   GRAPH_OBJ_PROP_FONT,                               // Font
   GRAPH_OBJ_PROP_BMPFILE,                            // BMP file name for the "Bitmap Level" object
   GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL,                   // Symbol for the Chart object 
  };
#define GRAPH_OBJ_PROP_STRING_TOTAL  (7)              // Total number of string properties
//+------------------------------------------------------------------+

El cometido de estas enumeraciones ya lo conocemos hace mucho, porque todos los objetos de la biblioteca se crean según un mismo principio.

Por consiguiente, también necesitaremos añadir a la lista de colección la enumeración con los posibles criterios de clasificación de los objetos gráficos:

//+------------------------------------------------------------------+
//| Possible sorting criteria of graphical objects                   |
//+------------------------------------------------------------------+
#define FIRST_GRAPH_OBJ_DBL_PROP  (GRAPH_OBJ_PROP_INTEGER_TOTAL-GRAPH_OBJ_PROP_INTEGER_SKIP)
#define FIRST_GRAPH_OBJ_STR_PROP  (GRAPH_OBJ_PROP_INTEGER_TOTAL-GRAPH_OBJ_PROP_INTEGER_SKIP+GRAPH_OBJ_PROP_DOUBLE_TOTAL-GRAPH_OBJ_PROP_DOUBLE_SKIP)
enum ENUM_SORT_GRAPH_OBJ_MODE
  {
//--- Sort by integer properties
   SORT_BY_GRAPH_OBJ_ID = 0,                             // Sort by object ID
   SORT_BY_GRAPH_OBJ_TYPE,                               // Sort by object type
   SORT_BY_GRAPH_OBJ_ELEMENT_TYPE,                       // Sort by graphical element type
   SORT_BY_GRAPH_OBJ_BELONG,                             //  Sort by a graphical element affiliation
   SORT_BY_GRAPH_OBJ_CHART_ID,                           // Sort by chart ID
   SORT_BY_GRAPH_OBJ_WND_NUM,                            // Sort by chart subwindow index
   SORT_BY_GRAPH_OBJ_NUM,                                // Sort by object index in the list
   SORT_BY_GRAPH_OBJ_CREATETIME,                         // Sort by object creation time
   SORT_BY_GRAPH_OBJ_TIMEFRAMES,                         // Sort by object visibility on timeframes
   SORT_BY_GRAPH_OBJ_BACK,                               // Sort by the "Background object" property
   SORT_BY_GRAPH_OBJ_ZORDER,                             // Sort by the priority of a graphical object for receiving the event of clicking on a chart
   SORT_BY_GRAPH_OBJ_HIDDEN,                             // Sort by a disabling display of the name of a graphical object in the terminal object list
   SORT_BY_GRAPH_OBJ_SELECTED,                           // Sort by the "Object selection" property
   SORT_BY_GRAPH_OBJ_SELECTABLE,                         // Sort by the "Object availability" property
   SORT_BY_GRAPH_OBJ_TIME,                               // Sort by time coordinate
   SORT_BY_GRAPH_OBJ_COLOR,                              // Sort by color
   SORT_BY_GRAPH_OBJ_STYLE,                              // Sort by style
   SORT_BY_GRAPH_OBJ_WIDTH,                              // Sort by line width
   SORT_BY_GRAPH_OBJ_FILL,                               // Sort by the "Object color filling" property
   SORT_BY_GRAPH_OBJ_READONLY,                           // Sort by the ability to edit text in the Edit object
   SORT_BY_GRAPH_OBJ_LEVELS,                             // Sort by number of levels
   SORT_BY_GRAPH_OBJ_LEVELCOLOR,                         // Sort by line level color
   SORT_BY_GRAPH_OBJ_LEVELSTYLE,                         // Sort by line level style
   SORT_BY_GRAPH_OBJ_LEVELWIDTH,                         // Sort by line level width
   SORT_BY_GRAPH_OBJ_ALIGN,                              // Sort by the "Horizontal text alignment in the Entry field" property
   SORT_BY_GRAPH_OBJ_FONTSIZE,                           // Sort by font size
   SORT_BY_GRAPH_OBJ_RAY_LEFT,                           // Sort by "Ray goes to the left" property
   SORT_BY_GRAPH_OBJ_RAY_RIGHT,                          // Sort by "Ray goes to the right" property
   SORT_BY_GRAPH_OBJ_RAY,                                // Sort by the "Vertical line goes through all windows of a chart" property
   SORT_BY_GRAPH_OBJ_ELLIPSE,                            // Sort by the "Display the full ellipse of the Fibonacci Arc object" property
   SORT_BY_GRAPH_OBJ_ARROWCODE,                          // Sort by an arrow code for the Arrow object
   SORT_BY_GRAPH_OBJ_ANCHOR,                             // Sort by the position of a binding point of a graphical object
   SORT_BY_GRAPH_OBJ_XDISTANCE,                          // Sort by a distance from the base corner along the X axis in pixels
   SORT_BY_GRAPH_OBJ_YDISTANCE,                          // Sort by a distance from the base corner along the Y axis in pixels
   SORT_BY_GRAPH_OBJ_DIRECTION,                          // Sort by the "Gann object trend" property
   SORT_BY_GRAPH_OBJ_DEGREE,                             // Sort by the "Elliott wave marking level" property
   SORT_BY_GRAPH_OBJ_DRAWLINES,                          // Sort by the "Display lines for Elliott wave marking" property
   SORT_BY_GRAPH_OBJ_STATE,                              // Sort by button state (pressed/released)
   SORT_BY_GRAPH_OBJ_OBJ_CHART_ID,                       // Sort by Chart object ID.
   SORT_BY_GRAPH_OBJ_CHART_OBJ_PERIOD,                   // Sort by Chart object period
   SORT_BY_GRAPH_OBJ_CHART_OBJ_DATE_SCALE,               // Sort by time scale display flag for the Chart object
   SORT_BY_GRAPH_OBJ_CHART_OBJ_PRICE_SCALE,              // Sort by price scale display flag for the Chart object
   SORT_BY_GRAPH_OBJ_CHART_OBJ_CHART_SCALE,              // Sort by Chart object scale
   SORT_BY_GRAPH_OBJ_XSIZE,                              // Sort by Object width along the X axis in pixels
   SORT_BY_GRAPH_OBJ_YSIZE,                              // Sort by object height along the Y axis in pixels
   SORT_BY_GRAPH_OBJ_XOFFSET,                            // Sort by X coordinate of the upper-left corner of the visibility area
   SORT_BY_GRAPH_OBJ_YOFFSET,                            // Sort by Y coordinate of the upper-left corner of the visibility area
   SORT_BY_GRAPH_OBJ_BGCOLOR,                            // Sort by background color for OBJ_EDIT, OBJ_BUTTON and OBJ_RECTANGLE_LABEL
   SORT_BY_GRAPH_OBJ_CORNER,                             // Sort by chart corner for binding a graphical object
   SORT_BY_GRAPH_OBJ_BORDER_TYPE,                        // Sort by border type for the "Rectangle border" object
   SORT_BY_GRAPH_OBJ_BORDER_COLOR,                       // Sort by frame color for the OBJ_EDIT and OBJ_BUTTON objects
//--- Sort by real properties
   SORT_BY_GRAPH_OBJ_PRICE = FIRST_GRAPH_OBJ_DBL_PROP,   // Sort by price coordinate
   SORT_BY_GRAPH_OBJ_LEVELVALUE,                         // Sort by level value
   SORT_BY_GRAPH_OBJ_SCALE,                              // Sort by scale (property of Gann objects and Fibonacci Arcs objects)
   SORT_BY_GRAPH_OBJ_ANGLE,                              // Sort by angle
   SORT_BY_GRAPH_OBJ_DEVIATION,                          // Sort by a deviation of the standard deviation channel
//--- Sort by string properties
   SORT_BY_GRAPH_OBJ_NAME = FIRST_GRAPH_OBJ_STR_PROP,    // Sort by object name
   SORT_BY_GRAPH_OBJ_TEXT,                               // Sort by object description
   SORT_BY_GRAPH_OBJ_TOOLTIP,                            // Sort by tooltip text
   SORT_BY_GRAPH_OBJ_LEVELTEXT,                          // Sort by level description
   SORT_BY_GRAPH_OBJ_FONT,                               // Sort by font
   SORT_BY_GRAPH_OBJ_BMPFILE,                            // Sort by BMP file name for the "Bitmap Level" object
   SORT_BY_GRAPH_OBJ_CHART_OBJ_SYMBOL,                   // Sort by Chart object period symbol
  };
//+------------------------------------------------------------------+


Ahora, vamos a añadir los textos con los nuevos mensajes de la biblioteca y las descripciones de todas las propiedades de los objetos gráficos.
Para ello, en el archivo \MQL5\Include\DoEasy\Data.mqh, escribiremos los índices de los nuevos mensajes:

   MSG_LIB_TEXT_JANUARY,                              // January
   MSG_LIB_TEXT_FEBRUARY,                             // February
   MSG_LIB_TEXT_MARCH,                                // March
   MSG_LIB_TEXT_APRIL,                                // April
   MSG_LIB_TEXT_MAY,                                  // May
   MSG_LIB_TEXT_JUNE,                                 // June
   MSG_LIB_TEXT_JULY,                                 // July
   MSG_LIB_TEXT_AUGUST,                               // August
   MSG_LIB_TEXT_SEPTEMBER,                            // September
   MSG_LIB_TEXT_OCTOBER,                              // October
   MSG_LIB_TEXT_NOVEMBER,                             // November
   MSG_LIB_TEXT_DECEMBER,                             // December
   
   MSG_LIB_TEXT_ALIGN_LEFT,                           // Left alignment 
   MSG_LIB_TEXT_ALIGN_CENTER,                         // Center alignment
   MSG_LIB_TEXT_ALIGN_RIGHT,                          // Right alignment
   
   MSG_LIB_TEXT_GANN_UP_TREND,                        // Line corresponds to an uptrend
   MSG_LIB_TEXT_GANN_DOWN_TREND,                      // Line corresponds to a downtrend
   
   MSG_LIB_TEXT_ELLIOTT_GRAND_SUPERCYCLE,             // Grand Supercycle
   MSG_LIB_TEXT_ELLIOTT_SUPERCYCLE,                   // Supercycle
   MSG_LIB_TEXT_ELLIOTT_CYCLE,                        // Cycle
   MSG_LIB_TEXT_ELLIOTT_PRIMARY,                      // Primary cycle
   MSG_LIB_TEXT_ELLIOTT_INTERMEDIATE,                 // Intermediate
   MSG_LIB_TEXT_ELLIOTT_MINOR,                        // Minor cycle
   MSG_LIB_TEXT_ELLIOTT_MINUTE,                       // Minute
   MSG_LIB_TEXT_ELLIOTT_MINUETTE,                     // Second (Minuette)
   MSG_LIB_TEXT_ELLIOTT_SUBMINUETTE,                  // Subsecond (Subminuette)
   
   MSG_LIB_TEXT_BUTTON_STATE_PRESSED,                 // Pressed
   MSG_LIB_TEXT_BUTTON_STATE_DEPRESSED,               // Released
   
   MSG_LIB_TEXT_CORNER_LEFT_UPPER,                    // Center of coordinates at the upper left corner of the chart
   MSG_LIB_TEXT_CORNER_LEFT_LOWER,                    // Center of coordinates at the lower left corner of the chart
   MSG_LIB_TEXT_CORNER_RIGHT_LOWER,                   // Center of coordinates at the lower right corner of the chart
   MSG_LIB_TEXT_CORNER_RIGHT_UPPER,                   // Center of coordinates at the upper right corner of the chart
   
   MSG_LIB_TEXT_BORDER_FLAT,                          // Flat
   MSG_LIB_TEXT_BORDER_RAISED,                        // Raised
   MSG_LIB_TEXT_BORDER_SUNKEN,                        // Sunken
   
   MSG_LIB_TEXT_SUNDAY,                               // Sunday
   MSG_LIB_TEXT_MONDAY,                               // Monday
   MSG_LIB_TEXT_TUESDAY,                              // Tuesday
   MSG_LIB_TEXT_WEDNESDAY,                            // Wednesday
   MSG_LIB_TEXT_THURSDAY,                             // Thursday
   MSG_LIB_TEXT_FRIDAY,                               // Friday
   MSG_LIB_TEXT_SATURDAY,                             // Saturday

...

//--- CGraphElementsCollection
   MSG_GRAPH_ELM_COLLECTION_ERR_OBJ_ALREADY_EXISTS,   // Error. A chart control object already exists with chart id 
   MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_CREATE_CTRL_OBJ,// Failed to create chart control object with chart ID 
   
//--- GStdGraphObj
   MSG_GRAPH_STD_OBJ_ERR_NOT_FIND_SUBWINDOW,          // Failed to find the chart subwindow
   
   MSG_GRAPH_ELEMENT_TYPE_STANDART,                   // Standard graphical object
   MSG_GRAPH_ELEMENT_TYPE_ELEMENT,                    // Element
   MSG_GRAPH_ELEMENT_TYPE_SHADOW_OBJ,                 // Shadow object
   MSG_GRAPH_ELEMENT_TYPE_FORM,                       // Form
   MSG_GRAPH_ELEMENT_TYPE_WINDOW,                     // Window
   
   MSG_GRAPH_OBJ_BELONG_PROGRAM,                      // Graphical object belongs to a program
   MSG_GRAPH_OBJ_BELONG_NO_PROGRAM,                   // Graphical object does not belong to a program
//---
   MSG_GRAPH_STD_OBJ_VLINE,                           // Vertical line
   MSG_GRAPH_STD_OBJ_HLINE,                           // Horizontal line
   MSG_GRAPH_STD_OBJ_TREND,                           // Trend line
   MSG_GRAPH_STD_OBJ_TRENDBYANGLE,                    // Trend line by angle
   MSG_GRAPH_STD_OBJ_CYCLES,                          // Cyclic lines
   MSG_GRAPH_STD_OBJ_ARROWED_LINE,                    // Arrowed line object
   MSG_GRAPH_STD_OBJ_CHANNEL,                         // Equidistant channel
   MSG_GRAPH_STD_OBJ_STDDEVCHANNEL,                   // Standard deviation channel
   MSG_GRAPH_STD_OBJ_REGRESSION,                      // Linear regression channel
   MSG_GRAPH_STD_OBJ_PITCHFORK,                       // Andrews' pitchfork
   MSG_GRAPH_STD_OBJ_GANNLINE,                        // Gann line
   MSG_GRAPH_STD_OBJ_GANNFAN,                         // Gann fan
   MSG_GRAPH_STD_OBJ_GANNGRID,                        // Gann grid
   MSG_GRAPH_STD_OBJ_FIBO,                            // Fibo levels
   MSG_GRAPH_STD_OBJ_FIBOTIMES,                       // Fibo time zones
   MSG_GRAPH_STD_OBJ_FIBOFAN,                         // Fibo fan
   MSG_GRAPH_STD_OBJ_FIBOARC,                         // Fibo arcs
   MSG_GRAPH_STD_OBJ_FIBOCHANNEL,                     // Fibo channel
   MSG_GRAPH_STD_OBJ_EXPANSION,                       // Fibo expansion
   MSG_GRAPH_STD_OBJ_ELLIOTWAVE5,                     // Elliott 5 waves
   MSG_GRAPH_STD_OBJ_ELLIOTWAVE3,                     // Elliott 3 waves
   MSG_GRAPH_STD_OBJ_RECTANGLE,                       // Rectangle
   MSG_GRAPH_STD_OBJ_TRIANGLE,                        // Triangle
   MSG_GRAPH_STD_OBJ_ELLIPSE,                         // Ellipse
   MSG_GRAPH_STD_OBJ_ARROW_THUMB_UP,                  // Thumb up
   MSG_GRAPH_STD_OBJ_ARROW_THUMB_DOWN,                // Thumb down
   MSG_GRAPH_STD_OBJ_ARROW_UP,                        // Arrow up
   MSG_GRAPH_STD_OBJ_ARROW_DOWN,                      // Arrow down
   MSG_GRAPH_STD_OBJ_ARROW_STOP,                      // Stop
   MSG_GRAPH_STD_OBJ_ARROW_CHECK,                     // Check mark
   MSG_GRAPH_STD_OBJ_ARROW_LEFT_PRICE,                // Left price label
   MSG_GRAPH_STD_OBJ_ARROW_RIGHT_PRICE,               // Right price label
   MSG_GRAPH_STD_OBJ_ARROW_BUY,                       // Buy
   MSG_GRAPH_STD_OBJ_ARROW_SELL,                      // Sell
   MSG_GRAPH_STD_OBJ_ARROW,                           // Arrow
   MSG_GRAPH_STD_OBJ_TEXT,                            // Text
   MSG_GRAPH_STD_OBJ_LABEL,                           // Text label
   MSG_GRAPH_STD_OBJ_BUTTON,                          // Button
   MSG_GRAPH_STD_OBJ_CHART,                           // Chart
   MSG_GRAPH_STD_OBJ_BITMAP,                          // Bitmap
   MSG_GRAPH_STD_OBJ_BITMAP_LABEL,                    // Bitmap label
   MSG_GRAPH_STD_OBJ_EDIT,                            // Edit
   MSG_GRAPH_STD_OBJ_EVENT,                           // Event object which corresponds to an event in Economic Calendar
   MSG_GRAPH_STD_OBJ_RECTANGLE_LABEL,                 // Rectangle Label object used to create and design the custom graphical interface

   MSG_GRAPH_OBJ_PROP_ID,                             // Object ID
   MSG_GRAPH_OBJ_PROP_TYPE,                           // Graphical object type (ENUM_OBJECT)
   MSG_GRAPH_OBJ_PROP_ELEMENT_TYPE,                   // Graphical element type (ENUM_GRAPH_ELEMENT_TYPE)
   MSG_GRAPH_OBJ_PROP_BELONG,                         // Graphical object affiliation
   MSG_GRAPH_OBJ_PROP_CHART_ID,                       // Chart ID
   MSG_GRAPH_OBJ_PROP_WND_NUM,                        // Chart subwindow index
   MSG_GRAPH_OBJ_PROP_CREATETIME,                     // Creation time
   MSG_GRAPH_OBJ_PROP_TIMEFRAMES,                     // Object visibility on timeframes
   MSG_GRAPH_OBJ_PROP_BACK,                           // Background object
   MSG_GRAPH_OBJ_PROP_ZORDER,                         // Priority of a graphical object for receiving the event of clicking on a chart
   MSG_GRAPH_OBJ_PROP_HIDDEN,                         // Disable displaying the name of a graphical object in the terminal object list
   MSG_GRAPH_OBJ_PROP_SELECTED,                       // Object selection
   MSG_GRAPH_OBJ_PROP_SELECTABLE,                     // Object availability
   MSG_GRAPH_OBJ_PROP_NUM,                            // Object index in the list
   MSG_GRAPH_OBJ_PROP_TIME,                           // Time coordinate
   MSG_GRAPH_OBJ_PROP_COLOR,                          // Color
   MSG_GRAPH_OBJ_PROP_STYLE,                          // Style
   MSG_GRAPH_OBJ_PROP_WIDTH,                          // Line width
   MSG_GRAPH_OBJ_PROP_FILL,                           // Object color filling
   MSG_GRAPH_OBJ_PROP_READONLY,                       // Ability to edit text in the Edit object
   MSG_GRAPH_OBJ_PROP_LEVELS,                         // Number of levels
   MSG_GRAPH_OBJ_PROP_LEVELCOLOR,                     // Level line color
   MSG_GRAPH_OBJ_PROP_LEVELSTYLE,                     // Level line style
   MSG_GRAPH_OBJ_PROP_LEVELWIDTH,                     // Level line width
   MSG_GRAPH_OBJ_PROP_ALIGN,                          // Horizontal text alignment in the Edit object (OBJ_EDIT)
   MSG_GRAPH_OBJ_PROP_FONTSIZE,                       // Font size
   MSG_GRAPH_OBJ_PROP_RAY_LEFT,                       // Ray goes to the left
   MSG_GRAPH_OBJ_PROP_RAY_RIGHT,                      // Ray goes to the right
   MSG_GRAPH_OBJ_PROP_RAY,                            // Vertical line goes through all windows of a chart
   MSG_GRAPH_OBJ_PROP_ELLIPSE,                        // Display the full ellipse of the Fibonacci Arc object
   MSG_GRAPH_OBJ_PROP_ARROWCODE,                      // Arrow code for the "Arrow" object
   MSG_GRAPH_OBJ_PROP_ANCHOR,                         // Position of the binding point of the graphical object
   MSG_GRAPH_OBJ_PROP_XDISTANCE,                      // Distance from the base corner along the X axis in pixels
   MSG_GRAPH_OBJ_PROP_YDISTANCE,                      // Distance from the base corner along the Y axis in pixels
   MSG_GRAPH_OBJ_PROP_DIRECTION,                      // Gann object trend
   MSG_GRAPH_OBJ_PROP_DEGREE,                         // Elliott wave marking level
   MSG_GRAPH_OBJ_PROP_DRAWLINES,                      // Display lines for Elliott wave marking
   MSG_GRAPH_OBJ_PROP_STATE,                          // Button state (pressed/released)
   MSG_GRAPH_OBJ_PROP_CHART_OBJ_PERIOD,               // Chart object period
   MSG_GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE,           // Time scale display flag for the Chart object
   MSG_GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE,          // Price scale display flag for the Chart object
   MSG_GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE,          // Chart object scale
   MSG_GRAPH_OBJ_PROP_XSIZE,                          // Object width along the X axis in pixels.
   MSG_GRAPH_OBJ_PROP_YSIZE,                          // Object height along the Y axis in pixels.
   MSG_GRAPH_OBJ_PROP_XOFFSET,                        // X coordinate of the upper-left corner of the visibility area.
   MSG_GRAPH_OBJ_PROP_YOFFSET,                        // Y coordinate of the upper-left corner of the visibility area.
   MSG_GRAPH_OBJ_PROP_BGCOLOR,                        // Background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL
   MSG_GRAPH_OBJ_PROP_CORNER,                         // Chart corner for binding a graphical object
   MSG_GRAPH_OBJ_PROP_BORDER_TYPE,                    // Border type for "Rectangle border"
   MSG_GRAPH_OBJ_PROP_BORDER_COLOR,                   // Border color for OBJ_EDIT and OBJ_BUTTON
//---
   MSG_GRAPH_OBJ_PROP_PRICE,                          // Price coordinate
   MSG_GRAPH_OBJ_PROP_LEVELVALUE,                     // Level value
   MSG_GRAPH_OBJ_PROP_SCALE,                          // Scale (property of Gann objects and Fibonacci Arcs objects)
   MSG_GRAPH_OBJ_PROP_ANGLE,                          // Angle
   MSG_GRAPH_OBJ_PROP_DEVIATION,                      // Deviation of the standard deviation channel
//---
   MSG_GRAPH_OBJ_PROP_NAME,                           // Object name
   MSG_GRAPH_OBJ_PROP_TEXT,                           // Object description (text contained in the object)
   MSG_GRAPH_OBJ_PROP_TOOLTIP,                        // Tooltip text
   MSG_GRAPH_OBJ_PROP_LEVELTEXT,                      // Level description
   MSG_GRAPH_OBJ_PROP_FONT,                           // Font
   MSG_GRAPH_OBJ_PROP_BMPFILE,                        // BMP file name for the "Bitmap Level" object
   MSG_GRAPH_OBJ_PROP_SYMBOL,                         // Symbol for the Chart object 
   
  };
//+------------------------------------------------------------------+

y los mensajes de texto que se corresponden con los índices nuevamente añadidos:

   {"Январь","January"},
   {"Февраль","February"},
   {"Март","March"},
   {"Апрель","April"},
   {"Май","May"},
   {"Июнь","June"},
   {"Июль","July"},
   {"Август","August"},
   {"Сентябрь","September"},
   {"Октябрь","October"},
   {"Ноябрь","November"},
   {"Декабрь","December"},
   
   {"Выравнивание по левой границе","Left alignment"},
   {"Выравнивание по центру","Centered"},
   {"Выравнивание по правой границе","Right alignment",},
   
   {"Линия соответствует восходящему тренду","Line corresponding to the uptrend line"},
   {"Линия соответствует нисходящему тренду","Line corresponding to the downward trend"},
   
   {"Главный Суперцикл (Grand Supercycle)","Grand Supercycle"},
   {"Суперцикл (Supercycle)","Supercycle"},
   {"Цикл (Cycle)","Cycle"},
   {"Первичный цикл (Primary)","Primary"},
   {"Промежуточное звено (Intermediate)","Intermediate"},
   {"Второстепенный цикл (Minor)","Minor"},
   {"Минута (Minute)","Minute"},
   {"Секунда (Minuette)","Minuette"},
   {"Субсекунда (Subminuette)","Subminuette"},
   
   {"Нажата","Pressed"},
   {"Отжата","Depressed"},
   
   {"Центр координат в левом верхнем углу графика","Center of coordinates is in the upper left corner of the chart"},
   {"Центр координат в левом нижнем углу графика","Center of coordinates is in the lower left corner of the chart"},
   {"Центр координат в правом нижнем углу графика","Center of coordinates is in the lower right corner of the chart"},
   {"Центр координат в правом верхнем углу графика","Center of coordinates is in the upper right corner of the chart"},
   
   {"Плоский вид","Flat form"},
   {"Выпуклый вид","Prominent form"},
   {"Вогнутый вид","Concave form"},
   
   {"Воскресение","Sunday"},
   {"Понедельник","Monday"},
   {"Вторник","Tuesday"},
   {"Среда","Wednesday"},
   {"Четверг","Thursday"},
   {"Пятница","Friday"},
   {"Суббота","Saturday"},

...

//--- CGraphElementsCollection
   {"Ошибка. Уже существует объект управления чартами с идентификатором чарта ","Error. A chart control object already exists with chart id "},
   {"Не удалось создать объект управления чартами с идентификатором чарта ","Failed to create chart control object with chart id "},

//--- GStdGraphObj
   {"Не удалось найти подокно графика","Could not find chart subwindow"},
   
   {"Стандартный графический объект","Standard graphic object"},
   {"Элемент","Element"},
   {"Объект тени","Shadow object"},
   {"Форма","Form"},
   {"Окно","Window"},
   
   {"Графический объект принадлежит программе","The graphic object belongs to the program"},
   {"Графический объект не принадлежит программе","The graphic object does not belong to the program"},
   
   {"Вертикальная линия","Vertical Line"},
   {"Горизонтальная линия","Horizontal Line"},
   {"Трендовая линия","Trend Line"},
   {"Трендовая линия по углу","Trend Line By Angle"},
   {"Циклические линии","Cycle Lines"},
   {"Линия со стрелкой","Arrowed Line"},
   {"Равноудаленный канал","Equidistant Channel"},
   {"Канал стандартного отклонения","Standard Deviation Channel"},
   {"Канал на линейной регрессии","Linear Regression Channel"},
   {"Вилы Эндрюса","Andrews’ Pitchfork"},
   {"Линия Ганна","Gann Line"},
   {"Веер Ганна","Gann Fan"},
   {"Сетка Ганна","Gann Grid"},
   {"Уровни Фибоначчи","Fibonacci Retracement"},
   {"Временные зоны Фибоначчи","Fibonacci Time Zones"},
   {"Веер Фибоначчи","Fibonacci Fan"},
   {"Дуги Фибоначчи","Fibonacci Arcs"},
   {"Канал Фибоначчи","Fibonacci Channel"},
   {"Расширение Фибоначчи","Fibonacci Expansion"},
   {"5-волновка Эллиотта","Elliott Motive Wave"},
   {"3-волновка Эллиотта","Elliott Correction Wave"},
   {"Прямоугольник","Rectangle"},
   {"Треугольник","Triangle"},
   {"Эллипс","Ellipse"},
   {"Знак \"Хорошо\"","Thumbs Up"},
   {"Знак \"Плохо\"","Thumbs Down"},
   {"Знак \"Стрелка вверх\"","Arrow Up"},
   {"Знак \"Стрелка вниз\"","Arrow Down"},
   {"Знак \"Стоп\"","Stop Sign"},
   {"Знак \"Птичка\"","Check Sign"},
   {"Левая ценовая метка","Left Price Label"},
   {"Правая ценовая метка","Right Price Label"},
   {"Знак \"Buy\"","Buy Sign"},
   {"Знак \"Sell\"","Sell Sign"},
   {"Стрелка","Arrow"},
   {"Текст","Text"},
   {"Текстовая метка","Label"},
   {"Кнопка","Button"},
   {"График","Chart"},
   {"Рисунок","Bitmap"},
   {"Графическая метка","Bitmap Label"},
   {"Поле ввода","Edit"},
   {"Событие в экономическом календаре","The \"Event\" object corresponding to an event in the economic calendar"},
   {"Прямоугольная метка","The \"Rectangle label\" object for creating and designing the custom graphical interface"},
   
   {"Идентификатор объекта","Object ID"},
   {"Тип объекта","Object type"},
   {"Тип графического элемента","Graphic element type"},
   {"Принадлежность объекта","Object belongs to"},
   {"Идентификатор графика объекта","Object chart ID"},
   {"Номер подокна графика","Chart subwindow number"},
   {"Время создания","Time of creation"},
   {"Видимость объекта на таймфреймах","Visibility of an object at timeframes"},
   {"Объект на заднем плане","Object in the background"},
   {"Приоритет графического объекта на получение события нажатия мышки на графике","Priority of a graphical object for receiving events of clicking on a chart"},
   {"Запрет на показ имени графического объекта в списке объектов терминала","Prohibit showing of the name of a graphical object in the terminal objects list"},
   {"Выделенность объекта","Object is selected"},
   {"Доступность объекта","Object availability"},
   {"Номер объекта в списке","Object number in the list"},
   {"Координата времени","Time coordinate"},
   {"Цвет","Color"},
   {"Стиль","Style"},
   {"Толщина линии","Line thickness"},
   {"Заливка объекта цветом","Fill an object with color"},
   {"Возможность редактирования текста","Ability to edit text"},
   {"Количество уровней","Number of levels"},
   {"Цвет линии-уровня","Color of the line-level"},
   {"Стиль линии-уровня","Style of the line-level"},
   {"Толщина линии-уровня","Thickness of the line-level"},
   {"Горизонтальное выравнивание текста","Horizontal text alignment"},
   {"Размер шрифта","Font size"},
   {"Луч продолжается влево","Ray goes to the left"},
   {"Луч продолжается вправо","Ray goes to the right"},
   {"Вертикальная линия продолжается на все окна графика","A vertical line goes through all the windows of a chart"},
   {"Отображение полного эллипса","Showing the full ellipse"},
   {"Код стрелки","Arrow code"},
   {"Положение точки привязки","Location of the anchor point"},
   {"Дистанция в пикселях по оси X от угла привязки","The distance in pixels along the X axis from the binding corner"},
   {"Дистанция в пикселях по оси Y от угла привязки","The distance in pixels along the Y axis from the binding corner"},
   {"Тренд","Trend"},
   {"Уровень","Level"},
   {"Отображение линий","Displaying lines"},
   {"Состояние кнопки","Button state"},
   {"Период графика","Chart timeframe"},
   {"Отображение шкалы времени","Displaying the time scale"},
   {"Отображение ценовой шкалы","Displaying the price scale"},
   {"Масштаб графика","Chart scale"},
   {"Ширина по оси X в пикселях","Width along the X axis in pixels"},
   {"Высота по оси Y в пикселях","Height along the Y axis in pixels"},
   {"X-координата левого верхнего угла прямоугольной области видимости","The X coordinate of the upper left corner of the rectangular visible area"},
   {"Y-координата левого верхнего угла прямоугольной области видимости","The Y coordinate of the upper left corner of the rectangular visible area"},
   {"Цвет фона","Background color"},
   {"Угол графика для привязки","The corner of the chart to link a graphical object"},
   {"Тип рамки","Border type"},
   {"Цвет рамки","Border color"},
   {"Координата цены","Price coordinate"},
   {"Значение уровня","Level value"},
   {"Масштаб","Scale"},
   {"Угол","Angle"},
   {"Отклонение канала стандартного отклонения","Deviation for the Standard Deviation Channel"},
   {"Имя","Name"},
   {"Описание","Description"},
   {"Текст всплывающей подсказки","The text of a tooltip"},
   {"Описание уровня","Level description"},
   {"Шрифт","Font"},
   {"Имя BMP-файла","BMP-file name"},
   {"Символ графика","Chart Symbol"},

  };
//+---------------------------------------------------------------------+


Algunas propiedades de los objetos gráficos tienen el tipo de enumeración. Para retornar la descripción de estas enumeraciones, necesitaremos crear las funciones en el archivo de funciones de servicio de la biblioteca \MQL5\Include\DoEasy\Services\DELib.mqh:

Funciones que retornan la descripción del estilo de línea:

//+------------------------------------------------------------------+
//| Return description of the line style                             |
//+------------------------------------------------------------------+
string LineStyleDescription(const ENUM_LINE_STYLE style)
  {
   return
     (
      style==STYLE_SOLID      ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_STYLE_SOLID)      :
      style==STYLE_DASH       ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASH)       :
      style==STYLE_DOT        ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DOT)        :
      style==STYLE_DASHDOT    ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASHDOT)    :
      style==STYLE_DASHDOTDOT ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASHDOTDOT) :
      "Unknown"
     );
  }
//+------------------------------------------------------------------+

Función que retorna el tipo de alineación:

//+------------------------------------------------------------------+
//| Return the alignment type description                            |
//+------------------------------------------------------------------+
string AlignModeDescription(ENUM_ALIGN_MODE align)
  {
   return
     (
      align==ALIGN_LEFT    ? CMessage::Text(MSG_LIB_TEXT_ALIGN_LEFT)    :
      align==ALIGN_CENTER  ? CMessage::Text(MSG_LIB_TEXT_ALIGN_CENTER)  :
      align==ALIGN_RIGHT   ? CMessage::Text(MSG_LIB_TEXT_ALIGN_RIGHT)   :
      "Unknown"
     );
  }
//+------------------------------------------------------------------+

Función que retorna la descripción de la dirección de la tendencia de la retícula de Gann:

//+------------------------------------------------------------------+
//| Return the description of the Gann grid trend direction          |
//+------------------------------------------------------------------+
string GannDirectDescription(const ENUM_GANN_DIRECTION direction)
  {
   return
     (
      direction==GANN_UP_TREND   ? CMessage::Text(MSG_LIB_TEXT_GANN_UP_TREND)    :
      direction==GANN_DOWN_TREND ? CMessage::Text(MSG_LIB_TEXT_GANN_DOWN_TREND)  :
      "Unknown"
     );
  }
//+------------------------------------------------------------------+

Función que retorna la descripción del nivel de marcado con ondas de Elliott:

//+------------------------------------------------------------------+
//| Return the description of the Elliott wave marking level         |
//+------------------------------------------------------------------+
string ElliotWaveDegreeDescription(const ENUM_ELLIOT_WAVE_DEGREE degree)
  {
   return
     (
      degree==ELLIOTT_GRAND_SUPERCYCLE ? CMessage::Text(MSG_LIB_TEXT_ELLIOTT_GRAND_SUPERCYCLE)  :
      degree==ELLIOTT_SUPERCYCLE       ? CMessage::Text(MSG_LIB_TEXT_ELLIOTT_SUPERCYCLE)        :
      degree==ELLIOTT_CYCLE            ? CMessage::Text(MSG_LIB_TEXT_ELLIOTT_CYCLE)             :
      degree==ELLIOTT_PRIMARY          ? CMessage::Text(MSG_LIB_TEXT_ELLIOTT_PRIMARY)           :
      degree==ELLIOTT_INTERMEDIATE     ? CMessage::Text(MSG_LIB_TEXT_ELLIOTT_INTERMEDIATE)      :
      degree==ELLIOTT_MINOR            ? CMessage::Text(MSG_LIB_TEXT_ELLIOTT_MINOR)             :
      degree==ELLIOTT_MINUTE           ? CMessage::Text(MSG_LIB_TEXT_ELLIOTT_MINUTE)            :
      degree==ELLIOTT_MINUETTE         ? CMessage::Text(MSG_LIB_TEXT_ELLIOTT_MINUETTE)          :
      degree==ELLIOTT_SUBMINUETTE      ? CMessage::Text(MSG_LIB_TEXT_ELLIOTT_SUBMINUETTE)       :
      "Unknown"
     );
  }
//+------------------------------------------------------------------+

Función que retorna la descripción del ángulo del gráfico respecto al cual se indican las coordenadas en píxeles:

//+------------------------------------------------------------------+
//| Return the description of the chart corner, relative to          |
//| which the coordinates in pixels are specified                    |
//+------------------------------------------------------------------+
string BaseCornerDescription(const ENUM_BASE_CORNER corner)
  {
   return
     (
      corner==CORNER_LEFT_UPPER  ? CMessage::Text(MSG_LIB_TEXT_CORNER_LEFT_UPPER)   :
      corner==CORNER_LEFT_LOWER  ? CMessage::Text(MSG_LIB_TEXT_CORNER_LEFT_LOWER)   :
      corner==CORNER_RIGHT_LOWER ? CMessage::Text(MSG_LIB_TEXT_CORNER_RIGHT_LOWER)  :
      corner==CORNER_RIGHT_UPPER ? CMessage::Text(MSG_LIB_TEXT_CORNER_RIGHT_UPPER)  :
      "Unknown"
     );
  }
//+------------------------------------------------------------------+

Función que retorna la descripción del tipo de representación del marco del objeto gráfico:

//+------------------------------------------------------------------+
//| Return the description of the graphical object frame look        |
//+------------------------------------------------------------------+
string BorderTypeDescription(const ENUM_BORDER_TYPE border_type)
  {
   return
     (
      border_type==BORDER_FLAT   ? CMessage::Text(MSG_LIB_TEXT_BORDER_FLAT)   :
      border_type==BORDER_RAISED ? CMessage::Text(MSG_LIB_TEXT_BORDER_RAISED) :
      border_type==BORDER_SUNKEN ? CMessage::Text(MSG_LIB_TEXT_BORDER_SUNKEN) :
      "Unknown"
     );
  }
//+------------------------------------------------------------------+

Función que retorna la descripción del tipo del objeto gráfico estándar:

//+------------------------------------------------------------------+
//| Return the description of the standard graphical object type     |
//+------------------------------------------------------------------+
string StdGraphObjectTypeDescription(const ENUM_OBJECT type)
  {
   return
     (
      type==OBJ_VLINE               ? CMessage::Text(MSG_GRAPH_STD_OBJ_VLINE)             :
      type==OBJ_HLINE               ? CMessage::Text(MSG_GRAPH_STD_OBJ_HLINE)             :
      type==OBJ_TREND               ? CMessage::Text(MSG_GRAPH_STD_OBJ_TREND)             :
      type==OBJ_TRENDBYANGLE        ? CMessage::Text(MSG_GRAPH_STD_OBJ_TRENDBYANGLE)      :
      type==OBJ_CYCLES              ? CMessage::Text(MSG_GRAPH_STD_OBJ_CYCLES)            :
      type==OBJ_ARROWED_LINE        ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROWED_LINE)      :
      type==OBJ_CHANNEL             ? CMessage::Text(MSG_GRAPH_STD_OBJ_CHANNEL)           :
      type==OBJ_STDDEVCHANNEL       ? CMessage::Text(MSG_GRAPH_STD_OBJ_STDDEVCHANNEL)     :
      type==OBJ_REGRESSION          ? CMessage::Text(MSG_GRAPH_STD_OBJ_REGRESSION)        :
      type==OBJ_PITCHFORK           ? CMessage::Text(MSG_GRAPH_STD_OBJ_PITCHFORK)         :
      type==OBJ_GANNLINE            ? CMessage::Text(MSG_GRAPH_STD_OBJ_GANNLINE)          :
      type==OBJ_GANNFAN             ? CMessage::Text(MSG_GRAPH_STD_OBJ_GANNFAN)           :
      type==OBJ_GANNGRID            ? CMessage::Text(MSG_GRAPH_STD_OBJ_GANNGRID)          :
      type==OBJ_FIBO                ? CMessage::Text(MSG_GRAPH_STD_OBJ_FIBO)              :
      type==OBJ_FIBOTIMES           ? CMessage::Text(MSG_GRAPH_STD_OBJ_FIBOTIMES)         :
      type==OBJ_FIBOFAN             ? CMessage::Text(MSG_GRAPH_STD_OBJ_FIBOFAN)           :
      type==OBJ_FIBOARC             ? CMessage::Text(MSG_GRAPH_STD_OBJ_FIBOARC)           :
      type==OBJ_FIBOCHANNEL         ? CMessage::Text(MSG_GRAPH_STD_OBJ_FIBOCHANNEL)       :
      type==OBJ_EXPANSION           ? CMessage::Text(MSG_GRAPH_STD_OBJ_EXPANSION)         :
      type==OBJ_ELLIOTWAVE5         ? CMessage::Text(MSG_GRAPH_STD_OBJ_ELLIOTWAVE5)       :
      type==OBJ_ELLIOTWAVE3         ? CMessage::Text(MSG_GRAPH_STD_OBJ_ELLIOTWAVE3)       :
      type==OBJ_RECTANGLE           ? CMessage::Text(MSG_GRAPH_STD_OBJ_RECTANGLE)         :
      type==OBJ_TRIANGLE            ? CMessage::Text(MSG_GRAPH_STD_OBJ_TRIANGLE)          :
      type==OBJ_ELLIPSE             ? CMessage::Text(MSG_GRAPH_STD_OBJ_ELLIPSE)           :
      type==OBJ_ARROW_THUMB_UP      ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROW_THUMB_UP)    :
      type==OBJ_ARROW_THUMB_DOWN    ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROW_THUMB_DOWN)  :
      type==OBJ_ARROW_UP            ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROW_UP)          :
      type==OBJ_ARROW_DOWN          ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROW_DOWN)        :
      type==OBJ_ARROW_STOP          ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROW_STOP)        :
      type==OBJ_ARROW_CHECK         ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROW_CHECK)       :
      type==OBJ_ARROW_LEFT_PRICE    ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROW_LEFT_PRICE)  :
      type==OBJ_ARROW_RIGHT_PRICE   ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROW_RIGHT_PRICE) :
      type==OBJ_ARROW_BUY           ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROW_BUY)         :
      type==OBJ_ARROW_SELL          ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROW_SELL)        :
      type==OBJ_ARROW               ? CMessage::Text(MSG_GRAPH_STD_OBJ_ARROW)             :
      type==OBJ_TEXT                ? CMessage::Text(MSG_GRAPH_STD_OBJ_TEXT)              :
      type==OBJ_LABEL               ? CMessage::Text(MSG_GRAPH_STD_OBJ_LABEL)             :
      type==OBJ_BUTTON              ? CMessage::Text(MSG_GRAPH_STD_OBJ_BUTTON)            :
      type==OBJ_CHART               ? CMessage::Text(MSG_GRAPH_STD_OBJ_CHART)             :
      type==OBJ_BITMAP              ? CMessage::Text(MSG_GRAPH_STD_OBJ_BITMAP)            :
      type==OBJ_BITMAP_LABEL        ? CMessage::Text(MSG_GRAPH_STD_OBJ_BITMAP_LABEL)      :
      type==OBJ_EDIT                ? CMessage::Text(MSG_GRAPH_STD_OBJ_EDIT)              :
      type==OBJ_EVENT               ? CMessage::Text(MSG_GRAPH_STD_OBJ_EVENT)             :
      type==OBJ_RECTANGLE_LABEL     ? CMessage::Text(MSG_GRAPH_STD_OBJ_RECTANGLE_LABEL)   :
      "Unknown"
     );
  }
//+------------------------------------------------------------------+

Como podemos ver, a cada función se le transmite una variable que indica el tipo comprobado por la función. A continuación, comparamos el tipo transmitido a la función y retornamos su descripción usando el método Text() de la clase CMessage.

En el archivo \MQL5\Include\DoEasy\Objects\Indicators\Buffer.mqh de la clase de búfer de indicador abstracto, reescribimos el método que retorna la descripción del estilo de la línea de dibujado del búfer de indicador. Antes, este método tenía exactamente la misma lógica que la función recién añadida LineStyleDescription(), es decir, la siguiente:

//+------------------------------------------------------------------+
//| Return description of the drawing line style                     |
//+------------------------------------------------------------------+
string CBuffer::GetLineStyleDescription(void) const
  {
   return
     (
      this.LineStyle()==STYLE_SOLID       ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_STYLE_SOLID)      :
      this.LineStyle()==STYLE_DASH        ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASH)       :
      this.LineStyle()==STYLE_DOT         ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DOT)        :
      this.LineStyle()==STYLE_DASHDOT     ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASHDOT)    :
      this.LineStyle()==STYLE_DASHDOTDOT  ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASHDOTDOT) :
      "Unknown"
     );
  }
//+------------------------------------------------------------------+

Ahora, como ya tenemos una función de servicio común para todas las clases de la biblioteca, simplemente retornamos en este método el resultado de la llamada a esta función:

//+------------------------------------------------------------------+
//| Return description of the drawing line style                     |
//+------------------------------------------------------------------+
string CBuffer::GetLineStyleDescription(void) const
  {
   return LineStyleDescription(this.LineStyle());
  }
//+------------------------------------------------------------------+


Puesto que hemos añadido a todos los objetos gráficos un gran número de nuevas propiedades (algunas de las cuales serán inherentes a todos los objetos gráficos de la biblioteca), deberemos rehacer la clase de objeto gráfico básico de la biblioteca de la que se heredan todos los objetos del gráfico en la biblioteca, en el archivo \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh. Para ello, le añadiremos todas las variables necesarias comunes a todos los objetos gráficos, y crearemos los métodos para establecer y retornar los valores de estas variables.

En la sección protegida de la clase, declaramos todas las variables necesarias:

//+------------------------------------------------------------------+
//|                                                     GBaseObj.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\Services\DELib.mqh"
#include <Graphics\Graphic.mqh>
//+------------------------------------------------------------------+
//| Class of the base object of the library graphical objects        |
//+------------------------------------------------------------------+
class CGBaseObj : public CObject
  {
private:

protected:
   ENUM_OBJECT       m_type_graph_obj;                   // Graphical object type
   ENUM_GRAPH_ELEMENT_TYPE m_type_element;               // Graphical element type
   ENUM_GRAPH_OBJ_BELONG m_belong;                       // Program affiliation
   string            m_name_prefix;                      // Object name prefix
   string            m_name;                             // Object name
   long              m_chart_id;                         // Object chart ID
   long              m_object_id;                        // Object ID
   long              m_zorder;                           // Priority of a graphical object for receiving the mouse click event
   int               m_subwindow;                        // Subwindow index
   int               m_shift_y;                          // Subwindow Y coordinate shift
   int               m_type;                             // Object type
   int               m_timeframes_visible;               // Visibility of an object on timeframes (a set of flags)
   int               m_digits;                           // Number of decimal places in a quote
   bool              m_visible;                          // Object visibility
   bool              m_back;                             // "Background object" flag
   bool              m_selected;                         // "Object selection" flag
   bool              m_selectable;                       // "Object availability" flag
   bool              m_hidden;                           // "Disable displaying the name of a graphical object in the terminal object list" flag
   datetime          m_create_time;                      // Object creation time
   
//--- Create (1) the object structure and (2) the object from the structure
   virtual bool      ObjectToStruct(void)                      { return true; }
   virtual void      StructToObject(void){;}

public:

En la sección pública de la clase, escribimos los métodos para establecer las propiedades del objeto presentes en cada objeto gráfico de la biblioteca:

public:
//--- Set the values of the class variables
   void              SetObjectID(const long value)             { this.m_object_id=value;           }
   void              SetBelong(const ENUM_GRAPH_OBJ_BELONG belong){ this.m_belong=belong;          }
   void              SetTypeGraphObject(const ENUM_OBJECT obj) { this.m_type_graph_obj=obj;        }
   void              SetTypeElement(const ENUM_GRAPH_ELEMENT_TYPE type) { this.m_type_element=type;}
   void              SetName(const string name)                { this.m_name=name;                 }
   void              SetChartID(const long chart_id)           { this.m_chart_id=chart_id;         }
   void              SetDigits(const int value)                { this.m_digits=value;              }

Los valores de las propiedades de los objetos indicadas, que son establecidos por estos métodos, se guardan solo en estas variables, por consiguiente, bastará con añadir a la variable el valor transmitido al método.

Pero aquellas propiedades que, además de almacenarse en las variables de clase también se escriben en el propio objeto gráfico, deberán establecerse de otra forma: primero, cambiaremos el valor de la propiedad directamente en el objeto gráfico, y solo al ejecutar con éxito la solicitud, intorduciremos el mismo valor en la variable de clase:

//--- Set the "Background object" flag
   bool              SetBack(const bool flag)
                       {
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_BACK,flag))
                          {
                           this.m_back=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }

Cabe señalar que la función de ajuste del valor del objeto gráfico usa una llamada asíncrona, lo cual significa que la función no estará esperando la ejecución del comando configurada con éxito en la cola del gráfico indicado, sino que retornará inmediatamente el control.

Por consiguiente, no podremos afirmar con seguridad que una función colocada con éxito en la cola de eventos vaya a cambiar con certeza la propiedad de una objeto gráfico.


Y, como se nos dice en la guía de ayuda, para verificar el resultado de la ejecución de una consulta en un gráfico ajeno, podemos usar la función que solicita la propiedad especificada del objeto. Sin embargo, deberemos tener en cuenta que estas funciones se colocan al final de la cola de comandos de la otra persona, por lo que tendremos que esperar el resultado, es decir, conllevará un cierto gasto de tiempo. No debemos olvidar esta circunstancia si trabajamos con un gran número de objetos en el gráfico.

Partiendo de esto, lo dejaremos todo tal y como está. Por ahora, vamos a explotar el supuesto de que el comando para cambiar las propiedades del objeto ha funcionado con éxito. Si, en el proceso de utilización de la biblioteca, surgen casos en los que no se asignan propiedades a un objeto gráfico con la propiedad de variable de clase ya establecida, añadiremos la comprobación referente al cambio real de la propiedad en el objeto gráfico.

Vamos a analizar todos los métodos similares de ajuste de las propiedades del objeto gráfico y las variables añadidas a la sección pública de la clase:

//--- Set the "Background object" flag
   bool              SetBack(const bool flag)
                       {
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_BACK,flag))
                          {
                           this.m_back=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set the "Object selection" flag
   bool              SetSelected(const bool flag)
                       {
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTED,flag))
                          {
                           this.m_selected=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set the "Object selection" flag
   bool              SetSelectable(const bool flag)
                       {
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTABLE,flag))
                          {
                           this.m_selectable=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set the "Disable displaying the name of a graphical object in the terminal object list" flag
   bool              SetHidden(const bool flag)
                       {
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTABLE,flag))
                          {
                           this.m_hidden=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set the priority of a graphical object for receiving the event of clicking on a chart 
   bool              SetZorder(const long value)
                       {
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_ZORDER,value))
                          {
                           this.m_zorder=value;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set object visibility on all timeframes
   bool              SetVisible(const bool flag)   
                       {
                        long value=(flag ? OBJ_ALL_PERIODS : OBJ_NO_PERIODS);
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_TIMEFRAMES,value))
                          {
                           this.m_visible=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set visibility flags on timeframes specified as flags
   bool              SetVisibleOnTimeframe(const int flags)
                       {
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_TIMEFRAMES,flags))
                          {
                           this.m_timeframes_visible=flags;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Add the visibility flag on a specified timeframe
   bool              SetVisibleOnTimeframe(const ENUM_TIMEFRAMES timeframe)
                       {
                        int flags=this.m_timeframes_visible;
                        switch(timeframe)
                          {
                           case PERIOD_M1    : flags |= OBJ_PERIOD_M1;  break;
                           case PERIOD_M2    : flags |= OBJ_PERIOD_M2;  break;
                           case PERIOD_M3    : flags |= OBJ_PERIOD_M3;  break;
                           case PERIOD_M4    : flags |= OBJ_PERIOD_M4;  break;
                           case PERIOD_M5    : flags |= OBJ_PERIOD_M5;  break;
                           case PERIOD_M6    : flags |= OBJ_PERIOD_M6;  break;
                           case PERIOD_M10   : flags |= OBJ_PERIOD_M10; break;
                           case PERIOD_M12   : flags |= OBJ_PERIOD_M12; break;
                           case PERIOD_M15   : flags |= OBJ_PERIOD_M15; break;
                           case PERIOD_M20   : flags |= OBJ_PERIOD_M20; break;
                           case PERIOD_M30   : flags |= OBJ_PERIOD_M30; break;
                           case PERIOD_H1    : flags |= OBJ_PERIOD_H1;  break;
                           case PERIOD_H2    : flags |= OBJ_PERIOD_H2;  break;
                           case PERIOD_H3    : flags |= OBJ_PERIOD_H3;  break;
                           case PERIOD_H4    : flags |= OBJ_PERIOD_H4;  break;
                           case PERIOD_H6    : flags |= OBJ_PERIOD_H6;  break;
                           case PERIOD_H8    : flags |= OBJ_PERIOD_H8;  break;
                           case PERIOD_H12   : flags |= OBJ_PERIOD_H12; break;
                           case PERIOD_D1    : flags |= OBJ_PERIOD_D1;  break;
                           case PERIOD_W1    : flags |= OBJ_PERIOD_W1;  break;
                           case PERIOD_MN1   : flags |= OBJ_PERIOD_MN1; break;
                           default           : return true;
                          }
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_TIMEFRAMES,flags))
                          {
                           this.m_timeframes_visible=flags;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set a subwindow index
   bool              SetSubwindow(const long chart_id,const string name)
                       {
                        ::ResetLastError();
                        this.m_subwindow=::ObjectFind(chart_id,name);
                        if(this.m_subwindow<0)
                           CMessage::ToLog(DFUN,MSG_GRAPH_STD_OBJ_ERR_NOT_FIND_SUBWINDOW);
                        return(this.m_subwindow>WRONG_VALUE);
                       }
   bool              SetSubwindow(void)
                       {
                        return this.SetSubwindow(this.m_chart_id,this.m_name);
                       }

//--- Return the values of class variables

A continuación, añadimos los métodos que retornan los valores de las variables de clase:

//--- Return the values of class variables
   ENUM_GRAPH_ELEMENT_TYPE TypeGraphElement(void)        const { return this.m_type_element;       }
   ENUM_GRAPH_OBJ_BELONG   Belong(void)                  const { return this.m_belong;             }
   ENUM_OBJECT       TypeGraphObject(void)               const { return this.m_type_graph_obj;     }
   datetime          TimeCreate(void)                    const { return this.m_create_time;        }
   string            Name(void)                          const { return this.m_name;               }
   long              ChartID(void)                       const { return this.m_chart_id;           }
   long              ObjectID(void)                      const { return this.m_object_id;          }
   long              Zorder(void)                        const { return this.m_zorder;             }
   int               SubWindow(void)                     const { return this.m_subwindow;          }
   int               ShiftY(void)                        const { return this.m_shift_y;            }
   int               VisibleOnTimeframes(void)           const { return this.m_timeframes_visible; }
   int               Digits(void)                        const { return this.m_digits;             }
   bool              IsBack(void)                        const { return this.m_back;               }
   bool              IsSelected(void)                    const { return this.m_selected;           }
   bool              IsSelectable(void)                  const { return this.m_selectable;         }
   bool              IsHidden(void)                      const { return this.m_hidden;             }
   bool              IsVisible(void)                     const { return this.m_visible;            }
//--- Return the object visibility flag on a specified timeframe
   bool              IsVisibleOnTimeframe(const ENUM_TIMEFRAMES timeframe) const
                       { return((this.m_timeframes_visible & timeframe)==timeframe);               }
//--- Return the graphical object type (ENUM_OBJECT) calculated from the object type (ENUM_OBJECT_DE_TYPE) passed to the method
   ENUM_OBJECT       GraphObjectType(const ENUM_OBJECT_DE_TYPE obj_type) const
                       { 
                        return ENUM_OBJECT(obj_type-OBJECT_DE_TYPE_GSTD_OBJ-1);
                       }
   
//--- Return the description of the graphical object type

Todos los métodos retornan los valores anotados en las variables de clase correspondientes.

El método GraphObjectType() calcula el tipo de objeto gráfico del valor del tipo de objeto de tal forma que, partiendo del tipo de objeto representado por el tipo de enumeración ENUM_OBJECT_DE_TYPE de la biblioteca, podamos obtener el tipo de la enumeración estándar ENUM_OBJECT.

Además, declaramos los métodos necesarios para retornar la descripción de los tipos de objeto y su pertenencia:

//--- Return the description of the type of the graphical (1) object, (2) element and (3) graphical object affiliation
string               TypeGraphObjectDescription(void);
string               TypeElementDescription(void);
string               BelongDescription(void);

//--- The virtual method returning the object type
   virtual int       Type(void)                          const { return this.m_type;               }

//--- Constructor/destructor
                     CGBaseObj();
                    ~CGBaseObj(){;}
  };
//+------------------------------------------------------------------+

En el constructor de la clase, asignamos a todas las variables de clase sus valores por defecto:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CGBaseObj::CGBaseObj() : m_shift_y(0),m_visible(false), m_name_prefix(::MQLInfoString(MQL_PROGRAM_NAME)+"_"),m_belong(GRAPH_OBJ_BELONG_PROGRAM)
  {
   this.m_type=OBJECT_DE_TYPE_GBASE;            // Object type
   this.m_type_graph_obj=WRONG_VALUE;           // Graphical object type
   this.m_type_element=WRONG_VALUE;             // Graphical object type
   this.m_belong=WRONG_VALUE;                   // Program/terminal affiliation
   this.m_name_prefix="";                       // Object name prefix
   this.m_name="";                              // Object name
   this.m_chart_id=0;                           // Object chart ID
   this.m_object_id=0;                          // Object ID
   this.m_zorder=0;                             // Priority of a graphical object for receiving the mouse click event
   this.m_subwindow=0;                          // Subwindow index
   this.m_shift_y=0;                            // Subwindow Y coordinate shift
   this.m_timeframes_visible=OBJ_ALL_PERIODS;   // Visibility of an object on timeframes (a set of flags)
   this.m_visible=true;                         // Object visibility
   this.m_back=false;                           // "Background object" flag
   this.m_selected=false;                       // "Object selection" flag
   this.m_selectable=false;                     // "Object availability" flag
   this.m_hidden=true;                          // "Disable displaying the name of a graphical object in the terminal object list" flag
   this.m_create_time=0;                        // Object creation time
   
  }
//+------------------------------------------------------------------+

Como consecuencia, partiendo de los herederos de la clase, podemos establecer los valores exactos de estas variables según el valor de las propiedades del objeto gráfico descrito por la clase heredera.

Implementación del método que retorna la descripción del tipo de objeto gráfico:

//+------------------------------------------------------------------+
//| Return the description of the graphical object type              |
//+------------------------------------------------------------------+
string CGBaseObj::TypeGraphObjectDescription(void)
  {
   if(this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_STANDART)
      return StdGraphObjectTypeDescription(this.m_type_graph_obj);
   else
      return this.TypeElementDescription();
  }
//+------------------------------------------------------------------+

Aquí, en primer lugar, miramos a qué tipo de elemento gráfico pertenece el objeto gráfico, y si se trata de un objeto gráfico estándar, retornamos su descripción usando la función de servicio StdGraphObjectTypeDescription() que hemos descrito más arriba.
De lo contrario, retornaremos la descripción del tipo de elemento gráfico usando el método TypeElementDescription() que analizaremos abajo:

//+------------------------------------------------------------------+
//| Return the description of the graphical element type             |
//+------------------------------------------------------------------+
string CGBaseObj::TypeElementDescription(void)
  {
   return
     (
      this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_STANDART     ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_STANDART)     :
      this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_ELEMENT      ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_ELEMENT)      :
      this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_SHADOW_OBJ   ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_SHADOW_OBJ)   :
      this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_FORM         ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_FORM)         :
      this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WINDOW       ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WINDOW)       :
      "Unknown"
     );
  }
//+------------------------------------------------------------------+

Método que retorna la descripción de la pertenencia de un objeto gráfico:

//+------------------------------------------------------------------+
//| Return the description of the graphical object affiliation       |
//+------------------------------------------------------------------+
string CGBaseObj::BelongDescription(void)
  {
   return
     (
      this.Belong()==GRAPH_OBJ_BELONG_PROGRAM      ? CMessage::Text(MSG_GRAPH_OBJ_BELONG_PROGRAM)     :
      this.Belong()==GRAPH_OBJ_BELONG_NO_PROGRAM   ? CMessage::Text(MSG_GRAPH_OBJ_BELONG_NO_PROGRAM)  :
      "Unknown"
     );
  }
//+------------------------------------------------------------------+

La lógica de los dos últimos métodos es similar a la lógica de las funciones de servicio que hemos visto más arriba.


Clase de objeto del objeto gráfico abstracto

Ya hemos superado todas las etapas preparatorias. A continuación, vamos a crear una clase de objeto gráfico abstracto.

En el directorio de la biblioteca \MQL5\Include\DoEasy\Objects\Graph\, creamos la nueva carpeta Standart\, y en ella, el nuevo archivo GStdGraphObj.mqh de la clase CGStdGraphObj.

La clase debe heredarse de la clase de objeto gráfico básico de todos los objetos gráficos de la biblioteca CGBaseObj, cuyo archivo también debe estar conectado al nuevo archivo de la clase generada:

//+------------------------------------------------------------------+
//|                                                 GStdGraphObj.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\GBaseObj.mqh"
//+------------------------------------------------------------------+
//| The class of the abstract standard graphical object              |
//+------------------------------------------------------------------+
class CGStdGraphObj : public CGBaseObj
  {
  }

En la sección privada de la clase, como ya sabemos por muchos artículos anteriores, colocamos las matrices para guardar las propiedades del objeto y los métodos para retornar el índice real de una propiedad en la matriz que le corresponde:

//+------------------------------------------------------------------+
//| The class of the abstract standard graphical object              |
//+------------------------------------------------------------------+
class CGStdGraphObj : public CGBaseObj
  {
private:

   long              m_long_prop[GRAPH_OBJ_PROP_INTEGER_TOTAL];      // Integer properties
   double            m_double_prop[GRAPH_OBJ_PROP_DOUBLE_TOTAL];     // Real properties
   string            m_string_prop[GRAPH_OBJ_PROP_STRING_TOTAL];     // String properties

//--- Return the index of the array the (1) double and (2) string properties are actually located at
   int               IndexProp(ENUM_GRAPH_OBJ_PROP_DOUBLE property)  const { return(int)property-GRAPH_OBJ_PROP_INTEGER_TOTAL;                              }
   int               IndexProp(ENUM_GRAPH_OBJ_PROP_STRING property)  const { return(int)property-GRAPH_OBJ_PROP_INTEGER_TOTAL-GRAPH_OBJ_PROP_DOUBLE_TOTAL;  }

public:

En la sección pública de la clase, colocamos los métodos estándar para todos los objetos de la biblioteca y los dos constructores (el constructor por defecto y el constructor paramétrico cerrado):

public:
//--- Set object's (1) integer, (2) real and (3) string properties
   void              SetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property,long value)   { this.m_long_prop[property]=value;                      }
   void              SetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property,double value)  { this.m_double_prop[this.IndexProp(property)]=value;    }
   void              SetProperty(ENUM_GRAPH_OBJ_PROP_STRING property,string value)  { this.m_string_prop[this.IndexProp(property)]=value;    }
//--- Return object’s (1) integer, (2) real and (3) string property from the properties array
   long              GetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property)        const { return this.m_long_prop[property];                     }
   double            GetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property)         const { return this.m_double_prop[this.IndexProp(property)];   }
   string            GetProperty(ENUM_GRAPH_OBJ_PROP_STRING property)         const { return this.m_string_prop[this.IndexProp(property)];   }
//--- Return itself
   CGStdGraphObj    *GetObject(void)                                                { return &this;}

//--- Return the flag of the object supporting this property
   virtual bool      SupportProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property)          { return true; }
   virtual bool      SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property)           { return true; }
   virtual bool      SupportProperty(ENUM_GRAPH_OBJ_PROP_STRING property)           { return true; }

//--- Get description of (1) integer, (2) real and (3) string properties
   string            GetPropertyDescription(ENUM_GRAPH_OBJ_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_GRAPH_OBJ_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_GRAPH_OBJ_PROP_STRING property);

//--- Return the description of the graphical object anchor point position
   virtual string    AnchorDescription(void)                                  const { return (string)this.GetProperty(GRAPH_OBJ_PROP_ANCHOR);}

//--- Display the description of the object properties in the journal (full_prop=true - all properties, false - supported ones only - implemented in descendant classes)
   virtual void      Print(const bool full_prop=false,const bool dash=false);
//--- Display a short description of the object in the journal
   virtual void      PrintShort(const bool dash=false,const bool symbol=false);
//--- Return the object short name
   virtual string    Header(const bool symbol=false);
  
//--- Compare CGStdGraphObj objects by a specified property (to sort the list by an object property)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Compare CGStdGraphObj objects with each other by all properties (to search for equal objects)
   bool              IsEqual(CGStdGraphObj* compared_req) const;
   
//--- Default constructor
                     CGStdGraphObj(){ this.m_type=OBJECT_DE_TYPE_GSTD_OBJ;  }
protected:
//--- Protected parametric constructor
                     CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type,const ENUM_GRAPH_OBJ_BELONG belong,const long chart_id,const string name);
                     
public:
//+--------------------------------------------------------------------+ 
//|Methods of simplified access and setting graphical object properties|
//+--------------------------------------------------------------------+

El método que retorna la descripción de la posición del punto de anclaje de un objeto gráfico, aquí no retorna la descripción en sí, sino un número. El hecho es que diferentes objetos usan enumeraciones distintas para indicar los puntos de anclaje. Por consiguiente, este método se ha hecho virtual y se ha redefinido en los objetos descendientes que tengan tales propiedades.

A continuación, usaremos el código de la clase para añadir los métodos que permiten acceder de forma simplificada al establecimiento y el retorno de las propiedades del objeto:

public:
//+--------------------------------------------------------------------+ 
//|Methods of simplified access and setting graphical object properties|
//+--------------------------------------------------------------------+
//--- Object index in the list
   int               Number(void)                  const { return (int)this.GetProperty(GRAPH_OBJ_PROP_NUM);                              }
   void              SetNumber(const int number)         { this.SetProperty(GRAPH_OBJ_PROP_NUM,number);                                   }
//--- Object ID
   long              ObjectID(void)                const { return this.GetProperty(GRAPH_OBJ_PROP_ID);                                    }
   void              SetObjectID(const long obj_id)
                       {
                        CGBaseObj::SetObjectID(obj_id);
                        this.SetProperty(GRAPH_OBJ_PROP_ID,obj_id);
                       }
//--- Graphical object type
   ENUM_OBJECT       GraphObjectType(void)         const { return (ENUM_OBJECT)this.GetProperty(GRAPH_OBJ_PROP_TYPE);                     }
   void              SetGraphObjectType(const ENUM_OBJECT obj_type)
                       {
                        CGBaseObj::SetTypeGraphObject(obj_type);
                        this.SetProperty(GRAPH_OBJ_PROP_TYPE,obj_type);
                       }
//--- Graphical element type
   ENUM_GRAPH_ELEMENT_TYPE GraphElementType(void)  const { return (ENUM_GRAPH_ELEMENT_TYPE)this.GetProperty(GRAPH_OBJ_PROP_ELEMENT_TYPE); }
   void              SetGraphElementType(const ENUM_GRAPH_ELEMENT_TYPE elm_type)
                       {
                        CGBaseObj::SetTypeElement(elm_type);
                        this.SetProperty(GRAPH_OBJ_PROP_ELEMENT_TYPE,elm_type);
                       }
//--- Graphical object affiliation
   ENUM_GRAPH_OBJ_BELONG Belong(void)              const { return (ENUM_GRAPH_OBJ_BELONG)this.GetProperty(GRAPH_OBJ_PROP_BELONG);         }
   void              SetBelong(const ENUM_GRAPH_OBJ_BELONG belong)
                       {
                        CGBaseObj::SetBelong(belong);
                        this.SetProperty(GRAPH_OBJ_PROP_BELONG,belong);
                       }
//--- Chart ID
   long              ChartID(void)                 const { return this.GetProperty(GRAPH_OBJ_PROP_CHART_ID);                              }
   void              SetChartID(const long chart_id)
                       {
                        CGBaseObj::SetChartID(chart_id);
                        this.SetProperty(GRAPH_OBJ_PROP_CHART_ID,chart_id);
                       }
//--- Chart subwindow index
   int               SubWindow(void)               const { return (int)this.GetProperty(GRAPH_OBJ_PROP_WND_NUM);                          }
   void              SetSubWindow(void)
                       {
                        if(CGBaseObj::SetSubwindow(CGBaseObj::ChartID(),CGBaseObj::Name()))
                           this.SetProperty(GRAPH_OBJ_PROP_WND_NUM,CGBaseObj::SubWindow());
                       }
//--- Object creation time
   datetime          TimeCteate(void)              const { return (datetime)this.GetProperty(GRAPH_OBJ_PROP_CREATETIME);                  }
//--- Object visibility on timeframes
   bool              Visible(void)                 const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES);                      }
   void              SetFlagVisible(const bool flag)
                       {
                        if(CGBaseObj::SetVisible(flag))
                           this.SetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,flag);
                       }
//--- Background object
   bool              Back(void)                    const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_BACK);                            }
   void              SetFlagBack(const bool flag)
                       {
                        if(CGBaseObj::SetBack(flag))
                           this.SetProperty(GRAPH_OBJ_PROP_BACK,flag);
                       }
//--- Priority of a graphical object for receiving the event of clicking on a chart
   long              Zorder(void)                  const { return this.GetProperty(GRAPH_OBJ_PROP_ZORDER);                                }
   void              SetZorder(const long value)
                       {
                        if(CGBaseObj::SetZorder(value))
                           this.SetProperty(GRAPH_OBJ_PROP_ZORDER,value);
                       }
//--- Disable displaying the name of a graphical object in the terminal object list
   bool              Hidden(void)                  const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_HIDDEN);                          }
   void              SetFlagHidden(const bool flag)
                       {
                        if(CGBaseObj::SetHidden(flag))
                           this.SetProperty(GRAPH_OBJ_PROP_HIDDEN,flag);
                       }
//--- Object selection
   bool              Selected(void)                const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTED);                        }
   void              SetFlagSelected(const bool flag)
                       {
                        if(CGBaseObj::SetSelected(flag))
                           this.SetProperty(GRAPH_OBJ_PROP_SELECTED,flag);
                       }
//--- Object availability
   bool              Selectable(void)              const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTABLE);                      }
   void              SetFlagSelectable(const bool flag)
                       {
                        if(CGBaseObj::SetSelectable(flag))
                           this.SetProperty(GRAPH_OBJ_PROP_SELECTABLE,flag);
                       }
//--- Time coordinate
   datetime          Time(void)                    const { return (datetime)this.GetProperty(GRAPH_OBJ_PROP_TIME);                        }
   void              SetTime(const datetime time)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_TIME,time))
                           this.SetProperty(GRAPH_OBJ_PROP_TIME,time);
                       }
//--- Color
   color             Color(void)                   const { return (color)this.GetProperty(GRAPH_OBJ_PROP_COLOR);                          }
   void              SetColor(const color colour)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_COLOR,colour))
                           this.SetProperty(GRAPH_OBJ_PROP_COLOR,colour);
                       }
//--- Style
   ENUM_LINE_STYLE   Style(void)                   const { return (ENUM_LINE_STYLE)this.GetProperty(GRAPH_OBJ_PROP_STYLE);                }
   void              SetStyle(const ENUM_LINE_STYLE style)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_STYLE,style))
                           this.SetProperty(GRAPH_OBJ_PROP_STYLE,style);
                       }
//--- Line width
   int               Width(void)                   const { return (int)this.GetProperty(GRAPH_OBJ_PROP_WIDTH);                            }
   void              SetWidth(const int width)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_WIDTH,width))
                           this.SetProperty(GRAPH_OBJ_PROP_WIDTH,width);
                       }
//--- Object color filling
   bool              Fill(void)                    const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_FILL);                            }
   void              SetFlagFill(const bool flag)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_FILL,flag))
                           this.SetProperty(GRAPH_OBJ_PROP_FILL,flag);
                       }
//--- Ability to edit text in the Edit object
   bool              ReadOnly(void)                const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_READONLY);                        }
   void              SetFlagReadOnly(const bool flag)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_READONLY,flag))
                           this.SetProperty(GRAPH_OBJ_PROP_READONLY,flag);
                       }
//--- Number of levels
   int               Levels(void)                  const { return (int)this.GetProperty(GRAPH_OBJ_PROP_LEVELS);                           }
   void              SetLevels(const int levels)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELS,levels))
                           this.SetProperty(GRAPH_OBJ_PROP_LEVELS,levels);
                       }
//--- Line level color
   color             LevelColor(void)              const { return (color)this.GetProperty(GRAPH_OBJ_PROP_LEVELCOLOR);                     }
   void              SetLevelColor(const color colour)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELCOLOR,colour))
                           this.SetProperty(GRAPH_OBJ_PROP_LEVELCOLOR,colour);
                       }
//--- Level line style
   ENUM_LINE_STYLE   LevelStyle(void)              const { return (ENUM_LINE_STYLE)this.GetProperty(GRAPH_OBJ_PROP_LEVELSTYLE);           }
   void              SetLevelStyle(const ENUM_LINE_STYLE style)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELSTYLE,style))
                           this.SetProperty(GRAPH_OBJ_PROP_LEVELSTYLE,style);
                       }
///--- Level line width
   int               LevelWidth(void)              const { return (int)this.GetProperty(GRAPH_OBJ_PROP_LEVELWIDTH);                       }
   void              SetLevelWidth(const int width)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELWIDTH,width))
                           this.SetProperty(GRAPH_OBJ_PROP_LEVELWIDTH,width);
                       }
//--- Horizontal text alignment in the Edit object (OBJ_EDIT)
   ENUM_ALIGN_MODE   Align(void)                   const { return (ENUM_ALIGN_MODE)this.GetProperty(GRAPH_OBJ_PROP_ALIGN);                }
   void              SetAlign(const ENUM_ALIGN_MODE align)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_ALIGN,align))
                           this.SetProperty(GRAPH_OBJ_PROP_ALIGN,align);
                       }
//--- Font size
   int               FontSize(void)                const { return (int)this.GetProperty(GRAPH_OBJ_PROP_FONTSIZE);                         }
   void              SetFontSize(const int size)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_FONTSIZE,size))
                           this.SetProperty(GRAPH_OBJ_PROP_FONTSIZE,size);
                       }
//--- Ray goes to the left
   bool              RayLeft(void)                 const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_RAY_LEFT);                        }
   void              SetFlagRayLeft(const bool flag)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_RAY_LEFT,flag))
                           this.SetProperty(GRAPH_OBJ_PROP_RAY_LEFT,flag);
                       }
//--- Ray goes to the right
   bool              RayRight(void)                const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_RAY_RIGHT);                       }
   void              SetFlagRayRight(const bool flag)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_RAY_RIGHT,flag))
                           this.SetProperty(GRAPH_OBJ_PROP_RAY_RIGHT,flag);
                       }
//--- Vertical line goes through all windows of a chart
   bool              Ray(void)                     const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_RAY);                             }
   void              SetFlagRay(const bool flag)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_RAY,flag))
                           this.SetProperty(GRAPH_OBJ_PROP_RAY,flag);
                       }
//--- Display the full ellipse of the Fibonacci Arc object
   bool              Ellipse(void)                 const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_ELLIPSE);                         }
   void              SetFlagEllipse(const bool flag)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_ELLIPSE,flag))
                           this.SetProperty(GRAPH_OBJ_PROP_ELLIPSE,flag);
                       }
//--- Arrow code for the "Arrow" object
   uchar             ArrowCode(void)               const { return (uchar)this.GetProperty(GRAPH_OBJ_PROP_ARROWCODE);                      }
   void              SetArrowCode(const uchar code)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_ARROWCODE,code))
                           this.SetProperty(GRAPH_OBJ_PROP_ARROWCODE,code);
                       }
//--- Position of the graphical object anchor point
   int               Anchor(void)                  const { return (int)this.GetProperty(GRAPH_OBJ_PROP_ANCHOR);                           }
   void              SetAnchor(const int anchor)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_ANCHOR,anchor))
                           this.SetProperty(GRAPH_OBJ_PROP_ANCHOR,anchor);
                       }
//--- Distance from the base corner along the X axis in pixels
   int               XDistance(void)               const { return (int)this.GetProperty(GRAPH_OBJ_PROP_XDISTANCE);                        }
   void              SetXDistance(const int distance)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_XDISTANCE,distance))
                           this.SetProperty(GRAPH_OBJ_PROP_XDISTANCE,distance);
                       }
//--- Distance from the base corner along the Y axis in pixels
   int               YDistance(void)               const { return (int)this.GetProperty(GRAPH_OBJ_PROP_YDISTANCE);                        }
   void              SetYDistance(const int distance)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_YDISTANCE,distance))
                           this.SetProperty(GRAPH_OBJ_PROP_YDISTANCE,distance);
                       }
//--- Gann object trend
   ENUM_GANN_DIRECTION Direction(void)             const { return (ENUM_GANN_DIRECTION)this.GetProperty(GRAPH_OBJ_PROP_DIRECTION);        }
   void              SetDirection(const ENUM_GANN_DIRECTION direction)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_DIRECTION,direction))
                           this.SetProperty(GRAPH_OBJ_PROP_DIRECTION,direction);
                       }
//--- Elliott wave marking level
   ENUM_ELLIOT_WAVE_DEGREE Degree(void)            const { return (ENUM_ELLIOT_WAVE_DEGREE)this.GetProperty(GRAPH_OBJ_PROP_DEGREE);       }
   void              SetDegree(const ENUM_ELLIOT_WAVE_DEGREE degree)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_DEGREE,degree))
                           this.SetProperty(GRAPH_OBJ_PROP_DEGREE,degree);
                       }
//--- Display lines for Elliott wave marking
   bool              DrawLines(void)               const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_DRAWLINES);                       }
   void              SetFlagDrawLines(const bool flag)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_DRAWLINES,flag))
                           this.SetProperty(GRAPH_OBJ_PROP_DRAWLINES,flag);
                       }
//--- Button state (pressed/released)
   bool              State(void)                   const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_STATE);                           }
   void              SetFlagState(const bool flag)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_STATE,flag))
                           this.SetProperty(GRAPH_OBJ_PROP_STATE,flag);
                       }
//--- Chart object ID (OBJ_CHART)
   long              ChartObjChartID(void)         const { return this.GetProperty(GRAPH_OBJ_PROP_OBJ_CHART_ID);                          }
   void              SetChartObjChartID(const long chart_id)
                       {
                        this.SetProperty(GRAPH_OBJ_PROP_OBJ_CHART_ID,chart_id);
                       }
//--- Chart object period
   ENUM_TIMEFRAMES   ChartObjPeriod(void)          const { return (ENUM_TIMEFRAMES)this.GetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PERIOD);     }
   void              SetChartObjPeriod(const ENUM_TIMEFRAMES timeframe)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_PERIOD,timeframe))
                           this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PERIOD,timeframe);
                       }
//--- Time scale display flag for the Chart object
   bool              ChartObjDateScale(void)       const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE);            }
   void              SetFlagChartObjDateScale(const bool flag)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_DATE_SCALE,flag))
                           this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE,flag);
                       }
//--- Price scale display flag for the Chart object
   bool              ChartObjPriceScale(void)      const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE);           }
   void              SetFlagPriceScale(const bool flag)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_PRICE_SCALE,flag))
                           this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE,flag);
                       }
//--- Chart object scale
   int               ChartObjChartScale(void)      const { return (int)this.GetProperty(GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE);            }
   void              SetChartObjChartScale(const int scale)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_CHART_SCALE,scale))
                           this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE,scale);
                       }
//--- Object width along the X axis in pixels
   int               XSize(void)                   const { return (int)this.GetProperty(GRAPH_OBJ_PROP_XSIZE);                            }
   void              SetXSize(const int size)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_XSIZE,size))
                           this.SetProperty(GRAPH_OBJ_PROP_XSIZE,size);
                       }
//--- Object height along the Y axis in pixels
   int               YSize(void)                   const { return (int)this.GetProperty(GRAPH_OBJ_PROP_YSIZE);                            }
   void              SetYSize(const int size)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_YSIZE,size))
                           this.SetProperty(GRAPH_OBJ_PROP_YSIZE,size);
                       }
//--- X coordinate of the upper-left corner of the visibility area
   int               XOffset(void)                 const { return (int)this.GetProperty(GRAPH_OBJ_PROP_XOFFSET);                          }
   void              SetXOffset(const int offset)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_XOFFSET,offset))
                           this.SetProperty(GRAPH_OBJ_PROP_XOFFSET,offset);
                       }
//--- Y coordinate of the upper-left corner of the visibility area
   int               YOffset(void)                 const { return (int)this.GetProperty(GRAPH_OBJ_PROP_YOFFSET);                          }
   void              SetYOffset(const int offset)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_YOFFSET,offset))
                           this.SetProperty(GRAPH_OBJ_PROP_YOFFSET,offset);
                       }
//--- Background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL
   color             BGColor(void)                 const { return (color)this.GetProperty(GRAPH_OBJ_PROP_BGCOLOR);                        }
   void              SetBGColor(const color colour)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_BGCOLOR,colour))
                           this.SetProperty(GRAPH_OBJ_PROP_BGCOLOR,colour);
                       }
//--- Chart corner for attaching a graphical object
   ENUM_BASE_CORNER  Corner(void)                  const { return (ENUM_BASE_CORNER)this.GetProperty(GRAPH_OBJ_PROP_CORNER);              }
   void              SetCorner(const ENUM_BASE_CORNER corner)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_CORNER,corner))
                           this.SetProperty(GRAPH_OBJ_PROP_CORNER,corner);
                       }
//--- Border type for the Rectangle label object
   ENUM_BORDER_TYPE  BorderType(void)              const { return (ENUM_BORDER_TYPE)this.GetProperty(GRAPH_OBJ_PROP_BORDER_TYPE);         }
   void              SetBorderType(const ENUM_BORDER_TYPE type)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_BORDER_TYPE,type))
                           this.SetProperty(GRAPH_OBJ_PROP_BORDER_TYPE,type);
                       }
//--- Border color for OBJ_EDIT and OBJ_BUTTON
   color             BorderColor(void)             const { return (color)this.GetProperty(GRAPH_OBJ_PROP_BORDER_COLOR);                   }
   void              SetBorderColor(const color colour)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_BORDER_COLOR,colour))
                           this.SetProperty(GRAPH_OBJ_PROP_BORDER_COLOR,colour);
                       }

//--- Price coordinate
   double            Price(void)                   const { return this.GetProperty(GRAPH_OBJ_PROP_PRICE);                                 }
   void              SetPrice(const double price)
                       {
                        if(::ObjectSetDouble(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_PRICE,price))
                           this.SetProperty(GRAPH_OBJ_PROP_PRICE,price);
                       }
//--- Level value
   double            LevelValue(void)              const { return this.GetProperty(GRAPH_OBJ_PROP_LEVELVALUE);                            }
   void              SetLevelValue(const double value)
                       {
                        if(::ObjectSetDouble(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELVALUE,value))
                           this.SetProperty(GRAPH_OBJ_PROP_LEVELVALUE,value);
                       }
//--- Scale
   double            Scale(void)                   const { return this.GetProperty(GRAPH_OBJ_PROP_SCALE);                                 }
   void              SetScale(const double scale)
                       {
                        if(::ObjectSetDouble(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_SCALE,scale))
                           this.SetProperty(GRAPH_OBJ_PROP_SCALE,scale);
                       }
//--- Angle
   double            Angle(void)                   const { return this.GetProperty(GRAPH_OBJ_PROP_ANGLE);                                 }
   void              SetAngle(const double angle)
                       {
                        if(::ObjectSetDouble(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_ANGLE,angle))
                           this.SetProperty(GRAPH_OBJ_PROP_ANGLE,angle);
                       }
//--- Deviation of the standard deviation channel
   double            Deviation(void)               const { return this.GetProperty(GRAPH_OBJ_PROP_DEVIATION);                             }
   void              SetDeviation(const double deviation)
                       {
                        if(::ObjectSetDouble(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_DEVIATION,deviation))
                           this.SetProperty(GRAPH_OBJ_PROP_DEVIATION,deviation);
                       }

//--- Object name
   string            Name(void)                    const { return this.GetProperty(GRAPH_OBJ_PROP_NAME);                                  }
   void              SetName(const string name)
                       {
                        if(CGBaseObj::Name()==name)
                           return;
                        if(CGBaseObj::Name()=="")
                          {
                           CGBaseObj::SetName(name);
                           this.SetProperty(GRAPH_OBJ_PROP_NAME,name);
                           return;
                          }
                        else
                          {
                           if(::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_NAME,name))
                             {
                              CGBaseObj::SetName(name);
                              this.SetProperty(GRAPH_OBJ_PROP_NAME,name);
                             }
                          }
                       }
//--- Object description (text contained in the object)
   string            Text(void)                    const { return this.GetProperty(GRAPH_OBJ_PROP_TEXT);                                  }
   void              SetText(const string text)
                       {
                        if(::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_TEXT,text))
                           this.SetProperty(GRAPH_OBJ_PROP_TEXT,text);
                       }
//--- Tooltip text
   string            Tooltip(void)                 const { return this.GetProperty(GRAPH_OBJ_PROP_TOOLTIP);                               }
   void              SetTooltip(const string tooltip)
                       {
                        if(::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_TOOLTIP,tooltip))
                           this.SetProperty(GRAPH_OBJ_PROP_TOOLTIP,tooltip);
                       }
//--- Level description
   string            LevelText(void)               const { return this.GetProperty(GRAPH_OBJ_PROP_LEVELTEXT);                             }
   void              SetLevelText(const string text)
                       {
                        if(::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELTEXT,text))
                           this.SetProperty(GRAPH_OBJ_PROP_LEVELTEXT,text);
                       }
//--- Font
   string            Font(void)                    const { return this.GetProperty(GRAPH_OBJ_PROP_FONT);                                  }
   void              SetFont(const string font)
                       {
                        if(::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_FONT,font))
                           this.SetProperty(GRAPH_OBJ_PROP_FONT,font);
                       }
//--- BMP file name for the "Bitmap Level" object
   string            BMPFile(void)                 const { return this.GetProperty(GRAPH_OBJ_PROP_BMPFILE);                               }
   void              SetBMPFile(const string bmp_file)
                       {
                        if(::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_BMPFILE,bmp_file))
                           this.SetProperty(GRAPH_OBJ_PROP_BMPFILE,bmp_file);
                       }
//--- Symbol for the Chart object 
   string            Symbol(void)                  const { return this.GetProperty(GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL);                      }
   void              SetChartObjSymbol(const string symbol)
                       {
                        if(::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_SYMBOL,symbol))
                           this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL,symbol);
                       }
   
  };
//+------------------------------------------------------------------+

Muchos métodos ya se han escrito aquí de antemano, y, en consecuencia, se moverán posteriormente a las clases de los objetos heredados, donde se encuentran las propiedades correspondientes para los objetos gráficos que describirán estas clases. Esto posibilitará que distintos objetos tengan diferentes conjuntos de métodos para trabajar con las propiedades, y que dichos conjuntos sean inherentes solo a aquellos.

Vamos a analizar la lógica usando varios métodos como ejemplo.

Las propiedades de objeto que solo posee el propio objeto, se retornan y se establecen directamente desde las propiedades de este:

//--- Object index in the list
   int               Number(void)                  const { return (int)this.GetProperty(GRAPH_OBJ_PROP_NUM);                              }
   void              SetNumber(const int number)         { this.SetProperty(GRAPH_OBJ_PROP_NUM,number);                                   }


Las propiedades inherentes a todos los objetos gráficos cuyas variables de almacenamiento se encuentran en la clase de objeto gráfico básico para todos los objetos gráficos de la biblioteca, se retornan desde las propiedades de este objeto y se establecen primero en el objeto básico, y luego en las propiedades de este objeto:

//--- Object ID
   long              ObjectID(void)                const { return this.GetProperty(GRAPH_OBJ_PROP_ID);                                    }
   void              SetObjectID(const long obj_id)
                       {
                        CGBaseObj::SetObjectID(obj_id);
                        this.SetProperty(GRAPH_OBJ_PROP_ID,obj_id);
                       }


Las propiedades de objeto que tiene el propio objeto gráfico, pero que no se encuentran en el objeto básico, se retornan directamente desde las propiedades de este objeto,
y se establecen primero en las propiedades del objeto gráfico en sí, y luego, si el evento de cambio de propiedad ha sido correctamente colocado en la cola, también se escriben en las propiedades de este objeto:

//--- Time coordinate
   datetime          Time(void)                    const { return (datetime)this.GetProperty(GRAPH_OBJ_PROP_TIME);                        }
   void              SetTime(const datetime time)
                       {
                        if(::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_TIME,time))
                           this.SetProperty(GRAPH_OBJ_PROP_TIME,time);
                       }


El método de configuración del nombre se distingue de otros métodos similares. El caso es que los objetos gráficos en el terminal se eligen según su índice en la lista y según el nombre del objeto (con la función ObjectName(), obtenemos el nombre del objeto según el índice en el lista de objetos, y con las funciones ObjectGetXXX(), obtenemos el resto de las propiedades ya según el nombre del objeto gráfico), y el nombre del objeto se le asigna inmediatamente después de su creación.

Por consiguiente, aquí solo necesitamos establecer el nombre de las variables de objeto. Y haremos esto en el caso de que el nombre aún no se haya escrito en la variable. Si el nombre ya ha sido escrito en la variable, y el nombre de la configuración no es igual al nombre existente (con nombres iguales, abandonamos el método), esto indicará que el objeto se ha renombrado. Hasta ahora, esta situación no se ha procesado aquí (la implementaremos en el futuro). Por el momento, simplemente enviaremos una solicitud para cambiar el nombre del objeto gráfico y sobrescribir su nombre en la variable de clase básica y en las propiedades de esta.
//--- Object name
   string            Name(void)                    const { return this.GetProperty(GRAPH_OBJ_PROP_NAME);                                  }
   void              SetName(const string name)
                       {
                        if(CGBaseObj::Name()==name)
                           return;
                        if(CGBaseObj::Name()=="")
                          {
                           CGBaseObj::SetName(name);
                           this.SetProperty(GRAPH_OBJ_PROP_NAME,name);
                           return;
                          }
                        else
                          {
                           if(::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_NAME,name))
                             {
                              CGBaseObj::SetName(name);
                              this.SetProperty(GRAPH_OBJ_PROP_NAME,name);
                             }
                          }
                       }


En el constructor paramétrico protegido, anotamos todos los valores transmitidos al constructor, tanto a la clase básica como a las propiedades de este objeto:

//+------------------------------------------------------------------+
//| Protected parametric constructor                                 |
//+------------------------------------------------------------------+
CGStdGraphObj::CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type,const ENUM_GRAPH_OBJ_BELONG belong,const long chart_id,const string name)
  {
//--- Set the object (1) type, type of graphical (2) object, (3) element, (4) subwindow affiliation and (5) index, as well as (6) chart symbol Digits
   this.m_type=obj_type;
   CGBaseObj::SetChartID(chart_id);
   CGBaseObj::SetTypeGraphObject(CGBaseObj::GraphObjectType(obj_type));
   CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_STANDART);
   CGBaseObj::SetBelong(belong);
   CGBaseObj::SetSubwindow(chart_id,name);
   CGBaseObj::SetDigits((int)::SymbolInfoInteger(::ChartSymbol(chart_id),SYMBOL_DIGITS));
   
//--- Save integer properties
   //--- properties inherent in all graphical objects but not present in a graphical object
   this.m_long_prop[GRAPH_OBJ_PROP_CHART_ID]    = CGBaseObj::ChartID();          // Chart ID

   this.m_long_prop[GRAPH_OBJ_PROP_WND_NUM]     = CGBaseObj::SubWindow();        // Chart subwindow index
   this.m_long_prop[GRAPH_OBJ_PROP_TYPE]        = CGBaseObj::TypeGraphObject();  // Graphical object type (ENUM_OBJECT)
   this.m_long_prop[GRAPH_OBJ_PROP_ELEMENT_TYPE]= CGBaseObj::TypeGraphElement(); // Graphical element type (ENUM_GRAPH_ELEMENT_TYPE)
   this.m_long_prop[GRAPH_OBJ_PROP_BELONG]      = CGBaseObj::Belong();           // Graphical object affiliation
   this.m_long_prop[GRAPH_OBJ_PROP_ID]          = 0;                             // Object ID
   this.m_long_prop[GRAPH_OBJ_PROP_NUM]         = 0;                             // Object index in the list
   //--- Properties inherent in all graphical objects and present in a graphical object
   this.m_long_prop[GRAPH_OBJ_PROP_CREATETIME]  = ::ObjectGetInteger(chart_id,name,OBJPROP_CREATETIME);  // Object creation time
   this.m_long_prop[GRAPH_OBJ_PROP_TIMEFRAMES]  = ::ObjectGetInteger(chart_id,name,OBJPROP_TIMEFRAMES);  // Object visibility on timeframes
   this.m_long_prop[GRAPH_OBJ_PROP_BACK]        = ::ObjectGetInteger(chart_id,name,OBJPROP_BACK);        // Background object
   this.m_long_prop[GRAPH_OBJ_PROP_ZORDER]      = ::ObjectGetInteger(chart_id,name,OBJPROP_ZORDER);      // Priority of a graphical object for receiving the event of clicking on a chart
   this.m_long_prop[GRAPH_OBJ_PROP_HIDDEN]      = ::ObjectGetInteger(chart_id,name,OBJPROP_HIDDEN);      // Disable displaying the name of a graphical object in the terminal object list
   this.m_long_prop[GRAPH_OBJ_PROP_SELECTED]    = ::ObjectGetInteger(chart_id,name,OBJPROP_SELECTED);    // Object selection
   this.m_long_prop[GRAPH_OBJ_PROP_SELECTABLE]  = ::ObjectGetInteger(chart_id,name,OBJPROP_SELECTABLE);  // Object availability
   this.m_long_prop[GRAPH_OBJ_PROP_TIME]        = ::ObjectGetInteger(chart_id,name,OBJPROP_TIME);        // First point time coordinate
   this.m_long_prop[GRAPH_OBJ_PROP_COLOR]       = ::ObjectGetInteger(chart_id,name,OBJPROP_COLOR);       // Color
   this.m_long_prop[GRAPH_OBJ_PROP_STYLE]       = ::ObjectGetInteger(chart_id,name,OBJPROP_STYLE);       // Style
   this.m_long_prop[GRAPH_OBJ_PROP_WIDTH]       = ::ObjectGetInteger(chart_id,name,OBJPROP_WIDTH);       // Line width
   //--- Properties belonging to different graphical objects
   this.m_long_prop[GRAPH_OBJ_PROP_FILL]                          = 0;  // Object color filling
   this.m_long_prop[GRAPH_OBJ_PROP_READONLY]                      = 0;  // Ability to edit text in the Edit object
   this.m_long_prop[GRAPH_OBJ_PROP_LEVELS]                        = 0;  // Number of levels
   this.m_long_prop[GRAPH_OBJ_PROP_LEVELCOLOR]                    = 0;  // Level line color
   this.m_long_prop[GRAPH_OBJ_PROP_LEVELSTYLE]                    = 0;  // Level line style
   this.m_long_prop[GRAPH_OBJ_PROP_LEVELWIDTH]                    = 0;  // Level line width
   this.m_long_prop[GRAPH_OBJ_PROP_ALIGN]                         = 0;  // Horizontal text alignment in the Edit object (OBJ_EDIT)
   this.m_long_prop[GRAPH_OBJ_PROP_FONTSIZE]                      = 0;  // Font size
   this.m_long_prop[GRAPH_OBJ_PROP_RAY_LEFT]                      = 0;  // Ray goes to the left
   this.m_long_prop[GRAPH_OBJ_PROP_RAY_RIGHT]                     = 0;  // Ray goes to the right
   this.m_long_prop[GRAPH_OBJ_PROP_RAY]                           = 0;  // Vertical line goes through all windows of a chart
   this.m_long_prop[GRAPH_OBJ_PROP_ELLIPSE]                       = 0;  // Display the full ellipse of the Fibonacci Arc object
   this.m_long_prop[GRAPH_OBJ_PROP_ARROWCODE]                     = 0;  // Arrow code for the "Arrow" object
   this.m_long_prop[GRAPH_OBJ_PROP_ANCHOR]                        = 0;  // Position of the binding point of the graphical object
   this.m_long_prop[GRAPH_OBJ_PROP_XDISTANCE]                     = 0;  // Distance from the base corner along the X axis in pixels
   this.m_long_prop[GRAPH_OBJ_PROP_YDISTANCE]                     = 0;  // Distance from the base corner along the Y axis in pixels
   this.m_long_prop[GRAPH_OBJ_PROP_DIRECTION]                     = 0;  // Gann object trend
   this.m_long_prop[GRAPH_OBJ_PROP_DEGREE]                        = 0;  // Elliott wave marking level
   this.m_long_prop[GRAPH_OBJ_PROP_DRAWLINES]                     = 0;  // Display lines for Elliott wave marking
   this.m_long_prop[GRAPH_OBJ_PROP_STATE]                         = 0;  // Button state (pressed/released)
   this.m_long_prop[GRAPH_OBJ_PROP_OBJ_CHART_ID]                  = 0;  // Chart object ID (OBJ_CHART).
   this.m_long_prop[GRAPH_OBJ_PROP_CHART_OBJ_PERIOD]              = 0;  // Chart object period<
   this.m_long_prop[GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE]          = 0;  // Time scale display flag for the Chart object
   this.m_long_prop[GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE]         = 0;  // Price scale display flag for the Chart object
   this.m_long_prop[GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE]         = 0;  // Chart object scale
   this.m_long_prop[GRAPH_OBJ_PROP_XSIZE]                         = 0;  // Object width along the X axis in pixels.
   this.m_long_prop[GRAPH_OBJ_PROP_YSIZE]                         = 0;  // Object height along the Y axis in pixels.
   this.m_long_prop[GRAPH_OBJ_PROP_XOFFSET]                       = 0;  // X coordinate of the upper-left corner of the visibility area.
   this.m_long_prop[GRAPH_OBJ_PROP_YOFFSET]                       = 0;  // Y coordinate of the upper-left corner of the visibility area.
   this.m_long_prop[GRAPH_OBJ_PROP_BGCOLOR]                       = 0;  // Background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL
   this.m_long_prop[GRAPH_OBJ_PROP_CORNER]                        = 0;  // Chart corner for binding a graphical object
   this.m_long_prop[GRAPH_OBJ_PROP_BORDER_TYPE]                   = 0;  // Border type for "Rectangle border"
   this.m_long_prop[GRAPH_OBJ_PROP_BORDER_COLOR]                  = 0;  // Border color for OBJ_EDIT and OBJ_BUTTON
   
//--- Save real properties
   this.m_double_prop[this.IndexProp(GRAPH_OBJ_PROP_PRICE)]       = ::ObjectGetDouble(chart_id,name,OBJPROP_PRICE);  // Price coordinate
   this.m_double_prop[this.IndexProp(GRAPH_OBJ_PROP_LEVELVALUE)]  = 0;                                               // Level value
   this.m_double_prop[this.IndexProp(GRAPH_OBJ_PROP_SCALE)]       = 0;                                               // Scale (property of Gann objects and Fibonacci Arcs objects)
   this.m_double_prop[this.IndexProp(GRAPH_OBJ_PROP_ANGLE)]       = 0;                                               // Angle
   this.m_double_prop[this.IndexProp(GRAPH_OBJ_PROP_DEVIATION)]   = 0;                                               // Deviation of the standard deviation channel
   
//--- Save string properties
   this.m_string_prop[this.IndexProp(GRAPH_OBJ_PROP_NAME)]        = name;                                            // Object name
   this.m_string_prop[this.IndexProp(GRAPH_OBJ_PROP_TEXT)]        = ::ObjectGetString(chart_id,name,OBJPROP_TEXT);   // Object description (the text contained in the object)
   this.m_string_prop[this.IndexProp(GRAPH_OBJ_PROP_TOOLTIP)]     = ::ObjectGetString(chart_id,name,OBJPROP_TOOLTIP);// Tooltip text
   this.m_string_prop[this.IndexProp(GRAPH_OBJ_PROP_LEVELTEXT)]   = "";                                              // Level description
   this.m_string_prop[this.IndexProp(GRAPH_OBJ_PROP_FONT)]        = "";                                              // Font
   this.m_string_prop[this.IndexProp(GRAPH_OBJ_PROP_BMPFILE)]     = "";                                              // BMP file name for the "Bitmap Level" object
   this.m_string_prop[this.IndexProp(GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL)]= "";                                          // Chart object symbol 
   
//--- Save basic properties in the parent object
   this.m_create_time=(datetime)this.GetProperty(GRAPH_OBJ_PROP_CREATETIME);
   this.m_back=(bool)this.GetProperty(GRAPH_OBJ_PROP_BACK);
   this.m_selected=(bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTED);
   this.m_selectable=(bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTABLE);
   this.m_hidden=(bool)this.GetProperty(GRAPH_OBJ_PROP_HIDDEN);
   this.m_name=this.GetProperty(GRAPH_OBJ_PROP_NAME);
   
  }
//+-------------------------------------------------------------------+

La secuencia de escritura de los valores en las variables de objeto se comenta aquí en el código. Ahora no anotamos todas las propiedades del objeto, sino solo aquellas que se transmiten al constructor, así como las que podemos obtener del objeto gráfico, siempre que sean comunes a todos los objetos gráficos. Las demás propiedades deberán registrarse en los constructores de las clases herederas, ya que todos los objetos gráficos tienen diferentes conjuntos de propiedades que se conocerán solo al crearse un objeto gráfico específico.

Métodos estándar para comparar dos objetos (para los objetos de la biblioteca):

//+-----------------------------------------------------------------------+
//|Compare CGStdGraphObj objects with each other by the specified property|
//+-----------------------------------------------------------------------+
int CGStdGraphObj::Compare(const CObject *node,const int mode=0) const
  {
   const CGStdGraphObj *obj_compared=node;
//--- compare integer properties of two orders
   if(mode<GRAPH_OBJ_PROP_INTEGER_TOTAL)
     {
      long value_compared=obj_compared.GetProperty((ENUM_GRAPH_OBJ_PROP_INTEGER)mode);
      long value_current=this.GetProperty((ENUM_GRAPH_OBJ_PROP_INTEGER)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare real properties of two orders
   else if(mode<GRAPH_OBJ_PROP_DOUBLE_TOTAL+GRAPH_OBJ_PROP_INTEGER_TOTAL)
     {
      double value_compared=obj_compared.GetProperty((ENUM_GRAPH_OBJ_PROP_DOUBLE)mode);
      double value_current=this.GetProperty((ENUM_GRAPH_OBJ_PROP_DOUBLE)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare string properties of two orders
   else if(mode<GRAPH_OBJ_PROP_DOUBLE_TOTAL+GRAPH_OBJ_PROP_INTEGER_TOTAL+GRAPH_OBJ_PROP_STRING_TOTAL)
     {
      string value_compared=obj_compared.GetProperty((ENUM_GRAPH_OBJ_PROP_STRING)mode);
      string value_current=this.GetProperty((ENUM_GRAPH_OBJ_PROP_STRING)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
   return 0;
  }
//+------------------------------------------------------------------+
//| Compare CGStdGraphObj objects by all properties                  |
//+------------------------------------------------------------------+
bool CGStdGraphObj::IsEqual(CGStdGraphObj *compared_obj) const
  {
   int beg=0, end=GRAPH_OBJ_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_INTEGER prop=(ENUM_GRAPH_OBJ_PROP_INTEGER)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=GRAPH_OBJ_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_DOUBLE prop=(ENUM_GRAPH_OBJ_PROP_DOUBLE)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=GRAPH_OBJ_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_STRING prop=(ENUM_GRAPH_OBJ_PROP_STRING)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   return true;
  }
//+------------------------------------------------------------------+

Método que muestra en el diario las propiedades del objeto:

//+------------------------------------------------------------------+
//| Display object properties in the journal                         |
//+------------------------------------------------------------------+
void CGStdGraphObj::Print(const bool full_prop=false,const bool dash=false)
  {
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," (",this.Header(),") =============");
   int beg=0, end=GRAPH_OBJ_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_INTEGER prop=(ENUM_GRAPH_OBJ_PROP_INTEGER)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=GRAPH_OBJ_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_DOUBLE prop=(ENUM_GRAPH_OBJ_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=GRAPH_OBJ_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_STRING prop=(ENUM_GRAPH_OBJ_PROP_STRING)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_END)," (",this.Header(),") =============\n");
  }
//+------------------------------------------------------------------+

Método que retorna el nombre breve del objeto:

//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CGStdGraphObj::Header(const bool symbol=false)
  {
   return CGBaseObj::TypeGraphObjectDescription();
  }
//+------------------------------------------------------------------+

Método que muestra en el diario la descripción breve del objeto:

//+------------------------------------------------------------------+
//| Display a short description of the object in the journal         |
//+------------------------------------------------------------------+
void CGStdGraphObj::PrintShort(const bool dash=false,const bool symbol=false)
  {
   ::Print
     (
      this.Header(symbol)," \"",CGBaseObj::Name(),"\": ID ",(string)this.GetProperty(GRAPH_OBJ_PROP_ID),
      " ",::TimeToString(CGBaseObj::TimeCreate(),TIME_DATE|TIME_MINUTES|TIME_SECONDS)
     );
  }
//+------------------------------------------------------------------+

Método que retorna las descripciones de las propiedades de tipo entero, real y string del objeto:

//+------------------------------------------------------------------+
//| Return description of object's integer property                  |
//+------------------------------------------------------------------+
string CGStdGraphObj::GetPropertyDescription(ENUM_GRAPH_OBJ_PROP_INTEGER property)
  {
   return
     (
      property==GRAPH_OBJ_PROP_ID         ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_ID)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_TYPE       ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_TYPE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+StdGraphObjectTypeDescription((ENUM_OBJECT)this.GetProperty(property))
         )  :
      property==GRAPH_OBJ_PROP_ELEMENT_TYPE  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_ELEMENT_TYPE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+CGBaseObj::TypeElementDescription()
         )  :
      property==GRAPH_OBJ_PROP_BELONG     ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_BELONG)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+CGBaseObj::BelongDescription()
         )  :
      property==GRAPH_OBJ_PROP_CHART_ID   ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_CHART_ID)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_WND_NUM    ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_WND_NUM)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_CREATETIME   ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_CREATETIME)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS)
         )  :
      property==GRAPH_OBJ_PROP_TIMEFRAMES ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_TIMEFRAMES)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_BACK       ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_BACK)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.IsBack() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_ZORDER     ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_ZORDER)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_HIDDEN     ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_HIDDEN)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.IsHidden() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_SELECTED   ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_SELECTED)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.IsSelected() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_SELECTABLE ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_SELECTABLE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.IsSelectable() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_NUM        ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_NUM)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_TIME       ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_TIME)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES)
         )  :
      property==GRAPH_OBJ_PROP_COLOR      ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_COLOR)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==GRAPH_OBJ_PROP_STYLE      ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_STYLE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+LineStyleDescription((ENUM_LINE_STYLE)this.GetProperty(property))
         )  :
      property==GRAPH_OBJ_PROP_WIDTH     ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_WIDTH)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_FILL       ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_FILL)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_READONLY   ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_READONLY)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_LEVELS     ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_LEVELCOLOR ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELCOLOR)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==GRAPH_OBJ_PROP_LEVELSTYLE ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELSTYLE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+LineStyleDescription((ENUM_LINE_STYLE)this.GetProperty(property))
         )  :
      property==GRAPH_OBJ_PROP_LEVELWIDTH ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELWIDTH)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_ALIGN      ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_ALIGN)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+AlignModeDescription((ENUM_ALIGN_MODE)this.GetProperty(property))
         )  :
      property==GRAPH_OBJ_PROP_FONTSIZE   ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_FONTSIZE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_RAY_LEFT   ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_RAY_LEFT)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_RAY_RIGHT  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_RAY_RIGHT)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_RAY        ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_RAY)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_ELLIPSE    ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_ELLIPSE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_ARROWCODE  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_ARROWCODE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_ANCHOR     ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_ANCHOR)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.AnchorDescription()
         )  :
      property==GRAPH_OBJ_PROP_XDISTANCE  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_XDISTANCE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_YDISTANCE  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_YDISTANCE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_DIRECTION  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_DIRECTION)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+GannDirectDescription((ENUM_GANN_DIRECTION)this.GetProperty(property))
         )  :
      property==GRAPH_OBJ_PROP_DEGREE     ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_DEGREE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+ElliotWaveDegreeDescription((ENUM_ELLIOT_WAVE_DEGREE)this.GetProperty(property))
         )  :
      property==GRAPH_OBJ_PROP_DRAWLINES  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_DRAWLINES)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_STATE      ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_STATE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_BUTTON_STATE_PRESSED) : CMessage::Text(MSG_LIB_TEXT_BUTTON_STATE_DEPRESSED))
         )  :
      property==GRAPH_OBJ_PROP_OBJ_CHART_ID  ?  CMessage::Text(MSG_CHART_OBJ_ID)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_CHART_OBJ_PERIOD ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_CHART_OBJ_PERIOD)+
         (!this.SupportProperty(property)       ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+TimeframeDescription((ENUM_TIMEFRAMES)this.GetProperty(property))
         )  :
      property==GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE   ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE)+
         (!this.SupportProperty(property)             ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE)+
         (!this.SupportProperty(property)             ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE)+
         (!this.SupportProperty(property)             ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_XSIZE      ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_XSIZE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_YSIZE      ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_YSIZE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_XOFFSET    ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_XOFFSET)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_YOFFSET    ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_YOFFSET)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_BGCOLOR    ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_BGCOLOR)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==GRAPH_OBJ_PROP_CORNER     ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_CORNER)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+BaseCornerDescription((ENUM_BASE_CORNER)this.GetProperty(property))
         )  :
      property==GRAPH_OBJ_PROP_BORDER_TYPE   ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_BORDER_TYPE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+BorderTypeDescription((ENUM_BORDER_TYPE)this.GetProperty(property))
         )  :
      property==GRAPH_OBJ_PROP_BORDER_COLOR  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_BORDER_COLOR)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return description of object's real property                     |
//+------------------------------------------------------------------+
string CGStdGraphObj::GetPropertyDescription(ENUM_GRAPH_OBJ_PROP_DOUBLE property)
  {
   int dg=(this.m_digits>0 ? this.m_digits : 1);
   return
     (
      property==GRAPH_OBJ_PROP_PRICE      ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_PRICE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==GRAPH_OBJ_PROP_LEVELVALUE ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELVALUE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==GRAPH_OBJ_PROP_SCALE      ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_SCALE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==GRAPH_OBJ_PROP_ANGLE      ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_ANGLE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==GRAPH_OBJ_PROP_DEVIATION  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_DEVIATION)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return description of object's string property                   |
//+------------------------------------------------------------------+
string CGStdGraphObj::GetPropertyDescription(ENUM_GRAPH_OBJ_PROP_STRING property)
  {
   return
     (
      property==GRAPH_OBJ_PROP_NAME       ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_NAME)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_TEXT       ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_TEXT)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_TOOLTIP    ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_TOOLTIP)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_LEVELTEXT  ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELTEXT)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_FONT       ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_FONT)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_BMPFILE    ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_BMPFILE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetProperty(property)
         )  :
      property==GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_SYMBOL)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetProperty(property)
         )  :
      ""
     );
  }

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

Ya analizamos el funcionamiento de métodos similares a los presentados anteriormente al comienzo de la descripción de la creación de la biblioteca; luego, repetidamente, en el transcurso de la escritura de varios objetos, afinamos la lógica del trabajo de dichos métodos. Por consiguiente, los lectores ya estarán familiarizados con el funcionamiento de tales métodos desde hace mucho tiempo. En cualquier caso, podrán escribir cualquier duda en los comentarios al artículo.

Podemos dar por finalizada la creación de la clase de objeto gráfico abstracto. Ahora necesitamos definir el hecho de la aparición de un objeto gráfico en un gráfico y crear el objeto gráfico abstracto correspondiente en la clase de colección de objetos gráficos.

No vamos a añadir hoy estos objetos a la lista de colección. Para ello, necesitaremos crear no un objeto abstracto, sino descendientes de este objeto que describan los tipos específicos de objetos gráficos añadidos al gráfico. Crearemos tales objetos en el próximo artículo. Hoy solo necesitaremos comprobar que la clase que hemos creado ahora funcione correctamente.

Vamos a necesitar hacer algunos cambios en el archivo \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh, en la clase encargada de controlar los objetos del gráfico (hay dos clases en el archivo). El caso es que aquí no podremos realizar un cálculo económico para encontrar el último objeto gráfico añadido al gráfico, como hemos hecho en otras colecciones donde iniciamos el ciclo no desde el principio, sino desde el valor del índice del último objeto entre los procesados por la clase de colección. No funcionará porque los objetos gráficos se añaden a la lista del terminal según su nombre, no por el orden en que se añaden al gráfico. Sí, por extraño que parezca, los objetos gráficos en la lista del terminal se ordenan según el nombre. Así, el último objeto añadido al gráfico de iconos, "Flecha", se convierte en el primero en la lista de objetos debido a su nombre ("Arrow"), mientras que el objeto "Rectángulo" se convierte en el segundo ("Rectangle") en virtud del mismo principio.

Por consiguiente, deberemos buscar en un bucle a través de todos los objetos gráficos del gráfico el objeto en el momento en que se añadió al gráfico: los objetos gráficos tienen esta propiedad. Por otra parte, deberemos borrar la variable extra para organizar la búsqueda económica que previamente hemos introducido en la clase, así como los cálculos escritos con su uso:

//+------------------------------------------------------------------+
//|                                      GraphElementsCollection.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "ListObj.mqh"
#include "..\Services\Select.mqh"
#include "..\Objects\Graph\Form.mqh"

//+------------------------------------------------------------------+
//| Chart object management class                                    |
//+------------------------------------------------------------------+
class CChartObjectsControl : public CObject
  {
private:
   ENUM_TIMEFRAMES   m_chart_timeframe;         // Chart timeframe
   long              m_chart_id;                // Chart ID
   string            m_chart_symbol;            // Chart symbol
   bool              m_is_graph_obj_event;      // Event flag in the list of graphical objects
   int               m_total_objects;           // Number of graphical objects
   int               m_last_objects;            // Number of graphical objects during the previous check
   int               m_index_object;            // Index of the last graphical object added to the collection from the terminal object list
   int               m_delta_graph_obj;         // Difference in the number of graphical objects compared to the previous check
public:
//--- Return the variable values
   ENUM_TIMEFRAMES   Timeframe(void)                           const { return this.m_chart_timeframe;    }
   long              ChartID(void)                             const { return this.m_chart_id;           }
   string            Symbol(void)                              const { return this.m_chart_symbol;       }
   bool              IsEvent(void)                             const { return this.m_is_graph_obj_event; }
   int               TotalObjects(void)                        const { return this.m_total_objects;      }
   int               Delta(void)                               const { return this.m_delta_graph_obj;    }
//--- Check the chart objects
   void              Refresh(void);
//--- Constructors
                     CChartObjectsControl(void)
                       { 
                        this.m_chart_id=::ChartID();
                        this.m_chart_timeframe=(ENUM_TIMEFRAMES)::ChartPeriod(this.m_chart_id);
                        this.m_chart_symbol=::ChartSymbol(this.m_chart_id);
                        this.m_is_graph_obj_event=false;
                        this.m_total_objects=0;
                        this.m_last_objects=0;
                        this.m_index_object=0;
                        this.m_delta_graph_obj=0;
                       }
                     CChartObjectsControl(const long chart_id)
                       {
                        this.m_chart_id=chart_id;
                        this.m_chart_timeframe=(ENUM_TIMEFRAMES)::ChartPeriod(this.m_chart_id);
                        this.m_chart_symbol=::ChartSymbol(this.m_chart_id);
                        this.m_is_graph_obj_event=false;
                        this.m_total_objects=0;
                        this.m_last_objects=0;
                        this.m_index_object=0;
                        this.m_delta_graph_obj=0;
                       }
                     
//--- Compare CChartObjectsControl objects by a chart ID (for sorting the list by an object property)
   virtual int       Compare(const CObject *node,const int mode=0) const
                       {
                        const CChartObjectsControl *obj_compared=node;
                        return(this.ChartID()>obj_compared.ChartID() ? 1 : this.ChartID()<obj_compared.ChartID() ? -1 : 0);
                       }
  };
//+------------------------------------------------------------------+
//| CChartObjectsControl Check objects on a chart                    |
//+------------------------------------------------------------------+
void CChartObjectsControl::Refresh(void)
  {
//--- Graphical objects on the chart
   this.m_total_objects=::ObjectsTotal(this.ChartID());
   int i=this.m_index_object;
   int delta=this.m_total_objects-this.m_last_objects;
   
//--- If the number of objects has changed
   if(delta!=0)
     {

En el método que comprueba los objetos en el gráfico, escribimos un manejador de eventos así para aumentar el número de objetos gráficos en el gráfico:

//+------------------------------------------------------------------+
//| CChartObjectsControl Check objects on a chart                    |
//+------------------------------------------------------------------+
void CChartObjectsControl::Refresh(void)
  {
//--- Graphical objects on the chart
   this.m_total_objects=::ObjectsTotal(this.ChartID());
   this.m_delta_graph_obj=this.m_total_objects-this.m_last_objects;
   
//--- If the number of objects has changed
   if(this.m_delta_graph_obj!=0)
     {
      //--- Create the string and display it in the journal with the chart ID, its symbol and timeframe
      string txt=", "+(m_delta_graph_obj>0 ? "Added: " : "Deleted: ")+(string)fabs(m_delta_graph_obj)+" obj";
      Print(DFUN,"ChartID=",this.ChartID(),", ",this.Symbol(),", ",TimeframeDescription(this.Timeframe()),txt);
     }
   //--- If an object is added to the chart
   if(this.m_delta_graph_obj>0)
     {
      int index=0;
      datetime time=0;
      string name="";
      //--- find the last added graphical object and write its index
      for(int j=0;j<this.m_total_objects;j++)
        {
         name=::ObjectName(this.ChartID(),j);
         datetime tm=(datetime)::ObjectGetInteger(this.ChartID(),name,OBJPROP_CREATETIME);
         if(tm>time)
           {
            time=tm;
            index=j;
           }
        }
      
      //--- Select the last graphical object by its index
      name=::ObjectName(this.ChartID(),index);
      if(name!="")
        {
         //--- Create the object of the abstract graphical object class
         ENUM_OBJECT type=(ENUM_OBJECT)::ObjectGetInteger(this.ChartID(),name,OBJPROP_TYPE);
         ENUM_OBJECT_DE_TYPE obj_type=ENUM_OBJECT_DE_TYPE(type+OBJECT_DE_TYPE_GSTD_OBJ+1);
         CGStdGraphObj *obj=new CGStdGraphObj(obj_type,GRAPH_OBJ_BELONG_NO_PROGRAM,this.ChartID(),name);
         if(obj!=NULL)
           {
            //--- Set the object index, display its short description and remove the created object
            obj.SetObjectID(this.m_total_objects);
            obj.PrintShort();
            delete obj;
           }
        }
     }
//--- save the index of the last added graphical object and the difference with the last check
   this.m_last_objects=this.m_total_objects;
   this.m_is_graph_obj_event=(bool)this.m_delta_graph_obj;
  }
//+------------------------------------------------------------------+

La lógica principal del método se describe en los comentarios al código y, esperamos, no planteará ninguna pregunta.

Como conclusión, y para corregir una omisión cometida hace mucho, en el destructor de clases de la clase de objeto principal de la biblioteca CEngine, en el archivo \MQL5\Include\DoEasy\Engine.mqh, añadimos la capacidad de borrar todos los comentarios presentes en el gráfico:

//+------------------------------------------------------------------+
//| CEngine destructor                                               |
//+------------------------------------------------------------------+
CEngine::~CEngine()
  {
   ::EventKillTimer();
   ::Comment("");
  }
//+------------------------------------------------------------------+

Ahora, necesitamos poner a prueba la funcionalidad creada.


Simulación

Para la simulación, vamos a tomar el asesor del artículo anterior y guardarlo en la nueva carpeta \MQL5\Experts\TestDoEasy\Part83\ con el nuevo nombre TestDoEasyPart83.mq5.

Por raro que parezca, no tenemos que introducir ningún cambio en la lógica del asesor. Solo debemos cambiar el comportamiento en el manejador OnDeinit():

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();
   Comment("");
  }
//+------------------------------------------------------------------+

En lugar de destruir el temporizador de milisegundos y borrar todos los comentarios del gráfico, añadimos una llamada al método homónimo de la biblioteca:

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Deinitialize library
   engine.OnDeinit();
  }
//+------------------------------------------------------------------+

Al intentar compilar el asesor, veremos el siguiente error:

'CGStdGraphObj::CGStdGraphObj' - cannot access protected member function
   see declaration of 'CGStdGraphObj::CGStdGraphObj'
1 errors, 0 warnings

Y resulta totalmente lógico: el constructor paramétrico de la clase de objeto gráfico abstracto ha sido declarado en la sección privada de la clase. Para corregir ese error, solo tenemos que indicar temporalmente el identificador de acceso "public" para el constructor:

//--- Default constructor
                     CGStdGraphObj(){ this.m_type=OBJECT_DE_TYPE_GSTD_OBJ;  }
protected:
public:
//--- Protected parametric constructor
                     CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type,const ENUM_GRAPH_OBJ_BELONG belong,const long chart_id,const string name);
                     

Compilamos el asesor nuevamente y lo ejecutamos.

Para realizar el test, añadiremos varios objetos gráficos al gráfico; el diario mostrará mensajes sobre cómo añadir un nuevo objeto y una breve descripción del mismo:


Como podemos ver, todo funciona como era esperado.


¿Qué es lo próximo?

En el próximo artículo, crearemos las clases de los objetos gráficos estándar y continuaremos trabajando en la colección de objetos gráficos.

Más abajo se adjuntan todos los archivos de la versión actual de la biblioteca y el archivo del asesor de prueba para MQL5. Podrá descargarlo todo y ponerlo a prueba por sí mismo.

Si tiene preguntas, observaciones o sugerencias, podrá concretarlas en los comentarios al artículo.

Volver al contenido

*Artículos de esta serie:

Gráficos en la biblioteca DoEasy (Parte 73): Objeto de formulario del elemento gráfico
Gráficos en la biblioteca DoEasy (Parte 74): Elemento gráfico básico sobre la clase CCanvas
Gráficos en la biblioteca DoEasy (Parte 75): Métodos de trabajo con primitivas y texto en el elemento gráfico básico.
Gráficos en la biblioteca DoEasy (Parte 76): Objeto de formulario y temas de color predeterminados
Gráficos en la biblioteca DoEasy (Parte 77): Clase de objeto Sombra
Gráficos en la biblioteca DoEasy (Parte 78): Fundamentos de animación en la biblioteca. Cortando las imágenes
Gráficos en la biblioteca DoEasy (Parte 79): Clase de objeto "Fotograma de animación" y sus objetos herederos
Gráficos en la biblioteca DoEasy (Parte 80): Clase de objeto "Fotograma de animación geométrica"
Gráficos en la biblioteca DoEasy (Parte 81): Integrando gráficos en los objetos de la biblioteca
Gráficos en la biblioteca DoEasy (Parte 82): Refactorización de los objetos de la biblioteca y colección de objetos gráficos

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/9902

Archivos adjuntos |
MQL5.zip (4068.71 KB)
Cómo ser un mejor programador (parte 05): Aprendiendo a desarrollar más rápido Cómo ser un mejor programador (parte 05): Aprendiendo a desarrollar más rápido
Sin duda, todo desarrollador querría escribir código más rápido; por eso, le agradará saber que la capacidad de codificar de forma más rápida y eficaz no es algo con lo que solo nazcan unas pocas personas, es una habilidad que se puede adquirir. Eso es lo que intentaremos trabajar en el artículo de hoy.
Perceptrón Multicapa y Algoritmo de Retropropagación (Parte II): Implementación en Python e integración en MQL5 Perceptrón Multicapa y Algoritmo de Retropropagación (Parte II): Implementación en Python e integración en MQL5
Se ha puesto a disposición un paquete de Python con el propósito de desarrollar la integración en MQL, lo que abre las puertas a numerosas posibilidades como la exploración de datos, la creación y el uso de modelos de aprendizaje automático. Esta integración nativa de MQL5 en Python abre las puertas a muchas posibilidades de uso que nos permiten construir desde una simple regresión lineal a un modelo de aprendizaje profundo. Entendamos cómo instalar y preparar el entorno de desarrollo y usar algunas de las bibliotecas de aprendizaje automático.
Gestionando el Horario (Parte 1): Fundamentos Gestionando el Horario (Parte 1): Fundamentos
Funciones y fragmentos de código que simplifican y aclaran el manejo del tiempo, la diferencia con el bróker y los cambios en el horario de verano o invierno. La sincronización precisa puede ser un elemento crucial en el trading. A la hora actual, ¿la bolsa de valores de Londres o Nueva York está ya abierta o sigue cerrada? ¿Cuándo comienza y finaliza el horario comercial para el trading en Fórex? Para un tráder que comercia de forma manual y en vivo, esto no supone un gran problema.
Explorando opciones para crear velas multicolores Explorando opciones para crear velas multicolores
En este artículo, abordaremos las distintas posibilidades de crear indicadores personalizados con velas, señalando sus correspondientes ventajas y desventajas.