530 lines
37 KiB
MQL5
530 lines
37 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Hor.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_HOR_MQH_BY_LEO
|
|
#define GRAPHICS_HISTOGRAM_EJE_EJES_HOR_MQH_BY_LEO
|
|
|
|
|
|
#include "Ejes.mqh"
|
|
|
|
#define HIST_LINE_MODE_IZQUIERDA 1
|
|
#define HIST_LINE_MODE_DERECHA 0
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CHistogramEjeLineHorizontal : public CHistogramEjeLine
|
|
{
|
|
protected:
|
|
void TituloActulize() override;
|
|
void RecalculeAndDrawSections() override;
|
|
void OnNewFunctionFormat() override;
|
|
void OnInitialize() override;
|
|
void RecalcValuesSections() override;
|
|
|
|
public:
|
|
void CreateTitulo(const string &txt, uint clr, int gap_titulo, int fontsize = 0, string font = NULL, uint flagtext = UINT_MAX) override;
|
|
|
|
|
|
//---
|
|
void CleanPx(const uint8_t flags) override;
|
|
void RedrawPx(const uint8_t flags) override;
|
|
|
|
|
|
//--- Cordenadas y tamaño
|
|
//- X
|
|
void X(int new_value, bool redraw = false) override;
|
|
|
|
//- Y
|
|
void Y(int new_value, bool redraw = false) override;
|
|
|
|
//- LineSize
|
|
void LineSize(int new_value, bool redraw = false) override;
|
|
|
|
//
|
|
void SetCordinates(int x, int y, int line_size, bool redraw = false) override;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::OnInitialize(void)
|
|
{
|
|
//---
|
|
m_c2 = m_y + m_size_line_sections;
|
|
|
|
//---
|
|
if(m_mode_line == HIST_LINE_MODE_IZQUIERDA)
|
|
{
|
|
m_sections_alingment = TA_RIGHT | TA_VCENTER;
|
|
if(m_co2 > 0)
|
|
m_co2 = m_co2 - m_x;
|
|
}
|
|
else // 0
|
|
{
|
|
m_sections_alingment = TA_LEFT | TA_VCENTER;
|
|
if(m_co2 > 0)
|
|
m_co2 = m_x - m_co2;
|
|
}
|
|
|
|
//---
|
|
m_canvas.LineVertical(m_x, m_y, m_c2, m_line_clr);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::LineSize(int new_value, bool redraw = false)
|
|
{
|
|
//--- LimpiamoS
|
|
CleanPx(HISTOGRAM_EJE_LINE_FLAG_LINE | HISTOGRAM_EJE_LINE_FLAG_SECTIONS | HISTOGRAM_EJE_LINE_FLAG_TEXT);
|
|
|
|
//---
|
|
m_size_line_sections = new_value;
|
|
m_c2 = m_y + new_value;
|
|
|
|
//--- Dibujamos las secciones
|
|
RedrawPx(HISTOGRAM_EJE_LINE_FLAG_LINE); // Linea
|
|
RecalculeAndDrawSections(); // Secciones/Texto
|
|
TituloActulize(); // Titulo
|
|
|
|
//---
|
|
if(redraw)
|
|
m_canvas.Update();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::X(int new_value, bool redraw = false)
|
|
{
|
|
//---
|
|
CleanPx(HISTOGRAM_EJE_LINE_FLAG_LINE | HISTOGRAM_EJE_LINE_FLAG_SECTIONS | HISTOGRAM_EJE_LINE_FLAG_TEXT);
|
|
|
|
//---
|
|
m_x = new_value;
|
|
|
|
//--- Dibujamos las secciones
|
|
RedrawPx(HISTOGRAM_EJE_LINE_FLAG_LINE); // Linea
|
|
RecalculeAndDrawSections(); // Secciones-Texto
|
|
TituloActulize(); // Titulo
|
|
|
|
//---
|
|
if(redraw)
|
|
m_canvas.Update();
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::Y(int new_value, bool redraw = false)
|
|
{
|
|
//---
|
|
CleanPx(HISTOGRAM_EJE_LINE_FLAG_LINE | HISTOGRAM_EJE_LINE_FLAG_SECTIONS | HISTOGRAM_EJE_LINE_FLAG_TEXT);
|
|
|
|
//---
|
|
m_y = new_value;
|
|
m_c2 = m_y + m_size_line_sections;
|
|
|
|
//--- Dibujamos las secciones
|
|
RedrawPx(HISTOGRAM_EJE_LINE_FLAG_LINE); // Linea
|
|
RecalculeAndDrawSections(); // Secciones-Texto
|
|
TituloActulize(); // Titulo
|
|
|
|
//---
|
|
if(redraw)
|
|
m_canvas.Update();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::SetCordinates(int x, int y, int line_size, bool redraw = false)
|
|
{
|
|
//--- Limpiamos la linea
|
|
CleanPx(HISTOGRAM_EJE_LINE_FLAG_LINE | HISTOGRAM_EJE_LINE_FLAG_SECTIONS | HISTOGRAM_EJE_LINE_FLAG_TEXT);
|
|
|
|
//---
|
|
m_x = x;
|
|
m_y = y;
|
|
m_size_line_sections = line_size;
|
|
m_c2 = y + line_size;
|
|
|
|
//--- Dibujamos las secciones
|
|
RedrawPx(HISTOGRAM_EJE_LINE_FLAG_LINE); // Linea
|
|
RecalculeAndDrawSections(); // Secciones-Line
|
|
TituloActulize(); // Titulo
|
|
|
|
//---
|
|
if(redraw)
|
|
m_canvas.Update();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::CreateTitulo(const string &txt, uint clr, int gap_titulo, int fontsize = 0, string font = NULL, uint flagtext = UINT_MAX)
|
|
{
|
|
if(HIST_EJE_IS_INIT_TITULO)
|
|
return;
|
|
|
|
// (1 = izquierda : 0 = derecha)
|
|
m_init_flags |= HIST_EJE_FLAG_INIT_TITULO;
|
|
m_titulo = new CTextCanvas();
|
|
m_titulo_gap_px = gap_titulo;
|
|
|
|
if(m_mode_line == HIST_LINE_MODE_IZQUIERDA)
|
|
{
|
|
int x = m_x - m_section_size_px - m_section_size_gap_value - m_sections_font_size - m_titulo_gap_px;
|
|
int y = m_y + (m_size_line_sections >> 1);
|
|
m_titulo.Create(m_canvas, x, y, txt, clr, TA_CENTER | TA_BOTTOM, fontsize, font, flagtext, 900);
|
|
}
|
|
else
|
|
{
|
|
int x = m_x + m_section_size_px + m_section_size_gap_value + m_sections_font_size + m_titulo_gap_px;
|
|
int y = m_y + (m_size_line_sections >> 1);
|
|
m_titulo.Create(m_canvas, x, y, txt, clr, TA_CENTER | TA_BOTTOM, fontsize, font, flagtext, 2700);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::TituloActulize()
|
|
{
|
|
if(!HIST_EJE_IS_INIT_TITULO)
|
|
return; // SI el titulo no esta seteado enotnces retornamos
|
|
|
|
if(m_mode_line == HIST_LINE_MODE_IZQUIERDA)
|
|
{
|
|
int x = m_x - m_section_size_px - m_section_size_gap_value - m_sections_font_size - m_titulo_gap_px;
|
|
int y = m_y + (m_size_line_sections >> 1);
|
|
m_titulo.ChangeYAndX(x, y);
|
|
}
|
|
else
|
|
{
|
|
int x = m_x + m_section_size_px + m_section_size_gap_value + m_sections_font_size + m_titulo_gap_px;
|
|
int y = m_y + (m_size_line_sections >> 1);
|
|
m_titulo.ChangeYAndX(x, y);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::RecalcValuesSections(void)
|
|
{
|
|
// Reclac, y limpieza el txt / sections
|
|
|
|
//---
|
|
const int lasti = m_secciones_size - 1;
|
|
const double range = (m_max_value - m_min_value);
|
|
double v_step = range / double(lasti);
|
|
double v = m_min_value; // Siguiente valor
|
|
|
|
//--- Line horizontal (1 = izquierda : 0 = derecha)
|
|
::TextSetFont(m_sections_font, m_sections_font_size);
|
|
m_canvas.LineStyleSet(m_style);
|
|
|
|
//---
|
|
if(m_use_change_value)
|
|
{
|
|
#define EsValorDeCambioONoDibj(fi) (fi==0 || fi==lasti || fi==m_idx_change_value)
|
|
|
|
//---
|
|
// De abajo (menor valor) hacia arriba (mayor valor)
|
|
const bool eizq = m_mode_line == HIST_LINE_MODE_IZQUIERDA;
|
|
const double y_percentages_step = 1.00 / double(lasti); // obtenemos el %decimal que le toca a cada seccion
|
|
double y_next_per = 0.00; // SIeuiguente porcenrge
|
|
|
|
//---
|
|
const double range_min = m_change_value - m_min_value;
|
|
const double corte_y_perce = range_min / (range);
|
|
const int y_corte = m_c2 - int(corte_y_perce * fabs(m_c2 - m_y)); // Cordenada de anclaje
|
|
|
|
// init = y
|
|
// c1 = x1
|
|
// c2 = x2
|
|
//---
|
|
m_idx_change_value = -1;
|
|
for(int i = 0; i < m_secciones_size; i++)
|
|
{
|
|
const int y = m_c2 - int(round(m_size_line_sections * y_next_per));
|
|
// PrintFormat("i = %d | ypercen = %.2f | value = %.2f", i, y_next_per, v);
|
|
m_canvas.LineAA(m_secciones[i].c1, m_secciones[i].init, m_secciones[i].c2, m_secciones[i].init, m_clr_clean);
|
|
m_canvas.TextOuTF(m_secciones[i].c_text, m_secciones[i].init, m_secciones[i].str_val, m_clr_clean, m_sections_alingment);
|
|
|
|
//--- 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_secciones[i].value = m_change_value;
|
|
m_secciones[i].init = y_corte;
|
|
m_idx_change_value = i;
|
|
}
|
|
else
|
|
{
|
|
m_secciones[i].value = v;
|
|
m_secciones[i].init = y;
|
|
}
|
|
|
|
//---
|
|
m_secciones[i].str_val = m_function_val_to_str(m_secciones[i].value, m_sections_decimals);
|
|
|
|
//--- Modo
|
|
// c_text = x_text
|
|
/*
|
|
x1 ---------- x2
|
|
*/
|
|
|
|
if(eizq)
|
|
{
|
|
m_secciones[i].c2 = m_x + (EsValorDeCambioONoDibj(i) ? 0 : m_co2);
|
|
m_secciones[i].c1 = m_x - m_section_size_px;
|
|
m_secciones[i].c_text = m_secciones[i].c1 - m_section_size_gap_value;
|
|
}
|
|
else
|
|
{
|
|
m_secciones[i].c1 = m_x - (EsValorDeCambioONoDibj(i) ? 0 : m_co2);
|
|
m_secciones[i].c2 = m_x + m_section_size_px;
|
|
m_secciones[i].c_text = m_secciones[i].c2 + m_section_size_gap_value;
|
|
}
|
|
|
|
//--- Dibujamos
|
|
m_canvas.TextOuTF(m_secciones[i].c_text, m_secciones[i].init, m_secciones[i].str_val, m_sections_text_clr, m_sections_alingment);
|
|
|
|
|
|
//--- Next
|
|
y_next_per += y_percentages_step;
|
|
v += v_step;
|
|
}
|
|
#undef EsValorDeCambioONoDibj
|
|
}
|
|
else
|
|
{
|
|
// Duplicaremos el coidog pero la idera es maximoar optimizacion ahcer un terminarioc a cada iteracion talvez no sea lo mejor
|
|
for(int i = 0; i < m_secciones_size; i++)
|
|
{
|
|
//---
|
|
//m_canvas.LineAA(m_secciones[i].c1, m_secciones[i].init, m_secciones[i].c2, m_secciones[i].init, m_clr_clean);
|
|
m_canvas.TextOuTF(m_secciones[i].c_text, m_secciones[i].init, m_secciones[i].str_val, m_clr_clean, m_sections_alingment);
|
|
|
|
//--- Valores de la seccion
|
|
m_secciones[i].value = v;
|
|
m_secciones[i].str_val = m_function_val_to_str(m_secciones[i].value, m_sections_decimals);
|
|
|
|
//--- Dibujamos
|
|
m_canvas.TextOuTF(m_secciones[i].c_text, m_secciones[i].init, m_secciones[i].str_val, m_sections_text_clr, m_sections_alingment);
|
|
|
|
//--- Next
|
|
v += v_step;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::RecalculeAndDrawSections(void)
|
|
{
|
|
//---
|
|
const int lasti = m_secciones_size - 1;
|
|
const double y_percentages_step = 1.00 / double(lasti); // obtenemos el %decimal que le toca a cada seccion
|
|
double y_next_per = 0.00; // SIeuiguente porcenrge
|
|
double ran = (m_max_value - m_min_value);
|
|
//
|
|
double v_step = ran / double(lasti);
|
|
double v = m_min_value; // Siguiente valor
|
|
|
|
//---
|
|
// m_x = x
|
|
// m_y = y1;
|
|
// m_c2 = y2
|
|
|
|
#define EsValorDeCambioONoDibj(fi) (fi==0 || fi==lasti || fi==m_idx_change_value)
|
|
//--- Line horizontal (1 = izquierda : 0 = derecha)
|
|
::TextSetFont(m_sections_font, m_sections_font_size);
|
|
m_canvas.LineStyleSet(m_style);
|
|
|
|
// De abajo (menor valor) hacia arriba (mayor valor)
|
|
const bool eizq = m_mode_line == HIST_LINE_MODE_IZQUIERDA;
|
|
|
|
//---
|
|
if(m_use_change_value)
|
|
{
|
|
const double range_min = m_change_value - m_min_value;
|
|
const double corte_y_perce = range_min / ran;
|
|
const int y_corte = m_c2 - int(corte_y_perce * fabs(m_c2 - m_y)); // Cordenada de anclaje
|
|
// init = y
|
|
// c1 = x1
|
|
// c2 = x2
|
|
|
|
m_idx_change_value = -1;
|
|
for(int i = 0; i < m_secciones_size; i++)
|
|
{
|
|
const int y = m_c2 - int(round(m_size_line_sections * y_next_per));
|
|
// PrintFormat("i = %d | ypercen = %.2f | value = %.2f", i, y_next_per, v);
|
|
|
|
//--- 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_secciones[i].value = m_change_value;
|
|
m_secciones[i].init = y_corte;
|
|
m_idx_change_value = i;
|
|
}
|
|
else
|
|
{
|
|
m_secciones[i].value = v;
|
|
m_secciones[i].init = y;
|
|
}
|
|
|
|
//---
|
|
m_secciones[i].str_val = m_function_val_to_str(m_secciones[i].value, m_sections_decimals);
|
|
|
|
//--- Modo
|
|
// c_text = x_text
|
|
/*
|
|
x1 ---------- x2
|
|
*/
|
|
|
|
if(eizq)
|
|
{
|
|
m_secciones[i].c2 = m_x + (EsValorDeCambioONoDibj(i) ? 0 : m_co2);
|
|
m_secciones[i].c1 = m_x - m_section_size_px;
|
|
m_secciones[i].c_text = m_secciones[i].c1 - m_section_size_gap_value;
|
|
}
|
|
else
|
|
{
|
|
m_secciones[i].c1 = m_x - (EsValorDeCambioONoDibj(i) ? 0 : m_co2);
|
|
m_secciones[i].c2 = m_x + m_section_size_px;
|
|
m_secciones[i].c_text = m_secciones[i].c2 + m_section_size_gap_value;
|
|
}
|
|
|
|
//--- Dibujamos
|
|
m_canvas.TextOuTF(m_secciones[i].c_text, m_secciones[i].init, m_secciones[i].str_val, m_sections_text_clr, m_sections_alingment);
|
|
m_canvas.LineAA(m_secciones[i].c1, m_secciones[i].init, m_secciones[i].c2, m_secciones[i].init, m_sections_clr);
|
|
|
|
//--- Next
|
|
y_next_per += y_percentages_step;
|
|
v += v_step;
|
|
}
|
|
#undef EsValorDeCambioONoDibj
|
|
}
|
|
else
|
|
{
|
|
#define EsValorDeCambioONoDibj(fi) (fi==lasti||fi==0)
|
|
// Duplicaremos el coidog pero la idera es maximoar optimizacion ahcer un terminarioc a cada iteracion talvez no sea lo mejor
|
|
for(int i = 0; i < m_secciones_size; i++)
|
|
{
|
|
const int y = m_c2 - int(round(m_size_line_sections * y_next_per));
|
|
|
|
//--- Valores de la seccion
|
|
m_secciones[i].value = v;
|
|
m_secciones[i].init = y;
|
|
m_secciones[i].str_val = m_function_val_to_str(m_secciones[i].value, m_sections_decimals);
|
|
|
|
//--- Modo
|
|
if(eizq)
|
|
{
|
|
m_secciones[i].c2 = m_x + (EsValorDeCambioONoDibj(i) ? 0 : m_co2);
|
|
m_secciones[i].c1 = m_x - m_section_size_px;
|
|
m_secciones[i].c_text = m_secciones[i].c1 - m_section_size_gap_value;
|
|
}
|
|
else
|
|
{
|
|
m_secciones[i].c1 = m_x - (EsValorDeCambioONoDibj(i) ? 0 : m_co2);
|
|
m_secciones[i].c2 = m_x + m_section_size_px;
|
|
m_secciones[i].c_text = m_secciones[i].c2 + m_section_size_gap_value;
|
|
}
|
|
|
|
//--- Dibujamos
|
|
m_canvas.TextOuTF(m_secciones[i].c_text, m_secciones[i].init, m_secciones[i].str_val, m_sections_text_clr, m_sections_alingment);
|
|
m_canvas.LineAA(m_secciones[i].c1, m_secciones[i].init, m_secciones[i].c2, m_secciones[i].init, m_sections_clr);
|
|
|
|
//--- Next
|
|
y_next_per += y_percentages_step;
|
|
v += v_step;
|
|
}
|
|
}
|
|
#undef EsValorDeCambioONoDibj
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::OnNewFunctionFormat()
|
|
{
|
|
//--- Line horizontal (1 = izquierda : 0 = derecha)
|
|
::TextSetFont(m_sections_font, m_sections_font_size);
|
|
|
|
//--- De abajo (menor valor) hacia arriba (mayor valor)
|
|
for(int i = 0; i < m_secciones_size; i++)
|
|
{
|
|
m_secciones[i].str_val = m_function_val_to_str(m_secciones[i].value, m_sections_decimals);
|
|
m_canvas.TextOuTF(m_secciones[i].c_text, m_secciones[i].init, m_secciones[i].str_val, m_sections_text_clr, m_sections_alingment);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::RedrawPx(const uchar flags)
|
|
{
|
|
//---
|
|
if((flags & HISTOGRAM_EJE_LINE_FLAG_SECTIONS) != 0)
|
|
{
|
|
m_canvas.LineStyleSet(m_style);
|
|
for(int i = 0; i < m_secciones_size; i++)
|
|
m_canvas.LineAA(m_secciones[i].c1, m_secciones[i].init, m_secciones[i].c2, m_secciones[i].init, m_sections_clr);
|
|
}
|
|
//---
|
|
if((flags & HISTOGRAM_EJE_LINE_FLAG_TEXT) != 0)
|
|
{
|
|
::TextSetFont(m_sections_font, m_sections_font_size);
|
|
for(int i = 0; i < m_secciones_size; i++)
|
|
m_canvas.TextOuTF(m_secciones[i].c_text, m_secciones[i].init, m_secciones[i].str_val, m_sections_text_clr, m_sections_alingment);
|
|
}
|
|
//---
|
|
if((flags & HISTOGRAM_EJE_LINE_FLAG_LINE) != 0)
|
|
{
|
|
m_canvas.LineVertical(m_x, m_y, m_c2, m_line_clr);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramEjeLineHorizontal::CleanPx(const uchar flags)
|
|
{
|
|
//---
|
|
if((flags & HISTOGRAM_EJE_LINE_FLAG_SECTIONS) != 0)
|
|
{
|
|
m_canvas.LineStyleSet(m_style);
|
|
for(int i = 0; i < m_secciones_size; i++)
|
|
m_canvas.LineAA(m_secciones[i].c1, m_secciones[i].init, m_secciones[i].c2, m_secciones[i].init, m_clr_clean);
|
|
}
|
|
//---
|
|
if((flags & HISTOGRAM_EJE_LINE_FLAG_TEXT) != 0)
|
|
{
|
|
::TextSetFont(m_sections_font, m_sections_font_size);
|
|
for(int i = 0; i < m_secciones_size; i++)
|
|
m_canvas.TextOuTF(m_secciones[i].c_text, m_secciones[i].init, m_secciones[i].str_val, m_clr_clean, m_sections_alingment);
|
|
}
|
|
//---
|
|
if((flags & HISTOGRAM_EJE_LINE_FLAG_LINE) != 0)
|
|
{
|
|
m_canvas.LineVertical(m_x, m_y, m_c2, m_clr_clean);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
#endif
|
|
//+------------------------------------------------------------------+
|