Русский 中文 Español Deutsch 日本語 Português
preview
DoEasy. Controls (Part 28): Bar styles in the ProgressBar control

DoEasy. Controls (Part 28): Bar styles in the ProgressBar control

MetaTrader 5Examples | 25 January 2023, 07:45
2 812 0
Artyom Trishkin
Artyom Trishkin

Contents


Concept

Currently, the ProgressBar control created for the library has a single progress bar display style — a continuous line (Continuous). But such a control has two more display styles - segmented blocks (Blocks) and continuous scrolling of a block in an object (Marquee). The Blocks style is pretty clear (a continuous line is replaced with separately located blocks). The Marquee style can be used if the number of iterations that need to be visually displayed using the ProgressBar control is not known in advance. In this case, a single block equal to half the width of the progress bar will constantly scroll. 

In addition to creating these two new styles, I will add a text to the progress bar to be displayed inside. The text itself will be represented by a regular object of the CLabel class of the library, and it will be bound not to the progress bar object, but to the underlay object, which is the base of the ProgressBar control. The text will be rendered inside a fully transparent text label object sized to the width and height of the progress bar. This object will always be in the foreground - above all objects in the ProgressBar control.

By default, the text will not be displayed on the progress bar, but it can always be added right during the execution of a library-based program. We just need to specify the output text and its attributes (font, size, font flags, color, opacity, etc).


Improving library classes

Before I start developing new styles for the ProgressBar control, let's simplify the constructors of the basic graphical element. After creating an object, I set the values of its properties in the protected and parametric constructors. In both constructors, this is a long list of more than a hundred different library graphical element parameters constantly added when new objects are created. Thus, we constantly have to write the setting of object properties twice - in the protected and in the parametric constructors of the CGCnvElement class. It would be logical to move the setting of all these properties into a separate initialization method. At the same time, if some properties should be set differently in different constructors, then they will simply be passed in the formal parameters of the new method and indicated in them.

In \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh, add new properties to the object structure:

   struct SData
     {
      //--- Object integer properties
      int            id;                                       // Element ID
      int            type;                                     // Graphical element type
      
      //---...
      //---...

      //---
      int            group;                                    // Group the graphical element belongs to
      int            tab_size_mode;                            // Tab size setting mode
      int            tab_page_number;                          // Tab index number
      int            tab_page_row;                             // Tab row index
      int            tab_page_column;                          // Tab column index
      int            progress_bar_minimum;                     // The lower bound of the range ProgressBar operates in
      int            progress_bar_maximum;                     // The upper bound of the range ProgressBar operates in
      int            progress_bar_step;                        // ProgressBar increment needed to redraw it
      int            progress_bar_style;                       // ProgressBar style
      int            progress_bar_value;                       // Current ProgressBar value from Min to Max
      int            progress_bar_marquee_speed;               // Progress bar animation speed in case of Marquee style
      //---
      ulong          tooltip_initial_delay;                    // Tooltip display delay
      ulong          tooltip_auto_pop_delay;                   // Tooltip display duration
      ulong          tooltip_reshow_delay;                     // One element new tooltip display delay
      bool           tooltip_show_always;                      // Display a tooltip in inactive window
      int            tooltip_icon;                             // Icon displayed in a tooltip
      bool           tooltip_is_balloon;                       // Tooltip in the form of a "cloud"
      bool           tooltip_use_fading;                       // Fade when showing/hiding a tooltip
      //--- Object real properties

      //--- Object string properties
      uchar          name_obj[64];                             // Graphical element object name
      uchar          name_res[64];                             // Graphical resource name
      uchar          text[256];                                // Graphical element text
      uchar          descript[256];                            // Graphical element description
      uchar          tooltip_title[256];                       // Element tooltip title
      uchar          tooltip_text[256];                        // Element tooltip text
     };
   SData             m_struct_obj;                             // Object structure

The structure of a graphical object is needed for the correct writing of the object properties to a file and reading them from the file during restoration. The properties now written into this structure have already been added to the object, but have not yet been added to the structure. Even if the fields of the structure do not match the properties of the object, then at this stage of development there is nothing to worry about. So far, I have not implemented saving the object to a file and reading its properties from the file. Subsequently, of course, I will save the properties of graphical objects to a file and read them from there. At that point, I will really need a complete match of the structure fields with the object properties.

In the private section of the class, declare a new method for initializing graphical element properties:

//--- Save the colors to the background color array
   void              SaveColorsBG(color &colors[])                         { this.CopyArraysColors(this.m_array_colors_bg,colors,DFUN);      }
   void              SaveColorsBGMouseDown(color &colors[])                { this.CopyArraysColors(this.m_array_colors_bg_dwn,colors,DFUN);  }
   void              SaveColorsBGMouseOver(color &colors[])                { this.CopyArraysColors(this.m_array_colors_bg_ovr,colors,DFUN);  }
   void              SaveColorsBGInit(color &colors[])                     { this.CopyArraysColors(this.m_array_colors_bg_init,colors,DFUN); }

//--- Initialize property values
   void              Initialize(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                                const int element_id,const int element_num,
                                const int x,const int y,const int w,const int h,
                                const string descript,const bool movable,const bool activity);

public:

The properties of the created object will be passed to the method. The properties have different values in different constructors or are specified directly in the formal parameters of the constructors, i.e. are passed from outside. I will pass all such properties to the method via its parameters.


Remove a long list of setting object properties in each of the constructors replacing it with a call to the initialization method:

//+---------------------------------------------+
//| Parametric constructor                      |
//+---------------------------------------------+
CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                           CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const int      element_id,
                           const int      element_num,
                           const long     chart_id,
                           const int      wnd_num,
                           const string   descript,
                           const int      x,
                           const int      y,
                           const int      w,
                           const int      h,
                           const color    colour,
                           const uchar    opacity,
                           const bool     movable=true,
                           const bool     activity=true,
                           const bool     redraw=false) : m_shadow(false)
  {
   this.SetTypeElement(element_type);
   this.m_type=OBJECT_DE_TYPE_GELEMENT; 
   this.m_element_main=main_obj;
   this.m_element_base=base_obj;
   this.m_chart_color_bg=(color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND);
   this.m_name=this.CreateNameGraphElement(element_type);
   this.m_chart_id=(chart_id==NULL || chart_id==0 ? ::ChartID() : chart_id);
   this.m_subwindow=wnd_num;
   this.SetFont(DEF_FONT,DEF_FONT_SIZE);
   this.m_text_anchor=0;
   this.m_text_x=0;
   this.m_text_y=0;
   this.SetBackgroundColor(colour,true);
   this.SetOpacity(opacity);
   this.m_shift_coord_x=0;
   this.m_shift_coord_y=0;
   if(::ArrayResize(this.m_array_colors_bg,1)==1)
      this.m_array_colors_bg[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_dwn,1)==1)
      this.m_array_colors_bg_dwn[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_ovr,1)==1)
      this.m_array_colors_bg_ovr[0]=this.BackgroundColor();
   if(this.Create(chart_id,wnd_num,x,y,w,h,redraw))
     {
      this.Initialize(element_type,element_id,element_num,x,y,w,h,descript,movable,activity);
      this.SetVisibleFlag(false,false);
     }
   else
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj());
     }
  }
//+---------------------------------------------+
//| Protected constructor                       |
//+---------------------------------------------+
CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                           CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const long    chart_id,
                           const int     wnd_num,
                           const string  descript,
                           const int     x,
                           const int     y,
                           const int     w,
                           const int     h) : m_shadow(false)
  {
   this.m_type=OBJECT_DE_TYPE_GELEMENT; 
   this.m_element_main=main_obj;
   this.m_element_base=base_obj;
   this.m_chart_color_bg=(color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND);
   this.m_name=this.CreateNameGraphElement(element_type);
   this.m_chart_id=(chart_id==NULL || chart_id==0 ? ::ChartID() : chart_id);
   this.m_subwindow=wnd_num;
   this.m_type_element=element_type;
   this.SetFont(DEF_FONT,DEF_FONT_SIZE);
   this.m_text_anchor=0;
   this.m_text_x=0;
   this.m_text_y=0;
   this.SetBackgroundColor(CLR_CANV_NULL,true);
   this.SetOpacity(0);
   this.m_shift_coord_x=0;
   this.m_shift_coord_y=0;
   if(::ArrayResize(this.m_array_colors_bg,1)==1)
      this.m_array_colors_bg[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_dwn,1)==1)
      this.m_array_colors_bg_dwn[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_ovr,1)==1)
      this.m_array_colors_bg_ovr[0]=this.BackgroundColor();
   if(this.Create(chart_id,wnd_num,x,y,w,h,false))
     {
      this.Initialize(element_type,0,0,x,y,w,h,descript,false,false);
      this.SetVisibleFlag(false,false);
     }
   else
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj());
     }
  }
//+------------------------------------------------------------------+

As we can see, the values inherent in each specific constructor are passed to the initialization method in both constructors.


In the new initialization method, move property setting removed from the class constructors:

