forked from nique_372/GrapichsByLeo
1622 lines
128 KiB
MQL5
1622 lines
128 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Base.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 HISTOGRAM_FINAL_FILE_BASES_BY_LEO_MQH
|
|
#define HISTOGRAM_FINAL_FILE_BASES_BY_LEO_MQH
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include "..\\..\\PartInf\\ParteInf.mqh"
|
|
#include "LineCorte.mqh"
|
|
#include "..\\Barra\\Barras.mqh"
|
|
#include "Titulo.mqh"
|
|
#include "..\\EjeHist\\Ver.mqh"
|
|
#include "..\\EjeHist\\Hor.mqh"
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
//---
|
|
#define HIST_FLAG_INIT_TITULO 1
|
|
#define HIST_FLAG_INIT_DATA 2
|
|
#define HIST_FLAG_ALL_INIT (HIST_FLAG_INIT_TITULO | HIST_FLAG_INIT_DATA)
|
|
|
|
#define HIST_FLAG_INIT_CREATE_BITMAP 8
|
|
#define HIST_FLAG_INIT_GENERAL 16
|
|
|
|
|
|
#define HIST_FLAG_INIT_PART_INFO 4
|
|
|
|
|
|
//---
|
|
#define HISTOGRAM_DEBUG
|
|
|
|
//---
|
|
/*
|
|
Nota para los textos y Font...
|
|
- El FontSet de canvas sera utiloizado mayormente por el usuario.. por jemeplo si el usuario quiere setear la fuenta debera
|
|
de usar el fontset de histogram, (hay parametro donde la fuenta es invalida, lo que sifnica que se usara la fuente de canvas, de lo contario una cusotm)
|
|
*/
|
|
|
|
enum ENUM_HIST_MODE_CORTE
|
|
{
|
|
HIST_CORTE_NOT_USE = 0,
|
|
HIST_CORTE_PERCENT = 1,
|
|
HIST_CORTE_VALUE = 2
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CHistogram : public CLoggerBase
|
|
{
|
|
protected:
|
|
CCanvasCustom* m_canvas; // Canvas
|
|
CColorGeneratorArgb m_color_generator; // Generador de colores aleatorios
|
|
ENUM_HIST_MODE_CORTE m_corte_mode;
|
|
|
|
//---
|
|
int m_bars_size; // Numero de cojuntos de barras
|
|
CHistogramConjuntoNor* m_bars[]; // Conjunto de barras
|
|
CHistogramConjuntoNor* m_bar_max; // Barra con el valor maixmo de value
|
|
CHistogramConjuntoNor* m_bar_min; // Barra con el valor minimo de value
|
|
|
|
//---
|
|
uint8_t m_init_flags; // Bandera de incilizacion
|
|
ENUM_HISTOGAM_TYPE m_type; // Tipo de histograma
|
|
|
|
|
|
//--- Generales
|
|
long m_chart_id; // Id del grafico
|
|
int m_subwin; // Subventana
|
|
int m_width; // Ancho total
|
|
int m_height; // Alto total
|
|
string m_obj_name; // Nombre del objeto (bitmap o bitmaplabel)
|
|
uint m_back_color; // Color de fonndo
|
|
|
|
//--- De la imagen
|
|
//- Conversiones y Corte
|
|
double m_fr_max_value; // Valor maximo
|
|
double m_fr_min_value; // Valor minimo
|
|
double m_fr_change_value; // Valor de cambio
|
|
double m_factor_conversion_value_to_pixel_pos; // Factor de conversion para valores positivos
|
|
double m_factor_conversion_value_to_pixel_neg; // Factor de conversion para valores negativos
|
|
double m_percent_corte_neg; // Porcentaje de corte negativo
|
|
double m_percent_corte_pos; // Porcentaje de corte positivo
|
|
HistogramFuncionCalculatePixel m_function_value_to_pixel; // Funcion para convertir valor a pixel
|
|
CHistogramLineCorteBase* m_line_corte; // Linea de corte
|
|
|
|
//- General
|
|
// Gaps del linezo de las barras
|
|
int m_gap_superior;
|
|
int m_gap_inferior;
|
|
int m_gap_derecha;
|
|
int m_gap_izquierda;
|
|
|
|
//- Espacio dibujable de barras
|
|
int m_barras_gap_init; // Gap inicial (lienzo)
|
|
int m_barras_gap_end; // Gap final (lienzo)
|
|
int m_barras_x1; // x1 inicial para barras (del lienzo sin contar gaps)
|
|
int m_barras_y1; // y1 inicial para barras
|
|
int m_barras_cordinate_init; // Contando el gap (cordenada de iinciio real)
|
|
int m_barras_cordenanda_eje_corte; // Cordenanda eje de cambio
|
|
int m_barras_espacio_dibujable_width; // Ancho disponible para las barras (ejex)
|
|
int m_barras_espacio_dibujable_height; // Alto disonible para las barras (ejey)
|
|
int m_barras_max_width; // Maximo ancho total de las barras (sumando todas, sin gaps)
|
|
int m_barras_max_height; // Maximo alto total de las barras (sumando todas, sin gaps)
|
|
int m_barras_espacio_entre; // Espacio entre barras
|
|
int m_barras_min_width; // Minimo ancho
|
|
|
|
//- Titulo
|
|
CHistogramTitulo* m_titulo; // Titulo
|
|
|
|
//- Parte informativa
|
|
ENUM_HISTOGRAM_PARTE_INFORMATIVA_POSICION m_part_info_position;
|
|
CHistogramParteInfo* m_part_info_ptr;
|
|
|
|
//- Copyright
|
|
CTextCanvas* m_copyright;
|
|
|
|
//- Linea de eje
|
|
CHistogramEje* m_eje;
|
|
|
|
//--- Añadir valores
|
|
int m_curr_index_bar_p; // Puntero actual en m_bars
|
|
|
|
|
|
//--- Funciones que debera de ser sobreescirtas
|
|
virtual void RecalculeCordinatesBarsAndText() = 0; // Recalcula las cordenans de todos los conhjntos (barras y texto)
|
|
virtual void OnNeweCordinatesBarsAndSize() = 0; // Recalcula las cordenans en un nuevo ancho y x1 e y1 ()
|
|
|
|
virtual void OnSetLienzo() = 0; // Funcion que se ejeucta una vez seteada los parametros geneles
|
|
virtual void OnBarraAdd(int index) = 0; // Funcion que se ejeucta cada vez qeu se agrega una nueva barra (ya iniciado)
|
|
virtual void OnBarrDelete(double extra_value) = 0; // Funcion que se ejeucta cada vez que se elimina una barra (ya iniciado)
|
|
virtual void OnMaxOrMinValueSuperate() = 0; // Funcion que se ejcuta para reclauclar los "anch9os" una vez superado el miaxmo o minimo
|
|
|
|
virtual void InitCordinates() = 0; // Inicializa todas las clases
|
|
|
|
//--- De la clase
|
|
void SetMaxMin();
|
|
|
|
//--- Superacion de maximo o minimo
|
|
void RecalculeFactorsMaxMinCortePer();
|
|
void RecalculeFactorsMaxMinDef();
|
|
void RecalculeFactorsMaxMinCorteVal();
|
|
void RecalculeFactorsMaxMin();
|
|
void OnAfterSetNewMaxMin();
|
|
|
|
private:
|
|
void CleanVariables();
|
|
|
|
public:
|
|
CHistogram(void);
|
|
~CHistogram(void);
|
|
|
|
|
|
//--- Creacion
|
|
// Inicializa la clase
|
|
void Initialize(int width, int height, string objname, long chart_id, int subwin, uint back_color);
|
|
|
|
// Crea un bitmap
|
|
inline void CreateBitmap(datetime time, double price, ENUM_COLOR_FORMAT format);
|
|
|
|
// Crea un bitmap lavel
|
|
inline void CreateBitmapLabel(int x, int y, ENUM_COLOR_FORMAT format);
|
|
|
|
//--- Limpeiza
|
|
void Clean(); // LIMPIA TODO
|
|
|
|
//---
|
|
CColorGeneratorArgb* GetColorGeneratorPointer() { return &m_color_generator; }
|
|
|
|
//--- Conjunto barras
|
|
//- Numero de barras
|
|
virtual void NumConjuntoBars(int num_bars, int reserve_bars = 0) = 0;
|
|
inline int NumConjuntoBars() const { return m_bars_size; }
|
|
|
|
//- Ninimo ancho
|
|
__forceinline int MinConjuntoAncho() const { return m_barras_min_width; }
|
|
virtual void MinConjuntoAncho(int new_value) = 0;
|
|
|
|
//- Añadir barras a un conj
|
|
virtual 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.00) = 0 ; // 0.00 = auto (0.00 - 1.00)
|
|
|
|
__forceinline int AddConjuntoBar(const string& label, 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.00);
|
|
__forceinline int AddConjuntoBarDefault(const string& label, int label_fontsize, int barras_de_reserva_ = 0);
|
|
|
|
void AddConjuntoBarWithBins(const string& label, uint label_clr, int label_fontsize, const string& label_font, ENUM_HISTOGRAM_TEXT_MODE label_mode,
|
|
int eje_gap, ENUM_HIST_DRAW_RECT_STYLE initial_style, double& data[], int bins, uint clr_barras);
|
|
|
|
__forceinline void AddConjuntoBarWithBinsDeft(const string& label, double& data[], int bins, uint clr_barras = 0);
|
|
|
|
//- Añade una barra a un conj (defreadindex)
|
|
__forceinline void AddBarToConjuntoBarFast(double value, uint clr);
|
|
__forceinline void AddBarToConjuntoBar(double value, uint clr, bool update_data);
|
|
|
|
//- Setea un conjunto de barras
|
|
__forceinline void BarConjuntoSet(const string label, uint label_clr, int label_fontsize, const string &label_font, ENUM_HISTOGRAM_TEXT_MODE label_mode, int eje_gap, ENUM_HIST_DRAW_RECT_STYLE initial_style,
|
|
double width = 0.00);
|
|
__forceinline void BarConjuntoSet(const string label, int label_fontsize, const string &label_font, ENUM_HISTOGRAM_TEXT_MODE label_mode, int eje_gap, ENUM_HIST_DRAW_RECT_STYLE initial_style,
|
|
double width = 0.00);
|
|
|
|
//- Setea la data de un conjunto com
|
|
void BarConjuntoSetBath(int index, const double& values[], const uint& colores[], bool redraw = false);
|
|
__forceinline void BarConjuntoSetBathCurrReadIndex(const double& values[], const uint& colores[], bool redraw = false) { BarConjuntoSetBath(m_curr_index_bar_p, values, colores, redraw);}
|
|
|
|
//- Eliminacion de un conjunto
|
|
void RemoveConjuntoBar(int index, bool redraw = false);
|
|
__forceinline void RemoveConjuntoBar(string name, bool redraw = false);
|
|
__forceinline void RemoveConjuntoBarCurrReadIndex(bool redraw = false) { RemoveConjuntoBar(m_curr_index_bar_p, redraw); }
|
|
|
|
//- Nombre de un conjunto
|
|
__forceinline void BarConjuntoTextValue(string new_name, bool redraw = false);
|
|
__forceinline string BarConjuntoTextValue(int index) const { return m_bars[index].TextValue(); }
|
|
__forceinline string BarConjuntoTextValueCurrReadIndex() const { return m_bars[m_curr_index_bar_p].TextValue(); }
|
|
|
|
//- Ancho del conjunto
|
|
virtual void ConjuntoBarWidth(int index, double new_value) = 0;
|
|
__forceinline double ConjuntoBarWidth(int index) const { return m_bars[index].ValueForAncho(); }
|
|
__forceinline double ConjuntoBarWidthCurrReadIndex() const { return m_bars[m_curr_index_bar_p].ValueForAncho(); }
|
|
|
|
//- Estilo de dibujado
|
|
__forceinline void DrawRectStyleConjuntoBar(int index, ENUM_HIST_DRAW_RECT_STYLE style, bool update_pixles) { m_bars[index].DrawRectStyle(style, update_pixles); }
|
|
__forceinline void DrawRectStyleConjuntoBarReadIndex(ENUM_HIST_DRAW_RECT_STYLE style, bool update_pixles) { m_bars[m_curr_index_bar_p].DrawRectStyle(style, update_pixles); }
|
|
__forceinline void DrawRectStyleConjuntoBar(int index, HistFunctionDrawRect function, ENUM_HIST_DRAW_RECT_STYLE style, bool update_pixles) { m_bars[index].DrawRectStyle(function, style, update_pixles); }
|
|
__forceinline void DrawRectStyleConjuntoBarReadIndex(HistFunctionDrawRect function, ENUM_HIST_DRAW_RECT_STYLE style, bool update_pixles) { m_bars[m_curr_index_bar_p].DrawRectStyle(function, style, update_pixles); }
|
|
__forceinline ENUM_HIST_DRAW_RECT_STYLE DrawRectStyleConjuntoBar(int index) const { return m_bars[index].DrawRectStyle(); }
|
|
__forceinline ENUM_HIST_DRAW_RECT_STYLE DrawRectStyleConjuntoBarReadIndex() const { return m_bars[m_curr_index_bar_p].DrawRectStyle(); }
|
|
|
|
//- Finaliza el add de barras a un conjunot (no es necesario si m_init es false, de lo contraio SI)
|
|
void FinalizeAddConjunto(int index_fin, bool update_data, bool redraw = false);
|
|
|
|
//- Encontrar y retornar
|
|
inline int FindIndexByBarConjuntoName(const string& name);
|
|
|
|
//--- Puntero de lectura interno
|
|
__forceinline int ReadIndex() const { return (m_curr_index_bar_p); }
|
|
__forceinline int ReadIndex(const int conjunto_bar_index) { return (m_curr_index_bar_p = conjunto_bar_index); }
|
|
__forceinline int ReadIndex(const string& name) { return (m_curr_index_bar_p = FindIndexByBarConjuntoName(name)); }
|
|
__forceinline int ReadIndexFisrtConjunto() { return (m_curr_index_bar_p = 0); }
|
|
__forceinline int ReadIndexLastConjunto() { return (m_curr_index_bar_p = m_bars_size - 1); }
|
|
__forceinline int ReadIndexAument(int add_value = 1) { return (m_curr_index_bar_p += add_value); }
|
|
__forceinline int ReadIndexReduce(int reduce_value = 1) { return (m_curr_index_bar_p -= reduce_value); }
|
|
__forceinline int ReadIndexMiddle() { return (m_curr_index_bar_p = int(round(m_bars_size / 2))); }
|
|
|
|
//--- Barra
|
|
// index: indice en conjunto
|
|
// Color de una barra
|
|
__forceinline void BarColor(int index, uint new_clr, bool redraw = false);
|
|
__forceinline uint BarColor(int index) const { return m_bars[m_curr_index_bar_p].BarColor(index); }
|
|
|
|
// Valor de un abarra
|
|
inline void BarValue(int index, double new_value, bool redraw = false);
|
|
__forceinline double BarValue(int index) const { return m_bars[m_curr_index_bar_p].BarValue(index); }
|
|
|
|
// Elimina una barra de un conjunto de barras
|
|
__forceinline void RemoveBarFromConjuntoBar(int index_in_conjunto, bool redraw = false);
|
|
|
|
// Tamaño
|
|
__forceinline int SizeBarsOfConjunto() const { return m_bars[m_curr_index_bar_p].SizeBarras(); }
|
|
|
|
//--- FontSet
|
|
__forceinline void FontSet(const string name, const int size, const uint flags, const uint angle) { m_canvas.FontSet(name, size, flags, angle);}
|
|
|
|
//--- Titulo
|
|
void Titulo(const string &titulo, ENUM_HISTOGRAM_TITULO_POSICION posicion, int y_gap_titulo, uint aligement, int x, int y, uint clr,
|
|
int fontsize = 0, string font = NULL, uint flagtext = UINT_MAX, uint textpos = UINT_MAX);
|
|
void TituloDefault(const string& titulo, int espacio_utilizado_por_el_titulo_y = 30);
|
|
CHistogramTitulo* TituloGetPointer() { return m_titulo; }
|
|
|
|
|
|
//--- Copyright
|
|
CTextCanvas* CopyrightGetPointer() { return m_copyright;}
|
|
void CreateCopyright(int x, int y, string txt, uint clr, uint align, int fontsize = 0, string font = NULL, uint flagtext = UINT_MAX, uint textpos = UINT_MAX);
|
|
void CreateCopyrightDefault(const string& autor, string font = "Arial", int fontsize = 15);
|
|
|
|
//--- Linea de eje
|
|
virtual 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) = 0;
|
|
CHistogramEje* EjeLineGetPointer() { return m_eje;}
|
|
|
|
|
|
//--- Init Lienzo general
|
|
// Deft
|
|
void InitLienzoBarras(int x1, int y1, int x2, int y2, int gap_init, int gap_end, int gap_espacio_entre_barras);
|
|
|
|
// Per
|
|
void InitLienzoBarras(int x1, int y1, int x2, int y2, int gap_init, int gap_end, int gap_espacio_entre_barras, double value_corte_neg, double value_corte_pos);
|
|
|
|
// Val
|
|
void InitLienzoBarras(int x1, int y1, int x2, int y2, int gap_init, int gap_end, int gap_espacio_entre_barras, double value_corte);
|
|
|
|
|
|
//--- Parte informativa - legenda
|
|
void CreatePartInformativa(ENUM_HISTOGRAM_PARTE_INFORMATIVA_POSICION pos, int xgap_inicial, int ygap_inicial);
|
|
__forceinline CHistogramParteInfo* GetPartInfPointer() { return m_part_info_ptr; }
|
|
|
|
//--- Linea de corte
|
|
CHistogramLineCorteBase* GetLineCortePtr() { return m_line_corte; } // Solo existe si es que hay corte si no no
|
|
|
|
|
|
//--- Redibujado
|
|
__forceinline void Redraw();
|
|
|
|
//--- Guardar como imagen
|
|
bool SavePicture(const string& filename, bool comon); // Guarda la imagen
|
|
|
|
//--- Obteener array de pixeles
|
|
void GetPixelsArray(uint& out_array_px[]) { m_canvas.GetPixelsArray(out_array_px); }
|
|
|
|
|
|
//--- Generales
|
|
__forceinline long ChartId() const { return m_chart_id; }
|
|
__forceinline int Subwin() const { return m_subwin; }
|
|
__forceinline string ObjName() const { return m_obj_name; }
|
|
__forceinline int Width() const { return m_width; }
|
|
__forceinline int Height() const { return m_height; }
|
|
__forceinline uint BackColor() const { return m_back_color; }
|
|
|
|
|
|
//--- Inicilizacion
|
|
__forceinline bool IsInitTitulo() const { return (m_init_flags & HIST_FLAG_INIT_TITULO) != 0; }
|
|
__forceinline bool IsInitBarras() const { return (m_init_flags & HIST_FLAG_INIT_DATA) != 0; }
|
|
__forceinline bool IsInitPartInf() const { return (m_init_flags & HIST_FLAG_INIT_PART_INFO) != 0; }
|
|
__forceinline bool IsInitGeneral() const { return (m_init_flags & HIST_FLAG_INIT_GENERAL) != 0; }
|
|
__forceinline bool IsCreateObj() const { return (m_init_flags & HIST_FLAG_INIT_CREATE_BITMAP) != 0; }
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Macros |
|
|
//+------------------------------------------------------------------+
|
|
//---
|
|
#define HISTOGRAM_VALUE_TO_PIXEL(value) m_function_value_to_pixel(value, m_fr_change_value, m_factor_conversion_value_to_pixel_pos, m_factor_conversion_value_to_pixel_neg)
|
|
|
|
//---
|
|
#define HISTOGRAM_IS_INIT_TITULO ((m_init_flags & HIST_FLAG_INIT_TITULO) != 0)
|
|
#define HISTOGRAM_IS_INIT_DATA ((m_init_flags & HIST_FLAG_INIT_DATA) != 0)
|
|
#define HISTOGRAM_IS_INIT_INFORMATIVE ((m_init_flags & HIST_FLAG_INIT_PART_INFO) != 0)
|
|
#define HISTOGRAM_IS_INIT_CREATE ((m_init_flags & HIST_FLAG_INIT_CREATE_BITMAP) != 0)
|
|
#define HISTOGRAM_IS_INIT_GENERAL ((m_init_flags & HIST_FLAG_INIT_GENERAL) != 0)
|
|
|
|
|
|
// nes = solo lo necesario, informativo es extra no hace falta
|
|
#define HISTOGRAM_IS_INIT_NES ((m_init_flags & HIST_FLAG_ALL_INIT) == HIST_FLAG_ALL_INIT)
|
|
|
|
//---
|
|
#define HISTOGRAM_IS_NOT_INIT_TITULO ((m_init_flags & HIST_FLAG_INIT_TITULO) == 0)
|
|
#define HISTOGRAM_IS_NOT_INIT_DATA ((m_init_flags & HIST_FLAG_INIT_DATA) == 0)
|
|
#define HISTOGRAM_IS_NOT_INIT_INFORMATIVE ((m_init_flags & HIST_FLAG_INIT_PART_INFO) == 0)
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CHistogram::CHistogram(void)
|
|
{
|
|
CleanVariables();
|
|
m_canvas = new CCanvasCustom();
|
|
m_canvas.FontSet("Arial", 12, 0, 0); // Seteamos un font por defecto
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
CHistogram::~CHistogram()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::CleanVariables(void)
|
|
{
|
|
//---
|
|
m_canvas = NULL;
|
|
m_titulo = NULL;
|
|
m_copyright = NULL;
|
|
m_eje = NULL;
|
|
m_corte_mode = WRONG_VALUE;
|
|
|
|
//--- Barras
|
|
m_bars_size = 0;
|
|
m_bar_max = NULL;
|
|
m_bar_min = NULL;
|
|
m_curr_index_bar_p = 0;
|
|
ArrayResize(m_bars, 0);
|
|
|
|
//--- Flags y tipo
|
|
m_init_flags = 0;
|
|
m_type = WRONG_VALUE;
|
|
|
|
//--- Generales
|
|
m_chart_id = 0;
|
|
m_subwin = 0;
|
|
m_width = 0;
|
|
m_height = 0;
|
|
m_obj_name = "";
|
|
m_back_color = 0x00000000;
|
|
|
|
//--- Conversiones y corte
|
|
m_fr_max_value = 0.0;
|
|
m_fr_min_value = 0.0;
|
|
m_fr_change_value = 0.0;
|
|
m_factor_conversion_value_to_pixel_pos = 0.0;
|
|
m_factor_conversion_value_to_pixel_neg = 0.0;
|
|
m_percent_corte_neg = 0.0;
|
|
m_percent_corte_pos = 0.0;
|
|
m_function_value_to_pixel = NULL;
|
|
m_line_corte = NULL;
|
|
|
|
//--- Gaps
|
|
m_gap_superior = 0;
|
|
m_gap_inferior = 0;
|
|
m_gap_derecha = 0;
|
|
m_gap_izquierda = 0;
|
|
|
|
//--- Espacio dibujable de barras
|
|
m_barras_gap_init = 0;
|
|
m_barras_gap_end = 0;
|
|
m_barras_x1 = 0;
|
|
m_barras_y1 = 0;
|
|
m_barras_cordinate_init = 0;
|
|
m_barras_cordenanda_eje_corte = 0;
|
|
m_barras_espacio_dibujable_width = 0;
|
|
m_barras_espacio_dibujable_height = 0;
|
|
m_barras_max_width = 0;
|
|
m_barras_max_height = 0;
|
|
m_barras_espacio_entre = 0;
|
|
m_barras_min_width = 0;
|
|
|
|
//--- Parte informativa
|
|
m_part_info_position = WRONG_VALUE;
|
|
m_part_info_ptr = NULL;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Limpieza total |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::Clean(void)
|
|
{
|
|
//--- Eliminamos ptrs
|
|
// Parte informativa
|
|
if(CheckPointer(m_part_info_ptr) == POINTER_DYNAMIC)
|
|
delete m_part_info_ptr;
|
|
|
|
// Barras
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
{
|
|
if(CheckPointer(m_bars[i]) == POINTER_DYNAMIC)
|
|
delete m_bars[i];
|
|
}
|
|
|
|
// Linea de corte
|
|
if(CheckPointer(m_line_corte) == POINTER_DYNAMIC)
|
|
delete m_line_corte;
|
|
|
|
// Canvas
|
|
if(CheckPointer(m_canvas) == POINTER_DYNAMIC)
|
|
{
|
|
m_canvas.Destroy();
|
|
delete m_canvas;
|
|
}
|
|
|
|
// Titulo
|
|
if(CheckPointer(m_titulo) == POINTER_DYNAMIC)
|
|
delete m_titulo;
|
|
|
|
// Copyright
|
|
if(CheckPointer(m_copyright) == POINTER_DYNAMIC)
|
|
{
|
|
delete m_copyright;
|
|
m_copyright = NULL;
|
|
}
|
|
|
|
// Linea de eje
|
|
if(CheckPointer(m_eje) == POINTER_DYNAMIC)
|
|
{
|
|
delete m_eje;
|
|
m_eje = NULL;
|
|
}
|
|
|
|
//---
|
|
CleanVariables();
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::Initialize(int width, int height, string objname, long chart_id, int subwin, uint back_color)
|
|
{
|
|
//---
|
|
if(HISTOGRAM_IS_INIT_GENERAL)
|
|
return;
|
|
|
|
//---
|
|
m_init_flags |= HIST_FLAG_INIT_GENERAL;
|
|
|
|
//---
|
|
m_width = width;
|
|
m_height = height;
|
|
m_obj_name = objname;
|
|
m_subwin = subwin;
|
|
m_chart_id = chart_id;
|
|
m_back_color = back_color;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
inline void CHistogram::CreateBitmap(datetime time, double price, ENUM_COLOR_FORMAT format)
|
|
{
|
|
if(HISTOGRAM_IS_INIT_CREATE)
|
|
return;
|
|
m_init_flags |= HIST_FLAG_INIT_CREATE_BITMAP;
|
|
m_canvas.CreateBitmap(m_chart_id, m_subwin, m_obj_name, time, price, m_width, m_height, format);
|
|
m_canvas.Erase(m_back_color);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
inline void CHistogram::CreateBitmapLabel(int x, int y, ENUM_COLOR_FORMAT format)
|
|
{
|
|
if(HISTOGRAM_IS_INIT_CREATE)
|
|
return;
|
|
m_init_flags |= HIST_FLAG_INIT_CREATE_BITMAP;
|
|
m_canvas.CreateBitmapLabel(m_chart_id, m_subwin, m_obj_name, x, y, m_width, m_height, format);
|
|
m_canvas.Erase(m_back_color);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::AddConjuntoBarWithBins(const string &label, uint label_clr, int label_fontsize, const string &label_font, ENUM_HISTOGRAM_TEXT_MODE label_mode,
|
|
int eje_gap, ENUM_HIST_DRAW_RECT_STYLE initial_style, double &data[], int bins, uint clr_barras)
|
|
{
|
|
|
|
//---
|
|
const int idx_conj = AddConjuntoBar(label, label_clr, label_fontsize, label_font, label_mode, bins, eje_gap, initial_style);
|
|
|
|
//---
|
|
const int data_size = ArraySize(data);
|
|
double min = data[0];
|
|
double max = data[0];
|
|
|
|
for(int i = 1; i < data_size; i++)
|
|
{
|
|
const double v = data[i];
|
|
if(v > max)
|
|
max = v;
|
|
if(v < min)
|
|
min = v;
|
|
}
|
|
|
|
//---
|
|
const double bins_range = (max - min) / double(bins);
|
|
|
|
//---
|
|
int frecuencias_data[];
|
|
ArrayResize(frecuencias_data, bins);
|
|
ArrayInitialize(frecuencias_data, 0);
|
|
|
|
//---
|
|
for(int i = 0; i < data_size; i++)
|
|
{
|
|
int idx = int((data[i] - min) / bins_range);
|
|
if(idx >= bins)
|
|
idx = bins - 1;
|
|
frecuencias_data[idx]++;
|
|
}
|
|
|
|
//---
|
|
for(int i = 0; i < bins; i++)
|
|
{
|
|
const double v = frecuencias_data[i];
|
|
AddBarToConjuntoBarFast(v, clr_barras);
|
|
}
|
|
|
|
//---
|
|
FinalizeAddConjunto(idx_conj, true, false); // NO redibuja
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
__forceinline void CHistogram::AddConjuntoBarWithBinsDeft(const string &label, double &data[], int bins, uint clr_barras = 0)
|
|
{
|
|
AddConjuntoBarWithBins(label, ColorToARGB(clrBlack), 12, "Arial", HISTOGRAM_TEXT_MODE_CENTER, 30, HIST_DRAW_RECT_FILL, data, bins, (clr_barras == 0 ? m_color_generator.Next() : clr_barras));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline int CHistogram::AddConjuntoBar(const string &label, 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)
|
|
{
|
|
return AddConjuntoBar(label, m_color_generator.Next(), label_fontsize, label_font, label_mode, barras_de_reserva_, eje_gap, initial_style, width);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
__forceinline int CHistogram::AddConjuntoBarDefault(const string &label, int label_fontsize, int barras_de_reserva_ = 0)
|
|
{
|
|
return AddConjuntoBar(label, m_color_generator.Next(), label_fontsize, "Arial", HISTOGRAM_TEXT_MODE_CENTER, barras_de_reserva_, label_fontsize >> 1, HIST_DRAW_RECT_FILL);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline void CHistogram::BarConjuntoSet(const string label, uint label_clr, int label_fontsize, const string &label_font, ENUM_HISTOGRAM_TEXT_MODE label_mode, int eje_gap,
|
|
ENUM_HIST_DRAW_RECT_STYLE initial_style, double width = 0.00)
|
|
{
|
|
m_bars[m_curr_index_bar_p].Set(m_canvas, label, label_clr, label_mode, label_fontsize, label_font, eje_gap, initial_style);
|
|
m_bars[m_curr_index_bar_p].ValueForAncho(width);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
__forceinline void CHistogram::BarConjuntoSet(const string label, int label_fontsize, const string &label_font, ENUM_HISTOGRAM_TEXT_MODE label_mode, int eje_gap,
|
|
ENUM_HIST_DRAW_RECT_STYLE initial_style, double width = 0.00)
|
|
{
|
|
m_bars[m_curr_index_bar_p].Set(m_canvas, label, m_color_generator.Next(), label_mode, label_fontsize, label_font, eje_gap, initial_style);
|
|
m_bars[m_curr_index_bar_p].ValueForAncho(width);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline void CHistogram::AddBarToConjuntoBarFast(double value, uint clr)
|
|
{
|
|
m_bars[m_curr_index_bar_p].AddBarraFast(value, clr);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
__forceinline void CHistogram::AddBarToConjuntoBar(double value, uint clr, bool update_data)
|
|
{
|
|
m_bars[m_curr_index_bar_p].AddBarra(value, clr, update_data);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::BarConjuntoSetBath(int index, const double &values[], const uint &colores[], bool redraw = false)
|
|
{
|
|
const int s_v = ArraySize(values);
|
|
const int s_c = ArraySize(colores);
|
|
|
|
//---
|
|
if(s_v != s_c)
|
|
{
|
|
LogCriticalError("Array de valores y colores, difieren en tamaño", FUNCION_ACTUAL);
|
|
Remover();
|
|
return;
|
|
}
|
|
|
|
//---
|
|
for(int i = 0; i < s_v; i++)
|
|
m_bars[index].AddBarraFast(values[i], colores[i]);
|
|
|
|
//---
|
|
FinalizeAddConjunto(index, true, redraw);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::FinalizeAddConjunto(int index_fin, bool update_data, bool redraw = false)
|
|
{
|
|
if(HISTOGRAM_IS_INIT_NES)
|
|
{
|
|
const bool ya_existe = m_bars[index_fin].IsInit();
|
|
|
|
//--- Set max min
|
|
m_bars[index_fin].SetMaxAndMinValue();
|
|
|
|
//--- Check rango
|
|
if(m_bars[index_fin].BarMaxValue() > m_bar_max.BarMaxValue())
|
|
{
|
|
m_bar_max = m_bars[index_fin];
|
|
|
|
//---
|
|
RecalculeFactorsMaxMin();
|
|
OnMaxOrMinValueSuperate(); // Recalculamos "los valores" de las barras
|
|
|
|
if(m_corte_mode) // No es 0
|
|
m_line_corte.SetNewValueEjePrincipal(m_barras_cordenanda_eje_corte, false);
|
|
}
|
|
else
|
|
if(m_bars[index_fin].BarMinValue() < m_bar_min.BarMinValue())
|
|
{
|
|
m_bar_min = m_bars[index_fin];
|
|
|
|
//---
|
|
RecalculeFactorsMaxMin();
|
|
OnMaxOrMinValueSuperate(); // Recalculamos "los valores" de las barras
|
|
|
|
if(m_corte_mode) // No es 0
|
|
m_line_corte.SetNewValueEjePrincipal(m_barras_cordenanda_eje_corte, false);
|
|
}
|
|
|
|
//---
|
|
if(ya_existe)
|
|
{
|
|
// Calculamos las cordenadas
|
|
if(update_data)
|
|
m_bars[index_fin].RecalculeCordinatesOnlyBars();
|
|
}
|
|
else
|
|
{
|
|
OnBarraAdd(index_fin);
|
|
}
|
|
|
|
//---
|
|
if(redraw) // Redibujamos
|
|
m_canvas.Update();
|
|
}
|
|
#ifdef HISTOGRAM_DEBUG
|
|
else
|
|
{
|
|
LogWarning("Solo se puede ejecutar FinalizeAddConjunto, para agregar barras a un histograma ya creado", FUNCION_ACTUAL);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::RemoveConjuntoBar(int index, bool redraw)
|
|
{
|
|
// Nota:
|
|
// - No ejeuctar cuando no hay elemetos
|
|
// - index debera de ser valido
|
|
// - Creo que podriamos acutlizar max y min con bucle pero no es necesario.. talvez a futuro
|
|
//---
|
|
double v = m_bars[index].ValueForAncho();
|
|
|
|
//---
|
|
if(m_bars_size > 1)
|
|
{
|
|
int idx = (index == 0) ? 1 : (index - 1);
|
|
m_bars[idx].CleanBarras(false, false);
|
|
}
|
|
|
|
//--- Elimianmos ptr
|
|
m_bars[index].Destroy(); // Limpiamos el espacio ocupado (texto y barras)
|
|
delete m_bars[index];
|
|
|
|
//--- Removemos
|
|
for(int i = index; i < m_bars_size - 1; i++)
|
|
{
|
|
m_bars[i] = m_bars[i + 1];
|
|
}
|
|
|
|
//---
|
|
m_bars_size--;
|
|
ArrayResize(m_bars, m_bars_size);
|
|
|
|
//---
|
|
if(m_bars_size > 0) // Solo revisar si al menos hay 1 barra, si no hay nada no hay que revisar
|
|
OnBarrDelete(v);
|
|
|
|
//--- SI se peude redibujar recalculamos las cordendas
|
|
if(redraw)
|
|
{
|
|
m_canvas.Update();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline void CHistogram::RemoveConjuntoBar(string name, bool redraw)
|
|
{
|
|
RemoveConjuntoBar(FindIndexByBarConjuntoName(name), redraw);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline void CHistogram::RemoveBarFromConjuntoBar(int index_in_conjunto, bool redraw = false)
|
|
{
|
|
m_bars[m_curr_index_bar_p].RemoveBar(index_in_conjunto, true);
|
|
if(redraw)
|
|
m_canvas.Update();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline void CHistogram::BarColor(int index, uint new_clr, bool redraw = false)
|
|
{
|
|
m_bars[m_curr_index_bar_p].BarColor(index, new_clr);
|
|
if(redraw)
|
|
m_canvas.Update();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::BarValue(int index, double new_value, bool redraw = false)
|
|
{
|
|
// Notas:
|
|
// - Solo ejecutar luego de haber iniciado la clase
|
|
// - m_curr_index_bar_p y index, no se compruebam, debera de ser validos
|
|
|
|
//--- Chekeamos valores
|
|
if(new_value > m_bar_max.BarMaxValue())
|
|
{
|
|
m_bars[m_curr_index_bar_p].BarValue(index, new_value, true, false); // Actulizamos (no el rect se hara en OnMar...)
|
|
m_bar_max = m_bars[m_curr_index_bar_p];
|
|
|
|
RecalculeFactorsMaxMin();
|
|
OnMaxOrMinValueSuperate(); // Recalculamos "los valores" de las barras
|
|
|
|
if(m_corte_mode) // No es 0
|
|
m_line_corte.SetNewValueEjePrincipal(m_barras_cordenanda_eje_corte, false);
|
|
}
|
|
else
|
|
if(new_value < m_bar_min.BarMinValue())
|
|
{
|
|
m_bars[m_curr_index_bar_p].BarValue(index, new_value, true, false); // Actulizamos (no el rect se hara en OnMar...)
|
|
m_bar_min = m_bars[m_curr_index_bar_p];
|
|
RecalculeFactorsMaxMin();
|
|
OnMaxOrMinValueSuperate(); // Recalculamos "los valores" de las barras
|
|
|
|
if(m_corte_mode) // No es 0
|
|
m_line_corte.SetNewValueEjePrincipal(m_barras_cordenanda_eje_corte, false);
|
|
}
|
|
else // No es un pico, actulizamos el rectangulo
|
|
{
|
|
m_bars[m_curr_index_bar_p].BarValue(index, new_value, true, true); // Actulizamos
|
|
}
|
|
|
|
//---
|
|
if(redraw)
|
|
m_canvas.Update();
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline void CHistogram::BarConjuntoTextValue(string new_name, bool redraw = false)
|
|
{
|
|
m_bars[m_curr_index_bar_p].TextValue(new_name);
|
|
if(redraw)
|
|
m_canvas.Update();
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
inline int CHistogram::FindIndexByBarConjuntoName(const string& name)
|
|
{
|
|
for(int i = 0; i < m_bars_size; i++)
|
|
if(m_bars[i].TextValue() == name)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::Titulo(const string &titulo, ENUM_HISTOGRAM_TITULO_POSICION posicion, int y_gap_titulo, uint aligement, int x, int y, uint clr,
|
|
int fontsize = 0, string font = NULL, uint flagtext = UINT_MAX, uint textpos = UINT_MAX)
|
|
{
|
|
//---
|
|
if(HISTOGRAM_IS_INIT_TITULO)
|
|
return;
|
|
m_titulo = new CHistogramTitulo();
|
|
m_titulo.Create(m_canvas, x, y, titulo, clr, aligement, posicion, y_gap_titulo, fontsize, font, flagtext, textpos);
|
|
m_titulo.CleanColor(m_back_color);
|
|
m_init_flags |= HIST_FLAG_INIT_TITULO;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::TituloDefault(const string &titulo, int espacio_utilizado_por_el_titulo_y = 30)
|
|
{
|
|
int fontsize = (espacio_utilizado_por_el_titulo_y >> 1) - 3;
|
|
int x_mitad = m_width >> 1;
|
|
int y_mitad = espacio_utilizado_por_el_titulo_y >> 1;
|
|
Titulo(titulo, HISTOGRAM_TITULO_ARRIBA, espacio_utilizado_por_el_titulo_y, TA_CENTER | TA_VCENTER, x_mitad, y_mitad, ColorToARGB(clrBlack), fontsize, "Arial",
|
|
0);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::SetMaxMin(void)
|
|
{
|
|
m_bars[0].SetMaxAndMinValue();
|
|
m_bar_max = m_bars[0];
|
|
m_bar_min = m_bars[0];
|
|
for(int i = 1; i < m_bars_size; i++)
|
|
{
|
|
m_bars[i].SetMaxAndMinValue();
|
|
if(m_bars[i].BarMaxValue() > m_bar_max.BarMaxValue())
|
|
m_bar_max = m_bars[i];
|
|
if(m_bars[i].BarMinValue() < m_bar_min.BarMinValue())
|
|
m_bar_min = m_bars[i];
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::InitLienzoBarras(int x1, int y1, int x2, int y2, int gap_init, int gap_end, int gap_espacio_entre_barras)
|
|
{
|
|
//--- Chek titulo
|
|
if(HISTOGRAM_IS_NOT_INIT_TITULO)
|
|
{
|
|
LogError("Primero se tuvo que haber seteado el titulo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
|
|
//--- Check Y
|
|
// Nota: El titulo siempre se setea antes de el lienzo siempre
|
|
if(m_titulo.TituloPosition() == HISTOGRAM_TITULO_ARRIBA)
|
|
{
|
|
if(y1 < m_titulo.ReserveY()) // El y1 inicia antes que la altura reservada para el titulo, conflicvto
|
|
{
|
|
LogError("Y1 Del titulo inicia antes de la altura reservada para el titulo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
if(y2 > m_height) // FUERA DE RANGHO
|
|
{
|
|
LogError(StringFormat("Y2[%d] Final mayor a height[%d]", y2, m_height), FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
// A que tener en cuenta que el y2 tambien debe de considerar el espacio para los texto fontsize que se puso al moet o de agregar barras
|
|
// Como es variable no podemos comporarlo
|
|
// En teoria podriamos metere mas comprobaciones para todos los parametros pero creo que no hace falta
|
|
}
|
|
else
|
|
if(m_titulo.TituloPosition() == HISTOGRAM_TITULO_ABAJO)
|
|
{
|
|
const int y2_titulo = m_width - m_titulo.ReserveY();
|
|
if(y2 > y2_titulo) // el y2 (eje y de fin) esta mas adelnta que el y2 del titulo, conflicto
|
|
{
|
|
LogError("Y2 Del linezo mayor al espacio inferior reservado para el titulo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
if(y1 < 1)
|
|
{
|
|
LogError("Y1 Negativo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
// A que tener en cuenta que el y2 tambien debe de considerar el espacio para los texto fontsize que se puso al moet o de agregar barras
|
|
// Como es variable no podemos comporarlo
|
|
}
|
|
|
|
//---
|
|
m_corte_mode = HIST_CORTE_NOT_USE;
|
|
|
|
//---
|
|
m_init_flags |= HIST_FLAG_INIT_DATA;
|
|
|
|
//---
|
|
m_barras_gap_end = gap_end;
|
|
m_barras_gap_init = gap_init;
|
|
m_barras_x1 = x1;
|
|
m_barras_y1 = y1;
|
|
m_barras_espacio_dibujable_height = fabs(y2 - y1);
|
|
m_barras_espacio_dibujable_width = fabs(x2 - x1);
|
|
m_barras_espacio_entre = gap_espacio_entre_barras;
|
|
|
|
//---
|
|
const bool is_h = (m_type == HISTOGRAM_HORIZONTAL);
|
|
|
|
//--- Cordenajda de inicial real
|
|
if(is_h)
|
|
m_barras_cordinate_init = m_barras_x1 + m_barras_gap_init;
|
|
else
|
|
m_barras_cordinate_init = m_barras_y1 + m_barras_gap_init;
|
|
//---
|
|
m_gap_izquierda = x1; // Gap entre el ejey y el "left" de la iamge
|
|
m_gap_derecha = m_width - (m_gap_izquierda + m_barras_espacio_dibujable_width); // Calculamos el gap de la derecha (faltante)
|
|
m_gap_inferior = m_height - y2; // Gap entre el ejex (inf) y el "bottom" de la imagen
|
|
m_gap_superior = y1;
|
|
|
|
//---
|
|
OnSetLienzo();
|
|
|
|
//--- Steamos maximo y minimo
|
|
SetMaxMin();
|
|
|
|
// Este gap es para cubrir el espacio de la liena de crote (para no suporniciones colisiones de pixeles)
|
|
// 1 De la linea de corte
|
|
// 1 liena del eje
|
|
#define HISTOGRAM_GAP_LINE_CORTE 2
|
|
//--- Maximo y minimo
|
|
m_fr_max_value = m_bar_max.BarMaxValue();
|
|
m_fr_min_value = m_bar_min.BarMinValue();
|
|
|
|
//--- Ptp
|
|
const double ptp = m_fr_max_value - m_fr_min_value;
|
|
double fc;
|
|
|
|
//--- Factor de conversion
|
|
if(is_h)
|
|
{
|
|
fc = double(m_barras_max_height - HISTOGRAM_GAP_LINE_CORTE) / ptp;
|
|
m_barras_cordenanda_eje_corte = (m_barras_y1 + m_barras_espacio_dibujable_height); // Y1Real = Corte (no hay separacion)
|
|
}
|
|
else
|
|
{
|
|
fc = double(m_barras_max_width - HISTOGRAM_GAP_LINE_CORTE) / ptp;
|
|
m_barras_cordenanda_eje_corte = m_barras_x1; // X1Real = Corte no hay separacion
|
|
}
|
|
|
|
//--- Set valores
|
|
m_fr_change_value = m_fr_min_value;
|
|
m_factor_conversion_value_to_pixel_neg = fc;
|
|
m_factor_conversion_value_to_pixel_pos = fc;
|
|
|
|
//--- Set funcion de pixel
|
|
m_function_value_to_pixel = HistogramFunctions::ValueToPixelComplete;
|
|
|
|
//--- Si existe una linea de corte
|
|
if(CheckPointer(m_line_corte) == POINTER_DYNAMIC)
|
|
delete m_line_corte;
|
|
m_line_corte = NULL;
|
|
|
|
|
|
//--- Creamos las barras solo pixeles no dibujamos aun (solo actulizamos pixeles)
|
|
InitCordinates();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::InitLienzoBarras(int x1, int y1, int x2, int y2, int gap_init, int gap_end, int gap_espacio_entre_barras, double value_corte_neg, double value_corte_pos)
|
|
{
|
|
//--- Chek titulo
|
|
if(HISTOGRAM_IS_NOT_INIT_TITULO)
|
|
{
|
|
LogError("Primero se tuvo que haber seteado el titulo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
|
|
//--- Check Y
|
|
// Nota: El titulo siempre se setea antes de el lienzo siempre
|
|
if(m_titulo.TituloPosition() == HISTOGRAM_TITULO_ARRIBA)
|
|
{
|
|
if(y1 < m_titulo.ReserveY()) // El y1 inicia antes que la altura reservada para el titulo, conflicvto
|
|
{
|
|
LogError("Y1 Del titulo inicia antes de la altura reservada para el titulo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
if(y2 > m_height) // FUERA DE RANGHO
|
|
{
|
|
LogError(StringFormat("Y2[%d] Final mayor a height[%d]", y2, m_height), FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
// A que tener en cuenta que el y2 tambien debe de considerar el espacio para los texto fontsize que se puso al moet o de agregar barras
|
|
// Como es variable no podemos comporarlo
|
|
// En teoria podriamos metere mas comprobaciones para todos los parametros pero creo que no hace falta
|
|
}
|
|
else
|
|
if(m_titulo.TituloPosition() == HISTOGRAM_TITULO_ABAJO)
|
|
{
|
|
const int y2_titulo = m_width - m_titulo.ReserveY();
|
|
if(y2 > y2_titulo) // el y2 (eje y de fin) esta mas adelnta que el y2 del titulo, conflicto
|
|
{
|
|
LogError("Y2 Del linezo mayor al espacio inferior reservado para el titulo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
if(y1 < 1)
|
|
{
|
|
LogError("Y1 Negativo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
// A que tener en cuenta que el y2 tambien debe de considerar el espacio para los texto fontsize que se puso al moet o de agregar barras
|
|
// Como es variable no podemos comporarlo
|
|
}
|
|
|
|
//---
|
|
m_corte_mode = HIST_CORTE_PERCENT;
|
|
|
|
//---
|
|
m_init_flags |= HIST_FLAG_INIT_DATA;
|
|
|
|
//---
|
|
m_barras_gap_end = gap_end;
|
|
m_barras_gap_init = gap_init;
|
|
m_barras_x1 = x1;
|
|
m_barras_y1 = y1;
|
|
m_barras_espacio_dibujable_height = fabs(y2 - y1);
|
|
m_barras_espacio_dibujable_width = fabs(x2 - x1);
|
|
m_barras_espacio_entre = gap_espacio_entre_barras;
|
|
m_percent_corte_neg = value_corte_neg;
|
|
m_percent_corte_pos = value_corte_pos;
|
|
|
|
//---
|
|
const bool is_h = (m_type == HISTOGRAM_HORIZONTAL);
|
|
|
|
//--- Cordenajda de inicial real
|
|
if(is_h)
|
|
m_barras_cordinate_init = m_barras_x1 + m_barras_gap_init;
|
|
else
|
|
m_barras_cordinate_init = m_barras_y1 + m_barras_gap_init;
|
|
//---
|
|
m_gap_izquierda = x1; // Gap entre el ejey y el "left" de la iamge
|
|
m_gap_derecha = m_width - (m_gap_izquierda + m_barras_espacio_dibujable_width); // Calculamos el gap de la derecha (faltante)
|
|
m_gap_inferior = m_height - y2; // Gap entre el ejex (inf) y el "bottom" de la imagen
|
|
m_gap_superior = y1;
|
|
|
|
//---
|
|
OnSetLienzo();
|
|
|
|
//--- Steamos maximo y minimo
|
|
SetMaxMin();
|
|
|
|
//--- Check corte
|
|
if(m_percent_corte_neg + m_percent_corte_pos != 1.00)
|
|
{
|
|
LogCriticalError("Los percentages decimales deben de sumar 1.00", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
|
|
//--- Maixmo y minimo, y ptp
|
|
m_fr_max_value = m_bar_max.BarMaxValue();
|
|
m_fr_min_value = m_bar_min.BarMinValue();
|
|
const double ptp = m_fr_max_value - m_fr_min_value;
|
|
m_fr_change_value = m_fr_min_value + (ptp * m_percent_corte_neg); // valor de cambio de "neg" a "pos"
|
|
|
|
//--- Funcion de pixel
|
|
m_function_value_to_pixel = HistogramFunctions::ValueToPixelCorte;
|
|
|
|
//--- Si no existe la creamos
|
|
const bool exist_pointer = (CheckPointer(m_line_corte) == POINTER_DYNAMIC);
|
|
|
|
//--- Rangos
|
|
const double range_mayor = m_fr_max_value - m_fr_change_value;
|
|
const double rango_menor = m_fr_change_value - m_fr_min_value;
|
|
|
|
//---
|
|
if(m_type) // Vertical
|
|
{
|
|
int width_disponible_neg = int(m_barras_espacio_dibujable_width * m_percent_corte_neg) - HISTOGRAM_GAP_LINE_CORTE; // Espacio disponible para negativos
|
|
m_factor_conversion_value_to_pixel_neg = double(width_disponible_neg) / rango_menor; // Maximo tamaño de la barra negativa
|
|
|
|
int width_disponible_pos = int(m_barras_espacio_dibujable_width * m_percent_corte_pos) - HISTOGRAM_GAP_LINE_CORTE;
|
|
m_factor_conversion_value_to_pixel_pos = double(width_disponible_pos) / range_mayor; // Maximo tamaño de la barra positiva
|
|
|
|
//--- Calculaos la cordenada de corte (neg -> pos)
|
|
m_barras_cordenanda_eje_corte = m_barras_x1 + width_disponible_neg + HISTOGRAM_GAP_LINE_CORTE;
|
|
|
|
//---
|
|
if(exist_pointer) // Si ya existe existe
|
|
{
|
|
m_line_corte.SetNewValueEjePrincipal(m_barras_cordenanda_eje_corte, true);
|
|
}
|
|
else
|
|
{
|
|
m_line_corte = new CHistogramLineCorteVer();
|
|
m_line_corte.Init(m_canvas);
|
|
int y1 = m_barras_y1 + 1;
|
|
int size_corte = m_barras_espacio_dibujable_height - 2;
|
|
m_line_corte.Set(m_barras_cordenanda_eje_corte, y1, size_corte, 0xFF000000, m_back_color); //negro por defecto
|
|
}
|
|
}
|
|
else // Horizontal
|
|
{
|
|
|
|
int height_disponible_neg = int(m_barras_espacio_dibujable_height * m_percent_corte_neg) - HISTOGRAM_GAP_LINE_CORTE; // Espacio disponible para negativos
|
|
m_factor_conversion_value_to_pixel_neg = double(height_disponible_neg) / rango_menor; // Maximo tamaño de la barra negativa
|
|
|
|
int height_disponible_pos = int(m_barras_espacio_dibujable_height * m_percent_corte_pos) - HISTOGRAM_GAP_LINE_CORTE;
|
|
m_factor_conversion_value_to_pixel_pos = double(height_disponible_pos) / range_mayor; // Maximo tamaño de la barra positiva
|
|
|
|
//--- Calculaos la cordenada de corte (neg -> pos)
|
|
//------------------------------| Y1 (para horizontal) - GAP
|
|
m_barras_cordenanda_eje_corte = (m_barras_y1 + m_barras_espacio_dibujable_height) - (height_disponible_neg + HISTOGRAM_GAP_LINE_CORTE);
|
|
|
|
|
|
//---
|
|
if(exist_pointer) // Si ya existe existe
|
|
{
|
|
m_line_corte.SetNewValueEjePrincipal(m_barras_cordenanda_eje_corte, true);
|
|
}
|
|
else
|
|
{
|
|
m_line_corte = new CHistogramLineCorteHor();
|
|
m_line_corte.Init(m_canvas);
|
|
int x1 = m_barras_x1 + 1;
|
|
int size_corte = m_barras_espacio_dibujable_width - 2;
|
|
m_line_corte.Set(x1, m_barras_cordenanda_eje_corte, size_corte, 0xFF000000, m_back_color);
|
|
}
|
|
}
|
|
|
|
//---
|
|
InitCordinates();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::InitLienzoBarras(int x1, int y1, int x2, int y2, int gap_init, int gap_end, int gap_espacio_entre_barras, double value_corte)
|
|
{
|
|
//--- Chek titulo
|
|
if(HISTOGRAM_IS_NOT_INIT_TITULO)
|
|
{
|
|
LogError("Primero se tuvo que haber seteado el titulo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
|
|
//--- Check Y
|
|
// Nota: El titulo siempre se setea antes de el lienzo siempre
|
|
if(m_titulo.TituloPosition() == HISTOGRAM_TITULO_ARRIBA)
|
|
{
|
|
if(y1 < m_titulo.ReserveY()) // El y1 inicia antes que la altura reservada para el titulo, conflicvto
|
|
{
|
|
LogError("Y1 Del titulo inicia antes de la altura reservada para el titulo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
if(y2 > m_height) // FUERA DE RANGHO
|
|
{
|
|
LogError(StringFormat("Y2[%d] Final mayor a height[%d]", y2, m_height), FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
// A que tener en cuenta que el y2 tambien debe de considerar el espacio para los texto fontsize que se puso al moet o de agregar barras
|
|
// Como es variable no podemos comporarlo
|
|
// En teoria podriamos metere mas comprobaciones para todos los parametros pero creo que no hace falta
|
|
}
|
|
else
|
|
if(m_titulo.TituloPosition() == HISTOGRAM_TITULO_ABAJO)
|
|
{
|
|
const int y2_titulo = m_width - m_titulo.ReserveY();
|
|
if(y2 > y2_titulo) // el y2 (eje y de fin) esta mas adelnta que el y2 del titulo, conflicto
|
|
{
|
|
LogError("Y2 Del linezo mayor al espacio inferior reservado para el titulo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
if(y1 < 1)
|
|
{
|
|
LogError("Y1 Negativo", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
// A que tener en cuenta que el y2 tambien debe de considerar el espacio para los texto fontsize que se puso al moet o de agregar barras
|
|
// Como es variable no podemos comporarlo
|
|
}
|
|
|
|
//---
|
|
//Print("Hola");
|
|
|
|
//---
|
|
m_corte_mode = HIST_CORTE_VALUE;
|
|
|
|
//---
|
|
m_init_flags |= HIST_FLAG_INIT_DATA;
|
|
|
|
//---
|
|
m_barras_gap_end = gap_end;
|
|
m_barras_gap_init = gap_init;
|
|
m_barras_x1 = x1;
|
|
m_barras_y1 = y1;
|
|
m_barras_espacio_dibujable_height = fabs(y2 - y1);
|
|
m_barras_espacio_dibujable_width = fabs(x2 - x1);
|
|
m_barras_espacio_entre = gap_espacio_entre_barras;
|
|
|
|
//---
|
|
const bool is_h = (m_type == HISTOGRAM_HORIZONTAL);
|
|
|
|
//--- Cordenajda de inicial real
|
|
if(is_h)
|
|
m_barras_cordinate_init = m_barras_x1 + m_barras_gap_init;
|
|
else
|
|
m_barras_cordinate_init = m_barras_y1 + m_barras_gap_init;
|
|
//---
|
|
m_gap_izquierda = x1; // Gap entre el ejey y el "left" de la iamge
|
|
m_gap_derecha = m_width - (m_gap_izquierda + m_barras_espacio_dibujable_width); // Calculamos el gap de la derecha (faltante)
|
|
m_gap_inferior = m_height - y2; // Gap entre el ejex (inf) y el "bottom" de la imagen
|
|
m_gap_superior = y1;
|
|
|
|
//--- Steamos valores del lienzo
|
|
OnSetLienzo();
|
|
|
|
//--- Steamos maximo y minimo
|
|
SetMaxMin();
|
|
|
|
//--- Maixmo y minimo, y ptp
|
|
m_fr_max_value = m_bar_max.BarMaxValue();
|
|
m_fr_min_value = m_bar_min.BarMinValue();
|
|
|
|
|
|
//--- Check corte
|
|
if(value_corte < m_fr_min_value || value_corte > m_fr_max_value)
|
|
{
|
|
LogCriticalError("Valor de corte ha superado los limites", FUNCION_ACTUAL);
|
|
Remover();
|
|
return;
|
|
}
|
|
|
|
//--- Ptp y asigancion a valor de cambio
|
|
const double ptp = m_fr_max_value - m_fr_min_value;
|
|
m_fr_change_value = value_corte;
|
|
|
|
//--- Funcion de pixel
|
|
m_function_value_to_pixel = HistogramFunctions::ValueToPixelCorte;
|
|
|
|
//--- Si no existe la creamos
|
|
const bool exist_pointer = (CheckPointer(m_line_corte) == POINTER_DYNAMIC);
|
|
|
|
|
|
|
|
//--- Rangos
|
|
const double range_mayor = m_fr_max_value - m_fr_change_value;
|
|
const double rango_menor = m_fr_change_value - m_fr_min_value;
|
|
|
|
PrintFormat("Rango mayor = %.2f | Rango menos = %.2f", range_mayor, rango_menor);
|
|
|
|
//--- Percentages
|
|
m_percent_corte_neg = rango_menor / ptp;
|
|
m_percent_corte_pos = range_mayor / ptp;
|
|
|
|
//--- Calc
|
|
if(m_type) // Vertical
|
|
{
|
|
int width_disponible_neg = int(m_barras_espacio_dibujable_width * m_percent_corte_neg) - HISTOGRAM_GAP_LINE_CORTE; // Espacio disponible para negativos
|
|
m_factor_conversion_value_to_pixel_neg = double(width_disponible_neg) / rango_menor; // Maximo tamaño de la barra negativa
|
|
|
|
int width_disponible_pos = int(m_barras_espacio_dibujable_width * m_percent_corte_pos) - HISTOGRAM_GAP_LINE_CORTE;
|
|
m_factor_conversion_value_to_pixel_pos = double(width_disponible_pos) / range_mayor; // Maximo tamaño de la barra positiva
|
|
|
|
//--- Calculaos la cordenada de corte (neg -> pos)
|
|
m_barras_cordenanda_eje_corte = m_barras_x1 + width_disponible_neg + HISTOGRAM_GAP_LINE_CORTE;
|
|
|
|
//---
|
|
if(exist_pointer) // Si ya existe existe
|
|
{
|
|
m_line_corte.SetNewValueEjePrincipal(m_barras_cordenanda_eje_corte, true);
|
|
}
|
|
else
|
|
{
|
|
m_line_corte = new CHistogramLineCorteVer();
|
|
m_line_corte.Init(m_canvas);
|
|
int y1 = m_barras_y1 + 1;
|
|
int size_corte = m_barras_espacio_dibujable_height - 2;
|
|
m_line_corte.Set(m_barras_cordenanda_eje_corte, y1, size_corte, 0xFF000000, m_back_color); //negro por defecto
|
|
}
|
|
}
|
|
else // Horizontal
|
|
{
|
|
int height_disponible_neg = int(m_barras_espacio_dibujable_height * m_percent_corte_neg) - HISTOGRAM_GAP_LINE_CORTE; // Espacio disponible para negativos
|
|
m_factor_conversion_value_to_pixel_neg = double(height_disponible_neg) / rango_menor; // Maximo tamaño de la barra negativa
|
|
|
|
int height_disponible_pos = int(m_barras_espacio_dibujable_height * m_percent_corte_pos) - HISTOGRAM_GAP_LINE_CORTE;
|
|
m_factor_conversion_value_to_pixel_pos = double(height_disponible_pos) / range_mayor; // Maximo tamaño de la barra positiva
|
|
|
|
//--- Calculaos la cordenada de corte (neg -> pos)
|
|
//------------------------------| Y1 (para horizontal) - GAP
|
|
m_barras_cordenanda_eje_corte = (m_barras_y1 + m_barras_espacio_dibujable_height) - (height_disponible_neg + HISTOGRAM_GAP_LINE_CORTE);
|
|
|
|
//---
|
|
if(exist_pointer) // Si ya existe existe
|
|
{
|
|
m_line_corte.SetNewValueEjePrincipal(m_barras_cordenanda_eje_corte, true);
|
|
}
|
|
else
|
|
{
|
|
m_line_corte = new CHistogramLineCorteHor();
|
|
m_line_corte.Init(m_canvas);
|
|
int x1 = m_barras_x1 + 1;
|
|
int size_corte = m_barras_espacio_dibujable_width - 2;
|
|
m_line_corte.Set(x1, m_barras_cordenanda_eje_corte, size_corte, 0xFF000000, m_back_color);
|
|
}
|
|
}
|
|
//---
|
|
InitCordinates();
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::RecalculeFactorsMaxMinCorteVal(void)
|
|
{
|
|
m_fr_max_value = m_bar_max.BarMaxValue();
|
|
m_fr_min_value = m_bar_min.BarMinValue();
|
|
const double ptp = m_fr_max_value - m_fr_min_value;
|
|
|
|
//---
|
|
const double range_mayor = m_fr_max_value - m_fr_change_value;
|
|
const double rango_menor = m_fr_change_value - m_fr_min_value;
|
|
|
|
//--- Percentages
|
|
m_percent_corte_neg = rango_menor / ptp;
|
|
m_percent_corte_pos = range_mayor / ptp;
|
|
|
|
//---
|
|
if(m_type) // Vertical
|
|
{
|
|
int width_disponible_neg = int(m_barras_espacio_dibujable_width * m_percent_corte_neg) - HISTOGRAM_GAP_LINE_CORTE; // Espacio disponible para negativos
|
|
m_factor_conversion_value_to_pixel_neg = double(width_disponible_neg) / rango_menor; // Maximo tamaño de la barra negativa
|
|
|
|
int width_disponible_pos = int(m_barras_espacio_dibujable_width * m_percent_corte_pos) - HISTOGRAM_GAP_LINE_CORTE;
|
|
m_factor_conversion_value_to_pixel_pos = double(width_disponible_pos) / range_mayor; // Maximo tamaño de la barra positiva
|
|
|
|
//--- Calculaos la cordenada de corte (neg -> pos)
|
|
m_barras_cordenanda_eje_corte = m_barras_x1 + width_disponible_neg + HISTOGRAM_GAP_LINE_CORTE;
|
|
m_line_corte.CleanLine();
|
|
}
|
|
else // Horizontal
|
|
{
|
|
int height_disponible_neg = int(m_barras_espacio_dibujable_height * m_percent_corte_neg) - HISTOGRAM_GAP_LINE_CORTE; // Espacio disponible para negativos
|
|
m_factor_conversion_value_to_pixel_neg = double(height_disponible_neg) / rango_menor; // Maximo tamaño de la barra negativa
|
|
|
|
int height_disponible_pos = int(m_barras_espacio_dibujable_height * m_percent_corte_pos) - HISTOGRAM_GAP_LINE_CORTE;
|
|
m_factor_conversion_value_to_pixel_pos = double(height_disponible_pos) / range_mayor; // Maximo tamaño de la barra positiva
|
|
|
|
//--- Calculaos la cordenada de corte (neg -> pos)
|
|
//------------------------------| Y1 (para horizontal) - GAP
|
|
m_barras_cordenanda_eje_corte = (m_barras_y1 + m_barras_espacio_dibujable_height) - (height_disponible_neg + HISTOGRAM_GAP_LINE_CORTE);
|
|
m_line_corte.CleanLine();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::RecalculeFactorsMaxMinCortePer(void)
|
|
{
|
|
m_fr_max_value = m_bar_max.BarMaxValue();
|
|
m_fr_min_value = m_bar_min.BarMinValue();
|
|
const double ptp = m_fr_max_value - m_fr_min_value;
|
|
m_fr_change_value = m_fr_min_value + (ptp * m_percent_corte_neg); // valor de cambio de "neg" a "pos"
|
|
|
|
//---
|
|
const double range_mayor = m_fr_max_value - m_fr_change_value;
|
|
const double rango_menor = m_fr_change_value - m_fr_min_value;
|
|
|
|
//---
|
|
if(m_type) // Vertical
|
|
{
|
|
int width_disponible_neg = int(m_barras_espacio_dibujable_width * m_percent_corte_neg) - HISTOGRAM_GAP_LINE_CORTE; // Espacio disponible para negativos
|
|
m_factor_conversion_value_to_pixel_neg = double(width_disponible_neg) / rango_menor; // Maximo tamaño de la barra negativa
|
|
|
|
int width_disponible_pos = int(m_barras_espacio_dibujable_width * m_percent_corte_pos) - HISTOGRAM_GAP_LINE_CORTE;
|
|
m_factor_conversion_value_to_pixel_pos = double(width_disponible_pos) / range_mayor; // Maximo tamaño de la barra positiva
|
|
|
|
//--- Calculaos la cordenada de corte (neg -> pos)
|
|
m_barras_cordenanda_eje_corte = m_barras_x1 + width_disponible_neg + HISTOGRAM_GAP_LINE_CORTE;
|
|
m_line_corte.CleanLine();
|
|
|
|
//---
|
|
// m_line_corte.SetNewValueEjePrincipal(m_barras_cordenanda_eje_corte);
|
|
}
|
|
else // Horizontal
|
|
{
|
|
int height_disponible_neg = int(m_barras_espacio_dibujable_height * m_percent_corte_neg) - HISTOGRAM_GAP_LINE_CORTE; // Espacio disponible para negativos
|
|
m_factor_conversion_value_to_pixel_neg = double(height_disponible_neg) / rango_menor; // Maximo tamaño de la barra negativa
|
|
|
|
int height_disponible_pos = int(m_barras_espacio_dibujable_height * m_percent_corte_pos) - HISTOGRAM_GAP_LINE_CORTE;
|
|
m_factor_conversion_value_to_pixel_pos = double(height_disponible_pos) / range_mayor; // Maximo tamaño de la barra positiva
|
|
|
|
//--- Calculaos la cordenada de corte (neg -> pos)
|
|
//------------------------------| Y1 (para horizontal) - GAP
|
|
m_barras_cordenanda_eje_corte = (m_barras_y1 + m_barras_espacio_dibujable_height) - (height_disponible_neg + HISTOGRAM_GAP_LINE_CORTE);
|
|
m_line_corte.CleanLine();
|
|
//---
|
|
// m_line_corte.SetNewValueEjePrincipal(m_barras_cordenanda_eje_corte);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::RecalculeFactorsMaxMinDef(void)
|
|
{
|
|
m_fr_max_value = m_bar_max.BarMaxValue();
|
|
m_fr_min_value = m_bar_min.BarMinValue();
|
|
|
|
//---
|
|
const double ptp = m_fr_max_value - m_fr_min_value;
|
|
double fc;
|
|
|
|
//---
|
|
if(m_type == HISTOGRAM_HORIZONTAL)
|
|
{
|
|
fc = double(m_barras_max_height - HISTOGRAM_GAP_LINE_CORTE) / ptp;
|
|
m_barras_cordenanda_eje_corte = (m_barras_y1 + m_barras_espacio_dibujable_height); // Y1Real = Corte (no hay separacion)
|
|
}
|
|
else
|
|
{
|
|
fc = double(m_barras_max_width - HISTOGRAM_GAP_LINE_CORTE) / ptp;
|
|
m_barras_cordenanda_eje_corte = m_barras_x1; // X1Real = Corte no hay separacion
|
|
}
|
|
|
|
//---
|
|
m_fr_change_value = m_fr_min_value;
|
|
m_factor_conversion_value_to_pixel_neg = fc;
|
|
m_factor_conversion_value_to_pixel_pos = fc;
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::RecalculeFactorsMaxMin()
|
|
{
|
|
switch(m_corte_mode)
|
|
{
|
|
case HIST_CORTE_NOT_USE:
|
|
RecalculeFactorsMaxMinDef();
|
|
break;
|
|
case HIST_CORTE_PERCENT:
|
|
RecalculeFactorsMaxMinCortePer();
|
|
break;
|
|
case HIST_CORTE_VALUE:
|
|
RecalculeFactorsMaxMinCorteVal();
|
|
break;
|
|
default:
|
|
LogCriticalError("No hay tipo de corte", FUNCION_ACTUAL);
|
|
Remover();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline void CHistogram::Redraw()
|
|
{
|
|
m_canvas.Update(true);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::CreatePartInformativa(ENUM_HISTOGRAM_PARTE_INFORMATIVA_POSICION pos, int xgap_inicial, int ygap_inicial)
|
|
{
|
|
if(HISTOGRAM_IS_INIT_INFORMATIVE)
|
|
return;
|
|
|
|
//---
|
|
m_init_flags |= HIST_FLAG_INIT_PART_INFO;
|
|
m_part_info_ptr = new CHistogramParteInfo();
|
|
m_part_info_position = pos;
|
|
|
|
//---
|
|
int x1, x2, y1, y2;
|
|
|
|
//---
|
|
if(m_part_info_position == HISTOGRAM_PARTE_INF_DERECHA)
|
|
{
|
|
x1 = m_width - m_gap_derecha;
|
|
x2 = m_width;
|
|
}
|
|
else
|
|
{
|
|
x1 = 0;
|
|
x2 = m_gap_izquierda; // Gap izquirdo
|
|
}
|
|
|
|
//---
|
|
y1 = m_gap_superior; // No antes del titulo
|
|
y2 = m_height; // Hasta el final
|
|
|
|
//---
|
|
m_part_info_ptr.Init(m_canvas, x1, y1, x2, y2, xgap_inicial, ygap_inicial);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::CreateCopyright(int x, int y, string txt, uint clr, uint align, int fontsize = 0, string font = NULL, uint flagtext = UINT_MAX, uint textpos = UINT_MAX)
|
|
{
|
|
if(m_copyright != NULL)
|
|
return;
|
|
m_copyright = new CTextCanvas();
|
|
m_copyright.Create(m_canvas, x, y, txt, clr, align, fontsize, font, flagtext, textpos);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CHistogram::CreateCopyrightDefault(const string &autor, string font = "Arial", int fontsize = 15)
|
|
{
|
|
MqlDateTime time;
|
|
TimeToStruct(TimeLocal(), time);
|
|
CreateCopyright(5, 5, StringFormat("© Copyright %d, %s", time.year, autor), ColorToARGB(clrBlack), TA_TOP | TA_LEFT, fontsize, font, 0, 0); // usar valores por defecto
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CHistogram::SavePicture(const string &filename, bool comon)
|
|
{
|
|
const bool res = ResourceSave(m_canvas.ResourceName(), filename);
|
|
|
|
//---
|
|
if(comon)
|
|
{
|
|
if(!FileMove(filename, true, filename, FILE_COMMON | FILE_REWRITE))
|
|
{
|
|
const string local = TerminalInfoString(TERMINAL_DATA_PATH);
|
|
const string common = TerminalInfoString(TERMINAL_COMMONDATA_PATH);
|
|
const string r_l = local + filename;
|
|
const string r_c = common + filename;
|
|
LogError(StringFormat("No se pudo mover el arhcivo %s de:\n%s\na\n%s", filename, r_l, r_c), FUNCION_ACTUAL);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
#endif
|
|
//+------------------------------------------------------------------+
|