forked from nique_372/GrapichsByLeo
496 lines
39 KiB
MQL5
496 lines
39 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Horizontal.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
|
|
|
|
#include "HistogramaBases.mqh"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#define HISTOGRAM_CALCULE_ANCHO(v,m) int((v)*(m))
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CHistogramHorizontal : public CHistogram
|
|
{
|
|
private:
|
|
void RecalculeCordinatesBarsAndText() override final;
|
|
void OnNeweCordinatesBarsAndSize() override final;
|
|
void OnBarraAdd(int index) override final;
|
|
void OnBarrDelete(double extra_value) override final;
|
|
void OnSetLienzo() override final;
|
|
void OnMaxOrMinValueSuperate() override final;
|
|
void InitCordinates() override final;
|
|
void ConjuntoBarWidth(int index, double new_value) override final;
|
|
|
|
public:
|
|
CHistogramHorizontal() { m_type = HISTOGRAM_HORIZONTAL; }
|
|
int AddConjuntoBar(const string &label, uint label_clr, int label_fontsize, const string &label_font, ENUM_HISTOGRAM_TEXT_MODE label_mode, int barras_de_reserva_, int eje_gap,
|
|
ENUM_HIST_DRAW_RECT_STYLE initial_style, double width = 0.000000) override final;
|
|
using CHistogram::AddConjuntoBar; // Desocultamos la funcion soibrecatgada de AddCounjtoBar con clr aleatorio
|
|
void MinConjuntoAncho(int new_value) override;
|
|
|
|
void CreateEjeLine(int mode_position_line_sections, uint clr_line_Sections, uint clr_line_fixed, int initial_sections,
|
|
int section_gap_value, int sections_size_px, int8_t section_decimals, int section_fontsize = 0, string section_font = NULL) override;
|
|
void NumConjuntoBars(int num_bars, int reserve_bars = 0) override;
|
|
using CHistogram::NumConjuntoBars; // Descoultamos el meotodo getter
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Resize al numero de barras |
|
|
//+------------------------------------------------------------------+
|
|
// Unicamente resize el tamaño de berras
|
|
// Para poder setear las barras use SetBar con redraw false (todavia no se le asigna cordenadas)
|
|
// O tambien SetBarFast
|
|
void CHistogramHorizontal::NumConjuntoBars(int num_bars, int reserve_bars = 0)
|
|
{
|
|
m_bars_size = num_bars;
|
|
ArrayResize(m_bars, m_bars_size);
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
m_bars[i] = new CHistogramConjuntoHorizontal();
|
|
m_bars[i].ReserveBarras(reserve_bars);
|
|
m_bars[i].CleanColor(m_back_color);
|
|
}
|
|
m_curr_index_bar_p = 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramHorizontal::CreateEjeLine(int mode_position_line_sections, uint clr_line_Sections, uint clr_line_fixed, int initial_sections,
|
|
int section_gap_value, int sections_size_px, int8_t section_decimals, int section_fontsize = 0, string section_font = NULL)
|
|
{
|
|
// Apunta a algo, es seguro comprar con NULL, dado que al eliminar o iniciar el puntero tendra un valor de NULL (no hay objeto invalido, pero direccion seigue apuntado a algo)
|
|
if(m_eje != NULL)
|
|
return;
|
|
|
|
m_eje = new CHistogramEjeHorizontal();
|
|
int x2 = m_barras_x1 + m_barras_espacio_dibujable_width;
|
|
int y2 = m_barras_y1 + m_barras_espacio_dibujable_height;
|
|
|
|
m_eje.Init(m_canvas, m_barras_x1, x2, m_barras_y1, y2, mode_position_line_sections, clr_line_Sections, clr_line_fixed, m_back_color);
|
|
const bool use_change_val = (m_fr_change_value == m_fr_min_value) ? false : true;
|
|
m_eje.HistogramLinePointerGet().CreateSections(initial_sections, m_fr_max_value, m_fr_min_value, use_change_val, m_fr_change_value, section_gap_value, sections_size_px,
|
|
section_decimals, section_fontsize, section_font);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramHorizontal::MinConjuntoAncho(int new_value)
|
|
{
|
|
//---
|
|
m_barras_min_width = new_value;
|
|
|
|
//--- Reducimos el "factor" de cada uno
|
|
int idx_to_Remove[];
|
|
double extra = 0.00;
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
m_bars[i].CleanBarras(false); // Limpaos las barras (solo pixeles, data no)
|
|
m_bars[i].TextClean(); // Limpiamos el texto (solo pxiesels, data no)
|
|
|
|
const double v = m_bars[i].ValueForAncho();
|
|
//PrintFormat("Ancho para %d = %d", i, m_bars[i].SizeBarrasInPixels());
|
|
const int a = HISTOGRAM_CALCULE_ANCHO(v, m_barras_max_width);
|
|
// PrintFormat("Nuevo ancho para %d = %d", i, a);
|
|
if(a < m_barras_min_width) // Nuevo ancho para esta bvarra muy pequeño
|
|
{
|
|
extra += v; // Sumamos
|
|
idx_to_Remove.Push(i);
|
|
}
|
|
}
|
|
|
|
//--- Eliminamos los muy pequeños
|
|
const int size_remove = ArraySize(idx_to_Remove);
|
|
if(size_remove > 0)
|
|
{
|
|
for(int i = 0; i < size_remove; i++)
|
|
{
|
|
const int k = idx_to_Remove[i];
|
|
m_bars[k].Destroy(); // Limpia el texto ocupado
|
|
delete m_bars[k];
|
|
}
|
|
|
|
RemoveMultipleIndexes(m_bars, idx_to_Remove, 0);
|
|
m_bars_size -= size_remove;
|
|
}
|
|
else
|
|
{
|
|
return; // Todos cumplen
|
|
}
|
|
|
|
//---
|
|
const double rest = extra / double(m_bars_size); // si extra es 0.00 esto dara 0.00 (si es 0.00, significa que no se supero el minimo ancho)
|
|
int x = m_barras_cordinate_init;
|
|
const int real_y = m_barras_y1 + m_barras_espacio_dibujable_height; // Conseguimos el Y1 real
|
|
const int gap_corte = real_y - m_barras_cordenanda_eje_corte; // Otenemos el gap de corte respecto a Y1 Real
|
|
|
|
//---
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
m_bars[i].ValueForAnchoAument(rest); // Aumentamos el ancho
|
|
const int a = HISTOGRAM_CALCULE_ANCHO(m_bars[i].ValueForAncho(), m_barras_max_width); // Nuevo ancho
|
|
m_bars[i].SetNewsCordenadasAndSize(x, real_y, a);// Set cordenadas y dibujado pxieles
|
|
x += a + m_barras_espacio_entre; // Nuewvas cordenadas
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Añade un nuevo conjunto de barras |
|
|
//+------------------------------------------------------------------+
|
|
int CHistogramHorizontal::AddConjuntoBar(const string &label, uint label_clr, int label_fontsize, const string &label_font, ENUM_HISTOGRAM_TEXT_MODE label_mode, int barras_de_reserva_, int eje_gap,
|
|
ENUM_HIST_DRAW_RECT_STYLE initial_style, double width = 0.000000)
|
|
{
|
|
m_curr_index_bar_p = m_bars_size;
|
|
ArrayResize(m_bars, m_bars_size + 1);
|
|
m_bars[m_bars_size] = new CHistogramConjuntoHorizontal(); // Cambiar esto, talvez com template.. <>
|
|
m_bars[m_bars_size].ReserveBarras(barras_de_reserva_);
|
|
m_bars[m_bars_size].Set(m_canvas, label, label_clr, label_mode, label_fontsize, label_font, eje_gap, initial_style);
|
|
m_bars[m_bars_size].ValueForAncho(width);
|
|
m_bars[m_bars_size].CleanColor(m_back_color); // Color de limpeiza que sea el fondo del lienzo
|
|
m_bars_size++;
|
|
return m_curr_index_bar_p;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramHorizontal::InitCordinates(void)
|
|
{
|
|
int x = m_barras_cordinate_init;
|
|
const int real_y = m_barras_y1 + m_barras_espacio_dibujable_height; // Conseguimos el Y1 real
|
|
const int gap_corte = real_y - m_barras_cordenanda_eje_corte; // Otenemos el gap de corte respecto a Y1 Real
|
|
|
|
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
// Inicilizacion
|
|
const int a = HISTOGRAM_CALCULE_ANCHO(m_bars[i].ValueForAncho(), m_barras_max_width);
|
|
m_bars[i].Init(m_function_value_to_pixel, x, real_y, gap_corte, a,
|
|
m_factor_conversion_value_to_pixel_pos, m_factor_conversion_value_to_pixel_neg, m_fr_change_value);
|
|
x += a + m_barras_espacio_entre;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramHorizontal::OnSetLienzo(void)
|
|
{
|
|
// Setemoas los maximos valores
|
|
m_barras_max_width = m_barras_espacio_dibujable_width;
|
|
m_barras_max_width -= (m_bars_size - 1) * m_barras_espacio_entre; // Restamos el el espacio entre barras
|
|
m_barras_max_width -= (m_barras_gap_init + m_barras_gap_end); // Restamos los dos gaps final e inicial
|
|
m_barras_max_height = m_barras_espacio_dibujable_height;
|
|
|
|
|
|
//---
|
|
int idx_no_tiene[];
|
|
double sum = 0.00;
|
|
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
const double v = m_bars[i].ValueForAncho();
|
|
if(v == 0.00)
|
|
idx_no_tiene.Push(i);
|
|
else
|
|
sum += v;
|
|
}
|
|
|
|
//--- Tamaño
|
|
const int s = ArraySize(idx_no_tiene);
|
|
|
|
//--- No hay defaults
|
|
if(s < 1)
|
|
return;
|
|
|
|
//--- Seteamos los defaults
|
|
const double def_factor = (1.0 - sum) / double(s);
|
|
for(int i = 0; i < s; i++)
|
|
m_bars[idx_no_tiene[i]].ValueForAncho(def_factor);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramHorizontal::RecalculeCordinatesBarsAndText(void)
|
|
{
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
m_bars[i].RecalculeCordinates();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramHorizontal::OnMaxOrMinValueSuperate(void)
|
|
{
|
|
//---
|
|
if(CheckPointer(m_eje))
|
|
{
|
|
m_eje.HistogramLinePointerGet().SetNewValues(m_fr_max_value, m_fr_min_value, m_fr_change_value);
|
|
}
|
|
|
|
//---
|
|
const int real_y = m_barras_y1 + m_barras_espacio_dibujable_height; // Conseguimos el Y1 real
|
|
const int gap_corte = real_y - m_barras_cordenanda_eje_corte; // Otenemos el gap de corte respecto a Y1 Real
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
m_bars[i].SetNewsValues(gap_corte, m_factor_conversion_value_to_pixel_pos, m_factor_conversion_value_to_pixel_neg, m_fr_change_value);
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramHorizontal::OnNeweCordinatesBarsAndSize(void)
|
|
{
|
|
int x = m_barras_cordinate_init;
|
|
const int real_y = m_barras_y1 + m_barras_espacio_dibujable_height; // Conseguimos el Y1 real
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
const int a = HISTOGRAM_CALCULE_ANCHO(m_bars[i].ValueForAncho(), m_barras_max_width);
|
|
m_bars[i].SetNewsCordenadasAndSize(x, real_y, a);
|
|
x += a + m_barras_espacio_entre;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Funcion que se ejeucta cada vez que se añade o remueve un |
|
|
//| Eleemto |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramHorizontal::OnBarraAdd(int index)
|
|
{
|
|
//---
|
|
m_barras_max_width -= m_barras_espacio_entre; // Espacio
|
|
|
|
//---
|
|
double extra = m_bars[index].ValueForAncho();
|
|
|
|
//---
|
|
if(extra == 0.00) // Default
|
|
{
|
|
extra = 1.0 / double(m_bars_size); // Valor default
|
|
}
|
|
// Print("Nuevo valor: ", extra);
|
|
|
|
double rest = extra / double(m_bars_size - 1);
|
|
|
|
//Print("Se le restara a cada barra: ", rest);
|
|
|
|
//--- Reducimos el "factor" de cada uno
|
|
int idx_to_Remove[];
|
|
extra = 0.00;
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
m_bars[i].CleanBarras(false); // Limpaos las barras (solo pixeles, data no)
|
|
m_bars[i].TextClean(); // Limpiamos el texto (solo pxiesels, data no)
|
|
|
|
if(i == index)
|
|
continue;
|
|
m_bars[i].ValueForAnchoReduce(rest);
|
|
|
|
const double v = m_bars[i].ValueForAncho();
|
|
|
|
//PrintFormat("Ancho para %d = %d", i, m_bars[i].SizeBarrasInPixels());
|
|
const int a = HISTOGRAM_CALCULE_ANCHO(v, m_barras_max_width);
|
|
// PrintFormat("Nuevo ancho para %d = %d", i, a);
|
|
if(a < m_barras_min_width) // Nuevo ancho para esta bvarra muy pequeño
|
|
{
|
|
extra += v; // Sumamos
|
|
idx_to_Remove.Push(i);
|
|
}
|
|
}
|
|
|
|
//--- Eliminamos los muy pequeños
|
|
const int size_remove = ArraySize(idx_to_Remove);
|
|
if(size_remove > 0)
|
|
{
|
|
for(int i = 0; i < size_remove; i++)
|
|
{
|
|
const int k = idx_to_Remove[i];
|
|
m_bars[k].Destroy(); // Limpia el texto ocupado
|
|
delete m_bars[k];
|
|
}
|
|
|
|
RemoveMultipleIndexes(m_bars, idx_to_Remove, 0);
|
|
m_bars_size -= size_remove;
|
|
}
|
|
|
|
//---
|
|
rest = extra / double(m_bars_size); // si extra es 0.00 esto dara 0.00 (si es 0.00, significa que no se supero el minimo ancho)
|
|
int x = m_barras_cordinate_init;
|
|
const int real_y = m_barras_y1 + m_barras_espacio_dibujable_height; // Conseguimos el Y1 real
|
|
const int gap_corte = real_y - m_barras_cordenanda_eje_corte; // Otenemos el gap de corte respecto a Y1 Real
|
|
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
m_bars[i].ValueForAnchoAument(rest); // Aumentamos el ancho
|
|
const int a = HISTOGRAM_CALCULE_ANCHO(m_bars[i].ValueForAncho(), m_barras_max_width);
|
|
|
|
if(i == index) // Ultimo eleento
|
|
{
|
|
// Inicilizacion
|
|
m_bars[i].Init(m_function_value_to_pixel, x, real_y, gap_corte, a,
|
|
m_factor_conversion_value_to_pixel_pos, m_factor_conversion_value_to_pixel_neg, m_fr_change_value);
|
|
}
|
|
else
|
|
{
|
|
// Reseteo
|
|
m_bars[i].SetNewsCordenadasAndSize(x, real_y, a);// Set cordenadas
|
|
}
|
|
x += a + m_barras_espacio_entre;
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramHorizontal::OnBarrDelete(double extra_value) // Elemento ya creado
|
|
{
|
|
// La limpeiza ya se hace en la clase base
|
|
//---
|
|
const double rest = extra_value / double(m_bars_size); // (calculamos el valor extra que le sumaremos a los demas indices)
|
|
int x = m_barras_cordinate_init;
|
|
const int real_y = m_barras_y1 + m_barras_espacio_dibujable_height; // Conseguimos el Y1 real
|
|
const int gap_corte = real_y - m_barras_cordenanda_eje_corte; // Otenemos el gap de corte respecto a Y1 Real
|
|
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
m_bars[i].ValueForAnchoAument(rest); // Aumentamos el ancho
|
|
const int a = HISTOGRAM_CALCULE_ANCHO(m_bars[i].ValueForAncho(), m_barras_max_width);
|
|
|
|
//--- Reseteo
|
|
m_bars[i].SetNewsCordenadasAndSize(x, real_y, a);// Set cordenadas
|
|
|
|
//---
|
|
x += a + m_barras_espacio_entre;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogramHorizontal::ConjuntoBarWidth(int index, double new_value)
|
|
{
|
|
double extra = new_value - m_bars[index].ValueForAncho();
|
|
m_bars[index].ValueForAncho(new_value);
|
|
|
|
//---
|
|
if(m_bars_size <= 1)
|
|
{
|
|
LogWarning("No se puede cambiar ancho con solo 1 grupo", FUNCION_ACTUAL); // El index ya ocupa todo el espacio del grupo
|
|
return;
|
|
}
|
|
//---
|
|
/*
|
|
if(new_value < 0.0 || new_value > 1.0) {
|
|
LogError(StringFormat("new_value=%.2f fuera de rango [0.0, 1.0]", new_value), __FUNCTION__);
|
|
return;
|
|
}
|
|
*/
|
|
|
|
//---
|
|
if(extra > 0.00)
|
|
{
|
|
double rest = extra / double(m_bars_size - 1);
|
|
|
|
//--- Reducimos el "factor" de cada uno
|
|
int idx_to_Remove[];
|
|
extra = 0.00;
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
m_bars[i].CleanBarras(false); // Limpaos las barras (solo pixeles, data no)
|
|
m_bars[i].TextClean(); // Limpiamos el texto (solo pxiesels, data no)
|
|
|
|
if(i != index)
|
|
m_bars[i].ValueForAnchoReduce(rest);
|
|
|
|
const double v = m_bars[i].ValueForAncho();
|
|
|
|
//PrintFormat("Ancho para %d = %d", i, m_bars[i].SizeBarrasInPixels());
|
|
const int a = HISTOGRAM_CALCULE_ANCHO(v, m_barras_max_width);
|
|
// PrintFormat("Nuevo ancho para %d = %d", i, a);
|
|
if(a < m_barras_min_width) // Nuevo ancho para esta bvarra muy pequeño
|
|
{
|
|
extra += v; // Sumamos
|
|
idx_to_Remove.Push(i);
|
|
}
|
|
}
|
|
|
|
//--- Eliminamos los muy pequeños
|
|
const int size_remove = ArraySize(idx_to_Remove);
|
|
if(size_remove > 0)
|
|
{
|
|
for(int i = 0; i < size_remove; i++)
|
|
{
|
|
const int k = idx_to_Remove[i];
|
|
m_bars[k].Destroy(); // Limpia el texto ocupado
|
|
delete m_bars[k];
|
|
}
|
|
|
|
RemoveMultipleIndexes(m_bars, idx_to_Remove, 0);
|
|
m_bars_size -= size_remove;
|
|
}
|
|
|
|
//---
|
|
rest = extra / double(m_bars_size); // si extra es 0.00 esto dara 0.00 (si es 0.00, significa que no se supero el minimo ancho)
|
|
int x = m_barras_cordinate_init;
|
|
const int real_y = m_barras_y1 + m_barras_espacio_dibujable_height; // Conseguimos el Y1 real
|
|
const int gap_corte = real_y - m_barras_cordenanda_eje_corte; // Otenemos el gap de corte respecto a Y1 Real
|
|
|
|
//---
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
m_bars[i].ValueForAnchoAument(rest); // Aumentamos el ancho
|
|
const int a = HISTOGRAM_CALCULE_ANCHO(m_bars[i].ValueForAncho(), m_barras_max_width); // Nuevo ancho
|
|
m_bars[i].SetNewsCordenadasAndSize(x, real_y, a);// Set cordenadas y dibujado pxieles
|
|
x += a + m_barras_espacio_entre; // Nuewvas cordenadas
|
|
}
|
|
}
|
|
else
|
|
{
|
|
extra *= -1.0; // Lo hacemos positivo
|
|
|
|
const double rest = extra / double(m_bars_size - 1); // (calculamos el valor extra que le sumaremos a los demas indices)
|
|
int x = m_barras_cordinate_init;
|
|
const int real_y = m_barras_y1 + m_barras_espacio_dibujable_height; // Conseguimos el Y1 real
|
|
const int gap_corte = real_y - m_barras_cordenanda_eje_corte; // Otenemos el gap de corte respecto a Y1 Real
|
|
|
|
//---
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
m_bars[i].CleanBarras(false);
|
|
m_bars[i].TextClean();
|
|
}
|
|
|
|
//---
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
if(i != index) // Solo aumenta al que no s indice
|
|
m_bars[i].ValueForAnchoAument(rest); // Aumentamos el ancho
|
|
|
|
//---
|
|
const int a = HISTOGRAM_CALCULE_ANCHO(m_bars[i].ValueForAncho(), m_barras_max_width);
|
|
|
|
//--- Reseteo
|
|
m_bars[i].SetNewsCordenadasAndSize(x, real_y, a);// Set cordenadas y dibujado pxieles
|
|
|
|
//---
|
|
x += a + m_barras_espacio_entre;
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
#undef HISTOGRAM_CALCULE_ANCHO
|
|
//+------------------------------------------------------------------+
|