//+------------------------------------------------------------------+ //| 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, 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) { ArrayResize(m_secciones, 0); m_function_val_to_str = DoubleToStrPrefix; // Funcion por defecto } //+------------------------------------------------------------------+ 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, 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; 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 //+------------------------------------------------------------------+