//+---------------------------------------------+
//| Initialize the properties                   |
//+---------------------------------------------+
void CGCnvElement::Initialize(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                              const int element_id,const int element_num,
                              const int x,const int y,const int w,const int h,
                              const string descript,const bool movable,const bool activity)
  {
   this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,this.m_canvas.ResourceName()); // Graphical resource name
   this.SetProperty(CANV_ELEMENT_PROP_CHART_ID,CGBaseObj::ChartID());         // Chart ID
   this.SetProperty(CANV_ELEMENT_PROP_WND_NUM,CGBaseObj::SubWindow());        // Chart subwindow index
   this.SetProperty(CANV_ELEMENT_PROP_NAME_OBJ,CGBaseObj::Name());            // Element object name
   this.SetProperty(CANV_ELEMENT_PROP_TYPE,element_type);                     // Graphical element type
   this.SetProperty(CANV_ELEMENT_PROP_ID,element_id);                         // Element ID
   this.SetProperty(CANV_ELEMENT_PROP_NUM,element_num);                       // Element index in the list
   this.SetProperty(CANV_ELEMENT_PROP_COORD_X,x);                             // Element's X coordinate on the chart
   this.SetProperty(CANV_ELEMENT_PROP_COORD_Y,y);                             // Element's Y coordinate on the chart
   this.SetProperty(CANV_ELEMENT_PROP_WIDTH,w);                               // Element width
   this.SetProperty(CANV_ELEMENT_PROP_HEIGHT,h);                              // Element height
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,0);                      // Active area offset from the left edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP,0);                       // Active area offset from the upper edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,0);                     // Active area offset from the right edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,0);                    // Active area offset from the bottom edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_MOVABLE,movable);                       // Element moveability flag
   this.SetProperty(CANV_ELEMENT_PROP_ACTIVE,activity);                       // Element activity flag
   this.SetProperty(CANV_ELEMENT_PROP_INTERACTION,false);                     // Flag of interaction with the outside environment
   this.SetProperty(CANV_ELEMENT_PROP_ENABLED,true);                          // Element availability flag
   this.SetProperty(CANV_ELEMENT_PROP_RIGHT,this.RightEdge());                // Element right border
   this.SetProperty(CANV_ELEMENT_PROP_BOTTOM,this.BottomEdge());              // Element bottom border
   this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_X,this.ActiveAreaLeft());     // X coordinate of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_Y,this.ActiveAreaTop());      // Y coordinate of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_ACT_RIGHT,this.ActiveAreaRight());      // Right border of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.ActiveAreaBottom());    // Bottom border of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_X,0);                      // Visibility scope X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y,0);                      // Visibility scope Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH,w);                  // Visibility scope width
   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,h);                 // Visibility scope height
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAYED,true);                        // Non-hidden control display flag
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_STATE,CANV_ELEMENT_DISPLAY_STATE_NORMAL);// Control display state
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_DURATION,DEF_CONTROL_PROCESS_DURATION);  // Control display duration
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_X,0);                      // Control area X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_Y,0);                      // Control area Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_WIDTH,0);                  // Control area width
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_HEIGHT,0);                 // Control area height
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_RIGHT,0);                 // Right scroll area X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_RIGHT,0);                 // Right scroll area Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_RIGHT,0);             // Right scroll area width
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_RIGHT,0);            // Right scroll area height
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_BOTTOM,0);                // Bottom scroll area X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_BOTTOM,0);                // Bottom scroll area Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_BOTTOM,0);            // Bottom scroll area width
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_BOTTOM,0);           // Bottom scroll area height
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_LEFT_AREA_WIDTH,0);              // Left edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_BOTTOM_AREA_WIDTH,0);            // Bottom edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_RIGHT_AREA_WIDTH,0);             // Right edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH,0);               // Top edge area width
   //---
   this.SetProperty(CANV_ELEMENT_PROP_BELONG,ENUM_GRAPH_OBJ_BELONG::GRAPH_OBJ_BELONG_PROGRAM);  // Graphical element affiliation
   this.SetProperty(CANV_ELEMENT_PROP_ZORDER,0);                              // Priority of a graphical object for receiving the event of clicking on a chart
   this.SetProperty(CANV_ELEMENT_PROP_BOLD_TYPE,FW_NORMAL);                   // Font width type
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_STYLE,FRAME_STYLE_NONE);         // Control frame style
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_TOP,0);                     // Control frame top size
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM,0);                  // Control frame bottom size
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_LEFT,0);                    // Control frame left size
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT,0);                   // Control frame right size
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR,this.BackgroundColor());   // Control frame color
   this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE,false);                        // Flag of the element auto resizing depending on the content
   this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE_MODE,CANV_ELEMENT_AUTO_SIZE_MODE_GROW); // Mode of the element auto resizing depending on the content
   this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL,false);                      // Auto scrollbar flag
   this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W,0);                 // Width of the field inside the element during auto scrolling
   this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H,0);                 // Height of the field inside the element during auto scrolling
   this.SetProperty(CANV_ELEMENT_PROP_DOCK_MODE,CANV_ELEMENT_DOCK_MODE_NONE); // Mode of binding control borders to the container
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_TOP,0);                          // Top margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_BOTTOM,0);                       // Bottom margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_LEFT,0);                         // Left margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_RIGHT,0);                        // Right margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_TOP,0);                         // Top margin inside the control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM,0);                      // Bottom margin inside the control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_LEFT,0);                        // Left margin inside the control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT,0);                       // Right margin inside the control
   this.SetProperty(CANV_ELEMENT_PROP_TEXT_ALIGN,ANCHOR_LEFT_UPPER);          // Text position within text label boundaries
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_ALIGN,ANCHOR_LEFT_UPPER);         // Position of the checkbox within control borders
   this.SetProperty(CANV_ELEMENT_PROP_CHECKED,false);                         // Control checkbox status
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_STATE,CANV_ELEMENT_CHEK_STATE_UNCHECKED);  // Status of a control having a checkbox
   this.SetProperty(CANV_ELEMENT_PROP_AUTOCHECK,true);                        // Auto change flag status when it is selected
   //---
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR,CLR_DEF_CHECK_BACK_COLOR);            // Color of control checkbox background
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY,CLR_DEF_CHECK_BACK_OPACITY);  // Opacity of the control checkbox background color
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_DOWN,CLR_DEF_CHECK_BACK_MOUSE_DOWN);// Color of control checkbox background when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_OVER,CLR_DEF_CHECK_BACK_MOUSE_OVER);// Color of control checkbox background when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR,CLR_DEF_CHECK_BORDER_COLOR);                // Color of control checkbox frame
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY,CLR_DEF_CHECK_BORDER_OPACITY);      // Opacity of the control checkbox frame color
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_DOWN,CLR_DEF_CHECK_BORDER_MOUSE_DOWN);// Color of control checkbox frame when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_OVER,CLR_DEF_CHECK_BORDER_MOUSE_OVER);// Color of control checkbox frame when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR,CLR_DEF_CHECK_FLAG_COLOR);                  // Control checkbox color
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY,CLR_DEF_CHECK_FLAG_OPACITY);        // Control checkbox color opacity
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_DOWN,CLR_DEF_CHECK_FLAG_MOUSE_DOWN);  // Control checkbox color when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_OVER,CLR_DEF_CHECK_FLAG_MOUSE_OVER);  // Control checkbox color when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR,CLR_DEF_FORE_COLOR);                              // Default text color for all control objects
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,CLR_DEF_FORE_COLOR_OPACITY);              // Opacity of the default text color for all control objects
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_DOWN,CLR_DEF_FORE_COLOR_MOUSE_DOWN);        // Default control text color when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_OVER,CLR_DEF_FORE_COLOR_MOUSE_OVER);        // Default control text color when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_STATE_ON,CLR_DEF_FORE_COLOR);                     // Text color of the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_STATE_ON_MOUSE_DOWN,CLR_DEF_FORE_COLOR_MOUSE_DOWN);// Default control text color when clicking on the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_STATE_ON_MOUSE_OVER,CLR_DEF_FORE_COLOR_MOUSE_OVER);// Default control text color when hovering the mouse over the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN,this.BackgroundColor());         // Control background color when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER,this.BackgroundColor());         // Control background color when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_STATE_ON,CLR_DEF_CONTROL_STD_BACK_COLOR_ON);// Background color of the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_STATE_ON_MOUSE_DOWN,CLR_DEF_CONTROL_STD_BACK_DOWN_ON);// Control background color when clicking on the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_STATE_ON_MOUSE_OVER,CLR_DEF_CONTROL_STD_BACK_OVER_ON);// Control background color when clicking on the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN,CLR_DEF_BORDER_MOUSE_DOWN);          // Control frame color when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER,CLR_DEF_BORDER_MOUSE_OVER);          // Control frame color when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_TOGGLE,false);                                        // Toggle flag of the control featuring a button
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_STATE,false);                                         // Status of the Toggle control featuring a button
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_GROUP,false);                                         // Button group flag
   this.SetProperty(CANV_ELEMENT_PROP_LIST_BOX_MULTI_COLUMN,false);                                // Horizontal display of columns in the ListBox control
   this.SetProperty(CANV_ELEMENT_PROP_LIST_BOX_COLUMN_WIDTH,0);                                    // Width of each ListBox control column
   this.SetProperty(CANV_ELEMENT_PROP_TAB_MULTILINE,false);                                        // Several lines of tabs in TabControl
   this.SetProperty(CANV_ELEMENT_PROP_TAB_ALIGNMENT,CANV_ELEMENT_ALIGNMENT_TOP);                   // Location of tabs inside the control
   this.SetProperty(CANV_ELEMENT_PROP_ALIGNMENT,CANV_ELEMENT_ALIGNMENT_TOP);                       // Location of an object inside the control
   this.SetProperty(CANV_ELEMENT_PROP_TEXT,"");                                                    // Graphical element text
   this.SetProperty(CANV_ELEMENT_PROP_DESCRIPTION,descript);                                       // Graphical element description
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_FIXED_PANEL,0);                              // Panel that retains its size when the container is resized
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_SPLITTER_FIXED,true);                        // Separator moveability flag
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_SPLITTER_DISTANCE,50);                       // Distance from edge to separator
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_SPLITTER_WIDTH,4);                           // Separator width
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_SPLITTER_ORIENTATION,0);                     // Separator location
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_PANEL1_COLLAPSED,false);                     // Flag for collapsed panel 1
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_PANEL1_MIN_SIZE,25);                         // Panel 1 minimum size
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_PANEL2_COLLAPSED,false);                     // Flag for collapsed panel 1
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_PANEL2_MIN_SIZE,25);                         // Panel 2 minimum size
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_INITIAL_DELAY,500);                                  // Tooltip display delay
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_AUTO_POP_DELAY,5000);                                // Tooltip display duration
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY,100);                                   // One element new tooltip display delay
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_SHOW_ALWAYS,false);                                  // Display a tooltip in inactive window
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_ICON,CANV_ELEMENT_TOOLTIP_ICON_NONE);                // Icon displayed in a tooltip
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_IS_BALLOON,false);                                   // Tooltip in the form of a "cloud"
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_USE_FADING,true);                                    // Fade when showing/hiding a tooltip
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TITLE,"");                                           // Tooltip title for the element
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TEXT,"");                                            // Tooltip text for the element
   this.SetProperty(CANV_ELEMENT_PROP_GROUP,0);                               // Group the graphical element belongs to
   this.SetProperty(CANV_ELEMENT_PROP_TAB_SIZE_MODE,CANV_ELEMENT_TAB_SIZE_MODE_NORMAL);// Tab size setting mode
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_NUMBER,0);                     // Tab index number
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_ROW,0);                        // Tab row index
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_COLUMN,0);                     // Tab column index
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM,100);              // The upper bound of the range ProgressBar operates in
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM,0);                // The lower bound of the range ProgressBar operates in
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STEP,10);                  // ProgressBar increment needed to redraw it
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE,CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS); // ProgressBar style
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,50);                 // Current ProgressBar value from Min to Max
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,10);    // Progress bar animation speed in case of Marquee style
  }
