From b616e1b926e8e2870ec2515a83e2e21736d2d328 Mon Sep 17 00:00:00 2001 From: guy Date: Wed, 12 Dec 2007 16:37:46 +0000 Subject: [PATCH] Patch level : 4.0 Files correlati : Ricompilazione Demo : [ ] Commento : Aggiunta gestione alberi git-svn-id: svn://10.65.10.50/trunk@15862 c028cbd2-c16b-5b4b-a496-9718f37d4682 --- include/treectrl.cpp | 1034 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1034 insertions(+) create mode 100755 include/treectrl.cpp diff --git a/include/treectrl.cpp b/include/treectrl.cpp new file mode 100755 index 000000000..c3c4fbd4d --- /dev/null +++ b/include/treectrl.cpp @@ -0,0 +1,1034 @@ +#include +#include +#include +#include + +#ifdef AGA_TREE + +/////////////////////////////////////////////////////////// +// TNode_info +/////////////////////////////////////////////////////////// + +class TNode_info : public TSortable +{ +public: + bool _valid : 1; + bool _enabled : 1; + bool _expandable : 1; + bool _expanded : 1; + TString _id; + long _plusx; + long _startx; + long _endx; + + const TNode_info& operator =(const TNode_info& ni) + { + _valid = ni._valid; + _enabled = ni._enabled; + _expanded = ni._expanded; + _expandable = ni._expandable; + _id = ni._id; + _plusx = ni._plusx; + _startx = ni._startx; + _endx = ni._endx; + return ni; + } + + virtual int compare(const TSortable& s) const + { + const TNode_info& ni = (const TNode_info&)s; + return _id.compare(ni._id); + } + + virtual bool ok() const { return _valid; } + void reset() { _valid = false; } + + TNode_info() : _valid(false) { } + virtual ~TNode_info() { } +}; + +class TNode_info_array : public TObject +{ + TArray _data; + +public: + int last() const; + int find(const TNode_info& ni) const; + TNode_info& operator[](int index); + const TNode_info& operator[](int index) const + { return (const TNode_info&)_data[index]; } + void reset(); +}; + +TNode_info& TNode_info_array::operator[](int index) +{ + CHECKD(index >= 0, "Bad index ", index); + TNode_info* ni = (TNode_info*)_data.objptr(index); + if (ni == NULL) + { + ni = new TNode_info; + _data.add(ni, index); + } + return *ni; +} + +void TNode_info_array::reset() +{ + for (int i = _data.last(); i >= 0; i = _data.pred(i)) + ((TNode_info*)_data.objptr(i))->reset(); +} + +int TNode_info_array::last() const +{ + int i; + for (i = _data.last(); i >= 0; i = _data.pred(i)) + if (_data[i].ok()) + break; + return i; +} + +int TNode_info_array::find(const TNode_info& ni) const +{ + int i; + for (i = last(); i >= 0; i = _data.pred(i)) + { + if (((TNode_info*)_data.objptr(i))->compare(ni) == 0) + break; + } + return i; +} + +/////////////////////////////////////////////////////////// +// TTree_window +/////////////////////////////////////////////////////////// + +class TTree_window : public TField_window +{ + TTree* _tree; + bool _hide_leaves; + long _first_line; // Prima riga disegnata + TNode_info_array _node_info; + TNode_info _curr_info; // Nodo attualmente selezionato + TAuto_token_string _header; + int _headlines; + + /*static*/ int _row_height; + static bool _tree_locked; + +protected: // TWindow + virtual void update(); + virtual bool on_key(KEY key); + virtual void handler(WINDOW win, EVENT* ep); + + int row_height() const { return _row_height; } + PNT log2dev(long x, long y) const; + TPoint dev2log(const PNT& p) const; + +protected: // Internal use + static bool callback_draw_node(TTree& node, void* jolly, word); + void update_header(); + void draw_plus_minus(); + void draw_text(int x, int y, const TString& str); + + int info2index(const TNode_info& ni) const; + bool index2info(long index, TNode_info& ni); + +public: + TTree* tree() const { return _tree; } + void set_tree(TTree* tree) { _tree = tree; _first_line = -1; } + void hide_leaves(bool yes) { _hide_leaves = yes; } + bool select_current(); + bool goto_selected(); + void set_header(const char* head); + void set_row_height(int rh); + + TTree_window(int x, int y, int dx, int dy, + WINDOW parent, TTree_field* owner); + virtual ~TTree_window() { } +}; + +bool TTree_window::_tree_locked = false; + +const int TABX = 3; + +struct TUpdate_info +{ + TTree_window* _win; + TToken_string _str; + long _x, _y; + long _firsty, _lasty; + long _jolly; + int _headlines; + TNode_info_array* _node_info; + TNode_info* _curr_info; +}; + + +PNT TTree_window::log2dev(long x, long y) const +{ + if (_headlines > 0) + y += _headlines; + + if (autoscrolling()) + { + if (_pixmap) + { + x -= origin().x * CHARX; + y -= origin().y * _row_height; + } + else + { + x -= origin().x; + y -= origin().y; + } + } + + PNT pnt; pnt.h = (int)x; pnt.v = (int)y; + + if (!_pixmap) + { + pnt.h *= CHARX; + pnt.v *= _row_height; + } + + return pnt; +} + +TPoint TTree_window::dev2log(const PNT& dp) const +{ + PNT p = dp; + + if (_headlines > 0) + p.v -= _headlines * _row_height; + + TPoint pnt(_pixmap ? p.h : p.h/CHARX, _pixmap ? p.v : p.v/_row_height); + return pnt; +} + +void TTree_window::draw_text(int x, int y, const TString& str) +{ + int start = 0, pos = 0; + while (pos >= 0) + { + pos = str.find(" ", start); + const TString& mid = str.sub(start, pos); + if (!mid.blank()) + stringat(x + start, y, mid); + start = pos+2; + } +} + +bool TTree_window::callback_draw_node(TTree& node, void* jolly, word when) +{ + TUpdate_info* ui = (TUpdate_info*)jolly; + + if (when == SCAN_PRE_ORDER) + { + if (ui->_y >= ui->_firsty && ui->_y <= ui->_lasty) + { + node.curr_id(ui->_str); + const bool is_selected = ui->_str == ui->_curr_info->_id; + const bool is_enabled = node.enabled(); + const bool is_marked = node.marked(); + int text_len = 0; + if (node.get_description(ui->_str)) + { + text_len = ui->_str.len(); + if (is_selected) + ui->_win->set_color(FOCUS_COLOR, FOCUS_BACK_COLOR); + else + ui->_win->set_color(is_enabled ? NORMAL_COLOR : DISABLED_COLOR, + is_marked ? REQUIRED_BACK_COLOR : NORMAL_BACK_COLOR); + ui->_win->draw_text(int(ui->_x+2), int(ui->_y), ui->_str); + } + + const int ry = int(ui->_y - ui->_firsty); + int by; + + for (by = ry-1; by >= 0; by--) + { + long rx = (*ui->_node_info)[by]._startx; + if (rx < ui->_x) + break; + } + + const PNT p = ui->_win->log2dev(ui->_x, ui->_y); + const WINDOW win = ui->_win->win(); + ui->_win->set_pen(DISABLED_BACK_COLOR); + + const int rh = ui->_win->row_height(); + + PNT q; + q.h = p.h; q.v = p.v + rh/2; + xvt_dwin_draw_set_pos(win, q); + q.h -= TABX*CHARX - 3*CHARX/2; + xvt_dwin_draw_line(win, q); + q.v = (by+1+ui->_headlines)*rh; + + xvt_dwin_draw_line(win, q); + + TImage* bmp = node.image(is_selected); + if (bmp) + { + const int x = p.h; + const int y = p.v + (rh - bmp->height()) / 2; + if (is_enabled) + bmp->draw(win, x, y); + else + { + TImage dis(*bmp); + for (int j = dis.height()-1; j >= 0; j--) + for (int i = dis.width() - (j&1 ? 2 : 1); i >= 0; i-=2) + dis.set_pixel(i, j, NORMAL_BACK_COLOR); + dis.draw(win, x, y); + } + } + + TNode_info& ni = (*ui->_node_info)[ry]; + node.curr_id(ni._id); + ni._valid = true; + ni._startx = ui->_x; + ni._endx = ui->_x + text_len + 2; + ni._enabled = is_enabled; + ni._expandable = is_enabled && node.has_son(); + if (ni._expandable) + { + ni._plusx = ui->_x - TABX + 1; + ni._expanded = node.expanded(); + } + else + { + ni._plusx = 0; + ni._expanded = false; + } + } + ui->_y++; + + ui->_x += TABX; + if (ui->_x > ui->_jolly) + ui->_jolly = ui->_x; + } else + if (when == SCAN_IN_ORDER) + { + ui->_x -= TABX; + if (ui->_y > ui->_lasty) + return true; + } + + return false; +} + +void TTree_window::draw_plus_minus() +{ + const long firsty = origin().y; + const int last_drawn = _node_info.last(); + for (int i = last_drawn; i >= 0; i--) + { + TNode_info& ni = _node_info[i]; + if (ni._plusx > 0) + { + if (ni._expanded) + { + bool spudorato = i == last_drawn; // Falso espandibile + if (!spudorato) + { + const TNode_info& nni = _node_info[i+1]; + spudorato = nni._startx <= ni._startx; + } + if (spudorato) + { + ni._expandable = false; + ni._expanded = false; + ni._plusx = 0; + continue; + } + } + + WINDOW w = win(); + PNT r = log2dev(ni._plusx, firsty + i); + r.v += _row_height/2; + r.h += CHARX/2; + + RCT rct; + rct.left = r.h - 4; + rct.top = r.v - 4; + rct.right = r.h + 5; + rct.bottom = r.v + 5; + set_pen(NORMAL_COLOR); + set_brush(NORMAL_BACK_COLOR); + xvt_dwin_draw_rect(w, &rct); + + PNT f, t; + f.h = rct.left+2; f.v = r.v; + t.h = rct.right+-2; t.v = r.v; + xvt_dwin_draw_set_pos(w, f); + xvt_dwin_draw_line(w, t); + + if (!ni._expanded) + { + f.h = r.h; f.v = rct.top+2; + t.h = r.h; t.v = rct.bottom-2; + xvt_dwin_draw_set_pos(w, f); + xvt_dwin_draw_line(w, t); + } + } + } +} + +void TTree_window::set_header(const char* head) +{ + _header = head; + _headlines = _header.items(); +} + +void TTree_window::update_header() +{ + if (_headlines > 0) + { + autoscroll(false); + set_brush(MASK_BACK_COLOR); + bar(0,-_headlines,columns(),0); + autoscroll(true); + set_opaque_text(false); + for (int i = 0; i < _headlines; i++) + { + const TFixed_string str(_header.get(i)); + draw_text(2, int(origin().y+i-_headlines), str); + } + } +} + +void TTree_window::update() +{ + TField_window::update(); + + if (_tree == NULL) + return; + + update_header(); + + TUpdate_info ui; + ui._win = this; + ui._x = 0; + ui._y = 0; + ui._firsty = origin().y; + ui._lasty = ui._firsty + rows(); + ui._jolly = 0; + ui._headlines = _headlines; + ui._node_info = &_node_info; + ui._curr_info = &_curr_info; + + bool ok = false; + if (_first_line > 0) + { + const long index = origin().y - _first_line; + TNode_info ni; + if (index2info(index, ni)) + { + ok = _tree->goto_node(ni._id); + ui._x = ni._startx; + ui._y = ui._firsty; + } + } + if (!ok) + { + ok = _tree->goto_root(); + if (!ok) + return; + } + + _node_info.reset(); + set_opaque_text(true); + + word flags = SCAN_PRE_ORDER | SCAN_IN_ORDER | SCAN_IGNORING_UNEXPANDED; + if (_hide_leaves) flags |= SCAN_IGNORING_LEAVES; + + _tree->scan_depth_first(callback_draw_node, &ui, flags); + while (ui._y < ui._lasty) + { + if (_tree->goto_father()) + { + ui._x -= TABX; + if (_tree->goto_rbrother()) + _tree->scan_depth_first(callback_draw_node, &ui, flags); + } + else + break; + } + draw_plus_minus(); + + set_scroll_max(ui._jolly+columns(), ui._y); + _first_line = ui._firsty; +} + +// Fa diventare il nodo corrente selezionato +bool TTree_window::select_current() +{ + if (_tree) + _tree->curr_id(_curr_info._id); + return _tree != NULL; +} + +// Salta al nodo correntemente selezionato +bool TTree_window::goto_selected() +{ + bool ok = false; + if (_tree) + ok = _tree->goto_node(_curr_info._id); + return ok; +} + +void TTree_window::set_row_height(int rh) +{ + if (rh <= 0) + rh = CHARY+2; + _row_height = rh; +} + +int TTree_window::info2index(const TNode_info& info) const +{ + return _node_info.find(info); +} + +bool TTree_window::index2info(long index, TNode_info& ni) +{ + bool ok = false; + const int last = _node_info.last(); + + if (index == -1) + { + if (index2info(0, ni) && _tree->goto_node(ni._id)) + { + ok = _tree->goto_lbrother(); + if (!ok) + { + ok = _tree->goto_father(); + ni._startx -= TABX; + } + if (ok) + _tree->curr_id(ni._id); + } + } else + if (index == last+1 && last >= 0) + { + if (index2info(last, ni) && _tree->goto_node(ni._id)) + { + ok = _tree->expanded() && _tree->goto_firstson(); + if (ok && _hide_leaves && !_tree->has_son()) + { + _tree->goto_node(ni._id); // Ritorno al padre perche' ignoro le foglie + ok = false; + } + if (!ok) + { + ok = _tree->goto_rbrother(); + ni._startx += TABX; + } + if (ok) + { + _tree->curr_id(ni._id); + } + } + } else + if (index >= 0 && index <= last) + { + TNode_info& info = _node_info[int(index)]; + ok = info.ok(); + if (ok) + ni = info; + } + + return ok; +} + +bool TTree_window::on_key(KEY key) +{ + if (_tree == NULL || _tree_locked) + return false; + + if (key == K_RIGHT) + { + if (_tree->goto_node(_curr_info._id) && + !_tree->expanded() && _tree->has_son()) + key = K_ENTER; + else + key = K_DOWN; + } + + if (key == K_LEFT) + { + if (_tree->goto_node(_curr_info._id) && + _tree->expanded()) + key = K_ENTER; + else + key = K_UP; + } + + if (key == K_UP || key == K_DOWN) + { + _tree_locked = true; + int index = info2index(_curr_info); + if (key == K_UP) + index--; + else + index++; + + bool ok = false; + bool scroll = false; + + TNode_info ni; + if (index2info(index, ni)) + { + ok = _tree->goto_node(ni._id); + scroll = ok && (index < 0 || index > _node_info.last()); + } + else + { + const int index = key == K_UP ? 0 : _node_info.last(); + ok = index2info(index, ni) && _tree->goto_node(ni._id); + } + + if (ok && _curr_info != ni) + { + _tree->curr_id(_curr_info._id); + owner().on_key(K_SPACE); + if (!scroll) + { + force_update(); + do_events(); + } + } + + _tree_locked = false; + if (!scroll) + return true; + } + + if (key == K_ENTER) + { + _tree_locked = true; + if (_tree->goto_node(_curr_info._id)) + { + if (_tree->has_son()) + { + bool ok; + if (_tree->expanded()) + ok = _tree->shrink(); + else + ok = _tree->expand(); + if (ok) + { + force_update(); + do_events(); + // Make sure of being well positioned after the redraw!!! + _tree->goto_node(_curr_info._id); + } + } + owner().on_key(K_CTRL + K_SPACE); + } + _tree_locked = false; + } + + return TField_window::on_key(key); +} + +void TTree_window::handler(WINDOW win, EVENT* ep) +{ + switch(ep->type) + { + case E_MOUSE_DBL: + case E_MOUSE_DOWN: + if (_tree && !_tree_locked) + { + _tree_locked = true; + const TPoint lp = dev2log(ep->v.mouse.where); + const int c = (int)lp.x; + const int r = (int)lp.y; + + TNode_info ni; + bool ok = index2info(r, ni); + if (ok && (c == ni._plusx || (c >= ni._startx && c < ni._endx)) && + _tree->goto_node(ni._id)) + { + if (c == ni._plusx || (ni._expandable && ep->type == E_MOUSE_DBL && c <= ni._plusx+3)) + { + if (_tree->expanded()) + ok = _tree->shrink(); + else + ok = _tree->expand(); + if (ok) + { + owner().on_key(K_SHIFT + K_SPACE); // Expansion + owner().on_key(K_SPACE); // Selection + } + } + else + { + KEY key = K_SPACE; + if (ep->type == E_MOUSE_DBL) + key += K_CTRL; // Double click selection + owner().on_key(key); + } + if (ok) + { + _curr_info = ni; + force_update(); + } + } + _tree_locked = false; + } + break; + default: + TField_window::handler(win, ep); + break; + } +} + +TTree_window::TTree_window(int x, int y, int dx, int dy, + WINDOW parent, TTree_field* owner) + : TField_window(x, y, dx, dy, parent, owner), _tree(NULL), + _hide_leaves(false), _headlines(0) +{ + set_row_height(-1); // Compute default row height +} + +#else + +/////////////////////////////////////////////////////////// +// TTree_window +/////////////////////////////////////////////////////////// + +class TTree_window : public TField_window +{ + TTree* _tree; + WINDOW _ctrl; + bool _hide_leaves; + TAuto_token_string _header; + +private: + void create_children(XVT_TREEVIEW_NODE node); + void handle_tree_event(EVENT* ep); + bool add_child(XVT_TREEVIEW_NODE parent); + +protected: // TWindow + virtual void update(); + virtual void handler(WINDOW win, EVENT* ep); + virtual void force_update(); + +public: + TTree* tree() const { return _tree; } + void set_tree(TTree* tree); + void hide_leaves(bool yes) { _hide_leaves = yes; } + bool select_current(); + bool goto_selected(); + void set_header(const char* head); + void set_row_height(int rh); + + TTree_window(int x, int y, int dx, int dy, WINDOW parent, TTree_field* owner); + virtual ~TTree_window() { } +}; + +bool TTree_window::add_child(XVT_TREEVIEW_NODE parent) +{ + XVT_TREEVIEW_NODE_TYPE type = _tree->has_son() ? XVT_TREEVIEW_NODE_NONTERMINAL + : XVT_TREEVIEW_NODE_TERMINAL; + if (_hide_leaves && type == XVT_TREEVIEW_NODE_TERMINAL) + return false; + + TString id; _tree->curr_id(id); + TString desc; _tree->get_description(desc); + + XVT_IMAGE ii = NULL, ic = NULL, ie = NULL; + TImage* im_nor = _tree->image(false); + if (type == XVT_TREEVIEW_NODE_NONTERMINAL) + { + TImage* im_sel = _tree->image(true); + ic = im_nor->xvt_image(); + ie = im_sel->xvt_image(); + } + else + ii = im_nor->xvt_image(); + XVT_TREEVIEW_NODE child = xvt_treeview_add_child_node(_ctrl, parent, type, ii, ic, ie, desc, NULL, id); + if (type == XVT_TREEVIEW_NODE_NONTERMINAL && _tree->expanded()) + xvt_treeview_expand_node(_ctrl, child, FALSE); + return true; +} + +void TTree_window::create_children(XVT_TREEVIEW_NODE node) +{ + bool ok = false; + TString id; + if (_tree != NULL) + { + if (node != NULL) + id = xvt_treeview_get_node_data(_ctrl, node); + if (id.empty()) // Sono sulla radice + { + node = xvt_treeview_get_root_node(_ctrl); + ok = _tree->goto_root(); + } + else + { + _tree->goto_node(id); + ok = _tree->goto_firstson(); + } + } + xvt_treeview_remove_node_children(_ctrl, node); + for (; ok; ok = _tree->goto_rbrother()) + add_child(node); + + // Riposiziona per benino l'alberello + if (id.empty()) + _tree->goto_root(); + else + _tree->goto_node(id); +} + +void TTree_window::set_tree(TTree* tree) +{ + _tree = tree; + if (_tree != NULL) + { + // Memorizza la posizione dell'albero per dopo ... + TString curr; tree->curr_id(curr); + create_children(NULL); // Rigenera i figli della radice + tree->goto_node(curr); // Riporta la selezione sul nodo memorizzato + } +} + +void TTree_window::handle_tree_event(EVENT* ep) +{ + XVT_TREEVIEW_NODE node = ep->v.ctl.ci.v.treeview.node; + const TString id = (const char*)xvt_treeview_get_node_data(_ctrl, node); + if (_tree->goto_node(id)) + { + if (ep->v.ctl.ci.v.treeview.sgl_click || ep->v.ctl.ci.v.treeview.dbl_click) + { + KEY key = K_SPACE; // Single click selection + if (ep->v.ctl.ci.v.treeview.dbl_click) + key += K_CTRL; // Double click selection + if (owner().on_key(key) && _tree->goto_node(id)) + { + // Aggiorna testo ed immagini che possono essere cambiate + XVT_IMAGE ii = NULL, ic = NULL, ie = NULL; + TImage* im_nor = _tree->image(false); + if (_tree->has_son()) + { + TImage* im_sel = _tree->image(true); + ic = im_nor->xvt_image(); + ie = im_sel->xvt_image(); + } + else + ii = im_nor->xvt_image(); + xvt_treeview_set_node_images(_ctrl, node, ii, ic, ie); + TString desc; _tree->get_description(desc); + xvt_treeview_set_node_string(_ctrl, node, desc); + } + } + else + { + int nWhat = 0; + if (ep->v.ctl.ci.v.treeview.expanded) + nWhat |= 0x1; + if (ep->v.ctl.ci.v.treeview.collapsed) + nWhat |= 0x2; + switch (nWhat) + { + case 0x1: // Expanded + _tree->expand(); + owner().on_key(K_SHIFT + K_SPACE); + break; + case 0x2: // Collapsed + _tree->shrink(); + break; + case 0x3: // Expanding + _tree->expand(); + create_children(node); + owner().on_key(K_SHIFT + K_SPACE); + owner().on_key(K_SPACE); + break; + default : break; + } + } + } +} + +void TTree_window::update() +{ + if (_header.full()) + { + set_brush(MASK_BACK_COLOR); + bar(0, 0, columns(), _header.items()); + short x = 3, y = 0; + FOR_EACH_TOKEN(_header, row) + stringat(x, y++, row); + } +} + +void TTree_window::handler(WINDOW win, EVENT* ep) +{ + switch (ep->type) + { + case E_CONTROL: + if (ep->v.ctl.ci.type == WC_TREE && _tree != NULL) + handle_tree_event(ep); + break; + default: + break; + } + TField_window::handler(win, ep); +} + +bool TTree_window::select_current() +{ + XVT_TREEVIEW_NODE selected = NULL; // Nodo da selezionare (se mai lo trovero') + + if (_tree != NULL) + { + xvt_treeview_suspend(_ctrl); // Sospendo le notifiche degli eventi + + TString id; _tree->curr_id(id); + TString_array a; + a.add(id); + // Creo la lista dei progenitori + while (_tree->goto_father()) + { + const int i = a.add(EMPTY_STRING); + _tree->curr_id(a.row(i)); + _tree->expand(); // Nel caso non fosse gia' espanso + } + + // Scandisco i progenitori partendo dalla radice + XVT_TREEVIEW_NODE parent = NULL; // was xvt_treeview_get_root_node(_ctrl); + bool killed = false; // Ho interrotto "bruscamente" la ricerca? + FOR_EACH_ARRAY_ROW_BACK(a, r, row) + { + if (killed) + break; + for (int i = 0; ; i++) + { + XVT_TREEVIEW_NODE child = xvt_treeview_get_child_node(_ctrl, parent, i); + if (child == NULL && i == 0) // Forse non c'e' nessun figlio ... + { + create_children(parent); // ... sara' vero? + child = xvt_treeview_get_child_node(_ctrl, parent, i); + } + if (child == NULL) // Certamente non ci sono piu' figli + { + //killed = true; // Non ho trovato quello che cercavo: esco subito + break; + } + const char* data = (const char*)xvt_treeview_get_node_data(_ctrl, child); + if (*row == data) + { + selected = child; + if (*row == id) // Ho finito + killed = true; + else + { + parent = child; + xvt_treeview_expand_node(_ctrl, child, FALSE); + } + break; + } + } + } + if (selected != NULL) + xvt_treeview_select_node(_ctrl, selected, TRUE); + xvt_treeview_resume(_ctrl); // Riattivo le notifiche degli eventi + + _tree->goto_node(id); + if (_tree->expanded()) + xvt_treeview_expand_node(_ctrl, selected, FALSE); + } + return selected != NULL; +} + +bool TTree_window::goto_selected() +{ + bool ok = false; + XVT_TREEVIEW_NODE child = xvt_treeview_get_selected_node(_ctrl); + if (child != NULL) + { + const char* data = (const char*)xvt_treeview_get_node_data(_ctrl, child); + ok = _tree->goto_node(data); + } + return ok; +} + +void TTree_window::set_header(const char* head) +{ + if (_header != head) + { + const int old_headlines = _header.items(); + _header = head; + const int new_headlines = _header.items(); + if (new_headlines != old_headlines) + { + RCT rctree; xvt_vobj_get_client_rect(win(), &rctree); + rctree.top += new_headlines * CHARY; + xvt_vobj_move(_ctrl, &rctree); + } + force_update(); + } +} + +void TTree_window::set_row_height(int rh) +{ +} + +TTree_window::TTree_window(int x, int y, int dx, int dy, + WINDOW parent, TTree_field* owner) + : TField_window(x, y, dx, dy, parent, owner), + _tree(NULL), _hide_leaves(false) +{ + set_scroll_max(0, 0); // Get rid of that useless scrollbars + RCT rct; xvt_vobj_get_client_rect(win(), &rct); + _ctrl = xvt_treeview_create(win(), &rct, "", 0, (long)this, owner->dlg(), + NULL, NULL, NULL, 0, CHARY+2); +} + +#endif + +/////////////////////////////////////////////////////////// +// TTree_field +/////////////////////////////////////////////////////////// + +word TTree_field::class_id() const +{ return CLASS_TREE_FIELD; } + +bool TTree_field::is_kind_of(word cid) const +{ return cid == CLASS_TREE_FIELD || TWindowed_field::is_kind_of(cid); } + +#define tree_win() ((TTree_window&)win()) + +TTree* TTree_field::tree() const +{ return tree_win().tree(); } + +void TTree_field::set_tree(TTree* tree) +{ + TTree_window& tv = tree_win(); + tv.set_tree(tree); + tv.select_current(); +} + +void TTree_window::force_update() +{ set_tree(tree()); } + +void TTree_field::hide_leaves(bool yes) +{ tree_win().hide_leaves(yes); } + +bool TTree_field::select_current() +{ return tree_win().select_current(); } + +bool TTree_field::goto_selected() +{ return tree_win().goto_selected(); } + +void TTree_field::set_header(const char* head) +{ tree_win().set_header(head); } + +void TTree_field::set_row_height(int rh) +{ tree_win().set_row_height(rh); } + +TField_window* TTree_field::create_window(int x, int y, int dx, int dy, WINDOW parent) +{ return new TTree_window(x, y, dx, dy, parent, this); }