//+------------------------------------------------------------------+ //| TreeView | //| Copyright 2006-2011, www.FXmaster.de | //| www.FXmaster.de | //+------------------------------------------------------------------+ #property copyright "Copyright 2006-2011, www.FXmaster.de" #property link "www.FXmaster.de" #property version "1.00" #include "View.mqh" #include "ScrollView.mqh" #include "..\Tree.mqh" #define BTN_CLEAR 0 #define BTN_COLLAPS 1 #define BTN_RESET 2 #define BTN_EXPAND 3 #define BTN_OPEN 4 #define BTN_SHOW 5 #define BTN_LABEL 6 #define BTN_CHECK 7 #define BTN_SCROLL 8 #define BTN_DESCRIPT 9 #define BTN_BREAK 10 //------------------------------------------------------------------ class CTreeView class CTreeView: public CView { //--- базовые функции public: CTreeView(); // конструктор ~CTreeView(); // деструктор virtual void Create(long chart, string name, int wnd, color clr, color bgclr, color selclr, int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Arial"); //--- функции обработки состояния public: CTreeCtrl *m_tree; // указатель на объект дерева для отображения int m_sid; // последний выделенный объект (для подсветки) virtual int OnClick(string name); // обработка события клика на объекте //--- функции отображения public: int m_ndx, m_ndy; // размер отступов от кнопки для отрисовки int m_bdx, m_bdy; // размер кнопки узлов CScrollView m_scroll; bool m_bDesc; // показывать описание рядом с узлом virtual void Draw(); // обновить вид virtual void DrawTree(CNode *first, int xpos, int &ypos, int &up, int &dn); // перерисовать virtual void DrawNode(CNode *node, int x, int y); // отрисовать узел virtual void DeleteView(CNode *root=NULL, bool delparent=true); // удалить все элементы отображения, начиная с заданного узла }; //------------------------------------------------------------------ CTreeView void CTreeView::CTreeView() { m_bdx=12; m_bdy=12; // размер кнопки узлов m_ndx=m_bdx+17; m_ndy=14; // размер отступов от кнопки m_sid=0; m_bDesc=false; } //------------------------------------------------------------------ ~CTreeView void CTreeView::~CTreeView() { ObjectDelete(m_chart, m_name); ObjectDelete(m_chart, m_name+".collaps"); ObjectDelete(m_chart, m_name+".expand"); ObjectDelete(m_chart, m_name+".clear"); ObjectDelete(m_chart, m_name+".reset"); ObjectDelete(m_chart, m_name+".desc"); DeleteView(); m_scroll.DeleteView(); } //------------------------------------------------------------------ Create void CTreeView::Create(long achart, string name, int wnd, color clr, color bgclr, color selclr, int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Arial") { CView::Create(achart, name, wnd, clr, bgclr, selclr, x, y, dx, dy, corn, fontsize, font); x=m_x+m_dx-20; dx=16; y=m_y+2*m_bdy; dy=m_dy-3*m_bdy; m_scroll.Create(m_chart, m_name+".scroll", m_wnd, m_selclr, m_bgclr, m_bgclr, x, y, dx, dy, m_corn, m_fontsize); m_scroll.m_dir=SV_VDIR; OnClick(m_name+string(m_sid)+".lbl"); } //------------------------------------------------------------------ OnClick int CTreeView::OnClick(string name) // имя объекта на который кликнули { int start=StringLen(m_name); int len=StringFind(name, ".")-start; int id=(int)StringToInteger(StringSubstr(name, start, len)); if (StringFind(name, ".clear")>=0) { DeleteView(); m_tree.Clear(); Draw(); ObjectSetInteger(m_chart, name, OBJPROP_STATE, false); return(BTN_CLEAR); } else if (StringFind(name, ".reset")>=0) { m_tree.Reset(); Draw(); ObjectSetInteger(m_chart, name, OBJPROP_STATE, false); return(BTN_RESET); } else if (StringFind(name, ".collaps")>=0) { DeleteView(); m_tree.ExpandBy(TG_ALL, NULL, false); Draw(); ObjectSetInteger(m_chart, name, OBJPROP_STATE, false); return(BTN_COLLAPS); } else if (StringFind(name, ".expand")>=0) { m_tree.ExpandBy(TG_ALL, NULL, true); Draw(); ObjectSetInteger(m_chart, name, OBJPROP_STATE, false); return(BTN_EXPAND); } else if (StringFind(name, ".desc")>=0) { m_bDesc=!m_bDesc; return(BTN_DESCRIPT); } else if (StringFind(name, ".break")>=0) { m_tree.m_bBreak=ObjectGetInteger(m_chart, name, OBJPROP_STATE); return(BTN_BREAK); } else if (StringFind(name, ".btn")>=0) // если кнопка { m_tree.ExpandIt(id, !m_tree.IsExpand(id)); // сменили состояние CNode *node=m_tree.FindNode(id); if (NIL(node)) return(0); // если ошибка взятия узла DeleteView(node); // удалили все объекты от этого узла Draw(); // отрисовали снова return(BTN_SHOW); } else if (StringFind(name, ".lbl")>=0) // если клик на элементе дерева { m_tree.SelectBy(TG_ALL, NULL, false);// если нет предыдущего то гасим все m_tree.CheckBy(TG_ALL, NULL, false); if (m_sid>=0) // иначе только один { ObjectSetInteger(m_chart, m_name+string(m_sid)+".lbl", OBJPROP_COLOR, m_clr); ObjectSetInteger(m_chart, m_name+string(m_sid)+".chk", OBJPROP_COLOR, m_clr); if (m_tree.IsCheck(m_sid)) m_tree.CheckIt(m_sid, false); if (m_tree.IsSelect(m_sid)) m_tree.SelectIt(m_sid, false); } // и выделяем один новый m_sid=id; // запоминаем ObjectSetInteger(m_chart, m_name+string(m_sid)+".lbl", OBJPROP_COLOR, m_selclr); ObjectSetInteger(m_chart, m_name+string(m_sid)+".chk", OBJPROP_COLOR, m_selclr); m_tree.CheckIt(m_sid, true); m_tree.SelectIt(m_sid, true); Draw(); // отрисовали снова return(BTN_LABEL); } else if (StringFind(name, ".chk")>=0) // если клик на элементе выбора { m_tree.SelectBy(TG_ALL, NULL, false);// если нет предыдущего то гасим все m_tree.CheckBy(TG_ALL, NULL, false); if (m_sid>=0) if (m_tree.IsCheck(m_sid)) m_tree.CheckIt(m_sid, false); // сменили состояние m_sid=id; // сменили выделение m_tree.CheckIt(m_sid, true); // сменили состояние Draw(); // отрисовали снова return(BTN_CHECK); } else if (StringFind(name, ".scroll")>=0) { int s=m_scroll.OnClick(name); // передали дальше if (s!=0) { m_y0=(int)-m_scroll.m_value*m_ndy; Draw(); } // отрисовали, если было обновление return(BTN_SCROLL); } return(-1); } //------------------------------------------------------------------ Draw void CTreeView::Draw() { if (!IsOpenView()) return; // если не создан просмотр, то выходим SetRectLbl(m_chart, m_name+".rect", m_wnd, "", m_clr, m_bgclr, m_x, m_y, m_dx, m_dy, m_corn, m_fontsize, m_font, true); int ax=int(m_x+m_dx-1.5*m_bdx); int adx=int(1.2*m_bdx); int i=-1; i++; SetButton(m_chart, m_name+".collaps", 0, "-", m_bgclr, m_selclr, ax-i*adx, int(m_y+0.5*m_bdy), m_bdx, m_bdy, 0, 7, "Tahoma", false); i++; SetButton(m_chart, m_name+".expand", 0, "+", m_bgclr, m_selclr, ax-i*adx, int(m_y+0.5*m_bdy), m_bdx, m_bdy, 0, 7, "Tahoma", false); if (m_tree.m_mode==1) { i++; SetButton(m_chart, m_name+".clear", 0, "X", m_bgclr, m_selclr, ax-i*adx, int(m_y+0.5*m_bdy), m_bdx, m_bdy, 0, 7, "Tahoma", false); i++; SetButton(m_chart, m_name+".reset", 0, "0", m_bgclr, m_selclr, ax-i*adx, int(m_y+0.5*m_bdy), m_bdx, m_bdy, 0, 7, "Tahoma", false); i++; SetButton(m_chart, m_name+".desc", 0, "i", m_bgclr, clrDarkOliveGreen, ax-i*adx, int(m_y+0.5*m_bdy), m_bdx, m_bdy, 0, 7, "Tahoma", m_bDesc); i++; SetButton(m_chart, m_name+".break", 0, "D", m_bgclr, clrRed, ax-i*adx, int(m_y+0.5*m_bdy), m_bdx, m_bdy, 0, 7, "Tahoma", m_tree.m_bBreak); } int show=0, up=0, dn=0; DrawTree(m_tree.m_root, 1, show, up, dn); // нарисовали дерево if (up<=0 && dn<=0) m_scroll.DeleteView(); // убрали полосу прокрутки для перерисовки else { m_scroll.m_max=up+dn; m_scroll.m_value=up; m_scroll.m_x=m_x+m_dx-20; m_scroll.m_dx=16; m_scroll.m_y=m_y+2*m_bdy; m_scroll.m_dy=m_dy-3*m_bdy+8; m_scroll.Draw(); // отрисовали полосу прокрутки } } //------------------------------------------------------------------ DrawTree void CTreeView::DrawTree(CNode *root, int xpos, int &ypos, int &up, int &dn) { if (xpos==1) { root=m_tree.m_root; ypos=0; } // если начали с первого элемента, то берем корень и левое положение if (root==NULL) { root=m_tree.m_root; xpos=1; } // если не указан первый узел, то берем корень и верхнее положение if (NIL(root)) return; // правильность указателя string name=m_name+string(root.m_id); if (!IsOpenView()) return; // если не создан просмотр, то выходим int x=m_x0+m_x+5+(xpos-1)*m_bdx; int y=m_y0+m_y+5+ypos*m_ndy; bool ishide=(y<=m_y || y>=m_y+m_dy-m_ndy); if (root.m_break && ishide) { while (ym_y+m_dy-m_ndy) { m_y0-=m_ndy; y=m_y0+m_y+5+ypos*m_ndy; }// подвинули вверх up=0; dn=0; DrawTree(m_tree.m_root, 1, ypos, up, dn); // отрисовали снова все дерево } if (!ishide) DrawNode(root, x, y); // если не уходит за область видимости else { ObjectDelete(m_chart, name+".lbl"); ObjectDelete(m_chart, name+".btn"); ObjectDelete(m_chart, name+".chk"); ObjectDelete(m_chart, name+".dbg"); if (y0) SetButton(m_chart, name+".btn", m_wnd, state, m_clr, m_bgclr, x, y, m_bdx, m_bdy, m_corn, m_fontsize, m_font, node.m_expand); else ObjectDelete(m_chart, name+".btn"); // кнопка дебага (её имя принадлежит всему дереву, так как она одна) if (node.m_break) SetButton(m_chart, name+".dbg", m_wnd, "*", clr, clr, x+m_ndx-m_bdx-2, y, m_bdx, m_bdy, m_corn, m_fontsize, m_font, false); else ObjectDelete(m_chart, name+".dbg"); } //------------------------------------------------------------------ DeleteView void CTreeView::DeleteView(CNode *root=NULL, bool delparent=true) { CView::DeleteView(); // метод базового if (root==NULL) root=m_tree.m_root; if (NIL(root)) return; if(delparent) // удаляем узел родителя { string name=m_name+string(root.m_id); ObjectDelete(m_chart, name+".btn"); ObjectDelete(m_chart, name+".lbl"); ObjectDelete(m_chart, name+".chk"); } for (int i=0; i