//+------------------------------------------------------------------+

Here we simply moved the strings removed from the class constructors. Property values that were different in different constructors are now passed and set to object properties through formal method parameters.


In the method creating an object structure, add setting values of the appropriate graphical element properties to the new structure fields:

//+---------------------------------------------+
//| Create the object structure                 |
//+---------------------------------------------+
bool CGCnvElement::ObjectToStruct(void)
  {
//--- Save integer properties
   this.m_struct_obj.id=(int)this.GetProperty(CANV_ELEMENT_PROP_ID);                               // Element ID
   this.m_struct_obj.type=(int)this.GetProperty(CANV_ELEMENT_PROP_TYPE);                           // Graphical element type
   this.m_struct_obj.belong=(int)this.GetProperty(CANV_ELEMENT_PROP_BELONG);                       // Graphical element affiliation
   this.m_struct_obj.number=(int)this.GetProperty(CANV_ELEMENT_PROP_NUM);                          // Element ID in the list

   //---...
   //---...

   this.m_struct_obj.border_right_area_width=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_RIGHT_AREA_WIDTH);    // Right edge area width
   this.m_struct_obj.border_top_area_width=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH);        // Top edge area width
   //---
   this.m_struct_obj.tooltip_initial_delay=this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_INITIAL_DELAY);    // Tooltip display delay
   this.m_struct_obj.tooltip_auto_pop_delay=this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_AUTO_POP_DELAY);  // Tooltip display duration
   this.m_struct_obj.tooltip_reshow_delay=this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY);      // One element new tooltip display delay
   this.m_struct_obj.tooltip_show_always=this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_SHOW_ALWAYS);        // Display a tooltip in inactive window
   this.m_struct_obj.tooltip_icon=(int)this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_ICON);                 // Icon displayed in the tooltip
   this.m_struct_obj.tooltip_is_balloon=(bool)this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_IS_BALLOON);    // Balloon tooltip
   this.m_struct_obj.tooltip_use_fading=(bool)this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_USE_FADING);    // Fade when showing and hiding the tooltip
      //---
   this.m_struct_obj.group=(int)this.GetProperty(CANV_ELEMENT_PROP_GROUP);                               // Group the graphical element belongs to
   this.m_struct_obj.tab_size_mode=(int)this.GetProperty(CANV_ELEMENT_PROP_TAB_SIZE_MODE);               // Tab size setting mode
   this.m_struct_obj.tab_page_number=(int)this.GetProperty(CANV_ELEMENT_PROP_TAB_PAGE_NUMBER);           // Tab index number
   this.m_struct_obj.tab_page_row=(int)this.GetProperty(CANV_ELEMENT_PROP_TAB_PAGE_ROW);                 // Tab row index
   this.m_struct_obj.tab_page_column=(int)this.GetProperty(CANV_ELEMENT_PROP_TAB_PAGE_COLUMN);           // Tab column index
   this.m_struct_obj.progress_bar_maximum=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM); // The upper bound of the range ProgressBar operates in
   this.m_struct_obj.progress_bar_minimum=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM); // The lower bound of the range ProgressBar operates in
   this.m_struct_obj.progress_bar_step=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STEP);       // ProgressBar increment needed to redraw it
   this.m_struct_obj.progress_bar_style=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE);     // ProgressBar style
   this.m_struct_obj.progress_bar_value=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE);     // Current ProgressBar value from Min to Max
   this.m_struct_obj.progress_bar_marquee_speed=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED);// Progress bar animation speed in case of Marquee style
//--- Save real properties

//--- Save string properties
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_OBJ),this.m_struct_obj.name_obj);   // Graphical element object name
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_RES),this.m_struct_obj.name_res);   // Graphical resource name
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_TEXT),this.m_struct_obj.text);           // Graphical element text
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_DESCRIPTION),this.m_struct_obj.descript);// Graphical element description
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_TITLE),this.m_struct_obj.tooltip_title);// Tooltip title for the element
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_TEXT),this.m_struct_obj.tooltip_text);  // Tooltip text for the element
   //--- Save the structure to the uchar array
   ::ResetLastError();
   if(!::StructToCharArray(this.m_struct_obj,this.m_uchar_array))
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY,true);
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+


In the method that creates an object from a structure, implement setting object properties from the corresponding structure fields added in the current article:

//+---------------------------------------------+
//| Create the object from the structure        |
//+---------------------------------------------+
void CGCnvElement::StructToObject(void)
  {
//--- Save integer properties
   this.SetProperty(CANV_ELEMENT_PROP_ID,this.m_struct_obj.id);                                    // Element ID
   this.SetProperty(CANV_ELEMENT_PROP_TYPE,this.m_struct_obj.type);                                // Graphical element type
   this.SetProperty(CANV_ELEMENT_PROP_BELONG,this.m_struct_obj.belong);                            // Graphical element affiliation
   this.SetProperty(CANV_ELEMENT_PROP_NUM,this.m_struct_obj.number);                               // Element index in the list

   //---...
   //---...

   this.SetProperty(CANV_ELEMENT_PROP_BORDER_RIGHT_AREA_WIDTH,this.m_struct_obj.border_right_area_width);      // Right edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH,this.m_struct_obj.border_top_area_width);          // Top edge area width
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_INITIAL_DELAY,this.m_struct_obj.tooltip_initial_delay);             // Tooltip display delay
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_AUTO_POP_DELAY,this.m_struct_obj.tooltip_auto_pop_delay);// Tooltip display duration
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY,this.m_struct_obj.tooltip_reshow_delay);// One element new tooltip display delay
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_SHOW_ALWAYS,this.m_struct_obj.tooltip_show_always);// Display a tooltip in inactive window
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_ICON,this.m_struct_obj.tooltip_icon);              // Icon displayed in a tooltip
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_IS_BALLOON,this.m_struct_obj.tooltip_is_balloon);  // Balloon tooltip
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_USE_FADING,this.m_struct_obj.tooltip_use_fading);  // Fade when showing/hiding a tooltip
   this.SetProperty(CANV_ELEMENT_PROP_GROUP,this.m_struct_obj.group);                            // Group the graphical element belongs to
   this.SetProperty(CANV_ELEMENT_PROP_TAB_SIZE_MODE,this.m_struct_obj.tab_size_mode);            // Tab size setting mode
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_NUMBER,this.m_struct_obj.tab_page_number);        // Tab index number
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_ROW,this.m_struct_obj.tab_page_row);              // Tab row index
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_COLUMN,this.m_struct_obj.tab_page_column);        // Tab column index
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM,this.m_struct_obj.progress_bar_maximum);// The upper bound of the range ProgressBar operates in
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM,this.m_struct_obj.progress_bar_minimum);// The lower bound of the range ProgressBar operates in
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STEP,this.m_struct_obj.progress_bar_step);    // ProgressBar increment needed to redraw it
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE,this.m_struct_obj.progress_bar_style);  // ProgressBar style
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,this.m_struct_obj.progress_bar_value);  // Current ProgressBar value from Min to Max
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,this.m_struct_obj.progress_bar_marquee_speed);  // Progress bar animation speed in case of Marquee style
//--- Save real properties

//--- Save string properties
   this.SetProperty(CANV_ELEMENT_PROP_NAME_OBJ,::CharArrayToString(this.m_struct_obj.name_obj));   // Graphical element object name
   this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,::CharArrayToString(this.m_struct_obj.name_res));   // Graphical resource name
   this.SetProperty(CANV_ELEMENT_PROP_TEXT,::CharArrayToString(this.m_struct_obj.text));           // Graphical element text
   this.SetProperty(CANV_ELEMENT_PROP_DESCRIPTION,::CharArrayToString(this.m_struct_obj.descript));// Graphical element description
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TITLE,::CharArrayToString(this.m_struct_obj.tooltip_title));// Tooltip title for the element
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TEXT,::CharArrayToString(this.m_struct_obj.tooltip_text));  // Tooltip text for the element
  }
//+------------------------------------------------------------------+

Now the graphical element object will be correctly saved to and restored from a file.


A glare running along the progress bar can have the shape of a parallelepiped. This is a skewed quad with the top face vertices offset by 6 pixels from the bottom face vertices. For a small object, this offset is enough to make the object look fairly slanted. But as its height increases, the slope, set rigidly at six pixels, becomes indistinguishable. To correct the situation, we need to make the slope a relative value - the higher the object, the stronger the slope. So, to set the size of the offset of the vertices, we will use the height of the object - then visually the slope will be at 45 degrees.

