286 lines
No EOL
11 KiB
MQL5
286 lines
No EOL
11 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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 (y<m_y) { m_y0+=m_ndy; y=m_y0+m_y+5+ypos*m_ndy; }// подвинули вниз
|
|
while (y>m_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 (y<m_y) up++; else dn++;
|
|
}
|
|
|
|
if (!root.m_expand) return; // если не раскрыт, то пропускаем
|
|
for (int i=0; i<ArraySize(root.m_next); i++)
|
|
{
|
|
if (NIL(root.m_next[i])) continue;
|
|
ypos++; // увеличили положение
|
|
DrawTree(root.m_next[i], xpos+1, ypos, up, dn); // отрисовали следующую ветку
|
|
}
|
|
}
|
|
//------------------------------------------------------------------ DrawNode
|
|
void CTreeView::DrawNode(CNode *node, int x, int y)
|
|
{
|
|
if (NIL(node)) return;
|
|
string name=m_name+string(node.m_id);
|
|
string txt=node.m_text;
|
|
StringTrimLeft(node.m_desc); // подчистили строку слева
|
|
if (m_bDesc && node.m_desc!="") txt+=" | "+node.m_desc; //если надо выводить описание
|
|
// определяем цвет
|
|
color clr=node.m_select ? m_selclr : m_clr;
|
|
if (node.m_break) clr=clrRed;
|
|
|
|
// выводим текст для узла
|
|
SetLabel(m_chart, name+".lbl", m_wnd, txt, clr, x+m_ndx, y-1, m_corn, m_fontsize, m_font);
|
|
|
|
// отметка узла
|
|
string state;
|
|
if (!node.m_break)
|
|
{
|
|
state=node.m_check ? CharToString(110) : CharToString(112);
|
|
SetLabel(m_chart, name+".chk", m_wnd, state, clr, x+m_ndx-m_bdx, y, m_corn, m_fontsize, "Wingdings");
|
|
}
|
|
else ObjectDelete(m_chart, name+".chk");
|
|
|
|
// кнопку раскрытости узла
|
|
state=node.m_expand ? "-" : "+";
|
|
if (ArraySize(node.m_next)>0)
|
|
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<ArraySize(root.m_next); i++)
|
|
if (!NIL(root.m_next[i])) DeleteView(root.m_next[i], true);
|
|
} |