| //+------------------------------------------------------------------+
|
| //| DateDropList.mqh |
|
| //| Copyright 2000-2025, MetaQuotes Ltd. |
|
| //| https://www.mql5.com |
|
| //+------------------------------------------------------------------+
|
| #include "WndContainer.mqh"
|
| #include "BmpButton.mqh"
|
| #include "Picture.mqh"
|
| #include <Canvas\Canvas.mqh>
|
| #include <Tools\DateTime.mqh>
|
| //+------------------------------------------------------------------+
|
| //| Enumerations |
|
| //+------------------------------------------------------------------+
|
| //--- date modes
|
| enum ENUM_DATE_MODES
|
| {
|
| DATE_MODE_MON, // month mode
|
| DATE_MODE_YEAR // year mode
|
| };
|
| //+------------------------------------------------------------------+
|
| //| Resources |
|
| //+------------------------------------------------------------------+
|
| //--- Can not place the same file into resource twice
|
| #resource "res\\LeftTransp.bmp"
|
| #resource "res\\RightTransp.bmp"
|
| //+------------------------------------------------------------------+
|
| //| Class CDateDropList |
|
| //| Usage: drop-down list |
|
| //+------------------------------------------------------------------+
|
| class CDateDropList : public CWndContainer
|
| {
|
| private:
|
| //--- dependent controls
|
| CBmpButton m_dec; // the button object
|
| CBmpButton m_inc; // the button object
|
| CPicture m_list; // the drop-down list object
|
| CCanvas m_canvas; // and its canvas
|
| //--- data
|
| CDateTime m_value; // current value
|
| //--- variable
|
| ENUM_DATE_MODES m_mode; // operation mode
|
| CRect m_click_rect[32]; // array of click sensibility areas on canvas
|
|
|
| public:
|
| CDateDropList(void);
|
| ~CDateDropList(void);
|
| //--- create
|
| virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
| //--- chart event handler
|
| virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
| //--- data
|
| datetime Value(void) { return(StructToTime(m_value)); }
|
| void Value(datetime value) { m_value.Date(value); }
|
| void Value(MqlDateTime& value) { m_value=value; }
|
| //--- state
|
| virtual bool Show(void);
|
|
|
| protected:
|
| //--- internal event handlers
|
| virtual bool OnClick(void);
|
| //--- create dependent controls
|
| virtual bool CreateButtons(void);
|
| virtual bool CreateList(void);
|
| //--- draw
|
| void DrawCanvas(void);
|
| void DrawClickRect(const int idx,int x,int y,string text,const uint clr,uint alignment=0);
|
| //--- handlers of the dependent controls events
|
| virtual bool OnClickDec(void);
|
| virtual bool OnClickInc(void);
|
| virtual bool OnClickList(void);
|
| };
|
| //+------------------------------------------------------------------+
|
| //| Common handler of chart events |
|
| //+------------------------------------------------------------------+
|
| EVENT_MAP_BEGIN(CDateDropList)
|
| ON_EVENT(ON_CLICK,m_dec,OnClickDec)
|
| ON_EVENT(ON_CLICK,m_inc,OnClickInc)
|
| ON_EVENT(ON_CLICK,m_list,OnClickList)
|
| EVENT_MAP_END(CWndContainer)
|
| //+------------------------------------------------------------------+
|
| //| Constructor |
|
| //+------------------------------------------------------------------+
|
| CDateDropList::CDateDropList(void) : m_mode(DATE_MODE_MON)
|
| {
|
| ZeroMemory(m_value);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Destructor |
|
| //+------------------------------------------------------------------+
|
| CDateDropList::~CDateDropList(void)
|
| {
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Create a control |
|
| //+------------------------------------------------------------------+
|
| bool CDateDropList::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
| {
|
| //--- need to find dimensions depending on font size
|
| //--- width 7 columns + 2 offsets
|
| int w=7*(2*CONTROLS_FONT_SIZE)+2*CONTROLS_FONT_SIZE;
|
| //--- header height + 7 rows
|
| int h=(CONTROLS_BUTTON_SIZE+4*CONTROLS_BORDER_WIDTH)+7*(2*CONTROLS_FONT_SIZE);
|
| //--- call method of the parent class
|
| if(!CWndContainer::Create(chart,name,subwin,x1,y1,x1+w,y1+h))
|
| return(false);
|
| //--- create dependent controls
|
| if(!CreateList())
|
| return(false);
|
| if(!CreateButtons())
|
| return(false);
|
| //--- succeeded
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Create drop-down list |
|
| //+------------------------------------------------------------------+
|
| bool CDateDropList::CreateList(void)
|
| {
|
| //--- create object
|
| if(!m_list.Create(m_chart_id,m_name+"List",m_subwin,0,0,Width(),Height()))
|
| return(false);
|
| if(!Add(m_list))
|
| return(false);
|
| //--- create canvas
|
| if(!m_canvas.Create(m_name,Width(),Height()))
|
| return(false);
|
| m_canvas.FontSet(CONTROLS_FONT_NAME,CONTROLS_FONT_SIZE*(-10));
|
| m_list.BmpName(m_canvas.ResourceName());
|
| //--- succeeded
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Create buttons |
|
| //+------------------------------------------------------------------+
|
| bool CDateDropList::CreateButtons(void)
|
| {
|
| //--- right align button (try to make equal offsets from top and bottom)
|
| int x1=2*CONTROLS_BORDER_WIDTH;
|
| int y1=2*CONTROLS_BORDER_WIDTH;
|
| int x2=x1+CONTROLS_BUTTON_SIZE;
|
| int y2=y1+CONTROLS_BUTTON_SIZE;
|
| //--- create "Dec" button
|
| if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
|
| return(false);
|
| if(!m_dec.BmpNames("::res\\LeftTransp.bmp"))
|
| return(false);
|
| if(!Add(m_dec))
|
| return(false);
|
| //---
|
| x2=Width()-2*CONTROLS_BORDER_WIDTH;
|
| x1=x2-CONTROLS_BUTTON_SIZE;
|
| //--- create "Inc" button
|
| if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
|
| return(false);
|
| if(!m_inc.BmpNames("::res\\RightTransp.bmp"))
|
| return(false);
|
| if(!Add(m_inc))
|
| return(false);
|
| //--- succeeded
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Makes the control visible |
|
| //+------------------------------------------------------------------+
|
| bool CDateDropList::Show(void)
|
| {
|
| //--- draw canvas
|
| DrawCanvas();
|
| //--- call method of the parent class
|
| return(CWndContainer::Show());
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Handler of click on button |
|
| //+------------------------------------------------------------------+
|
| bool CDateDropList::OnClickDec(void)
|
| {
|
| switch(m_mode)
|
| {
|
| //--- within the month
|
| case DATE_MODE_MON:
|
| m_value.MonDec();
|
| break;
|
| //--- within the year
|
| case DATE_MODE_YEAR:
|
| m_value.YearDec();
|
| break;
|
| }
|
| DrawCanvas();
|
| //--- handled
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Handler of click on button |
|
| //+------------------------------------------------------------------+
|
| bool CDateDropList::OnClickInc(void)
|
| {
|
| switch(m_mode)
|
| {
|
| //--- within the month
|
| case DATE_MODE_MON:
|
| m_value.MonInc();
|
| break;
|
| //--- within the year
|
| case DATE_MODE_YEAR:
|
| m_value.YearInc();
|
| break;
|
| }
|
| DrawCanvas();
|
| //--- handled
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Handler of click on picture |
|
| //+------------------------------------------------------------------+
|
| bool CDateDropList::OnClickList(void)
|
| {
|
| m_mouse_x=m_list.MouseX();
|
| m_mouse_y=m_list.MouseY();
|
| //---
|
| OnClick();
|
| //---
|
| m_mouse_x=0;
|
| m_mouse_y=0;
|
| //--- handled
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Handler of the "click" event |
|
| //+------------------------------------------------------------------+
|
| bool CDateDropList::OnClick(void)
|
| {
|
| for(int i=0;i<32;i++)
|
| {
|
| if(m_click_rect[i].Contains(m_mouse_x,m_mouse_y))
|
| {
|
| if(i==0)
|
| {
|
| //--- clicked on the header
|
| switch(m_mode)
|
| {
|
| //--- within the month
|
| case DATE_MODE_MON:
|
| //--- switch to the "within the year" mode
|
| m_mode=DATE_MODE_YEAR;
|
| DrawCanvas();
|
| break;
|
| //--- within the year
|
| case DATE_MODE_YEAR:
|
| //--- do nothing for now
|
| break;
|
| }
|
| }
|
| else
|
| {
|
| //--- selected
|
| switch(m_mode)
|
| {
|
| //--- within the month
|
| case DATE_MODE_MON:
|
| m_value.Day(i);
|
| Hide();
|
| //--- send notification
|
| EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
|
| break;
|
| //--- within the year
|
| case DATE_MODE_YEAR:
|
| m_value.Mon(i);
|
| m_mode=DATE_MODE_MON;
|
| DrawCanvas();
|
| break;
|
| default:
|
| break;
|
| }
|
| }
|
| break;
|
| }
|
| }
|
| //--- handled
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Draw canvas |
|
| //+------------------------------------------------------------------+
|
| void CDateDropList::DrawCanvas(void)
|
| {
|
| int x,y;
|
| int dx,dy;
|
| string text;
|
| uint text_al=TA_CENTER|TA_VCENTER;
|
| CDateTime tmp_date;
|
| int rows,cols;
|
| int idx;
|
| //--- zero out array of areas
|
| for(int i=0;i<32;i++)
|
| ZeroMemory(m_click_rect[i]);
|
| //---
|
| m_canvas.Erase(COLOR2RGB(CONTROLS_EDIT_COLOR_BG));
|
| m_canvas.Rectangle(0,0,Width()-1,Height()-1,COLOR2RGB(CONTROLS_EDIT_COLOR_BORDER));
|
| x=Width()/2;
|
| y=CONTROLS_BUTTON_SIZE/2+2*CONTROLS_BORDER_WIDTH;
|
| switch(m_mode)
|
| {
|
| //--- within the month
|
| case DATE_MODE_MON:
|
| text=m_value.MonthName()+" "+IntegerToString(m_value.year);
|
| DrawClickRect(0,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
|
| rows=6;
|
| cols=7;
|
| x=dx=Width()/(cols+1);
|
| y+=y;
|
| dy=(Height()-y-2*CONTROLS_BORDER_WIDTH)/(rows+1);
|
| y+=dy/2;
|
| for(int i=0;i<cols;i++,x+=dx)
|
| m_canvas.TextOut(x,y,m_value.ShortDayName(i),COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
|
| //--- backup data
|
| tmp_date=m_value;
|
| //--- find the beginning of the first displayed week
|
| tmp_date.DayDec(tmp_date.day_of_week);
|
| while(tmp_date.mon==m_value.mon && tmp_date.day!=1)
|
| tmp_date.DayDec(cols);
|
| //--- draw
|
| idx=1;
|
| y+=dy;
|
| for(int i=0;i<rows;i++,y+=dy)
|
| {
|
| x=dx;
|
| for(int j=0;j<cols;j++,x+=dx)
|
| {
|
| text=IntegerToString(tmp_date.day);
|
| if(tmp_date.mon==m_value.mon)
|
| {
|
| if(tmp_date.day==m_value.day)
|
| m_canvas.FillRectangle(x-dx/2,y-dy/2,x+dx/2,y+dy/2,COLOR2RGB(CONTROLS_COLOR_BG_SEL));
|
| DrawClickRect(idx++,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
|
| }
|
| else
|
| m_canvas.TextOut(x,y,text,COLOR2RGB(CONTROLS_BUTTON_COLOR_BORDER),text_al);
|
| tmp_date.DayInc();
|
| }
|
| }
|
| break;
|
| //--- within the year
|
| case DATE_MODE_YEAR:
|
| text=IntegerToString(m_value.year);
|
| DrawClickRect(0,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
|
| rows=3;
|
| cols=4;
|
| x=dx=Width()/(cols+1);
|
| y+=y;
|
| dy=(Height()-y)/rows;
|
| y+=dy/2;
|
| for(int i=0;i<rows*cols;i++)
|
| {
|
| if(i+1==m_value.mon)
|
| m_canvas.FillRectangle(x-dx/2,y-dy/4,x+dx/2,y+dy/4,COLOR2RGB(CONTROLS_COLOR_BG_SEL));
|
| DrawClickRect(i+1,x,y,m_value.ShortMonthName(i+1),COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
|
| if(i%cols==cols-1)
|
| {
|
| x=dx;
|
| y+=dy;
|
| }
|
| else
|
| x+=dx;
|
| }
|
| break;
|
| default:
|
| break;
|
| }
|
| m_canvas.Update();
|
| }
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| void CDateDropList::DrawClickRect(const int idx,int x,int y,string text,const uint clr,uint alignment)
|
| {
|
| int text_w,text_h;
|
| //--- display the text
|
| m_canvas.TextOut(x,y,text,clr,alignment);
|
| //--- determine area occupied by text
|
| m_canvas.TextSize(text,text_w,text_h);
|
| //--- convert relative coordinated to absolute ones
|
| x+=Left();
|
| y+=Top();
|
| //--- check flags of horizontal alignment
|
| switch(alignment&(TA_LEFT|TA_CENTER|TA_RIGHT))
|
| {
|
| case TA_LEFT:
|
| m_click_rect[idx].left=x;
|
| break;
|
| case TA_CENTER:
|
| m_click_rect[idx].left=x-text_w/2;
|
| break;
|
| case TA_RIGHT:
|
| m_click_rect[idx].left=x-text_w;
|
| break;
|
| }
|
| m_click_rect[idx].Width(text_w);
|
| //--- check flags of vertical alignment
|
| switch(alignment&(TA_TOP|TA_VCENTER|TA_BOTTOM))
|
| {
|
| case TA_TOP:
|
| m_click_rect[idx].top=y;
|
| break;
|
| case TA_VCENTER:
|
| m_click_rect[idx].top=y-text_h/2;
|
| break;
|
| case TA_BOTTOM:
|
| m_click_rect[idx].top=y-text_h;
|
| break;
|
| }
|
| m_click_rect[idx].Height(text_h);
|
| }
|
| //+------------------------------------------------------------------+
|