In \MQL5\Include\DoEasy\Objects\Graph\WForms\GlareObj.mqh, in the method that draws the shape of the object glare in the form of a parallelogram, fix the initialization of the parameters of the vertex coordinates. Instead of the number 6, assign the value of the graphical object height:

//+------------------------------------------------------------------+
//| Draw the shape of the object glare as a parallelogram            |
//+------------------------------------------------------------------+
void CGlareObj::DrawFigureParallelogram(void)
  {
   int array_x[]={this.Height(),this.Width()-1,this.Width()-1-this.Height(),0};
   int array_y[]={0,0,this.Height()-1,this.Height()-1};
   CGCnvElement::DrawPolygonFill(array_x,array_y,this.m_color,this.OpacityDraw());
   CGCnvElement::Update();
  }
//+------------------------------------------------------------------+

Now the vertices will be offset by the value of the height of the object and the slope will always be at about 45 degrees, regardless of the object height.


I can use different options to create a "Segmented Blocks" progress bar style — from directly creating each block to simply drawing them. I am going to do this as follows. I already have a completely filled progress bar, and I only need to erase the background of this object in those places where there are no blocks. In this case, I will get the appearance of a progress bar, consisting of segmented blocks. The disadvantage of this approach is that the location of each block should be calculated. The advantage of this approach is the simplicity of its implementation.

In the private section in \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\BarProgressBar.mqh, add the variables for storing segment parameters and declare the method for the object background segmentation:

//+------------------------------------------------------------------+
//| BarProgressBar object class of the ProgressBar control           |
//+------------------------------------------------------------------+
class CBarProgressBar : public CWinFormBase
  {
private:
   int               m_segment_s;                                 // Segment countdown start
   int               m_segment_x;                                 // Last segment X coordinate
   int               m_segment_w;                                 // Segment width
   int               m_segment_d;                                 // Distance between segments
//--- Segment the background
   void              Segmentation(void);
//--- (1) Set and (2) return a pause before displaying the effect
   void              SetShowDelay(const long delay)               { this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY,delay);             }
   ulong             ShowDelay(void)                              { return this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY);            }
//--- Initialize the properties
   void              Initialize(void);
protected:
//--- Protected constructor with object type, chart ID and subwindow
                     CBarProgressBar(const ENUM_GRAPH_ELEMENT_TYPE type,
                                     CGCnvElement *main_obj,CGCnvElement *base_obj,
                                     const long chart_id,
                                     const int subwindow,
                                     const string descript,
                                     const int x,
                                     const int y,
                                     const int w,
                                     const int h);
public:

The declared variables will contain the initial parameters the location of the segments can be calculated from. The segment width will always be 3/4 of the height, and the distance between the segments will be calculated from the resulting segment width. This data will be recorded when the object is initialized, and then it can be used to calculate the location of any segment by its number. Since we are not drawing the segments themselves, but the spaces between them, the starting point will be the width of the first segment counted either from zero or from one. If the height of the progress bar is more than three pixels, then a one-pixel empty space should be drawn around the edge of the object on all sides. This will separate the segments from the outer edge of the bar, making them visually independent units. In this case, the indent of the first segment should start at one, which is a one-pixel empty space from the edge of the object to the first segment. If the height of the progress bar is three pixels or less, then we do not need to draw empty space - it will occupy the entire usable area of the object the segments are drawn on. In this case, the indent to the beginning of the first segment should be zero.

In the public section of the class, implement the method that returns the style of the progress bar and the methods that return the values of the variable parameters of the segments. Let's declare the methods for calculating the width of the segment and the distance between them. I will also need to redefine the virtual methods for clearing the object background:

public:
//--- Set the (1) animation speed in case of Marquee style, (2) display style, (3) increment value and (4) the current value of the ProgressBar control
   void              SetMarqueeAnimationSpeed(const int value)    { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,value);  }
   void              SetStyle(const ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE style) { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE,style); }
   void              SetStep(const int value)                     { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STEP,value);                }
   void              SetValue(const int value)                    { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,value);               }
   
//--- Return the display style
   ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE Style(void) const
                       { return (ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE); }

//--- Return (1) the X coordinate of the last segment, (2) segment width, (3) distance between segments and (4) segment countdown start
   int               SegmentX(void)                         const { return this.m_segment_x; }
   int               SegmentWidth(void)                     const { return this.m_segment_w; }
   int               SegmentDistance(void)                  const { return this.m_segment_d; }
   int               SegmentStart(void)                     const { return this.m_segment_s; }
   
//--- Calculate (1) the segment width and (2) the distance between segments
   int               CalculateSegmentWidth(void);
   int               CalculateSegmentDistance(const int width);

//--- Supported object properties (1) integer, (2) real and (3) string ones
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property) { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)  { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property)  { return true; }

//--- Clear the element filling it with color and opacity
   virtual void      Erase(const color colour,const uchar opacity,const bool redraw=false);
//--- Clear the element with a gradient fill
   virtual void      Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false);
   
//--- Constructor
                     CBarProgressBar(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                     const long chart_id,
                                     const int subwindow,
                                     const string descript,
                                     const int x,
                                     const int y,
                                     const int w,
                                     const int h);
//--- Timer
   virtual void      OnTimer(void);
  };
//+------------------------------------------------------------------+

In the clearing methods, the element background is filled with its background color. Accordingly, after the filling, it is necessary to remove the background from the gaps between the segments. In these methods, we will call the method declared in the private section for segmenting the drawn object background. Since they are virtual, it is always these methods that will be called when calling the cleaning method if the object is a progress bar or its successor.

In the object properties initialization method, enter the default values for the variables that store the segmentation parameters. The last segment X coordinate and the countdown start will be equal to zero, while the segment width and the distance between them will be calculated at once:

//+---------------------------------------------+
//| Initialize the properties                   |
//+---------------------------------------------+
void CBarProgressBar::Initialize(void)
  {
   this.SetPaddingAll(0);
   this.SetMarginAll(0);
   this.SetBorderSizeAll(0);
   this.SetBackgroundColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
   this.SetBorderColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
   this.SetForeColor(CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR,true);
   this.SetShowDelay(2000);
   this.m_segment_x=0;
   this.m_segment_s=0;
   this.m_segment_w=this.CalculateSegmentWidth();
   this.m_segment_d=this.CalculateSegmentDistance(this.m_segment_w);
  }
//+------------------------------------------------------------------+


Let's consider the declared methods in details.

The method clearing the element filling it with color and opacity:

//+------------------------------------------------------------------+
//| Clear the element filling it with color and opacity              |
//+------------------------------------------------------------------+
void CBarProgressBar::Erase(const color colour,const uchar opacity,const bool redraw=false)
  {
//--- Fill the element having the specified color and the redrawing flag
   CGCnvElement::EraseNoCrop(colour,opacity,false);
//--- Segment the background
   this.Segmentation();
//--- If the object has a frame, draw it
   if(this.BorderStyle()!=FRAME_STYLE_NONE)
      this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.Opacity(),this.BorderStyle());
//--- Crop the excess and update the element with the specified redraw flag
   this.Crop();
   this.Update(redraw);
  }
//+------------------------------------------------------------------+

Here, the entire background of the element is first filled. The segmentation method is then called erasing the background in those places of the object where there should be no segments. If the object has a frame, then it is drawn. The parts of the object protruding beyond the parent container are cropped, and the background of the object is updated with the chart redrawing flag passed to the method.

The method that clears an element with a gradient fill:

//+---------------------------------------------+
//| Clear the element with a gradient fill      |
//+---------------------------------------------+
void CBarProgressBar::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false)
  {
//--- Fill the element having the specified color array and the redrawing flag
   CGCnvElement::EraseNoCrop(colors,opacity,vgradient,cycle,false);
//--- Segment the background
   this.Segmentation();
//--- If the object has a frame, draw it
   if(this.BorderStyle()!=FRAME_STYLE_NONE)
      this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.Opacity(),this.BorderStyle());
//--- Crop the excess and update the element with the specified redraw flag
   this.Crop();
   this.Update(redraw);
  }
//+------------------------------------------------------------------+

The logic of the method is identical to the logic of the above method, except that not a single color is passed to the method, but rather the color array of the gradient fill and its direction flag — vertical/horizontal and cyclic.


The method that calculates the segment width:

//+---------------------------------------------+
//| Calculate the segment width                 |
//+---------------------------------------------+
int CBarProgressBar::CalculateSegmentWidth(void)
  {
   int w=(int)::ceil((this.Height()-2)/1.75);
   return(w>3 ? w : 3);
  }
//+------------------------------------------------------------------+

The width of any segment should be 2/3 of its height. This method calculates the width of the segment based on the height of the progress bar object. Let's take the height of the object minus two pixels. More often, the height of the progress bar will be more than three pixels, which means that free space of one pixel will be drawn on each side of the progress bar along its perimeter, which will reduce the visible height of the segment by two pixels (one above and one below). The resulting height is divided by 1.75, which will give an aspect ratio of 3/4. If the resulting width is less than three pixels, then the width will be equal to three pixels, since segments that are too small in height look bad with a width of 1-2 pixels.


The method that calculates the distance between segments:

//+---------------------------------------------+
//| Calculate the distance between segments     |
//+---------------------------------------------+
int CBarProgressBar::CalculateSegmentDistance(const int width)
  {
   int d=(int)::ceil(width/6);
   return(d<1 ? 1 : d);
  }
//+------------------------------------------------------------------+

All is simple here. The method receives the width the indent should be calculated from. The distance between the segments should be six times less than the width of the block, but not less than one pixel.


Background segmentation method:

