//+------------------------------------------------------------------+ //| Dialog.mqh | //| Copyright 2000-2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "WndContainer.mqh" #include "WndClient.mqh" #include "Panel.mqh" #include "Edit.mqh" #include "BmpButton.mqh" #include //+------------------------------------------------------------------+ //| Resources | //+------------------------------------------------------------------+ #resource "res\\Close.bmp" #resource "res\\Restore.bmp" #resource "res\\Turn.bmp" //+------------------------------------------------------------------+ //| Class CDialog | //| Usage: base class to create dialog boxes | //| and indicator panels | //+------------------------------------------------------------------+ class CDialog : public CWndContainer { private: //--- dependent controls CPanel m_white_border; // the "white border" object CPanel m_background; // the background object CEdit m_caption; // the window title object CBmpButton m_button_close; // the "Close" button object CWndClient m_client_area; // the client area object protected: //--- flags bool m_panel_flag; // the "panel in a separate window" flag //--- flags bool m_minimized; // "create in minimized state" flag //--- additional areas CRect m_min_rect; // minimal area coordinates CRect m_norm_rect; // normal area coordinates public: CDialog(void); ~CDialog(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); //--- set up string Caption(void) const { return(m_caption.Text()); } bool Caption(const string text) { return(m_caption.Text(text)); } //--- fill bool Add(CWnd *control); bool Add(CWnd &control); //--- methods for working with files virtual bool Save(const int file_handle); virtual bool Load(const int file_handle); protected: //--- create dependent controls virtual bool CreateWhiteBorder(void); virtual bool CreateBackground(void); virtual bool CreateCaption(void); virtual bool CreateButtonClose(void); virtual bool CreateClientArea(void); //--- handlers of the dependent controls events virtual void OnClickCaption(void); virtual void OnClickButtonClose(void); //--- access properties of caption void CaptionAlignment(const int flags,const int left,const int top,const int right,const int bottom) { m_caption.Alignment(flags,left,top,right,bottom); } //--- access properties of client area bool ClientAreaVisible(const bool visible) { return(m_client_area.Visible(visible)); } int ClientAreaLeft(void) const { return(m_client_area.Left()); } int ClientAreaTop(void) const { return(m_client_area.Top()); } int ClientAreaRight(void) const { return(m_client_area.Right()); } int ClientAreaBottom(void) const { return(m_client_area.Bottom()); } int ClientAreaWidth(void) const { return(m_client_area.Width()); } int ClientAreaHeight(void) const { return(m_client_area.Height()); } //--- handlers of drag virtual bool OnDialogDragStart(void); virtual bool OnDialogDragProcess(void); virtual bool OnDialogDragEnd(void); }; //+------------------------------------------------------------------+ //| Common handler of events | //+------------------------------------------------------------------+ EVENT_MAP_BEGIN(CDialog) ON_EVENT(ON_CLICK,m_button_close,OnClickButtonClose) ON_EVENT(ON_CLICK,m_caption,OnClickCaption) ON_EVENT(ON_DRAG_START,m_caption,OnDialogDragStart) ON_EVENT_PTR(ON_DRAG_PROCESS,m_drag_object,OnDialogDragProcess) ON_EVENT_PTR(ON_DRAG_END,m_drag_object,OnDialogDragEnd) EVENT_MAP_END(CWndContainer) //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CDialog::CDialog(void) : m_panel_flag(false), m_minimized(false) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CDialog::~CDialog(void) { } //+------------------------------------------------------------------+ //| Create a control | //+------------------------------------------------------------------+ bool CDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) { //--- call method of parent class if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2)) return(false); //--- create dependent controls if(!m_panel_flag && !CreateWhiteBorder()) return(false); if(!CreateBackground()) return(false); if(!CreateCaption()) return(false); if(!CreateButtonClose()) return(false); if(!CreateClientArea()) return(false); //--- set up additional areas m_norm_rect.SetBound(m_rect); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Add control to the client area (by pointer) | //+------------------------------------------------------------------+ bool CDialog::Add(CWnd *control) { return(m_client_area.Add(control)); } //+------------------------------------------------------------------+ //| Add control to the client area (by reference) | //+------------------------------------------------------------------+ bool CDialog::Add(CWnd &control) { return(m_client_area.Add(control)); } //+------------------------------------------------------------------+ //| Save | //+------------------------------------------------------------------+ bool CDialog::Save(const int file_handle) { //--- check if(file_handle==INVALID_HANDLE) return(false); //--- save FileWriteStruct(file_handle,m_norm_rect); FileWriteInteger(file_handle,m_min_rect.left); FileWriteInteger(file_handle,m_min_rect.top); FileWriteInteger(file_handle,m_minimized); //--- result return(CWndContainer::Save(file_handle)); } //+------------------------------------------------------------------+ //| Load | //+------------------------------------------------------------------+ bool CDialog::Load(const int file_handle) { if(file_handle==INVALID_HANDLE) return(false); //--- load if(!FileIsEnding(file_handle)) { FileReadStruct(file_handle,m_norm_rect); int left=FileReadInteger(file_handle); int top=FileReadInteger(file_handle); m_min_rect.Move(left,top); m_minimized=FileReadInteger(file_handle); } //--- result return(CWndContainer::Load(file_handle)); } //+------------------------------------------------------------------+ //| Create "white border" | //+------------------------------------------------------------------+ bool CDialog::CreateWhiteBorder(void) { //--- coordinates int x1=0; int y1=0; int x2=Width(); int y2=Height(); //--- create if(!m_white_border.Create(m_chart_id,m_name+"Border",m_subwin,x1,y1,x2,y2)) return(false); if(!m_white_border.ColorBackground(CONTROLS_DIALOG_COLOR_BG)) return(false); if(!m_white_border.ColorBorder(CONTROLS_DIALOG_COLOR_BORDER_LIGHT)) return(false); if(!CWndContainer::Add(m_white_border)) return(false); m_white_border.Alignment(WND_ALIGN_CLIENT,0,0,0,0); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Create background | //+------------------------------------------------------------------+ bool CDialog::CreateBackground(void) { int off=(m_panel_flag) ? 0:CONTROLS_BORDER_WIDTH; //--- coordinates int x1=off; int y1=off; int x2=Width()-off; int y2=Height()-off; //--- create if(!m_background.Create(m_chart_id,m_name+"Back",m_subwin,x1,y1,x2,y2)) return(false); if(!m_background.ColorBackground(CONTROLS_DIALOG_COLOR_BG)) return(false); color border=(m_panel_flag) ? CONTROLS_DIALOG_COLOR_BG : CONTROLS_DIALOG_COLOR_BORDER_DARK; if(!m_background.ColorBorder(border)) return(false); if(!CWndContainer::Add(m_background)) return(false); m_background.Alignment(WND_ALIGN_CLIENT,off,off,off,off); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Create window title | //+------------------------------------------------------------------+ bool CDialog::CreateCaption(void) { int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH; //--- coordinates int x1=off; int y1=off; int x2=Width()-off; int y2=y1+CONTROLS_DIALOG_CAPTION_HEIGHT; //--- create if(!m_caption.Create(m_chart_id,m_name+"Caption",m_subwin,x1,y1,x2,y2)) return(false); if(!m_caption.Color(CONTROLS_DIALOG_COLOR_CAPTION_TEXT)) return(false); if(!m_caption.ColorBackground(CONTROLS_DIALOG_COLOR_BG)) return(false); if(!m_caption.ColorBorder(CONTROLS_DIALOG_COLOR_BG)) return(false); if(!m_caption.ReadOnly(true)) return(false); if(!m_caption.Text(m_name)) return(false); if(!CWndContainer::Add(m_caption)) return(false); m_caption.Alignment(WND_ALIGN_WIDTH,off,0,off,0); if(!m_panel_flag) m_caption.PropFlags(WND_PROP_FLAG_CAN_DRAG); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Create the "Close" button | //+------------------------------------------------------------------+ bool CDialog::CreateButtonClose(void) { int off=(m_panel_flag) ? 0 : 2*CONTROLS_BORDER_WIDTH; //--- coordinates int x1=Width()-off-(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF); int y1=off+CONTROLS_DIALOG_BUTTON_OFF; int x2=x1+CONTROLS_BUTTON_SIZE; int y2=y1+CONTROLS_BUTTON_SIZE; //--- create if(!m_button_close.Create(m_chart_id,m_name+"Close",m_subwin,x1,y1,x2,y2)) return(false); if(!m_button_close.BmpNames("::res\\Close.bmp")) return(false); if(!CWndContainer::Add(m_button_close)) return(false); m_button_close.Alignment(WND_ALIGN_RIGHT,0,0,off+CONTROLS_DIALOG_BUTTON_OFF,0); //--- change caption CaptionAlignment(WND_ALIGN_WIDTH,off,0,off+(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF),0); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Create client area | //+------------------------------------------------------------------+ bool CDialog::CreateClientArea(void) { int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH; //--- coordinates int x1=off+CONTROLS_DIALOG_CLIENT_OFF; int y1=off+CONTROLS_DIALOG_CAPTION_HEIGHT; int x2=Width()-(off+CONTROLS_DIALOG_CLIENT_OFF); int y2=Height()-(off+CONTROLS_DIALOG_CLIENT_OFF); //--- create if(!m_client_area.Create(m_chart_id,m_name+"Client",m_subwin,x1,y1,x2,y2)) return(false); if(!m_client_area.ColorBackground(CONTROLS_DIALOG_COLOR_CLIENT_BG)) return(false); if(!m_client_area.ColorBorder(CONTROLS_DIALOG_COLOR_CLIENT_BORDER)) return(false); CWndContainer::Add(m_client_area); m_client_area.Alignment(WND_ALIGN_CLIENT,x1,y1,x1,x1); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Handler of click on the window title | //+------------------------------------------------------------------+ void CDialog::OnClickCaption(void) { } //+------------------------------------------------------------------+ //| Handler of click on the "Close" button | //+------------------------------------------------------------------+ void CDialog::OnClickButtonClose(void) { Visible(false); } //+------------------------------------------------------------------+ //| Start dragging the dialog box | //+------------------------------------------------------------------+ bool CDialog::OnDialogDragStart(void) { if(m_drag_object==NULL) { m_drag_object=new CDragWnd; if(m_drag_object==NULL) return(false); } //--- calculate coordinates int x1=Left()-CONTROLS_DRAG_SPACING; int y1=Top()-CONTROLS_DRAG_SPACING; int x2=Right()+CONTROLS_DRAG_SPACING; int y2=Bottom()+CONTROLS_DRAG_SPACING; //--- create m_drag_object.Create(m_chart_id,"",m_subwin,x1,y1,x2,y2); m_drag_object.PropFlags(WND_PROP_FLAG_CAN_DRAG); //--- constraints CChart chart; chart.Attach(m_chart_id); m_drag_object.Limits(-CONTROLS_DRAG_SPACING,-CONTROLS_DRAG_SPACING, chart.WidthInPixels()+CONTROLS_DRAG_SPACING, chart.HeightInPixels(m_subwin)+CONTROLS_DRAG_SPACING); chart.Detach(); //--- set mouse params m_drag_object.MouseX(m_caption.MouseX()); m_drag_object.MouseY(m_caption.MouseY()); m_drag_object.MouseFlags(m_caption.MouseFlags()); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Continue dragging the dialog box | //+------------------------------------------------------------------+ bool CDialog::OnDialogDragProcess(void) { //--- checking if(m_drag_object==NULL) return(false); //--- calculate coordinates int x=m_drag_object.Left()+50; int y=m_drag_object.Top()+50; //--- move dialog Move(x,y); //--- succeed return(true); } //+------------------------------------------------------------------+ //| End dragging the dialog box | //+------------------------------------------------------------------+ bool CDialog::OnDialogDragEnd(void) { if(m_drag_object!=NULL) { m_caption.MouseFlags(m_drag_object.MouseFlags()); delete m_drag_object; m_drag_object=NULL; } //--- set up additional areas if(m_minimized) m_min_rect.SetBound(m_rect); else m_norm_rect.SetBound(m_rect); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Class CAppDialog | //| Usage: main dialog box of MQL5 application | //+------------------------------------------------------------------+ class CAppDialog : public CDialog { private: //--- dependent controls CBmpButton m_button_minmax; // the "Minimize/Maximize" button object //--- variables string m_program_name; // name of program string m_instance_id; // unique string ID ENUM_PROGRAM_TYPE m_program_type; // type of program string m_indicator_name; int m_deinit_reason; //--- for mouse int m_subwin_Yoff; // subwindow Y offset CWnd* m_focused_wnd; // pointer to object that has mouse focus CWnd* m_top_wnd; // pointer to object that has priority over mouse events handling protected: CChart m_chart; // object to access chart public: CAppDialog(void); ~CAppDialog(void); //--- main application dialog creation and destroy virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2); virtual void Destroy(const int reason=REASON_PROGRAM); //--- chart event handler virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //--- dialog run bool Run(void); //--- chart events processing void ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //--- set up void Minimized(const bool flag) { m_minimized=flag; } //--- to save/restore state void IniFileSave(void); void IniFileLoad(void); virtual string IniFileName(void) const; virtual string IniFileExt(void) const { return(".dat"); } virtual bool Load(const int file_handle); virtual bool Save(const int file_handle); private: bool CreateCommon(const long chart,const string name,const int subwin); bool CreateExpert(const int x1,const int y1,const int x2,const int y2); bool CreateIndicator(const int x1,const int y1,const int x2,const int y2); protected: //--- create dependent controls virtual bool CreateButtonMinMax(void); //--- handlers of the dependent controls events virtual void OnClickButtonClose(void); virtual void OnClickButtonMinMax(void); //--- external event handlers virtual void OnAnotherApplicationClose(const long &lparam,const double &dparam,const string &sparam); //--- methods virtual bool Rebound(const CRect &rect); virtual void Minimize(void); virtual void Maximize(void); string CreateInstanceId(void); string ProgramName(void) const { return(m_program_name); } void SubwinOff(void); }; //+------------------------------------------------------------------+ //| Common handler of events | //+------------------------------------------------------------------+ EVENT_MAP_BEGIN(CAppDialog) ON_EVENT(ON_CLICK,m_button_minmax,OnClickButtonMinMax) ON_EXTERNAL_EVENT(ON_APP_CLOSE,OnAnotherApplicationClose) EVENT_MAP_END(CDialog) //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CAppDialog::CAppDialog(void) : m_program_type(WRONG_VALUE), m_deinit_reason(WRONG_VALUE), m_subwin_Yoff(0), m_focused_wnd(NULL), m_top_wnd(NULL) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CAppDialog::~CAppDialog(void) { } //+------------------------------------------------------------------+ //| Application dialog initialization function | //+------------------------------------------------------------------+ bool CAppDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) { if(!CreateCommon(chart,name,subwin)) return(false); //--- switch(m_program_type) { case PROGRAM_EXPERT: if(!CreateExpert(x1,y1,x2,y2)) return(false); break; case PROGRAM_INDICATOR: if(!CreateIndicator(x1,y1,x2,y2)) return(false); break; default: Print("CAppDialog: invalid program type"); return(false); } //--- Title of dialog window if(!Caption(m_program_name)) return(false); //--- create dependent controls if(!CreateButtonMinMax()) return(false); //--- get subwindow offset SubwinOff(); //--- if flag is set, minimize the dialog if(m_minimized) Minimize(); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Initialize common area | //+------------------------------------------------------------------+ bool CAppDialog::CreateCommon(const long chart,const string name,const int subwin) { //--- save parameters m_chart_id =chart; m_name =name; m_subwin =subwin; m_program_name =name; m_deinit_reason=WRONG_VALUE; //--- get unique ID m_instance_id=CreateInstanceId(); //--- initialize chart object m_chart.Attach(chart); //--- determine type of program m_program_type=(ENUM_PROGRAM_TYPE)MQLInfoInteger(MQL_PROGRAM_TYPE); //--- specify object and mouse events if(!m_chart.EventObjectCreate() || !m_chart.EventObjectDelete() || !m_chart.EventMouseMove()) { Print("CAppDialog: object events specify error"); m_chart.Detach(); return(false); } //--- succeed return(true); } //+------------------------------------------------------------------+ //| Initialize in Expert Advisor | //+------------------------------------------------------------------+ bool CAppDialog::CreateExpert(const int x1,const int y1,const int x2,const int y2) { //--- EA works only in main window m_subwin=0; //--- geometry for the minimized state m_min_rect.SetBound(CONTROLS_DIALOG_MINIMIZE_LEFT, CONTROLS_DIALOG_MINIMIZE_TOP, CONTROLS_DIALOG_MINIMIZE_LEFT+CONTROLS_DIALOG_MINIMIZE_WIDTH, CONTROLS_DIALOG_MINIMIZE_TOP+CONTROLS_DIALOG_MINIMIZE_HEIGHT); //--- call method of the parent class if(!CDialog::Create(m_chart.ChartId(),m_instance_id,m_subwin,x1,y1,x2,y2)) { Print("CAppDialog: expert dialog create error"); m_chart.Detach(); return(false); } //--- succeed return(true); } //+------------------------------------------------------------------+ //| Initialize in Indicator | //+------------------------------------------------------------------+ bool CAppDialog::CreateIndicator(const int x1,const int y1,const int x2,const int y2) { int width=m_chart.WidthInPixels(); //--- geometry for the minimized state m_min_rect.LeftTop(0,0); m_min_rect.Width(width); m_min_rect.Height(CONTROLS_DIALOG_MINIMIZE_HEIGHT-2*CONTROLS_BORDER_WIDTH); //--- determine subwindow m_subwin=ChartWindowFind(); if(m_subwin==-1) { Print("CAppDialog: find subwindow error"); m_chart.Detach(); return(false); } //--- int total=ChartIndicatorsTotal(m_chart.ChartId(),m_subwin); m_indicator_name=ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1); //--- if subwindow number is 0 (main window), then our program is //--- not an indicator panel, but is an indicator with built-in settings dialog //--- dialog of such an indicator should behave as an Expert Advisor dialog if(m_subwin==0) return(CreateExpert(x1,y1,x2,y2)); //--- if subwindow number is not 0, then our program is an indicator panel //--- check if subwindow is not occupied by other indicators if(total!=1) { Print("CAppDialog: subwindow busy"); ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1)); m_chart.Detach(); return(false); } //--- resize subwindow by dialog height if(!IndicatorSetInteger(INDICATOR_HEIGHT,(y2-y1)+1)) { Print("CAppDialog: subwindow resize error"); ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1)); m_chart.Detach(); return(false); } //--- indicator short name m_indicator_name=m_program_name+IntegerToString(m_subwin); if(!IndicatorSetString(INDICATOR_SHORTNAME,m_indicator_name)) { Print("CAppDialog: shortname error"); ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1)); m_chart.Detach(); return(false); } //--- set flag m_panel_flag=true; //--- call method of the parent class if(!CDialog::Create(m_chart.ChartId(),m_instance_id,m_subwin,0,0,width,y2-y1)) { Print("CAppDialog: indicator dialog create error"); ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1)); m_chart.Detach(); return(false); } //--- succeed return(true); } //+------------------------------------------------------------------+ //| Application dialog deinitialization function | //+------------------------------------------------------------------+ void CAppDialog::Destroy(const int reason) { //--- destroyed already? if(m_deinit_reason!=WRONG_VALUE) return; //--- m_deinit_reason=reason; IniFileSave(); //--- detach chart object from chart m_chart.Detach(); //--- call parent destroy CDialog::Destroy(); //--- if(reason==REASON_PROGRAM) { if(m_program_type==PROGRAM_EXPERT) ExpertRemove(); if(m_program_type==PROGRAM_INDICATOR) ChartIndicatorDelete(m_chart_id,m_subwin,m_indicator_name); } //--- send message EventChartCustom(CONTROLS_SELF_MESSAGE,ON_APP_CLOSE,m_subwin,0.0,m_program_name); } //+------------------------------------------------------------------+ //| Calculate subwindow offset | //+------------------------------------------------------------------+ void CAppDialog::SubwinOff(void) { m_subwin_Yoff=m_chart.SubwindowY(m_subwin); } //+------------------------------------------------------------------+ //| Create the "Minimize/Maximize" button | //+------------------------------------------------------------------+ bool CAppDialog::CreateButtonMinMax(void) { int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH; //--- coordinates int x1=Width()-off-2*(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF); int y1=off+CONTROLS_DIALOG_BUTTON_OFF; int x2=x1+CONTROLS_BUTTON_SIZE; int y2=y1+CONTROLS_BUTTON_SIZE; //--- create if(!m_button_minmax.Create(m_chart_id,m_name+"MinMax",m_subwin,x1,y1,x2,y2)) return(false); if(!m_button_minmax.BmpNames("::res\\Turn.bmp","::res\\Restore.bmp")) return(false); if(!CWndContainer::Add(m_button_minmax)) return(false); m_button_minmax.Locking(true); m_button_minmax.Alignment(WND_ALIGN_RIGHT,0,0,off+CONTROLS_BUTTON_SIZE+2*CONTROLS_DIALOG_BUTTON_OFF,0); //--- change caption CaptionAlignment(WND_ALIGN_WIDTH,off,0,off+2*(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF),0); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Charts event processing | //+------------------------------------------------------------------+ void CAppDialog::ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { int mouse_x=(int)lparam; int mouse_y=(int)dparam-m_subwin_Yoff; //--- separate mouse events from others switch(id) { case CHARTEVENT_CHART_CHANGE: //--- assumed that the CHARTEVENT_CHART_CHANGE event can handle only the application dialog break; case CHARTEVENT_OBJECT_CLICK: //--- we won't handle the CHARTEVENT_OBJECT_CLICK event, as we are working with the CHARTEVENT_MOUSE_MOVE events return; case CHARTEVENT_CUSTOM+ON_MOUSE_FOCUS_SET: //--- the CHARTEVENT_CUSTOM + ON_MOUSE_FOCUS_SET event if(CheckPointer(m_focused_wnd)!=POINTER_INVALID) { //--- if there is an element with focus, try to take its focus away if(!m_focused_wnd.MouseFocusKill(lparam)) return; } m_focused_wnd=ControlFind(lparam); return; case CHARTEVENT_CUSTOM+ON_BRING_TO_TOP: m_top_wnd=ControlFind(lparam); return; case CHARTEVENT_MOUSE_MOVE: //--- the CHARTEVENT_MOUSE_MOVE event if(CheckPointer(m_top_wnd)!=POINTER_INVALID) { //--- if a priority element already exists, pass control to it if(m_top_wnd.OnMouseEvent(mouse_x,mouse_y,(int)StringToInteger(sparam))) { //--- event handled m_chart.Redraw(); return; } } if(OnMouseEvent(mouse_x,mouse_y,(int)StringToInteger(sparam))) m_chart.Redraw(); return; default: //--- call event processing and redraw chart if event handled if(OnEvent(id,lparam,dparam,sparam)) m_chart.Redraw(); return; } //--- if event was not handled, try to handle the CHARTEVENT_CHART_CHANGE event if(id==CHARTEVENT_CHART_CHANGE) { //--- if subwindow number is not 0, and dialog subwindow has changed its number, then restart if(m_subwin!=0 && m_subwin!=ChartWindowFind()) { long fiction=1; OnAnotherApplicationClose(fiction,dparam,sparam); } //--- if subwindow height is less that dialog height, minimize application window (always) if(m_chart.HeightInPixels(m_subwin)CONTROLS_MAXIMUM_ID) { Print("CAppDialog: too many objects"); return(false); } //--- succeed return(true); } //+------------------------------------------------------------------+ //| Stop application | //+------------------------------------------------------------------+ void CAppDialog::OnClickButtonClose(void) { //--- destroy application Destroy(); } //+------------------------------------------------------------------+ //| Handler of click on the "Minimize/Maximize" button | //+------------------------------------------------------------------+ void CAppDialog::OnClickButtonMinMax(void) { if(m_button_minmax.Pressed()) Minimize(); else Maximize(); //--- get subwindow offset SubwinOff(); } //+------------------------------------------------------------------+ //| Resize | //+------------------------------------------------------------------+ bool CAppDialog::Rebound(const CRect &rect) { if(!Move(rect.LeftTop())) return(false); if(!Size(rect.Size())) return(false); //--- resize subwindow if(m_program_type==PROGRAM_INDICATOR && !IndicatorSetInteger(INDICATOR_HEIGHT,rect.Height()+1)) { Print("CAppDialog: subwindow resize error"); return(false); } //--- succeed return(true); } //+------------------------------------------------------------------+ //| Minimize dialog window | //+------------------------------------------------------------------+ void CAppDialog::Minimize(void) { //--- set flag m_minimized=true; //--- resize Rebound(m_min_rect); //--- hide client area ClientAreaVisible(false); } //+------------------------------------------------------------------+ //| Restore dialog window | //+------------------------------------------------------------------+ void CAppDialog::Maximize(void) { //--- reset flag m_minimized=false; //--- resize Rebound(m_norm_rect); //--- show client area ClientAreaVisible(true); } //+------------------------------------------------------------------+ //| Create unique prefix for object names | //+------------------------------------------------------------------+ string CAppDialog::CreateInstanceId(void) { return(IntegerToString(rand(),5,'0')); } //+------------------------------------------------------------------+ //| Handler of the ON_APP_CLOSE external event | //+------------------------------------------------------------------+ void CAppDialog::OnAnotherApplicationClose(const long &lparam,const double &dparam,const string &sparam) { //--- exit if we are in the main window if(m_subwin==0) return; //--- exit if external program was closed in main window if(lparam==0) return; //--- get subwindow offset SubwinOff(); //--- exit if external program was closed in subwindow with greater number if(lparam>=m_subwin) return; //--- after all the checks we must change the subwindow //--- get the new number of subwindow m_subwin=ChartWindowFind(); //--- change short name m_indicator_name=m_program_name+IntegerToString(m_subwin); IndicatorSetString(INDICATOR_SHORTNAME,m_indicator_name); //--- change dialog title Caption(m_program_name); //--- reassign IDs Run(); } //+------------------------------------------------------------------+ //| Save the current state of the program | //+------------------------------------------------------------------+ void CAppDialog::IniFileSave(void) { string filename=IniFileName()+IniFileExt(); int handle=FileOpen(filename,FILE_WRITE|FILE_BIN|FILE_ANSI); //--- if(handle!=INVALID_HANDLE) { Save(handle); FileClose(handle); } } //+------------------------------------------------------------------+ //| Read the previous state of the program | //+------------------------------------------------------------------+ void CAppDialog::IniFileLoad(void) { string filename=IniFileName()+IniFileExt(); int handle=FileOpen(filename,FILE_READ|FILE_BIN|FILE_ANSI); //--- if(handle!=INVALID_HANDLE) { Load(handle); FileClose(handle); } } //+------------------------------------------------------------------+ //| Generate the filename | //+------------------------------------------------------------------+ string CAppDialog::IniFileName(void) const { string name; //--- name=(m_indicator_name!=NULL) ? m_indicator_name : m_program_name; //--- name+="_"+Symbol(); name+="_Ini"; //--- return(name); } //+------------------------------------------------------------------+ //| Load data | //+------------------------------------------------------------------+ bool CAppDialog::Load(const int file_handle) { if(CDialog::Load(file_handle)) { if(m_minimized) { m_button_minmax.Pressed(true); Minimize(); } else { m_button_minmax.Pressed(false); Maximize(); } int prev_deinit_reason=FileReadInteger(file_handle); if(prev_deinit_reason==REASON_CHARTCLOSE || prev_deinit_reason==REASON_CLOSE) { //--- if the previous time program ended after closing the chart window, //--- delete object left since the last start of the program string prev_instance_id=IntegerToString(FileReadInteger(file_handle),5,'0'); if(prev_instance_id!=m_instance_id) { long chart_id=m_chart.ChartId(); int total=ObjectsTotal(chart_id,m_subwin); for(int i=total-1;i>=0;i--) { string obj_name=ObjectName(chart_id,i,m_subwin); if(StringFind(obj_name,prev_instance_id)==0) ObjectDelete(chart_id,obj_name); } } } return(true); } //--- failure return(false); } //+------------------------------------------------------------------+ //| Save data | //+------------------------------------------------------------------+ bool CAppDialog::Save(const int file_handle) { if(CDialog::Save(file_handle)) { FileWriteInteger(file_handle,m_deinit_reason); FileWriteInteger(file_handle,(int)StringToInteger(m_instance_id)); return(true); } //--- failure return(false); } //+------------------------------------------------------------------+