1998-02-06 16:13:56 +00:00
|
|
|
#include <colors.h>
|
|
|
|
#include <tree.h>
|
|
|
|
#include <urldefid.h>
|
2002-02-28 11:35:23 +00:00
|
|
|
#include <image.h>
|
1998-02-06 16:13:56 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// Callbacks
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
HIDDEN bool callback_compare_node(TTree& node, void* jolly, word when)
|
|
|
|
{
|
|
|
|
const TString& id = *((TString*)jolly);
|
|
|
|
TString cur_id; node.curr_id(cur_id);
|
|
|
|
return id == cur_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
HIDDEN bool callback_expand_node(TTree& node, void* jolly, word when)
|
|
|
|
{
|
1998-05-04 08:17:15 +00:00
|
|
|
if (when == SCAN_PRE_ORDER)
|
1998-02-06 16:13:56 +00:00
|
|
|
node.expand();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
HIDDEN bool callback_find_father(TTree& node, void* jolly, word when)
|
|
|
|
{
|
|
|
|
TString_array& father_and_son = *(TString_array*)jolly;
|
|
|
|
TString myself; node.curr_id(myself);
|
|
|
|
|
|
|
|
if (when == SCAN_PRE_ORDER)
|
|
|
|
{
|
|
|
|
if (myself == father_and_son.row(1))
|
|
|
|
father_and_son.add(myself, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (father_and_son.objptr(0))
|
|
|
|
{
|
|
|
|
father_and_son.add(myself, 0);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
HIDDEN bool callback_find_brother(TTree& node, void* jolly, word when)
|
|
|
|
{
|
|
|
|
TString_array& brother_and_sister = *(TString_array*)jolly;
|
|
|
|
TString myself; node.curr_id(myself);
|
|
|
|
|
|
|
|
if (when == SCAN_PRE_ORDER)
|
|
|
|
{
|
|
|
|
if (myself == brother_and_sister.row(1))
|
|
|
|
brother_and_sister.add(myself, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (brother_and_sister.objptr(0))
|
|
|
|
{
|
|
|
|
brother_and_sister.add(myself, 0);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TTtree
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
bool TTree::scan_depth_first(NODE_HANDLER nh, void* jolly, word flags)
|
|
|
|
{
|
1999-01-19 09:15:17 +00:00
|
|
|
if ((flags & 0x7) == 0)
|
1998-02-06 16:13:56 +00:00
|
|
|
flags |= SCAN_PRE_ORDER;
|
1998-02-16 16:31:24 +00:00
|
|
|
|
|
|
|
bool test_myself = TRUE;
|
|
|
|
if ((flags & SCAN_IGNORING_LEAVES) && !has_son())
|
|
|
|
test_myself = FALSE;
|
1998-02-06 16:13:56 +00:00
|
|
|
|
|
|
|
TString myself;
|
|
|
|
curr_id(myself);
|
1998-02-16 16:31:24 +00:00
|
|
|
|
|
|
|
if (test_myself)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
1998-02-16 16:31:24 +00:00
|
|
|
if ((flags & SCAN_PRE_ORDER) && nh(*this, jolly, SCAN_PRE_ORDER))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
const bool stop = (flags & SCAN_IGNORING_UNEXPANDED) && !expanded();
|
|
|
|
if (!stop && goto_firstson())
|
|
|
|
{
|
|
|
|
if (scan_depth_first(nh, jolly, flags))
|
|
|
|
return TRUE;
|
|
|
|
goto_node(myself);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((flags & SCAN_IN_ORDER) && nh(*this, jolly, SCAN_IN_ORDER))
|
1998-02-06 16:13:56 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (goto_rbrother())
|
|
|
|
{
|
|
|
|
if (scan_depth_first(nh, jolly, flags))
|
|
|
|
return TRUE;
|
|
|
|
goto_node(myself);
|
|
|
|
}
|
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
if (test_myself)
|
|
|
|
{
|
|
|
|
if ((flags & SCAN_POST_ORDER) && nh(*this, jolly, SCAN_POST_ORDER))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree::scan_breadth_first(NODE_HANDLER nh, void* jolly, word flags)
|
|
|
|
{
|
1999-01-19 09:15:17 +00:00
|
|
|
if ((flags & 0x7) == 0)
|
1998-02-06 16:13:56 +00:00
|
|
|
flags |= SCAN_PRE_ORDER;
|
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
bool test_myself = TRUE;
|
|
|
|
if ((flags & SCAN_IGNORING_LEAVES) && !has_son())
|
|
|
|
test_myself = FALSE;
|
1998-02-06 16:13:56 +00:00
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
if (test_myself)
|
|
|
|
{
|
|
|
|
if ((flags & SCAN_PRE_ORDER) && nh(*this, jolly, SCAN_PRE_ORDER))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
TString myself;
|
|
|
|
curr_id(myself);
|
|
|
|
|
|
|
|
if (goto_rbrother())
|
|
|
|
{
|
|
|
|
if (scan_breadth_first(nh, jolly, flags))
|
|
|
|
return TRUE;
|
|
|
|
goto_node(myself);
|
|
|
|
}
|
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
if (test_myself)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
1998-02-16 16:31:24 +00:00
|
|
|
if ((flags & SCAN_IN_ORDER) && nh(*this, jolly, SCAN_IN_ORDER))
|
1998-02-06 16:13:56 +00:00
|
|
|
return TRUE;
|
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
const bool stop = (flags & SCAN_IGNORING_UNEXPANDED) && !expanded();
|
|
|
|
if (!stop && goto_firstson())
|
|
|
|
{
|
|
|
|
if (scan_breadth_first(nh, jolly, flags))
|
|
|
|
return TRUE;
|
|
|
|
goto_node(myself);
|
|
|
|
}
|
|
|
|
if ((flags & SCAN_POST_ORDER) && nh(*this, jolly, SCAN_POST_ORDER))
|
|
|
|
return TRUE;
|
|
|
|
}
|
1998-02-06 16:13:56 +00:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree::has_root() const
|
|
|
|
{
|
|
|
|
TString myself; curr_id(myself);
|
|
|
|
bool ok = ((TTree*)this)->goto_root();
|
|
|
|
if (ok)
|
|
|
|
((TTree*)this)->goto_node(myself);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree::has_father() const
|
|
|
|
{
|
|
|
|
TString myself; curr_id(myself);
|
|
|
|
bool ok = ((TTree*)this)->goto_father();
|
|
|
|
if (ok)
|
|
|
|
((TTree*)this)->goto_node(myself);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree::goto_father()
|
|
|
|
{
|
|
|
|
TString myself; curr_id(myself);
|
|
|
|
bool ok = goto_root();
|
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
TString_array father_and_son;
|
|
|
|
father_and_son.add(myself, 1);
|
|
|
|
ok = scan_breadth_first(callback_find_father, &father_and_son,
|
|
|
|
SCAN_PRE_ORDER | SCAN_IN_ORDER);
|
|
|
|
}
|
|
|
|
if (!ok)
|
|
|
|
goto_node(myself);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree::has_lbrother() const
|
|
|
|
{
|
|
|
|
TString myself; curr_id(myself);
|
|
|
|
bool ok = ((TTree*)this)->goto_lbrother();
|
|
|
|
if (ok)
|
|
|
|
((TTree*)this)->goto_node(myself);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree::goto_lbrother()
|
|
|
|
{
|
|
|
|
TString myself; curr_id(myself);
|
|
|
|
bool ok = goto_root();
|
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
TString_array brother_and_sister;
|
|
|
|
brother_and_sister.add(myself, 1);
|
|
|
|
ok = scan_depth_first(callback_find_brother, &brother_and_sister,
|
|
|
|
SCAN_PRE_ORDER | SCAN_POST_ORDER);
|
|
|
|
}
|
|
|
|
if (!ok)
|
|
|
|
goto_node(myself);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree::expanded() const
|
|
|
|
{
|
|
|
|
TString str;
|
|
|
|
curr_id(str);
|
|
|
|
bool yes = _expanded.is_key(str);
|
|
|
|
return yes;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree::expand()
|
|
|
|
{
|
1998-12-10 16:25:48 +00:00
|
|
|
bool ok = enabled() && has_son();
|
1998-02-06 16:13:56 +00:00
|
|
|
if (ok)
|
1998-12-10 16:25:48 +00:00
|
|
|
{
|
|
|
|
TString str; curr_id(str);
|
|
|
|
ok = !_expanded.is_key(str);
|
|
|
|
if (ok)
|
|
|
|
_expanded.add(str);
|
|
|
|
}
|
1998-02-06 16:13:56 +00:00
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree::shrink()
|
|
|
|
{
|
|
|
|
TString str;
|
|
|
|
curr_id(str);
|
|
|
|
bool ok = _expanded.is_key(str);
|
|
|
|
if (ok)
|
|
|
|
_expanded.remove(str);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree::expand_all()
|
|
|
|
{
|
|
|
|
bool ok = goto_root();
|
|
|
|
if (ok)
|
1998-05-04 08:17:15 +00:00
|
|
|
scan_breadth_first(callback_expand_node, NULL);
|
1998-02-06 16:13:56 +00:00
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
1998-05-04 08:17:15 +00:00
|
|
|
bool TTree::shrink_all()
|
|
|
|
{
|
|
|
|
_expanded.destroy();
|
|
|
|
return goto_root();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
TImage* TTree::get_res_image(short bmp_id) const
|
|
|
|
{
|
|
|
|
TImage* bmp = (TImage*)_image.objptr(bmp_id);
|
|
|
|
if (bmp == NULL)
|
|
|
|
{
|
|
|
|
bmp = new TImage(bmp_id);
|
|
|
|
if (bmp->ok())
|
|
|
|
{
|
|
|
|
bmp->convert_transparent_color(NORMAL_BACK_COLOR);
|
|
|
|
((TTree*)this)->_image.add(bmp, bmp_id);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delete bmp;
|
|
|
|
bmp = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bmp;
|
|
|
|
}
|
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
TImage* TTree::image(bool selected) const
|
|
|
|
{
|
1998-02-06 16:13:56 +00:00
|
|
|
short bmp_id = BMP_FILE;
|
|
|
|
if (has_son())
|
1998-02-16 16:31:24 +00:00
|
|
|
bmp_id = selected ? BMP_DIRDN : BMP_DIR;
|
1998-02-06 16:13:56 +00:00
|
|
|
return get_res_image(bmp_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TBidirectional_tree
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
bool TBidirectional_tree::scan_depth_first(NODE_HANDLER nh, void* jolly, word flags)
|
|
|
|
{
|
1999-01-19 09:15:17 +00:00
|
|
|
if ((flags & 0x7) == 0)
|
1998-02-06 16:13:56 +00:00
|
|
|
flags |= SCAN_PRE_ORDER;
|
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
bool test_myself = TRUE;
|
|
|
|
if ((flags & SCAN_IGNORING_LEAVES) && !has_son())
|
|
|
|
test_myself = FALSE;
|
|
|
|
|
|
|
|
if (test_myself)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
1998-02-16 16:31:24 +00:00
|
|
|
if ((flags & SCAN_PRE_ORDER) && nh(*this, jolly, SCAN_PRE_ORDER))
|
1998-02-06 16:13:56 +00:00
|
|
|
return TRUE;
|
1998-02-16 16:31:24 +00:00
|
|
|
|
|
|
|
const bool stop = (flags & SCAN_IGNORING_UNEXPANDED) && !expanded();
|
|
|
|
if (!stop && goto_firstson())
|
|
|
|
{
|
|
|
|
if (scan_depth_first(nh, jolly, flags))
|
|
|
|
return TRUE;
|
|
|
|
goto_father();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((flags & SCAN_IN_ORDER) && nh(*this, jolly, SCAN_IN_ORDER))
|
|
|
|
return TRUE;
|
|
|
|
}
|
1998-02-06 16:13:56 +00:00
|
|
|
|
|
|
|
if (goto_rbrother())
|
|
|
|
{
|
|
|
|
if (scan_depth_first(nh, jolly, flags))
|
|
|
|
return TRUE;
|
|
|
|
goto_lbrother();
|
|
|
|
}
|
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
if (test_myself)
|
|
|
|
{
|
|
|
|
if ((flags & SCAN_POST_ORDER) && nh(*this, jolly, SCAN_POST_ORDER))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TBidirectional_tree::scan_breadth_first(NODE_HANDLER nh, void* jolly, word flags)
|
|
|
|
{
|
1999-01-19 09:15:17 +00:00
|
|
|
if ((flags & 0x7) == 0)
|
1998-02-06 16:13:56 +00:00
|
|
|
flags |= SCAN_PRE_ORDER;
|
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
bool test_myself = TRUE;
|
|
|
|
if ((flags & SCAN_IGNORING_LEAVES) && !has_son())
|
|
|
|
test_myself = FALSE;
|
|
|
|
|
|
|
|
if (test_myself)
|
|
|
|
{
|
|
|
|
if ((flags & SCAN_PRE_ORDER) && nh(*this, jolly, SCAN_PRE_ORDER))
|
|
|
|
return TRUE;
|
|
|
|
}
|
1998-02-06 16:13:56 +00:00
|
|
|
|
|
|
|
if (goto_rbrother())
|
|
|
|
{
|
|
|
|
if (scan_breadth_first(nh, jolly, flags))
|
|
|
|
return TRUE;
|
|
|
|
goto_lbrother();
|
|
|
|
}
|
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
if (test_myself)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
1998-02-16 16:31:24 +00:00
|
|
|
if ((flags & SCAN_IN_ORDER) && nh(*this, jolly, SCAN_IN_ORDER))
|
1998-02-06 16:13:56 +00:00
|
|
|
return TRUE;
|
1998-02-16 16:31:24 +00:00
|
|
|
const bool stop = (flags & SCAN_IGNORING_UNEXPANDED) && !expanded();
|
|
|
|
if (!stop && goto_firstson())
|
|
|
|
{
|
|
|
|
if (scan_breadth_first(nh, jolly, flags))
|
|
|
|
return TRUE;
|
|
|
|
goto_father();
|
|
|
|
}
|
|
|
|
if ((flags & SCAN_POST_ORDER) && nh(*this, jolly, SCAN_POST_ORDER))
|
|
|
|
return TRUE;
|
|
|
|
}
|
1998-02-06 16:13:56 +00:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TBidirectional_tree::goto_node(const TString &id)
|
|
|
|
{
|
|
|
|
bool ok = goto_root();
|
|
|
|
if (ok && id.not_empty())
|
|
|
|
ok = scan_breadth_first(callback_compare_node, (void *)&id);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TObject tree
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
bool TObject_tree::expanded() const
|
|
|
|
{
|
|
|
|
bool ok = _current && _current->_expanded;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::expand()
|
|
|
|
{
|
1998-12-10 16:25:48 +00:00
|
|
|
bool ok = _current && _current->_son && !_current->_expanded && enabled();
|
1998-02-06 16:13:56 +00:00
|
|
|
if (ok)
|
|
|
|
_current->_expanded = TRUE;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::shrink()
|
|
|
|
{
|
|
|
|
bool ok = _current && _current->_expanded;
|
|
|
|
if (ok)
|
|
|
|
_current->_expanded = FALSE;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TObject_tree::node2id(const TObject* node, TString& id) const
|
|
|
|
{
|
|
|
|
id.format("%p", (const void*)node);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::goto_node(const TString& node)
|
|
|
|
{
|
|
|
|
bool ok = TRUE;
|
|
|
|
if (node.not_empty())
|
|
|
|
{
|
1999-10-22 10:00:18 +00:00
|
|
|
#ifdef DBG_TREE
|
1998-02-06 16:13:56 +00:00
|
|
|
if (!_expanded.is_key(node)) // Usa l'assoc array per testare i nodi validi!
|
|
|
|
{
|
|
|
|
NFCHECK("Invalid node: %s", (const char*)node);
|
|
|
|
return goto_root();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void* p;
|
|
|
|
sscanf(node, "%p", &p);
|
|
|
|
_current = (TTree_node*)p;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ok = goto_root();
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::goto_root()
|
|
|
|
{
|
|
|
|
_current = _root;
|
|
|
|
return _root != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::goto_firstson()
|
|
|
|
{
|
|
|
|
TTree_node* n = _current ? _current->_son : NULL;
|
|
|
|
if (n) _current = n;
|
|
|
|
return n != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::goto_rbrother()
|
|
|
|
{
|
|
|
|
TTree_node* n = _current ? _current->_rbrother : NULL;
|
|
|
|
if (n) _current = n;
|
|
|
|
return n != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::goto_father()
|
|
|
|
{
|
|
|
|
TTree_node* n = _current ? _current->_father : NULL;
|
|
|
|
if (n) _current = n;
|
|
|
|
return n != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::goto_lbrother()
|
|
|
|
{
|
|
|
|
TTree_node* n = _current ? _current->_lbrother : NULL;
|
|
|
|
if (n) _current = n;
|
|
|
|
return n != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::set_object(TObject* obj)
|
|
|
|
{
|
|
|
|
if (_current)
|
|
|
|
{
|
1999-10-22 10:00:18 +00:00
|
|
|
#ifdef DBG_TREE
|
1998-02-06 16:13:56 +00:00
|
|
|
TString str; curr_id(str);
|
|
|
|
_expanded.add(str); // Usa l'assoc array per memorizzare i nodi validi!
|
|
|
|
#endif
|
|
|
|
if (_current->_obj)
|
|
|
|
delete _current->_obj;
|
|
|
|
_current->_obj = obj;
|
|
|
|
}
|
|
|
|
return _current != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::set_object(const TObject& obj)
|
|
|
|
{
|
|
|
|
bool ok = FALSE;
|
|
|
|
if (_current)
|
|
|
|
{
|
|
|
|
TObject* ptr = obj.dup();
|
|
|
|
ok = set_object(ptr);
|
|
|
|
if (!ok)
|
|
|
|
delete ptr;
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::create_root()
|
|
|
|
{
|
|
|
|
if (!has_root())
|
|
|
|
_root = _current = new TTree_node;
|
|
|
|
return goto_root();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::add_son(TObject* obj)
|
|
|
|
{
|
|
|
|
bool ok = FALSE;
|
1998-12-10 16:25:48 +00:00
|
|
|
if (_root)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
|
|
|
TTree_node*& curson = _current->_son;
|
|
|
|
TTree_node* newson = new TTree_node;
|
|
|
|
newson->_father = _current;
|
|
|
|
if (curson != NULL)
|
|
|
|
{
|
|
|
|
curson->_lbrother = newson;
|
|
|
|
newson->_rbrother = curson;
|
|
|
|
}
|
|
|
|
curson = newson;
|
|
|
|
ok = goto_firstson();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ok = create_root();
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
ok = set_object(obj);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::add_son(const TObject& obj)
|
|
|
|
{
|
|
|
|
TObject* ptr = obj.dup();
|
|
|
|
bool ok = add_son(ptr);
|
|
|
|
if (!ok) delete ptr;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::add_brother(TObject* obj)
|
|
|
|
{
|
|
|
|
bool ok = FALSE;
|
|
|
|
if (goto_father())
|
|
|
|
ok = add_son(obj);
|
|
|
|
else
|
|
|
|
ok = create_root() && set_object(obj);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::add_brother(const TObject& obj)
|
|
|
|
{
|
|
|
|
TObject* ptr = obj.dup();
|
|
|
|
bool ok = add_brother(ptr);
|
|
|
|
if (!ok) delete ptr;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::add_rbrother(TObject* obj)
|
|
|
|
{
|
|
|
|
bool ok = FALSE;
|
|
|
|
if (has_father())
|
|
|
|
{
|
|
|
|
TTree_node* newbrother = new TTree_node;
|
|
|
|
newbrother->_father = _current->_father;
|
|
|
|
newbrother->_lbrother = _current;
|
|
|
|
newbrother->_rbrother = _current->_rbrother;
|
|
|
|
_current->_rbrother = newbrother;
|
|
|
|
ok = goto_rbrother();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ok = create_root();
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
set_object(obj);
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::add_rbrother(const TObject& obj)
|
|
|
|
{
|
|
|
|
TObject* ptr = obj.dup();
|
|
|
|
bool ok = add_rbrother(ptr);
|
|
|
|
if (!ok) delete ptr;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::add_lbrother(TObject* obj)
|
|
|
|
{
|
|
|
|
bool ok = FALSE;
|
|
|
|
if (has_father())
|
|
|
|
{
|
|
|
|
if (_current->_lbrother == NULL)
|
|
|
|
ok = add_brother(obj);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TTree_node* newbrother = new TTree_node;
|
|
|
|
newbrother->_father = _current->_father;
|
|
|
|
newbrother->_rbrother = _current;
|
|
|
|
newbrother->_lbrother = _current->_lbrother;
|
|
|
|
_current->_lbrother = newbrother;
|
|
|
|
ok = goto_lbrother();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ok = create_root();
|
|
|
|
if (ok)
|
|
|
|
set_object(obj);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::add_lbrother(const TObject& obj)
|
|
|
|
{
|
|
|
|
TObject* ptr = obj.dup();
|
|
|
|
bool ok = add_lbrother(ptr);
|
|
|
|
if (!ok) delete ptr;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::kill_node()
|
|
|
|
{
|
|
|
|
bool ok = FALSE;
|
|
|
|
if (_current)
|
|
|
|
{
|
|
|
|
TTree_node* cur = _current;
|
|
|
|
while (goto_firstson())
|
|
|
|
{
|
|
|
|
kill_node();
|
|
|
|
_current = cur;
|
|
|
|
}
|
|
|
|
if (_current->_lbrother)
|
|
|
|
{
|
|
|
|
_current->_lbrother->_rbrother = _current->_rbrother;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (_current->_father)
|
|
|
|
_current->_father->_son = _current->_rbrother;
|
|
|
|
}
|
|
|
|
if (_current->_rbrother)
|
|
|
|
_current->_rbrother->_lbrother = _current->_lbrother;
|
|
|
|
|
1999-10-22 10:00:18 +00:00
|
|
|
#ifdef DBG_TREE
|
1998-02-06 16:13:56 +00:00
|
|
|
TString id; curr_id(id);
|
|
|
|
_expanded.remove(id);
|
|
|
|
#endif
|
|
|
|
delete _current;
|
|
|
|
if (_current == _root)
|
|
|
|
_root = NULL;
|
|
|
|
|
|
|
|
if (cur->_rbrother)
|
|
|
|
_current = cur->_rbrother;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (cur->_lbrother)
|
|
|
|
_current = cur->_lbrother;
|
|
|
|
else
|
|
|
|
_current = cur->_father;
|
|
|
|
}
|
|
|
|
ok = TRUE;
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TObject_tree::get_description(TString& str) const
|
|
|
|
{
|
|
|
|
TObject* obj = curr_node();
|
|
|
|
if (obj)
|
|
|
|
str << *obj;
|
|
|
|
return obj != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
TObject_tree::TObject_tree()
|
|
|
|
{
|
|
|
|
_root = _current = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
TObject_tree::~TObject_tree()
|
|
|
|
{
|
|
|
|
if (goto_root())
|
|
|
|
kill_node();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TString_tree
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
bool TString_tree::get_description(TString& str) const
|
|
|
|
{
|
|
|
|
const TString* obj = (const TString*)curr_node();
|
|
|
|
if (obj)
|
|
|
|
str = *obj;
|
|
|
|
else
|
|
|
|
str.cut(0);
|
|
|
|
return obj != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
1998-02-13 13:59:33 +00:00
|
|
|
// TNode_info
|
1998-02-06 16:13:56 +00:00
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
class TNode_info : public TSortable
|
|
|
|
{
|
|
|
|
public:
|
1998-02-17 10:15:46 +00:00
|
|
|
bool _valid : 1;
|
1998-12-10 16:25:48 +00:00
|
|
|
bool _enabled : 1;
|
1998-02-17 10:15:46 +00:00
|
|
|
bool _expandable : 1;
|
|
|
|
bool _expanded : 1;
|
1998-02-06 16:13:56 +00:00
|
|
|
TString _id;
|
|
|
|
long _plusx;
|
|
|
|
long _startx;
|
|
|
|
long _endx;
|
|
|
|
|
|
|
|
const TNode_info& operator =(const TNode_info& ni)
|
|
|
|
{
|
1998-02-17 10:15:46 +00:00
|
|
|
_valid = ni._valid;
|
1998-12-10 16:25:48 +00:00
|
|
|
_enabled = ni._enabled;
|
1998-05-04 08:17:15 +00:00
|
|
|
_expanded = ni._expanded;
|
|
|
|
_expandable = ni._expandable;
|
1998-02-06 16:13:56 +00:00
|
|
|
_id = ni._id;
|
1998-05-04 08:17:15 +00:00
|
|
|
_plusx = ni._plusx;
|
1998-02-06 16:13:56 +00:00
|
|
|
_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);
|
|
|
|
}
|
|
|
|
|
1998-02-17 10:15:46 +00:00
|
|
|
virtual bool ok() const { return _valid; }
|
|
|
|
void reset() { _valid = FALSE; }
|
1998-02-06 16:13:56 +00:00
|
|
|
|
1998-02-17 10:15:46 +00:00
|
|
|
TNode_info() : _valid(FALSE) { }
|
1998-05-04 08:17:15 +00:00
|
|
|
virtual ~TNode_info() { }
|
1998-02-06 16:13:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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))
|
1998-02-17 10:15:46 +00:00
|
|
|
((TNode_info*)_data.objptr(i))->reset();
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int TNode_info_array::last() const
|
|
|
|
{
|
|
|
|
for (int i = _data.last(); i >= 0; i = _data.pred(i))
|
1998-02-17 10:15:46 +00:00
|
|
|
if (_data[i].ok())
|
1998-02-06 16:13:56 +00:00
|
|
|
break;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TNode_info_array::find(const TNode_info& ni) const
|
|
|
|
{
|
|
|
|
for (int i = last(); i >= 0; i = _data.pred(i))
|
|
|
|
{
|
1998-02-17 10:15:46 +00:00
|
|
|
if (((TNode_info*)_data.objptr(i))->compare(ni) == 0)
|
1998-02-06 16:13:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
1998-02-13 13:59:33 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TTree_window
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include <maskfld.h>
|
|
|
|
|
|
|
|
class TTree_window : public TField_window
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
|
|
|
TTree* _tree;
|
1998-02-13 13:59:33 +00:00
|
|
|
bool _hide_leaves;
|
1998-02-06 16:13:56 +00:00
|
|
|
long _first_line; // Prima riga disegnata
|
|
|
|
TNode_info_array _node_info;
|
|
|
|
TNode_info _curr_info; // Nodo attualmente selezionato
|
2002-07-02 16:21:23 +00:00
|
|
|
TAuto_token_string _header;
|
|
|
|
int _headlines;
|
1998-02-06 16:13:56 +00:00
|
|
|
|
2003-01-28 14:27:05 +00:00
|
|
|
/*static*/ int _row_height;
|
1999-10-22 10:00:18 +00:00
|
|
|
static bool _tree_locked;
|
1998-07-20 13:29:52 +00:00
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
protected: // TWindow
|
|
|
|
virtual void update();
|
|
|
|
virtual bool on_key(KEY key);
|
|
|
|
virtual void handler(WINDOW win, EVENT* ep);
|
2003-01-28 14:27:05 +00:00
|
|
|
|
|
|
|
int row_height() const { return _row_height; }
|
1998-07-20 13:29:52 +00:00
|
|
|
PNT log2dev(long x, long y) const;
|
|
|
|
TPoint dev2log(const PNT& p) const;
|
1998-02-06 16:13:56 +00:00
|
|
|
|
|
|
|
protected: // Internal use
|
|
|
|
static bool callback_draw_node(TTree& node, void* jolly, word);
|
2002-07-02 16:21:23 +00:00
|
|
|
void update_header();
|
1998-02-06 16:13:56 +00:00
|
|
|
void draw_plus_minus();
|
|
|
|
|
|
|
|
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; }
|
1998-02-13 13:59:33 +00:00
|
|
|
void hide_leaves(bool yes) { _hide_leaves = yes; }
|
1998-05-04 08:17:15 +00:00
|
|
|
bool select_current();
|
1999-05-24 13:34:11 +00:00
|
|
|
bool goto_selected();
|
2002-07-02 16:21:23 +00:00
|
|
|
void set_header(const char* head);
|
2003-02-04 09:34:53 +00:00
|
|
|
void set_row_height(int rh);
|
2003-01-28 14:27:05 +00:00
|
|
|
|
2003-02-05 14:26:24 +00:00
|
|
|
|
2003-02-25 15:22:52 +00:00
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
TTree_window(int x, int y, int dx, int dy,
|
|
|
|
WINDOW parent, TTree_field* owner);
|
|
|
|
virtual ~TTree_window() { }
|
|
|
|
};
|
|
|
|
|
2003-01-28 14:27:05 +00:00
|
|
|
/* int TTree_window::_row_height = CHARY+2; */
|
1999-10-22 10:00:18 +00:00
|
|
|
bool TTree_window::_tree_locked = FALSE;
|
1998-07-20 13:29:52 +00:00
|
|
|
|
|
|
|
const int TABX = 3;
|
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
struct TUpdate_info
|
|
|
|
{
|
|
|
|
TTree_window* _win;
|
|
|
|
TToken_string _str;
|
|
|
|
long _x, _y;
|
|
|
|
long _firsty, _lasty;
|
|
|
|
long _jolly;
|
2002-07-02 16:21:23 +00:00
|
|
|
int _headlines;
|
1998-02-06 16:13:56 +00:00
|
|
|
TNode_info_array* _node_info;
|
|
|
|
TNode_info* _curr_info;
|
|
|
|
};
|
|
|
|
|
1998-07-20 13:29:52 +00:00
|
|
|
|
|
|
|
PNT TTree_window::log2dev(long x, long y) const
|
|
|
|
{
|
2002-07-02 16:21:23 +00:00
|
|
|
if (_headlines > 0)
|
|
|
|
y += _headlines;
|
|
|
|
|
1998-07-20 13:29:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2002-07-02 16:21:23 +00:00
|
|
|
TPoint TTree_window::dev2log(const PNT& dp) const
|
1998-07-20 13:29:52 +00:00
|
|
|
{
|
2002-07-02 16:21:23 +00:00
|
|
|
PNT p = dp;
|
|
|
|
|
|
|
|
if (_headlines > 0)
|
|
|
|
p.v -= _headlines * _row_height;
|
|
|
|
|
1998-07-20 13:29:52 +00:00
|
|
|
TPoint pnt(_pixmap ? p.h : p.h/CHARX, _pixmap ? p.v : p.v/_row_height);
|
|
|
|
return pnt;
|
|
|
|
}
|
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
|
1998-02-10 09:25:41 +00:00
|
|
|
bool TTree_window::callback_draw_node(TTree& node, void* jolly, word when)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
|
|
|
TUpdate_info* ui = (TUpdate_info*)jolly;
|
1998-02-10 09:25:41 +00:00
|
|
|
|
|
|
|
if (when == SCAN_PRE_ORDER)
|
|
|
|
{
|
1998-05-04 08:17:15 +00:00
|
|
|
if (ui->_y >= ui->_firsty && ui->_y <= ui->_lasty)
|
1998-02-10 09:25:41 +00:00
|
|
|
{
|
|
|
|
node.curr_id(ui->_str);
|
|
|
|
const bool is_selected = ui->_str == ui->_curr_info->_id;
|
1998-12-10 16:25:48 +00:00
|
|
|
const bool is_enabled = node.enabled();
|
1998-02-10 09:25:41 +00:00
|
|
|
int text_len = 0;
|
|
|
|
if (node.get_description(ui->_str))
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
1998-02-10 09:25:41 +00:00
|
|
|
text_len = ui->_str.len();
|
|
|
|
if (is_selected)
|
|
|
|
ui->_win->set_color(FOCUS_COLOR, FOCUS_BACK_COLOR);
|
1998-12-10 16:25:48 +00:00
|
|
|
else
|
|
|
|
ui->_win->set_color(is_enabled ? NORMAL_COLOR : DISABLED_COLOR, NORMAL_BACK_COLOR);
|
1998-02-10 09:25:41 +00:00
|
|
|
ui->_win->stringat(int(ui->_x+2), int(ui->_y), ui->_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
const int ry = int(ui->_y - ui->_firsty);
|
|
|
|
for (int by = ry-1; by >= 0; by--)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
1998-02-10 09:25:41 +00:00
|
|
|
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_COLOR);
|
|
|
|
|
2003-01-28 14:27:05 +00:00
|
|
|
const int rh = ui->_win->row_height();
|
|
|
|
|
1998-02-10 09:25:41 +00:00
|
|
|
PNT q;
|
2003-01-28 14:27:05 +00:00
|
|
|
q.h = p.h; q.v = p.v + rh/2;
|
1998-02-10 09:25:41 +00:00
|
|
|
xvt_dwin_draw_set_pos(win, q);
|
|
|
|
q.h -= TABX*CHARX - 3*CHARX/2;
|
|
|
|
xvt_dwin_draw_line(win, q);
|
2003-06-11 07:44:57 +00:00
|
|
|
q.v = (by+1+ui->_headlines)*rh;
|
2003-02-25 15:22:52 +00:00
|
|
|
|
1998-02-10 09:25:41 +00:00
|
|
|
xvt_dwin_draw_line(win, q);
|
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
TImage* bmp = node.image(is_selected);
|
1998-02-10 09:25:41 +00:00
|
|
|
if (bmp)
|
1998-12-10 16:25:48 +00:00
|
|
|
{
|
|
|
|
const int x = p.h;
|
2003-01-28 14:27:05 +00:00
|
|
|
const int y = p.v + (rh - bmp->height()) / 2;
|
1998-12-10 16:25:48 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
1998-02-10 09:25:41 +00:00
|
|
|
|
|
|
|
TNode_info& ni = (*ui->_node_info)[ry];
|
|
|
|
node.curr_id(ni._id);
|
1998-12-10 16:25:48 +00:00
|
|
|
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();
|
1998-02-16 16:31:24 +00:00
|
|
|
if (ni._expandable)
|
|
|
|
{
|
|
|
|
ni._plusx = ui->_x - TABX + 1;
|
|
|
|
ni._expanded = node.expanded();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ni._plusx = 0;
|
|
|
|
ni._expanded = FALSE;
|
|
|
|
}
|
1998-02-10 09:25:41 +00:00
|
|
|
}
|
|
|
|
ui->_y++;
|
1998-02-06 16:13:56 +00:00
|
|
|
|
|
|
|
ui->_x += TABX;
|
|
|
|
if (ui->_x > ui->_jolly)
|
|
|
|
ui->_jolly = ui->_x;
|
1998-02-10 09:25:41 +00:00
|
|
|
} else
|
|
|
|
if (when == SCAN_IN_ORDER)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
1998-02-10 09:25:41 +00:00
|
|
|
ui->_x -= TABX;
|
1998-05-04 08:17:15 +00:00
|
|
|
if (ui->_y > ui->_lasty)
|
|
|
|
return TRUE;
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TTree_window::draw_plus_minus()
|
|
|
|
{
|
|
|
|
const long firsty = origin().y;
|
1998-02-16 16:31:24 +00:00
|
|
|
const int last_drawn = _node_info.last();
|
|
|
|
for (int i = last_drawn; i >= 0; i--)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
1998-02-16 16:31:24 +00:00
|
|
|
TNode_info& ni = _node_info[i];
|
1998-02-06 16:13:56 +00:00
|
|
|
if (ni._plusx > 0)
|
|
|
|
{
|
1998-02-16 16:31:24 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
WINDOW w = win();
|
|
|
|
PNT r = log2dev(ni._plusx, firsty + i);
|
1998-07-20 13:29:52 +00:00
|
|
|
r.v += _row_height/2;
|
1998-02-06 16:13:56 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-07-02 16:21:23 +00:00
|
|
|
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++)
|
|
|
|
stringat(2, int(origin().y+i-_headlines), _header.get(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
void TTree_window::update()
|
1999-10-22 10:00:18 +00:00
|
|
|
{
|
1998-02-13 13:59:33 +00:00
|
|
|
TField_window::update();
|
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
if (_tree == NULL)
|
|
|
|
return;
|
1999-10-22 10:00:18 +00:00
|
|
|
|
2002-07-02 16:21:23 +00:00
|
|
|
update_header();
|
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
TUpdate_info ui;
|
|
|
|
ui._win = this;
|
|
|
|
ui._x = 0;
|
|
|
|
ui._y = 0;
|
|
|
|
ui._firsty = origin().y;
|
|
|
|
ui._lasty = ui._firsty + rows();
|
|
|
|
ui._jolly = 0;
|
2002-07-02 16:21:23 +00:00
|
|
|
ui._headlines = _headlines;
|
1998-02-06 16:13:56 +00:00
|
|
|
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();
|
1999-10-22 10:00:18 +00:00
|
|
|
if (!ok)
|
|
|
|
return;
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_node_info.reset();
|
1998-12-10 16:25:48 +00:00
|
|
|
set_opaque_text(TRUE);
|
1998-02-10 09:25:41 +00:00
|
|
|
|
1998-02-13 13:59:33 +00:00
|
|
|
word flags = SCAN_PRE_ORDER | SCAN_IN_ORDER | SCAN_IGNORING_UNEXPANDED;
|
|
|
|
if (_hide_leaves) flags |= SCAN_IGNORING_LEAVES;
|
|
|
|
|
1998-02-10 09:25:41 +00:00
|
|
|
_tree->scan_depth_first(callback_draw_node, &ui, flags);
|
1998-02-06 16:13:56 +00:00
|
|
|
while (ui._y < ui._lasty)
|
|
|
|
{
|
|
|
|
if (_tree->goto_father())
|
1998-02-10 09:25:41 +00:00
|
|
|
{
|
|
|
|
ui._x -= TABX;
|
1998-02-06 16:13:56 +00:00
|
|
|
if (_tree->goto_rbrother())
|
1998-02-10 09:25:41 +00:00
|
|
|
_tree->scan_depth_first(callback_draw_node, &ui, flags);
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
draw_plus_minus();
|
|
|
|
|
|
|
|
set_scroll_max(ui._jolly+columns(), ui._y);
|
|
|
|
_first_line = ui._firsty;
|
|
|
|
}
|
|
|
|
|
1999-05-24 13:34:11 +00:00
|
|
|
// Fa diventare il nodo corrente selezionato
|
1998-05-04 08:17:15 +00:00
|
|
|
bool TTree_window::select_current()
|
|
|
|
{
|
|
|
|
if (_tree)
|
|
|
|
_tree->curr_id(_curr_info._id);
|
|
|
|
return _tree != NULL;
|
|
|
|
}
|
|
|
|
|
1999-05-24 13:34:11 +00:00
|
|
|
// Salta al nodo correntemente selezionato
|
|
|
|
bool TTree_window::goto_selected()
|
|
|
|
{
|
|
|
|
bool ok = FALSE;
|
|
|
|
if (_tree)
|
|
|
|
ok = _tree->goto_node(_curr_info._id);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2003-01-28 14:27:05 +00:00
|
|
|
void TTree_window::set_row_height(int rh)
|
|
|
|
{
|
|
|
|
if (rh <= 0)
|
|
|
|
rh = CHARY+2;
|
|
|
|
_row_height = rh;
|
|
|
|
}
|
1999-05-24 13:34:11 +00:00
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
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();
|
1998-02-17 10:15:46 +00:00
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
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
|
1998-02-17 10:15:46 +00:00
|
|
|
if (index == last+1 && last >= 0)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
|
|
|
if (index2info(last, ni) && _tree->goto_node(ni._id))
|
|
|
|
{
|
|
|
|
ok = _tree->expanded() && _tree->goto_firstson();
|
1998-02-17 10:15:46 +00:00
|
|
|
if (ok && _hide_leaves && !_tree->has_son())
|
|
|
|
{
|
|
|
|
_tree->goto_node(ni._id); // Ritorno al padre perche' ignoro le foglie
|
|
|
|
ok = FALSE;
|
|
|
|
}
|
1998-02-06 16:13:56 +00:00
|
|
|
if (!ok)
|
|
|
|
{
|
|
|
|
ok = _tree->goto_rbrother();
|
|
|
|
ni._startx += TABX;
|
|
|
|
}
|
|
|
|
if (ok)
|
1998-02-17 10:15:46 +00:00
|
|
|
{
|
1998-02-06 16:13:56 +00:00
|
|
|
_tree->curr_id(ni._id);
|
1998-02-17 10:15:46 +00:00
|
|
|
}
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
} 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)
|
|
|
|
{
|
1999-10-22 10:00:18 +00:00
|
|
|
if (_tree == NULL || _tree_locked)
|
1998-02-16 16:31:24 +00:00
|
|
|
return FALSE;
|
|
|
|
|
1998-05-04 08:17:15 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
1998-02-16 16:31:24 +00:00
|
|
|
if (key == K_UP || key == K_DOWN)
|
1999-10-22 10:00:18 +00:00
|
|
|
{
|
|
|
|
_tree_locked = TRUE;
|
1998-02-06 16:13:56 +00:00
|
|
|
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
|
|
|
|
{
|
1998-02-17 10:15:46 +00:00
|
|
|
const int index = key == K_UP ? 0 : _node_info.last();
|
|
|
|
ok = index2info(index, ni) && _tree->goto_node(ni._id);
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ok && _curr_info != ni)
|
|
|
|
{
|
|
|
|
_tree->curr_id(_curr_info._id);
|
1998-02-13 13:59:33 +00:00
|
|
|
owner().on_key(K_SPACE);
|
1998-02-06 16:13:56 +00:00
|
|
|
if (!scroll)
|
1999-10-22 10:00:18 +00:00
|
|
|
{
|
1998-02-06 16:13:56 +00:00
|
|
|
force_update();
|
1999-10-22 10:00:18 +00:00
|
|
|
do_events();
|
|
|
|
}
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
1999-10-22 10:00:18 +00:00
|
|
|
|
|
|
|
_tree_locked = FALSE;
|
1998-02-06 16:13:56 +00:00
|
|
|
if (!scroll)
|
|
|
|
return TRUE;
|
|
|
|
}
|
1998-02-16 16:31:24 +00:00
|
|
|
|
|
|
|
if (key == K_ENTER)
|
1999-10-22 10:00:18 +00:00
|
|
|
{
|
|
|
|
_tree_locked = TRUE;
|
1998-02-17 10:15:46 +00:00
|
|
|
if (_tree->goto_node(_curr_info._id))
|
1998-02-16 16:31:24 +00:00
|
|
|
{
|
1999-10-22 10:00:18 +00:00
|
|
|
if (_tree->has_son())
|
1998-05-04 08:17:15 +00:00
|
|
|
{
|
1999-10-22 10:00:18 +00:00
|
|
|
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);
|
|
|
|
}
|
1998-05-04 08:17:15 +00:00
|
|
|
}
|
|
|
|
owner().on_key(K_CTRL + K_SPACE);
|
1998-02-16 16:31:24 +00:00
|
|
|
}
|
1999-10-22 10:00:18 +00:00
|
|
|
_tree_locked = FALSE;
|
1998-02-16 16:31:24 +00:00
|
|
|
}
|
|
|
|
|
1998-02-13 13:59:33 +00:00
|
|
|
return TField_window::on_key(key);
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TTree_window::handler(WINDOW win, EVENT* ep)
|
|
|
|
{
|
|
|
|
switch(ep->type)
|
|
|
|
{
|
|
|
|
case E_MOUSE_DBL:
|
1998-02-16 16:31:24 +00:00
|
|
|
case E_MOUSE_DOWN:
|
1999-10-22 10:00:18 +00:00
|
|
|
if (_tree && !_tree_locked)
|
|
|
|
{
|
|
|
|
_tree_locked = TRUE;
|
2002-07-02 16:21:23 +00:00
|
|
|
const TPoint lp = dev2log(ep->v.mouse.where);
|
|
|
|
const int c = (int)lp.x;
|
|
|
|
const int r = (int)lp.y;
|
1998-07-20 13:29:52 +00:00
|
|
|
|
1998-02-06 16:13:56 +00:00
|
|
|
TNode_info ni;
|
|
|
|
bool ok = index2info(r, ni);
|
|
|
|
if (ok && (c == ni._plusx || (c >= ni._startx && c < ni._endx)) &&
|
|
|
|
_tree->goto_node(ni._id))
|
|
|
|
{
|
1998-02-16 16:31:24 +00:00
|
|
|
if (c == ni._plusx || (ni._expandable && ep->type == E_MOUSE_DBL))
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
|
|
|
if (_tree->expanded())
|
|
|
|
ok = _tree->shrink();
|
|
|
|
else
|
|
|
|
ok = _tree->expand();
|
|
|
|
if (ok)
|
1998-02-13 13:59:33 +00:00
|
|
|
owner().on_key(K_CTRL + K_SPACE);
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-05-04 08:17:15 +00:00
|
|
|
KEY key = K_SPACE;
|
|
|
|
if (ep->type == E_MOUSE_DBL)
|
|
|
|
key += K_CTRL;
|
|
|
|
owner().on_key(key);
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
_curr_info = ni;
|
|
|
|
force_update();
|
|
|
|
}
|
|
|
|
}
|
1999-10-22 10:00:18 +00:00
|
|
|
_tree_locked = FALSE;
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
1998-02-13 13:59:33 +00:00
|
|
|
TField_window::handler(win, ep);
|
1998-02-06 16:13:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TTree_window::TTree_window(int x, int y, int dx, int dy,
|
|
|
|
WINDOW parent, TTree_field* owner)
|
1998-07-20 13:29:52 +00:00
|
|
|
: TField_window(x, y, dx, dy, parent, owner), _tree(NULL),
|
2002-09-13 14:06:05 +00:00
|
|
|
_hide_leaves(FALSE), _headlines(0)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
2003-01-28 14:27:05 +00:00
|
|
|
set_row_height(-1); // Compute default row height
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TTree_field
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
word TTree_field::class_id() const
|
|
|
|
{
|
|
|
|
return CLASS_TREE_FIELD;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree_field::is_kind_of(word cid) const
|
|
|
|
{
|
1999-05-24 13:34:11 +00:00
|
|
|
return cid == CLASS_TREE_FIELD || TWindowed_field::is_kind_of(cid);
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define tree_win() ((TTree_window&)win())
|
|
|
|
|
|
|
|
TTree* TTree_field::tree() const
|
|
|
|
{
|
|
|
|
return tree_win().tree();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TTree_field::set_tree(TTree* tree)
|
|
|
|
{
|
|
|
|
tree_win().set_tree(tree);
|
1998-05-04 08:17:15 +00:00
|
|
|
tree_win().select_current();
|
1998-02-06 16:13:56 +00:00
|
|
|
}
|
|
|
|
|
1998-02-13 13:59:33 +00:00
|
|
|
void TTree_field::hide_leaves(bool yes)
|
|
|
|
{
|
|
|
|
tree_win().hide_leaves(yes);
|
|
|
|
}
|
|
|
|
|
1998-05-04 08:17:15 +00:00
|
|
|
bool TTree_field::select_current()
|
|
|
|
{
|
|
|
|
return tree_win().select_current();
|
|
|
|
}
|
|
|
|
|
1999-05-24 13:34:11 +00:00
|
|
|
bool TTree_field::goto_selected()
|
|
|
|
{
|
|
|
|
return tree_win().goto_selected();
|
|
|
|
}
|
|
|
|
|
2002-07-02 16:21:23 +00:00
|
|
|
void TTree_field::set_header(const char* head)
|
|
|
|
{
|
|
|
|
tree_win().set_header(head);
|
|
|
|
}
|
|
|
|
|
2003-01-28 14:27:05 +00:00
|
|
|
void TTree_field::set_row_height(int rh)
|
|
|
|
{
|
|
|
|
tree_win().set_row_height(rh);
|
|
|
|
}
|
|
|
|
|
1998-02-13 13:59:33 +00:00
|
|
|
TField_window* TTree_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
|
1998-02-06 16:13:56 +00:00
|
|
|
{
|
1998-02-13 13:59:33 +00:00
|
|
|
return new TTree_window(x, y, dx, dy, parent, this);
|
2003-01-28 14:27:05 +00:00
|
|
|
}
|