//+---------------------------------------------+
//| Segment the background                      |
//+---------------------------------------------+
void CBarProgressBar::Segmentation(void)
  {
//--- If the drawing style is not "Segmented blocks", leave
   if(this.Style()!=CANV_ELEMENT_PROGRESS_BAR_STYLE_BLOCKS)
      return;
//--- Reset the X coordinate of the segment
   this.m_segment_x=0;
//--- Get the block width as 3/4 of its height
   int w=this.SegmentWidth();
//--- Get the distance between the segments (six times less than the block width)
   int d=this.SegmentDistance();
//--- Get the countdown start
   this.m_segment_s=w+(this.Height()>3 ? 1 : 0);
//--- In the loop from the beginning of the countdown to the width of the progress bar with a step in the block width + indent between segments
   for(int i=this.SegmentStart();i<this.Width();i+=w+d)
     {
      //--- draw an empty fully transparent rectangle (erasing the element background)
      this.DrawRectangleFill(i,0,i+d-1,this.Height()-1,CLR_CANV_NULL,0);
      //--- Store the X coordinate of the segment
      this.m_segment_x=i;
     }
//--- If the height of the progress line is more than three pixels, draw a completely transparent frame around the perimeter
   if(this.Height()>3)
      this.DrawRectangle(0,0,this.Width()-1,this.Height()-1,CLR_CANV_NULL,0);
  }
//+------------------------------------------------------------------+

The method logic is fully described in the code comments. If the progress bar style is "Segmented blocks", then in a loop we go through the entire background of the object and erase the background where there should be no segments. If the height of the object is more than three pixels, then we additionally erase the background along the perimeter with a one-pixel wide border, which will make the segments separated from the edges of the progress bar.


In the ProgressBar object, add the ability to include a description displayed on the progress bar. By default, the description will not be displayed, but it is enough just to define its text in order to enable it. The description will be built by a CLabel object permanently attached to the object. Naturally, it will be possible to create as many such objects as you like and set them in the right places. But the progress bar description object will be created by default when the ProgressBar is created, and it will be easier to access using special methods.

In the \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\ProgressBar.mqh CProgressBar class file, remove the variable for storing the number of skipped steps from the private section since there was no need for it:

//+------------------------------------------------------------------+
//| ArrowLeftRightBox object class of WForms controls                |
//+------------------------------------------------------------------+
class CProgressBar : public CContainer
  {
private:
   int               m_progress_bar_max;  // Maximum progress bar width
   int               m_value_by_max;      // Value relative to Maximum
   int               m_steps_skipped;     // Number of skipped steps of increasing the width of the progress bar

//--- Create a new graphical object


Also, in the private section, declare the variables to store text label properties with the progress bar description:

//+------------------------------------------------------------------+
//| ArrowLeftRightBox object class of WForms controls                |
//+------------------------------------------------------------------+
class CProgressBar : public CContainer
  {
private:
   int               m_progress_bar_max;           // Maximum progress bar width
   int               m_value_by_max;               // Value relative to Maximum
   int               m_progress_bar_text_x;        // X coordinate of the text label with the description of the progress bar
   int               m_progress_bar_text_y;        // Y coordinate of the text label with the description of the progress bar
   color             m_progress_bar_text_color;    // Color of the text describing the progress bar
   uchar             m_progress_bar_text_opacity;  // Opacity of the text describing the progress bar
   string            m_progress_bar_text;          // Text describing the progress bar
   ENUM_FRAME_ANCHOR m_progress_bar_text_anchor;   // Method for binding the text with a progress bar description
//--- Create a new graphical object

We will need the variables to set and return the properties of the text label object, which acts as a description of the progress bar.


The data displayed in the description line can be either actual, displaying each step of the execution, or as a percentage of the already completed steps.

In the public section of the class, implement the methods returning Value as a text and as a percentage in numeric and text forms:

//--- (1) Set and (2) return the current value of the progress bar in the range from Min to Max as a number and (3) as a text
   void              SetValue(const int value);
   int               Value(void)                         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE);   }
   string            ValueDescription(void)              const { return (string)this.Value();                                          }
//--- Return the current progress bar value in the range from Min to Max as a percentage in the form of (1) a number and (2) a text
   double            ValuePercent(void) const;
   string            ValuePercentDescription(void)       const { return ::DoubleToString(this.ValuePercent(),2)+"%";                   }
   
//--- (1) Set and (2) return the upper bound of the ProgressBar operating range


In order to get a simplified access to the glare object, declare the methods for set its properties, as well as the methods for getting the pointers to the created attached objects in the public section of the class, and declare the methods for handling the progress bar description object:

//--- (1) Set and (2) return the lower bound of the ProgressBar operating range
   void              SetMinimum(const int value)               { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM,value);       }
   int               Minimum(void)                       const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM); }
   
//--- Set (1) style, (2) opacity and (3) color for the glare object
   void              SetGlareStyle(const ENUM_CANV_ELEMENT_VISUAL_EFF_STYLE style);
   void              SetGlareOpacity(const uchar opacity);
   void              SetGlareColor(const color clr);

//--- Return the pointer to the (1) progress bar object, (2) glare object and (3) the text label object with the progress bar description
   CBarProgressBar  *GetProgressBar(void)                { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,0);     }
   CGlareObj        *GetGlareObj(void)                   { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,0);            }
   CLabel           *GetProgressDescriptionObj(void)     { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_LABEL,0);                }

//--- Set the (1) text, (2) color
//--- (3) opacity, (4) X, (5) Y coordinates, (6) font, (7) size and (8) font flags to the progress bar text label
   void              SetBarDescriptionText(const string text,const bool redraw=false);
   void              SetBarDescriptionColor(const color clr,const bool redraw=false,const bool set_init_color=false);
   void              SetBarDescriptionOpacity(const uchar opacity,const bool redraw=false);
   void              SetBarDescriptionX(const int x,const bool redraw=false);
   void              SetBarDescriptionY(const int y,const bool redraw=false);
   void              SetBarDescriptionFontName(const string font,const bool redraw=false);
   void              SetBarDescriptionFontSize(const int size,const bool relative=false,const bool redraw=false);
   void              SetBarDescriptionFontFlags(const uint flags,const bool redraw=false);
   
//--- (1) hide and (2) display the progress bar text label
   void              HideBarDescription(void);
   void              ShowBarDescription(void);
     
//--- Resets the progress bar values to the set minimum


In the class constructor, initialize declared variables with default values:

//+---------------------------------------------+
//| Initialize the element properties           |
//+---------------------------------------------+
void CProgressBar::Initialize(void)
  {
   this.SetBorderSizeAll(1);
   this.SetBorderStyle(FRAME_STYLE_SIMPLE);
   this.SetBackgroundColor(CLR_DEF_CONTROL_PROGRESS_BAR_BACK_COLOR,true);
   this.SetBorderColor(CLR_DEF_CONTROL_PROGRESS_BAR_BORDER_COLOR,true);
   this.SetForeColor(CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR,true);
   this.SetMarqueeAnimationSpeed(10);
   this.SetMaximum(100);
   this.SetMinimum(0);
   this.SetValue(50);
   this.SetStep(10);
   this.SetStyle(CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS);
   this.m_progress_bar_max=this.Width()-this.BorderSizeLeft()-this.BorderSizeRight();
   this.m_value_by_max=this.Value()*100/this.Maximum();
   this.m_progress_bar_text="";
   this.m_progress_bar_text_x=1;
   this.m_progress_bar_text_y=0;
   this.m_progress_bar_text_color=CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR;
   this.m_progress_bar_text_opacity=255;
   this.m_progress_bar_text_anchor=FRAME_ANCHOR_LEFT_TOP;
  }
//+------------------------------------------------------------------+


In the method that creates the progress bar object, a glare object is also created. Add and create the progress bar description object there as well:

//+---------------------------------------------+
//| Create the progress bar object              |
//+---------------------------------------------+
void CProgressBar::CreateProgressBar(void)
  {
//--- Set the length of the progress bar equal to the object Value()
//--- The height of the progress bar is set equal to the height of the object minus the top and bottom border sizes
   int w=this.CalculateProgressBarWidth();
   int h=this.Height()-this.BorderSizeTop()-this.BorderSizeBottom();
   if(h<1)
      h=1;
//--- Create the progress bar object
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,0,0,w,h,clrNONE,255,false,false);
//--- Create a description of the progress bar, get the text label object and set the default parameters
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_LABEL,1,0,this.Width()-2,this.Height()-2,clrNONE,0,false,false);
   CLabel *obj=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_LABEL,0);
   if(obj!=NULL)
     {
      obj.SetText(this.m_progress_bar_text);
      obj.SetFontName(DEF_FONT);
      obj.SetFontSize(DEF_FONT_SIZE);
      obj.SetTextAnchor(FRAME_ANCHOR_LEFT_TOP);
      obj.SetTextAlign(ANCHOR_LEFT_UPPER);
      this.HideBarDescription();
     }
//--- Create the glare object
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,0,0,w,h,CLR_CANV_NULL,0,true,false);
//--- Add the current CProgressBar object to the list of active elements of the collection
   this.AddObjToListActiveElements();
  }
//+------------------------------------------------------------------+

Immediately after creating the text label, get the pointer to this object and set some properties for it: text, font name, font size, anchoring method and text alignment, and then hide the created object. The remaining parameters of the object can be obtained later by obtaining the pointer to this object using the GetProgressDescriptionObj() method, and then setting the necessary properties to the already received object.
If we try to create the progress bar object with a height of less than one pixel, this will not work since the object cannot be created with zero size. So let's introduce a check for the zero size and adjust it in case the check is positive.


In the method creating a new graphical object, add the code block for creating a text label object:

