| //+------------------------------------------------------------------+
|
| //| Grid.mqh |
|
| //| Copyright 2025, Niquel Mendoza. |
|
| //| https://www.mql5.com/es/users/nique_372/news |
|
| //+------------------------------------------------------------------+
|
| #property copyright "Copyright 2025, Niquel Mendoza."
|
| #property link "https://www.mql5.com/es/users/nique_372/news"
|
| #property strict
|
|
|
| #ifndef GRAPHICS_HISTOGRAM_EJE_EJES_MQH_BY_LEO
|
| #define GRAPHICS_HISTOGRAM_EJE_EJES_MQH_BY_LEO
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| #include "..\\..\\PartInf\\ParteInf.mqh"
|
| #include "..\\TextoCanvas.mqh"
|
| #include "..\\..\\General\\LineSim\\HorLine.mqh"
|
| #include "..\\..\\General\\LineSim\\VerticalLine.mqh"
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| const string DoubleToStrPrefixArrFormats[5] = {"%.*f", "%.*f K", "%.*f M", "%.*f B", "%.*f T"};
|
| //+------------------------------------------------------------------+
|
| string DoubleToStrPrefix(double value, int8_t decimals)
|
| {
|
| const double abs_val = MathAbs(value);
|
| int idx = 0;
|
| double v = value;
|
|
|
| if(abs_val >= 1000000000000.0)
|
| {
|
| v /= 1000000000000.0;
|
| idx = 4;
|
| }
|
| else
|
| if(abs_val >= 1000000000.0)
|
| {
|
| v /= 1000000000.0;
|
| idx = 3;
|
| }
|
| else
|
| if(abs_val >= 1000000.0)
|
| {
|
| v /= 1000000.0;
|
| idx = 2;
|
| }
|
| else
|
| if(abs_val >= 1000.0)
|
| {
|
| v /= 1000.0;
|
| idx = 1;
|
| }
|
| return StringFormat(DoubleToStrPrefixArrFormats[idx], decimals, v);
|
| }
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| struct HistogramEjeLineSection
|
| {
|
| string str_val;
|
| double value;
|
| int init; // X - Y
|
| int c1; // Y1 -X1
|
| int c2; // Y2 - X2
|
|
|
| int c_text;
|
| };
|
|
|
| //--- EJe de X
|
| struct HistogramEjeLineBasic
|
| {
|
| int init;
|
| int c1;
|
| int c2;
|
| uint clr;
|
| };
|
|
|
| //---
|
|
|
|
|
| //--- Eje Y con multiples secciones
|
| // Obligtorios
|
| #define HIST_EJE_FLAG_INIT_GENERAL 1
|
| #define HIST_EJE_FLAG_INIT_LINE 2
|
|
|
|
|
| // General
|
| #define HIST_EJE_FLAG_INIT_TITULO 4
|
|
|
| /*
|
| X1
|
| Y1
|
| */
|
|
|
| //---
|
| #define HISTOGRAM_EJE_LINE_FLAG_TEXT 1
|
| #define HISTOGRAM_EJE_LINE_FLAG_LINE 2
|
| #define HISTOGRAM_EJE_LINE_FLAG_SECTIONS 4
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| typedef string(*HistFunctionFormatDouble)(double value, int8_t decimals);
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| class CHistogramEjeLine
|
| {
|
| protected:
|
| uint m_init_flags;
|
| CCanvasCustom* m_canvas;
|
|
|
| uint m_clr_clean;
|
|
|
| //---
|
| CTextCanvas* m_titulo; // Titulo del eje
|
| int m_titulo_gap_px; // Gap respecto al titulok
|
|
|
| //--- Linea general
|
| int m_x;
|
| int m_y;
|
| int m_c2; // Cordanada 2
|
| int m_size_line_sections;
|
| uint m_line_clr;
|
|
|
| uint m_style;
|
|
|
| //--- Secciones
|
| int m_secciones_size;
|
| HistogramEjeLineSection m_secciones[];
|
| int m_section_size_px; // Tamaño en picxlex
|
| int m_section_size_gap_value; // Gap entre la linea y el texto
|
| int m_sections_font_size;
|
| string m_sections_font;
|
| int m_co2;
|
| uint m_sections_alingment;
|
| int8_t m_sections_decimals;
|
| HistFunctionFormatDouble m_function_val_to_str;
|
| uint m_sections_clr;
|
| uint m_sections_text_clr;
|
|
|
| //--- Valores
|
| double m_max_value;
|
| double m_min_value;
|
| double m_change_value;
|
| int m_idx_change_value;
|
| int m_idx_change_value_prev;
|
|
|
| // 0 se ubica a la izquierda lineas a oiuiqer, 1 se ubica a la derecha lineas a la derecha
|
| int m_mode_line;
|
| bool m_use_change_value;
|
|
|
|
|
| //---
|
| virtual void TituloActulize() = 0;
|
| virtual void RecalculeAndDrawSections() = 0;
|
| virtual void OnNewFunctionFormat() = 0;
|
| virtual void OnInitialize() = 0;
|
|
|
| //--- Funciones necesarias
|
| virtual void RecalcValuesSections() = 0;
|
|
|
| //---
|
| void SetIndexChangeValueAndValues();
|
|
|
| public:
|
| CHistogramEjeLine();
|
| ~CHistogramEjeLine();
|
|
|
| //--- Inicializa la clase (clr = linevertial tamibne las lines de las sessionces y texto de cada seccion)
|
| void Init(CCanvasCustom* c, int x, int y, int size_line, uint clr_line, int mode, int co2, uint style);
|
| void CreateSections(int inital_sections, double max_value, double min_value, bool use_change_val, double change_value,
|
| int section_gap_value, int sections_size_px, int8_t decimals, uint clr_sections, uint clr_text_setions, HistFunctionFormatDouble func_txt = NULL
|
| , int fontsize = 0, string font = NULL);
|
| virtual void CreateTitulo(const string &txt, uint clr, int gap_titulo, int fontsize = 0, string font = NULL, uint flagtext = UINT_MAX) = 0;
|
|
|
| //--- Limpa los pixles ocupados por la linea dejee, secciones y texto de cada sesion (menos el titulo), solo linmepa pxieles, no cambia el valores
|
| virtual void CleanPx(const uint8_t flags) = 0;
|
|
|
| //---
|
| virtual void RedrawPx(const uint8_t flags) = 0;
|
|
|
|
|
| //--- Secciones
|
| //- Funcion de formateo
|
| void SectionsFormatStrFunction(HistFunctionFormatDouble new_function, bool redraw = false);
|
| __forceinline HistFunctionFormatDouble SectionsFormatStrFunction() const { return m_function_val_to_str; }
|
|
|
| //- Tamaño de cada "line" de valor
|
| void SectionsUniqueSizeInPixels(int new_value, bool redraw = false);
|
| __forceinline int SectionsUniqueSizeInPixels() const { return m_section_size_px; }
|
|
|
| //- Numero de seccions de la linea del eje
|
| void SectionsSize(int new_value, bool redraw = false);
|
| __forceinline int SectionsSize() const { return m_secciones_size; }
|
|
|
| //- COlor de (lineas de sccion + texto de linea de seccion + line general)
|
| void SectionsColor(uint new_clr, bool redraw = false);
|
| __forceinline uint SectionsColor() const { return m_sections_clr; }
|
|
|
| //- Estilo de linea
|
| void SectionsStyle(uint new_style, bool redraw = false);
|
| __forceinline uint SectionsStyle() const { return m_style; }
|
|
|
| //- Maximo de la linea del eje
|
| void Max(double max, bool redraw = false);
|
| __forceinline double Max() const { return m_max_value; }
|
|
|
| //- Minimo de la linea del eje
|
| void Min(double min, bool redraw = false);
|
| __forceinline double Min() const { return m_min_value; }
|
|
|
| //- Valor de cambio
|
| void ChangeValue(double new_value, bool redraw = false);
|
| __forceinline double ChangeValue() const { return m_change_value; }
|
| __forceinline bool ChangeValueEnable() const { return m_use_change_value; }
|
|
|
| //- Setear max, min, y chanbge_value opcional
|
| void SetNewValues(double max, double min, double change_value, bool redraw = false);
|
|
|
| //- Texto
|
| // Fontsize de los textos de la linea del eje
|
| void SectionsTextFontSize(int new_value, bool redraw = false);
|
| __forceinline int SectionsTextFontSize() const { return m_sections_font_size;}
|
|
|
| // Font de los textos de la linea de eje
|
| void SectionsTextFont(const string& new_value, bool redraw = false);
|
| __forceinline string SectionsTextFont() const { return m_sections_font;}
|
|
|
| // Color
|
| void SectionsTextColor(uint new_value, bool redraw = false);
|
| __forceinline uint SectionsTextColor() const { return m_sections_clr; }
|
|
|
| //--- Linea
|
| //- X
|
| virtual void X(int new_value, bool redraw = false) = 0;
|
| __forceinline int X() const { return m_x; }
|
|
|
| //- Y
|
| virtual void Y(int new_value, bool redraw = false) = 0;
|
| __forceinline int Y() const { return m_y; }
|
|
|
| //- LineSize
|
| virtual void LineSize(int new_value, bool redraw = false) = 0;
|
| __forceinline int LineSize() const { return m_size_line_sections; }
|
|
|
| //- Set cordenadas
|
| virtual void SetCordinates(int x, int y, int line_size, bool redraw = false) = 0;
|
|
|
| //- Modo
|
| __forceinline int ModeLine() const { return m_mode_line; }
|
|
|
| //- Color
|
| void LineColor(uint new_clr, bool redraw = false);
|
| __forceinline uint LineColor() const { return m_line_clr; }
|
|
|
|
|
| //---
|
| void CleanColor(uint new_value) { m_clr_clean = new_value;}
|
| __forceinline uint CleanColor() const { return m_clr_clean; }
|
|
|
|
|
| //---
|
| __forceinline bool HasCo2() const { return m_co2 > 0;}
|
|
|
| //---
|
| CTextCanvas* TituloGetPointer() { return m_titulo;}
|
| };
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| //| Macros |
|
| //+------------------------------------------------------------------+
|
| #define HIST_EJE_IS_INIT_GENERAL ((m_init_flags&HIST_EJE_FLAG_INIT_GENERAL) != 0)
|
| #define HIST_EJE_IS_INIT_SECTIONS ((m_init_flags&HIST_EJE_FLAG_INIT_LINE) != 0)
|
| #define HIST_EJE_IS_INIT_TITULO ((m_init_flags&HIST_EJE_FLAG_INIT_TITULO) != 0)
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| CHistogramEjeLine::CHistogramEjeLine()
|
| : m_init_flags(0), m_titulo(NULL), m_canvas(NULL), m_use_change_value(false), m_co2(0), m_style(STYLE_SOLID), m_idx_change_value(-1), m_idx_change_value_prev(-1),
|
| m_function_val_to_str(NULL)
|
| {
|
| ArrayResize(m_secciones, 0);
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| CHistogramEjeLine::~CHistogramEjeLine()
|
| {
|
| if(CheckPointer(m_titulo) == POINTER_DYNAMIC)
|
| {
|
| delete m_titulo;
|
| }
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::Init(CCanvasCustom *c, int x, int y, int size_line, uint clr_line, int mode, int co2, uint style)
|
| {
|
| if(HIST_EJE_IS_INIT_GENERAL)
|
| return;
|
|
|
| //---
|
| m_canvas = c;
|
| m_init_flags |= HIST_EJE_FLAG_INIT_GENERAL;
|
| m_size_line_sections = size_line;
|
| m_x = x;
|
| m_y = y;
|
| m_style = style;
|
| m_line_clr = clr_line;
|
| m_mode_line = mode;
|
|
|
|
|
| //---
|
| if(co2 > 1)
|
| m_co2 = co2 - 1;
|
|
|
| //--- Seteamos alingement
|
| OnInitialize();
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::CreateSections(int inital_sections, double max_value, double min_value, bool use_change_val, double change_value,
|
| int section_gap_value, int sections_size_px, int8_t decimals, uint clr_sections, uint clr_text_setions, HistFunctionFormatDouble func_txt = NULL
|
| , int fontsize = 0, string font = NULL)
|
| {
|
| if(HIST_EJE_IS_INIT_SECTIONS)
|
| return;
|
| /*
|
| Como siempre si el fontsize es 0 o font es null, se usa el de canvas, asi que si el usuario ya tiene en fontseteado en canvas (usa el de la clase CHistogram)
|
| , peude dejar los parametros como esta, pero si quiere un font o fontsize cusotm para los ejes le da un valor
|
| */
|
| //---
|
| int is = inital_sections;
|
| is += 1; // Agregamos el maximo
|
| is += 1; // Agregamos al minimo
|
| is += int(use_change_val); // Si use es true=1, se le sumara 1
|
|
|
| //---
|
| m_sections_clr = clr_sections;
|
| m_sections_text_clr = clr_text_setions;
|
|
|
| //---
|
| m_init_flags |= HIST_EJE_FLAG_INIT_LINE;
|
| m_max_value = max_value;
|
| m_min_value = min_value;
|
| m_change_value = change_value;
|
| m_sections_font = font != NULL ? font : m_canvas.FontNameGet();
|
| m_sections_font_size = fontsize > 0 ? fontsize : m_canvas.FontSizeGet();
|
| m_section_size_gap_value = section_gap_value;
|
| // CAST expkicito (bug en la 6090) antes: m_function_val_to_str = func_txt == NULL ? DoubleToStrPrefix : func_txt
|
| m_function_val_to_str = func_txt == NULL ? (HistFunctionFormatDouble)DoubleToStrPrefix : func_txt;
|
| m_sections_decimals = decimals;
|
| m_use_change_value = use_change_val;
|
| m_section_size_px = sections_size_px;
|
| m_secciones_size = is;
|
| ArrayResize(m_secciones, m_secciones_size);
|
|
|
| //---
|
| if(!use_change_val)
|
| m_change_value = DBL_MAX; // Lo ponemos a un valor invalido
|
|
|
| //---
|
| RecalculeAndDrawSections();
|
|
|
| //---
|
| // int xmin = m_section_size_gap_value + m_sections_font_size;
|
| }
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::ChangeValue(double new_value, bool redraw = false)
|
| {
|
| //---
|
| if(!m_use_change_value)
|
| return;
|
|
|
| //---
|
| m_change_value = new_value;
|
|
|
|
|
| //--- Dibujamos las secciones
|
| RecalcValuesSections();
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::Min(double min, bool redraw = false)
|
| {
|
| //---
|
| m_min_value = min;
|
|
|
| //--- Dibujamos las secciones
|
| RecalcValuesSections();
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::Max(double max, bool redraw = false)
|
| {
|
| //---
|
| m_max_value = max;
|
|
|
| //--- Dibujamos las secciones
|
| RecalcValuesSections();
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::SetNewValues(double max, double min, double change_value, bool redraw = false)
|
| {
|
| //---
|
| m_min_value = min;
|
| m_max_value = max;
|
| m_change_value = change_value;
|
|
|
| //--- Dibujamos las secciones
|
| RecalcValuesSections();
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::SectionsColor(uint new_clr, bool redraw = false)
|
| {
|
| //---
|
| CleanPx(HISTOGRAM_EJE_LINE_FLAG_SECTIONS);
|
|
|
| //---
|
| m_sections_clr = new_clr;
|
|
|
| //---
|
| RedrawPx(HISTOGRAM_EJE_LINE_FLAG_SECTIONS);
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::SectionsSize(int new_value, bool redraw = false)
|
| {
|
| //---
|
| if(new_value <= 0)
|
| return;
|
|
|
| //---
|
| int nv = new_value + 2 + int(m_use_change_value); // se le suma 2 del minimo y el maximo, ademas de 1 si es que se usa change_value
|
|
|
| //---
|
| CleanPx(HISTOGRAM_EJE_LINE_FLAG_SECTIONS | HISTOGRAM_EJE_LINE_FLAG_TEXT);
|
|
|
| //---
|
| m_secciones_size = nv;
|
| ArrayResize(m_secciones, m_secciones_size);
|
|
|
| //--- Dibujamos las secciones
|
| RecalculeAndDrawSections(); // Secciones-Line
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::SectionsUniqueSizeInPixels(int new_value, bool redraw = false)
|
| {
|
| //---
|
| CleanPx(HISTOGRAM_EJE_LINE_FLAG_SECTIONS | HISTOGRAM_EJE_LINE_FLAG_TEXT);
|
|
|
| //---
|
| m_section_size_px = new_value;
|
|
|
| //--- Dibujamos las secciones
|
| // Cuidado un ancho mas grande haria que el titulo se dezplaze myucho, hacinedo que posibledmne desapareza
|
| RecalculeAndDrawSections(); // Secciones-Line
|
| TituloActulize();
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::SectionsFormatStrFunction(HistFunctionFormatDouble new_function, bool redraw = false)
|
| {
|
| //---
|
| CleanPx(HISTOGRAM_EJE_LINE_FLAG_TEXT);
|
|
|
| //---
|
| m_function_val_to_str = new_function;
|
|
|
| //---
|
| // Cuidado con el titulo un texto mas gradne podira hacer colisiones, esto se podria ajustar auto auqnue es mas responsabidliad del usuario
|
| OnNewFunctionFormat();
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::SectionsStyle(uint new_style, bool redraw = false)
|
| {
|
| //---
|
| CleanPx(HISTOGRAM_EJE_LINE_FLAG_SECTIONS);
|
|
|
| //---
|
| m_style = new_style;
|
|
|
| //---
|
| RedrawPx(HISTOGRAM_EJE_LINE_FLAG_SECTIONS);
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::SectionsTextFont(const string &new_value, bool redraw = false)
|
| {
|
| //---
|
| CleanPx(HISTOGRAM_EJE_LINE_FLAG_TEXT); // Limpieza previa
|
|
|
| //---
|
| m_sections_font = new_value;
|
|
|
| //--- Dibujamos las secciones
|
| RedrawPx(HISTOGRAM_EJE_LINE_FLAG_TEXT); // Secciones-Line
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::SectionsTextFontSize(int new_value, bool redraw = false)
|
| {
|
| //---
|
| CleanPx(HISTOGRAM_EJE_LINE_FLAG_TEXT); // Limpieza previaa
|
|
|
| //---
|
| m_sections_font_size = new_value;
|
|
|
| //--- Dibujamos las secciones
|
| RedrawPx(HISTOGRAM_EJE_LINE_FLAG_TEXT); // Secciones-Line
|
| // Cuidado un fontsize mas grande haria que el titulo se dezplaze myucho, hacinedo que posibledmne desapareza
|
| TituloActulize();
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::SectionsTextColor(uint new_value, bool redraw = false)
|
| {
|
| //---
|
| CleanPx(HISTOGRAM_EJE_LINE_FLAG_TEXT); // Limpieza previa
|
|
|
| //---
|
| m_sections_clr = new_value;
|
|
|
| //--- Dibujamos las secciones
|
| RedrawPx(HISTOGRAM_EJE_LINE_FLAG_TEXT); // Secciones-Line
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::LineColor(uint new_clr, bool redraw = false)
|
| {
|
| //---
|
| CleanPx(HISTOGRAM_EJE_LINE_FLAG_LINE);
|
|
|
| //---
|
| m_line_clr = new_clr;
|
|
|
| //---
|
| RedrawPx(HISTOGRAM_EJE_LINE_FLAG_LINE);
|
|
|
| //---
|
| if(redraw)
|
| m_canvas.Update();
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| void CHistogramEjeLine::SetIndexChangeValueAndValues(void)
|
| {
|
| //---
|
| m_idx_change_value_prev = m_idx_change_value;
|
| m_idx_change_value = -1;
|
|
|
| //---
|
| const double v_step = (m_max_value - m_min_value) / double(m_secciones_size - 1);
|
| double v = m_min_value; // Siguiente valor
|
|
|
| //---
|
| for(int i = 0; i < m_secciones_size; i++)
|
| {
|
| //--- Valores de la seccion
|
| if(m_idx_change_value == -1 && v >= m_change_value) // Si c es falso y se uspero el change value forzamos
|
| {
|
| m_idx_change_value = i;
|
| m_secciones[i].value = m_change_value;
|
| }
|
| else
|
| m_secciones[i].value = v;
|
|
|
| //--- Siguiente valor
|
| v += v_step;
|
| }
|
| }
|
|
|
| #endif
|
| //+------------------------------------------------------------------+
|