//+---------------------------------------------+
//| Create a new graphical object               |
//+---------------------------------------------+
CGCnvElement *CProgressBar::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                             const int obj_num,
                                             const string descript,
                                             const int x,
                                             const int y,
                                             const int w,
                                             const int h,
                                             const color colour,
                                             const uchar opacity,
                                             const bool movable,
                                             const bool activity)
  {
   CGCnvElement *element=NULL;
   switch(type)
     {
      case GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR  :
         element=new CBarProgressBar(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ         :
         element=new CGlareObj(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_LABEL             :
         element=new CLabel(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      default:
        break;
     }
   if(element==NULL)
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(type));
   return element;
  }
//+------------------------------------------------------------------+

Now the ProgressBar object can create bound objects of the Progress Bar, Glare and Text Label types.


The Progress Bar object is the active control handled in the timer. At the moment, the timer is handling a glare that runs along the progress bar. The progress bar displayed in the Marquee style is to be handled in the timer as well. In this mode, the progress bar has a fixed width, equal to half the width of the entire object, and constantly scrolls inside the ProgressBar object, thereby showing the progress of the process, the number of iterations of which is not known in advance.

Let's add the following handling of the progress bar to the object timer handler:

//+---------------------------------------------+
//| Timer                                       |
//+---------------------------------------------+
void CProgressBar::OnTimer(void)
  {
   CBarProgressBar *bar=this.GetProgressBar();
   if(bar!=NULL)
     {
      if(bar.Style()==CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE)
        {
         int x=bar.CoordX()+8;
         if(x>this.RightEdge())
            x=this.CoordX()-bar.Width();
         bar.Move(x,bar.CoordY());
         bar.Redraw(true);
        }
      else
         bar.OnTimer();
     }
  }
//+------------------------------------------------------------------+

Here, if the progress bar display style is "Continuous scrolling", then we get the X coordinate the object needs to be shifted to. At the moment, we add an offset of 8 pixels to the current X coordinate and shift the progress bar to the new coordinate horizontally. We first check that the progress bar object is completely outside its container on the right - in this case, we set its X coordinate so that the object is at the value of its width on the left beyond the left edge of its container. The Redraw() method, in addition to redrawing the object, performs one more function - it cuts off the parts of the object that protrude beyond the edges of the container. We have created a complete cycle of moving the progress bar inside its container, and at the same time, the parts that protrude beyond the edges are cut off.
If the object has a different rendering style, then we call the timer of the progress bar object to display the glare object.


Since we now have a progress bar drawing style of "Segmented Blocks", we need to refine the method that sets the progress bar value. Currently, this method, after setting the value, immediately resizes the object according to the new value. However, since segmented blocks should not be drawn pixel-by-pixel, but block-by-block, we need to understand how many blocks can fit on the set width of the progress bar. If the width is sufficient to draw a new segment, then the object changes its width already set in its property. If the width is insufficient (the current drawing segment will be incomplete and cropped), then we need to subtract the width of one segment from the set width of the object and set exactly this width for the progress bar. Only the penultimate segment with all the previous ones will be drawn in that case. Thus, the object width will always change only when all segments can be fully drawn without cropping them, which will give us a block-by-block change in the visible width of the progress bar. In this case, the Value will always be the one that was passed to the object. In other words, we only visually change the width of the object discretely, and the Value in it is always the one that is set for it.

I will implement the improvements described above to the method that sets the current value of the progress bar:

//+---------------------------------------------+
//| Set the current value of the progress bar   |
//+---------------------------------------------+
void CProgressBar::SetValue(const int value)
  {
//--- Correct the value passed to the method and set it to the object property
   int v=(value<this.Minimum() ? this.Minimum() : value>this.Maximum() ? this.Maximum() : value);
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,v);
//--- Get the progress bar object
   CBarProgressBar *bar=this.GetProgressBar();
   if(bar!=NULL)
     {
      //--- Set 'value' for the progress bar
      bar.SetValue(v);
      //--- Calculate the width of the progress bar object
      int w=this.CalculateProgressBarWidth();
      //--- If the calculated width is greater than the maximum possible value, set the maximum width
      if(w>this.m_progress_bar_max)
         w=this.m_progress_bar_max;
      //--- If the width is less than 1, then
      if(w<1)
        {
         //--- hide the progress bar and redraw the chart to display changes immediately
         bar.Hide();
         ::ChartRedraw(bar.ChartID());
        }
      //--- If the width value is not less than 1
      else
        {
         //--- If the progress bar is hidden, display it and
         if(!bar.IsVisible())
            bar.Show();
         //--- If the style of the progress bar is "Continuous line", change the width of the object to the calculated value
         if(this.Style()==CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS)
            bar.Resize(w,bar.Height(),true);
         //--- Otherwise, if the progress bar style is "Segmented blocks"
         else if(this.Style()==CANV_ELEMENT_PROGRESS_BAR_STYLE_BLOCKS)
           {
            //--- Segment width including indent
            int wd=bar.SegmentWidth()+bar.SegmentDistance();
            //--- The number of segments that fit the width of the progress bar
            int num=w/(wd>0 ? wd : 1);
            //--- The X coordinate of the last segment calculated from the beginning of the segment count
            int wx=bar.SegmentStart()+num*wd;
            //--- If the calculated width of the progress bar is less than the coordinate of the last segment, and this is not the last segment,
            //--- set the width of the progress bar equal to the penultimate segment coordinate
            if(w<wx-bar.SegmentDistance() && w<this.m_progress_bar_max)
               w=wx-wd+bar.SegmentDistance();
            //--- If the calculated width of the progress bar is less than the coordinate of the last segment, or it is not the last segment,
            if(w<wx-bar.SegmentDistance() || w==this.m_progress_bar_max)
               //--- change the size of the progress bar in accordance with the received and adjusted width
               bar.Resize(w,bar.Height(),true);
           }
        }
      //--- If the progress bar description text is set,
      if(this.m_progress_bar_text!="")
        {
         //--- get the object description of the progress bar and bring it to the foreground
         CLabel *obj=this.GetProgressDescriptionObj();
         if(obj!=NULL)
            obj.BringToTop();
        }
     }
  }
//+------------------------------------------------------------------+

The method logic is described in the code comments. The description text also needs to be handled: each time you change the value of the progress bar, you may need to change the description as well. Therefore, this object is always brought to the foreground if text is set for it.


The method that calculates the width of the progress bar needs to be improved so that it returns half the size of the ProgressBar control if the progress bar style is set to "Continuous scrolling":

//+---------------------------------------------+
//| Calculate the width of the progress bar     |
//+---------------------------------------------+
int CProgressBar::CalculateProgressBarWidth(void)   

  {
   this.m_value_by_max=this.Value()*100/this.Maximum();
   return(this.Style()==CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE ? this.m_progress_bar_max/2 : this.m_progress_bar_max*this.m_value_by_max/100);
  }
//+------------------------------------------------------------------+

Now the method will return the correct size of the scrollbar for any of its display styles.


In the method that sets the new width, you need to assign the width set in the object also for the text label object, which is used to display the description of the progress bar:

//+---------------------------------------------+
//| Set a new width                             |
//+---------------------------------------------+
bool CProgressBar::SetWidth(const int width)
  {
   if(!CGCnvElement::SetWidth(width))
      return false;
   this.m_progress_bar_max=this.Width()-this.BorderSizeLeft()-this.BorderSizeRight();
   CBarProgressBar *bar=this.GetProgressBar();
   if(bar==NULL)
      return false;
   int w=this.CalculateProgressBarWidth();
   bar.SetWidth(w);
   CLabel *lbl=this.GetProgressDescriptionObj();
   if(lbl!=NULL)
      lbl.SetWidth(w);
   return true;
  }
//+------------------------------------------------------------------+

If the size of the text label object is not adjusted to the size of the progress bar, then text written to the apparent size of the progress bar may not fit in an object whose width is smaller than it visually appears. This will cause the text to simply be cropped. Therefore, it is necessary that the text label and the progress bar have the same dimensions.

Let's look at the auxiliary methods that serve to facilitate access to the properties of objects bound to the ProgressBar control.

The method that sets the style for the glare object:

//+---------------------------------------------+
//| Set the glare object style                  |
//+---------------------------------------------+
void CProgressBar::SetGlareStyle(const ENUM_CANV_ELEMENT_VISUAL_EFF_STYLE style)
  {
   CGlareObj *obj=this.GetGlareObj();
   if(obj==NULL)
      return;
   obj.SetVisualEffectStyle(style);
  }
//+------------------------------------------------------------------+

Here we get the pointer to the glare object and set the style to the resulting object.


The method that sets opacity for a glare object:

//+---------------------------------------------+
//| Set the opacity of the highlight object     |
//+---------------------------------------------+
void CProgressBar::SetGlareOpacity(const uchar opacity)
  {
   CGlareObj *obj=this.GetGlareObj();
   if(obj==NULL)
      return;
   obj.SetOpacity(opacity);
  }
//+------------------------------------------------------------------+

Get the pointer to the glare object and set the opacity value to the resulting object.


The method that sets the color for the glare object:

//+---------------------------------------------+
//| Set the color for the glare object          |
//+---------------------------------------------+
void CProgressBar::SetGlareColor(const color clr)
  {
   CGlareObj *obj=this.GetGlareObj();
   if(obj==NULL)
      return;
   obj.SetColor(clr);
  }
//+------------------------------------------------------------------+

Get the pointer to the glare object and set the color value passed to the method to the resulting object.


The method that sets a text to the text label of the progress bar:

//+------------------------------------------------------------------+
//| Set a text to the text label of the progress bar                 |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionText(const string text,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   this.m_progress_bar_text=text;
   obj.SetText(text);
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+

Here we get the pointer to the text label object. Set the text, passed to the method, to the m_progress_bar_text variable. Then set that text to the object. Since the text will immediately be displayed on the object, in order to avoid overlapping one text on another, the background and everything that was drawn on it should be erased. Next, display the text and update the element.


The method that sets the text color of the progress bar to the text label:

//+------------------------------------------------------------------+
//| Set the text color of the progress bar to the text label         |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionColor(const color clr,const bool redraw=false,const bool set_init_color=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   this.m_progress_bar_text_color=clr;
   obj.SetForeColor(clr,false);
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+

Get the pointer to the text label object. Set the color, passed to the method, to the m_progress_bar_text_color variable. Next, set the color for the object as the text color. Since the text will be displayed immediately, in order to avoid overlapping one text on another, the background of the text label is erased. Further on, the text is displayed and the element is updated.


The method that sets opacity to the progress bar text label:

//+---------------------------------------------+
//| Set opacity to the progress bar text label  |
//+---------------------------------------------+
void CProgressBar::SetBarDescriptionOpacity(const uchar opacity,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   this.m_progress_bar_text_opacity=opacity;
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+

The logic of the method is identical to the above, but we set the opacity value to the corresponding variable and object.


The method that sets the X coordinate to the text label of the progress bar:

//+------------------------------------------------------------------+
//| Set the X coordinate to the text label of the progress bar       |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionX(const int x,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   this.m_progress_bar_text_x=x;
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+


The method that sets the Y coordinate to the text label of the progress bar:

//+------------------------------------------------------------------+
//| Set the Y coordinate to the text label of the progress bar       |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionY(const int y,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   this.m_progress_bar_text_y=y;
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+


The method that sets the font in the text label of the progress bar:

//+------------------------------------------------------------------+
//| Set the font in the text label of the progress bar               |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionFontName(const string font,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   obj.SetFontName(font);
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+


The method that sets the font size to the progress bar text label:

//+------------------------------------------------------------------+
//| Set the font size to the progress bar text label                 |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionFontSize(const int size,const bool relative=false,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   obj.SetFontSize(size,relative);
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+


The method that sets the font flags in the text label of the progress bar:

//+------------------------------------------------------------------+
//| Set the font flags in the text label of the progress bar         |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionFontFlags(const uint flags,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   obj.SetFontFlags(flags);
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+

All the methods shown above have the same logic and allow us to quickly set the desired text and font parameters to the progress bar description (to the text label). The changes are immediately displayed on the screen.


If we need to hide the description of the progress bar, then in addition to hiding it, the object needs to set its non-display flag, since it is constantly brought to the foreground, which causes it to be displayed. If, after hiding the object, we set the non-display flag for it, then the object will not be redrawn until it receives the display flag again.

The method hiding the text label of the progress bar:

//+---------------------------------------------+
//| Hide the progress bar text label            |
//+---------------------------------------------+
void CProgressBar::HideBarDescription(void)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   obj.SetDisplayed(false);
   obj.Hide();
  }
//+------------------------------------------------------------------+

Here we get a text label object with a description of the progress bar, set the non-display flag for it and hide the object.


The method that displays the text label of the progress bar:

//+---------------------------------------------+
//| Display a text label for the progress bar   |
//+---------------------------------------------+
void CProgressBar::ShowBarDescription(void)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   obj.SetDisplayed(true);
   obj.Show();
  }
//+------------------------------------------------------------------+

Here we get a text label object with a description of the progress bar, set the display flag for it and display the object.


The method returning the current progress bar value in the range from Min to Max as a percentage:

//+---------------------------------------------+
//| Return the current value of the progress bar|
//| in the range from Min to Max as a percentage|
//+---------------------------------------------+
double CProgressBar::ValuePercent(void) const
  {
   double range=this.Maximum()-this.Minimum();
   return(this.Value()*100.0/(range>0 ? range : 1));
  }
//+------------------------------------------------------------------+

If we need to get the Value of the progress bar as a percentage of the range from Min to Max, then this method will calculate and return the value of how many percent of the specified range have already been processed. 100% is the difference between the maximum and minimum values set in the ProgressBar object.

Let's check the results.


Test

To perform the test, I will use the EA from the previous article and save it in \MQL5\Experts\TestDoEasy\Part128\ as TestDoEasy128.mq5.

Create a progress bar style enumeration for the English language and user language compilation versions:

//--- enumerations by compilation language
#ifdef COMPILE_EN
enum ENUM_AUTO_SIZE_MODE
  {
   AUTO_SIZE_MODE_GROW=CANV_ELEMENT_AUTO_SIZE_MODE_GROW,                               // Grow
   AUTO_SIZE_MODE_GROW_SHRINK=CANV_ELEMENT_AUTO_SIZE_MODE_GROW_SHRINK                  // Grow and Shrink
  };
enum ENUM_BORDER_STYLE
  {
   BORDER_STYLE_NONE=FRAME_STYLE_NONE,                                                 // None
   BORDER_STYLE_SIMPLE=FRAME_STYLE_SIMPLE,                                             // Simple
   BORDER_STYLE_FLAT=FRAME_STYLE_FLAT,                                                 // Flat
   BORDER_STYLE_BEVEL=FRAME_STYLE_BEVEL,                                               // Embossed (bevel)
   BORDER_STYLE_STAMP=FRAME_STYLE_STAMP,                                               // Embossed (stamp)
  };
enum ENUM_CHEK_STATE
  {
   CHEK_STATE_UNCHECKED=CANV_ELEMENT_CHEK_STATE_UNCHECKED,                             // Unchecked
   CHEK_STATE_CHECKED=CANV_ELEMENT_CHEK_STATE_CHECKED,                                 // Checked
   CHEK_STATE_INDETERMINATE=CANV_ELEMENT_CHEK_STATE_INDETERMINATE,                     // Indeterminate
  };
enum ENUM_ELEMENT_ALIGNMENT
  {
   ELEMENT_ALIGNMENT_TOP=CANV_ELEMENT_ALIGNMENT_TOP,                                   // Top
   ELEMENT_ALIGNMENT_BOTTOM=CANV_ELEMENT_ALIGNMENT_BOTTOM,                             // Bottom
   ELEMENT_ALIGNMENT_LEFT=CANV_ELEMENT_ALIGNMENT_LEFT,                                 // Left
   ELEMENT_ALIGNMENT_RIGHT=CANV_ELEMENT_ALIGNMENT_RIGHT,                               // Right
  };
enum ENUM_ELEMENT_TAB_SIZE_MODE
  {
   ELEMENT_TAB_SIZE_MODE_NORMAL=CANV_ELEMENT_TAB_SIZE_MODE_NORMAL,                     // Fit to tab title text width
   ELEMENT_TAB_SIZE_MODE_FIXED=CANV_ELEMENT_TAB_SIZE_MODE_FIXED,                       // Fixed size
   ELEMENT_TAB_SIZE_MODE_FILL=CANV_ELEMENT_TAB_SIZE_MODE_FILL,                         // Fit TabControl Size
  };
enum ENUM_ELEMENT_PROGRESS_BAR_STYLE
  {
   ELEMENT_PROGRESS_BAR_STYLE_BLOCKS=CANV_ELEMENT_PROGRESS_BAR_STYLE_BLOCKS,           // Blocks
   ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS=CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS,   // Continuous
   ELEMENT_PROGRESS_BAR_STYLE_MARQUEE=CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE,         // Marquee
  };  
#else 
enum ENUM_AUTO_SIZE_MODE
  {
   AUTO_SIZE_MODE_GROW=CANV_ELEMENT_AUTO_SIZE_MODE_GROW,                               // Increase only
   AUTO_SIZE_MODE_GROW_SHRINK=CANV_ELEMENT_AUTO_SIZE_MODE_GROW_SHRINK                  // Increase and decrease
  };
enum ENUM_BORDER_STYLE
  {
   BORDER_STYLE_NONE=FRAME_STYLE_NONE,                                                 // No frame
   BORDER_STYLE_SIMPLE=FRAME_STYLE_SIMPLE,                                             // Simple frame
   BORDER_STYLE_FLAT=FRAME_STYLE_FLAT,                                                 // Flat frame
   BORDER_STYLE_BEVEL=FRAME_STYLE_BEVEL,                                               // Embossed (convex)
   BORDER_STYLE_STAMP=FRAME_STYLE_STAMP,                                               // Embossed (concave)
  };
enum ENUM_CHEK_STATE
  {
   CHEK_STATE_UNCHECKED=CANV_ELEMENT_CHEK_STATE_UNCHECKED,                             // Unchecked
   CHEK_STATE_CHECKED=CANV_ELEMENT_CHEK_STATE_CHECKED,                                 // Checked
   CHEK_STATE_INDETERMINATE=CANV_ELEMENT_CHEK_STATE_INDETERMINATE,                     // Undefined
  };
enum ENUM_ELEMENT_ALIGNMENT
  {
   ELEMENT_ALIGNMENT_TOP=CANV_ELEMENT_ALIGNMENT_TOP,                                   // Top
   ELEMENT_ALIGNMENT_BOTTOM=CANV_ELEMENT_ALIGNMENT_BOTTOM,                             // Bottom
   ELEMENT_ALIGNMENT_LEFT=CANV_ELEMENT_ALIGNMENT_LEFT,                                 // Left
   ELEMENT_ALIGNMENT_RIGHT=CANV_ELEMENT_ALIGNMENT_RIGHT,                               // Right
  };
enum ENUM_ELEMENT_TAB_SIZE_MODE
  {
   ELEMENT_TAB_SIZE_MODE_NORMAL=CANV_ELEMENT_TAB_SIZE_MODE_NORMAL,                     // By tab title width
   ELEMENT_TAB_SIZE_MODE_FIXED=CANV_ELEMENT_TAB_SIZE_MODE_FIXED,                       // Fixed size
   ELEMENT_TAB_SIZE_MODE_FILL=CANV_ELEMENT_TAB_SIZE_MODE_FILL,                         // By TabControl size
  };
enum ENUM_ELEMENT_PROGRESS_BAR_STYLE
  {
   ELEMENT_PROGRESS_BAR_STYLE_BLOCKS=CANV_ELEMENT_PROGRESS_BAR_STYLE_BLOCKS,           // Segmented blocks
   ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS=CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS,   // Continuous bar
   ELEMENT_PROGRESS_BAR_STYLE_MARQUEE=CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE,         // Continuous scrolling
  };  
#endif 
//--- input parameters


Let's add two new parameters to the inputs — progress bar style and the flag for displaying progress bar values in percent:

//--- input parameters
sinput   bool                          InpMovable           =  true;                   // Panel Movable flag
sinput   ENUM_INPUT_YES_NO             InpAutoSize          =  INPUT_YES;              // Panel Autosize
sinput   ENUM_AUTO_SIZE_MODE           InpAutoSizeMode      =  AUTO_SIZE_MODE_GROW;    // Panel Autosize mode
sinput   ENUM_BORDER_STYLE             InpFrameStyle        =  BORDER_STYLE_SIMPLE;    // Label border style
sinput   ENUM_ANCHOR_POINT             InpTextAlign         =  ANCHOR_CENTER;          // Label text align
sinput   ENUM_INPUT_YES_NO             InpTextAutoSize      =  INPUT_NO;               // Label autosize
sinput   ENUM_ANCHOR_POINT             InpCheckAlign        =  ANCHOR_LEFT;            // Check flag align
sinput   ENUM_ANCHOR_POINT             InpCheckTextAlign    =  ANCHOR_LEFT;            // Check label text align
sinput   ENUM_CHEK_STATE               InpCheckState        =  CHEK_STATE_UNCHECKED;   // Check flag state
sinput   ENUM_INPUT_YES_NO             InpCheckAutoSize     =  INPUT_YES;              // CheckBox autosize
sinput   ENUM_BORDER_STYLE             InpCheckFrameStyle   =  BORDER_STYLE_NONE;      // CheckBox border style
sinput   ENUM_ANCHOR_POINT             InpButtonTextAlign   =  ANCHOR_CENTER;          // Button text align
sinput   ENUM_INPUT_YES_NO             InpButtonAutoSize    =  INPUT_YES;              // Button autosize
sinput   ENUM_AUTO_SIZE_MODE           InpButtonAutoSizeMode=  AUTO_SIZE_MODE_GROW;    // Button Autosize mode
sinput   ENUM_BORDER_STYLE             InpButtonFrameStyle  =  BORDER_STYLE_NONE;      // Button border style
sinput   bool                          InpButtonToggle      =  true ;                  // Button toggle flag
sinput   bool                          InpButtListMSelect   =  false;                  // ButtonListBox Button MultiSelect flag
sinput   bool                          InpListBoxMColumn    =  true;                   // ListBox MultiColumn flag
sinput   bool                          InpTabCtrlMultiline  =  false;                   // Tab Control Multiline flag
sinput   ENUM_ELEMENT_ALIGNMENT        InpHeaderAlignment   =  ELEMENT_ALIGNMENT_TOP;  // TabHeader Alignment
sinput   ENUM_ELEMENT_TAB_SIZE_MODE    InpTabPageSizeMode   =  ELEMENT_TAB_SIZE_MODE_FILL; // TabHeader Size Mode
sinput   int                           InpTabControlX       =  10;                     // TabControl X coord
sinput   int                           InpTabControlY       =  20;                     // TabControl Y coord
sinput   ENUM_CANV_ELEMENT_TOOLTIP_ICON InpTooltipIcon      =  CANV_ELEMENT_TOOLTIP_ICON_NONE;  // Tooltip Icon
sinput   string                        InpTooltipTitle      =  "";                     // Tooltip Title
sinput   ENUM_ELEMENT_PROGRESS_BAR_STYLE InpProgressBarStyle=  ELEMENT_PROGRESS_BAR_STYLE_BLOCKS;  // Progress Bar Style
sinput   bool                          InpProgressBarPercent=  false;                  // Show progress bar values as a percentage
//--- global variables


In the EA's OnInit() handler when creating the ProgressBar control, set the style to the progress bar from the variable in the settings and set the parameters to describe the progress bar:

                     //--- If this is the first tab and the second panel
                     if(n==0 && j==1)
                       {
                        //--- Create the ProgressBar control on it
                        if(split_container.CreateNewElement(j,GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,4,4,100,12,clrNONE,255,false,false))
                          {
                           CProgressBar *progress_bar=split_container.GetPanelElementByType(j,GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,0);
                           if(progress_bar!=NULL)
                             {
                              //--- Set the style of the progress bar specified in the EA settings
                              progress_bar.SetStyle((ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE)InpProgressBarStyle);
                              //--- Set the parameters for describing the progress bar
                              progress_bar.SetBarDescriptionText("Progress Bar ");
                              progress_bar.SetBarDescriptionColor(panel.BackgroundColor());
                              progress_bar.SetBarDescriptionOpacity(255);
                              progress_bar.SetBarDescriptionY(-2);
                             }
                          }
                       }


In the loop of displaying and redrawing all panels, display the description when the progress bar style is "Continuous Line". At each iteration of the loop of incrementing the Value of the progress bar, display the Values in the description depending on the settings - as a percentage or in completed steps. Upon the loop completion, write in the description of the progress bar a message about the completion of the increment loop with the font changed to bold.
To set the parameters of the glare object, I will use the object quick access methods:

//--- Display and redraw all created panels
   for(int i=0;i<FORMS_TOTAL;i++)
     {
      //--- Get the panel object
      pnl=engine.GetWFPanel("WinForms Panel"+(string)i);
      if(pnl!=NULL)
        {
         //--- display and redraw the panel
         pnl.Show();
         pnl.Redraw(true);
         //--- Get the TabControl object from the panel
         CTabControl *tc=pnl.GetElementByType(GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,0);
         //--- Get the SplitContainer object from the first tab of the TabControl object
         CSplitContainer *sc=tc.GetTabElementByType(0,GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER,0);
         //--- Get the second panel from the SplitContainer object
         CSplitContainerPanel *scp=sc.GetPanel(1);
         //--- Get the ProgressBar object from the received panel
         CProgressBar *pb=scp.GetElementByType(GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,0);
         //--- Wait for 1/10 of a second
         Sleep(100);
         //--- Get the width of the ProgressBar object
         int w=pb.Width();
         //--- In the loop, increase the width of the ProgressBar by 180 pixels with a delay of 1/50
         for(int n=0;n<180;n++)
           {
            Sleep(20);
            pb.Resize(w+n,pb.Height(),true);
           }
         //--- Set the values for PerformStep of the ProgressBar object
         pb.SetValuesForProcessing(0,350,1,0);
         //--- Reset ProgressBar to minimum
         pb.ResetProgressBar();
         //--- If the style of the progress bar is "Continuous line", display the progress bar description
         if(pb.Style()==CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS)
            pb.ShowBarDescription();
         //--- Wait for 1/5 second
         Sleep(200);
         //--- If the style of the progress bar is not "Continuous scrolling"
         if(pb.Style()!=CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE)
           {
            //--- In the loop from the minimum to the maximum value of ProgressBar
            for(int n=0;n<=pb.Maximum();n++)
              {
               //--- call the method for increasing the progress bar by a given step with a wait of 1/5 second
               pb.PerformStep();
               //--- Set the number of completed steps in the description of the progress bar
               pb.SetBarDescriptionText("Progress Bar, pass: "+(InpProgressBarPercent ? pb.ValuePercentDescription() : pb.ValueDescription()));
               Sleep(20);
              }
           }
         //--- Wait for 1/2 second, set the description font type to Bold and write a completion message on the progress bar
         Sleep(500);
         pb.SetBarDescriptionFontFlags(FW_BOLD);
         pb.SetBarDescriptionText("Progress Bar: Done");
         //--- Set the glare object type - rectangle, opacity 40, color - white
         pb.SetGlareStyle(CANV_ELEMENT_VISUAL_EFF_STYLE_RECTANGLE);
         pb.SetGlareOpacity(40);
         pb.SetGlareColor(clrWhite);
        }
     }
        
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+


Compile the EA and launch it on the chart:


As we can see, all the declared modes work well.


What's next?

In the next article, I will start developing the TrackBar control.

Back to contents

*Previous articles within the series:

 
DoEasy. Controls (Part 26): Finalizing the ToolTip WinForms object and moving on to ProgressBar development
DoEasy. Controls (Part 27): Working on ProgressBar WinForms object

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

Attached files |
MQL5.zip (4527.27 KB)
Population optimization algorithms: Cuckoo Optimization Algorithm (COA) Population optimization algorithms: Cuckoo Optimization Algorithm (COA)
The next algorithm I will consider is cuckoo search optimization using Levy flights. This is one of the latest optimization algorithms and a new leader in the leaderboard.
Data Science and Machine Learning (Part 10): Ridge Regression Data Science and Machine Learning (Part 10): Ridge Regression
Ridge regression is a simple technique to reduce model complexity and prevent over-fitting which may result from simple linear regression
MQL5 Cookbook — Services MQL5 Cookbook — Services
The article describes the versatile capabilities of services — MQL5 programs that do not require binding graphs. I will also highlight the differences of services from other MQL5 programs and emphasize the nuances of the developer's work with services. As examples, the reader is offered various tasks covering a wide range of functionality that can be implemented as a service.
Population optimization algorithms: Grey Wolf Optimizer (GWO) Population optimization algorithms: Grey Wolf Optimizer (GWO)
Let's consider one of the newest modern optimization algorithms - Grey Wolf Optimization. The original behavior on test functions makes this algorithm one of the most interesting among the ones considered earlier. This is one of the top algorithms for use in training neural networks, smooth functions with many variables.