2008-01-31 14:02:52 +00:00
|
|
|
#define XI_INTERNAL
|
|
|
|
#include <xinclude.h>
|
|
|
|
|
2007-12-12 16:37:46 +00:00
|
|
|
#include <colors.h>
|
2008-09-29 14:21:49 +00:00
|
|
|
#include <controls.h>
|
2007-12-12 16:37:46 +00:00
|
|
|
#include <image.h>
|
2008-01-31 14:02:52 +00:00
|
|
|
#include <mask.h>
|
2007-12-12 16:37:46 +00:00
|
|
|
#include <tree.h>
|
2008-01-31 14:02:52 +00:00
|
|
|
#include <treectrl.h>
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TField_window
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#ifndef INCL_XI
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
void xi_draw_3d_rect( WINDOW win, RCT* rctp, BOOLEAN well, int height,
|
|
|
|
COLOR color_light, COLOR color_ctrl, COLOR color_dark );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void TField_window::handler(WINDOW win, EVENT* ep)
|
|
|
|
{
|
|
|
|
switch (ep->type)
|
|
|
|
{
|
|
|
|
case E_FOCUS:
|
|
|
|
if (ep->v.active)
|
|
|
|
{
|
|
|
|
WINDOW parent = xvt_vobj_get_parent(win);
|
|
|
|
XI_OBJ* itf = xi_get_itf((XinWindow)parent);
|
|
|
|
xi_set_focus(itf);
|
|
|
|
}
|
|
|
|
break;
|
2008-09-19 15:35:09 +00:00
|
|
|
case E_MOUSE_DOWN:
|
|
|
|
if (ep->v.mouse.button == 1 && _owner != NULL)
|
|
|
|
{
|
|
|
|
_owner->on_key(K_F11);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
2008-01-31 14:02:52 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
TScroll_window::handler(win, ep);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TField_window::on_key(KEY k)
|
|
|
|
{
|
|
|
|
if (k == K_TAB || k == K_BTAB || k == K_F3 || k == K_F4)
|
|
|
|
{
|
|
|
|
const TMask& m = _owner->mask();
|
|
|
|
const short id = _owner->dlg();
|
|
|
|
const int start = m.id2pos(id);
|
|
|
|
const int dir = (k == K_TAB || k == K_F3) ? +1 : -1;
|
|
|
|
|
|
|
|
int pos = start;
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
pos += dir;
|
|
|
|
if (pos < 0) pos = m.fields()-1;
|
|
|
|
if (pos >= m.fields()) pos = 0;
|
|
|
|
if (pos == start)
|
|
|
|
break;
|
|
|
|
TMask_field& f = m.fld(pos);
|
|
|
|
if (f.is_operable())
|
|
|
|
{
|
|
|
|
f.set_focus();
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TScroll_window::on_key(k);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TField_window::update()
|
|
|
|
{
|
|
|
|
const WINDOW me = win();
|
|
|
|
if (CAMPI_SCAVATI)
|
|
|
|
{
|
|
|
|
const WINDOW pa = parent();
|
|
|
|
RCT rct; xvt_vobj_get_outer_rect(me, &rct);
|
|
|
|
rct.left -= 2; rct.top -= 2; rct.right += 2; rct.bottom += 2;
|
2008-05-15 14:59:21 +00:00
|
|
|
xi_draw_3d_rect((XinWindow)pa, (XinRect *) &rct, TRUE, 2,
|
2008-01-31 14:02:52 +00:00
|
|
|
MASK_LIGHT_COLOR, MASK_BACK_COLOR, MASK_DARK_COLOR);
|
|
|
|
}
|
|
|
|
xvt_dwin_clear(me, NORMAL_BACK_COLOR);
|
|
|
|
set_font();
|
|
|
|
}
|
|
|
|
|
2008-05-15 14:59:21 +00:00
|
|
|
// Serve quando si chiama il costruttore senza owner
|
|
|
|
void TField_window::set_owner(TWindowed_field* o)
|
|
|
|
{ _owner = o; }
|
|
|
|
|
2008-01-31 14:02:52 +00:00
|
|
|
TField_window::TField_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner)
|
|
|
|
: _owner(owner)
|
|
|
|
{
|
|
|
|
if (owner != NULL)
|
|
|
|
{
|
2008-05-15 14:59:21 +00:00
|
|
|
CHECK(parent, "Null control parent");
|
2008-01-31 14:02:52 +00:00
|
|
|
create(x, y, dx, dy, "", WSF_HSCROLL | WSF_VSCROLL, W_PLAIN, parent);
|
|
|
|
activate(owner->enabled());
|
|
|
|
if (owner->shown())
|
|
|
|
open();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TWindowed field
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void TWindowed_field::enable(bool on)
|
|
|
|
{
|
|
|
|
TOperable_field::enable(on);
|
|
|
|
if (_win)
|
|
|
|
_win->activate(on);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TWindowed_field::show(bool on)
|
|
|
|
{
|
|
|
|
TOperable_field::show(on);
|
|
|
|
if (_win && _win->is_open() != on)
|
|
|
|
{
|
|
|
|
if (on)
|
|
|
|
_win->open();
|
|
|
|
else
|
|
|
|
_win->close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TWindowed_field::highlight() const
|
|
|
|
{
|
|
|
|
if (_win && active())
|
|
|
|
_win->set_focus();
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT& TWindowed_field::get_rect(RCT& r) const
|
|
|
|
{
|
|
|
|
if (_win)
|
|
|
|
xvt_vobj_get_outer_rect(_win->win(), &r);
|
|
|
|
else
|
|
|
|
xvt_rect_set_empty(&r);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TWindowed_field::set_rect(const RCT& r)
|
|
|
|
{
|
|
|
|
if (_win)
|
|
|
|
xvt_vobj_move(_win->win(), (RCT*)&r);
|
|
|
|
}
|
|
|
|
|
|
|
|
word TWindowed_field::class_id() const
|
|
|
|
{ return CLASS_WINDOWED_FIELD; }
|
|
|
|
|
|
|
|
bool TWindowed_field::is_kind_of(word id) const
|
|
|
|
{ return id == CLASS_WINDOWED_FIELD || TOperable_field::is_kind_of(id); }
|
|
|
|
|
|
|
|
const char* TWindowed_field::class_name() const
|
|
|
|
{ return "WINDOWED"; }
|
|
|
|
|
|
|
|
short TWindowed_field::dlg() const
|
|
|
|
{ return _dlg ? _dlg : _ctl_data._dlg; }
|
|
|
|
|
|
|
|
void TWindowed_field::parse_head(TScanner& scanner)
|
|
|
|
{
|
|
|
|
_ctl_data._width = scanner.integer();
|
|
|
|
_ctl_data._height = scanner.integer();
|
|
|
|
}
|
|
|
|
|
|
|
|
TField_window* TWindowed_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
|
|
|
|
{
|
|
|
|
// Must be always overridden and look like this
|
|
|
|
return new TField_window(x, y, dx, dy, parent, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TWindowed_field::create(short id, int x, int y, int dx, int dy, WINDOW parent)
|
|
|
|
{
|
|
|
|
if (parent == NULL_WIN)
|
|
|
|
parent = mask().win();
|
|
|
|
_dlg = id;
|
|
|
|
_win = create_window(x, y, dx, dy, parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TWindowed_field::create(WINDOW parent)
|
|
|
|
{
|
|
|
|
create(_ctl_data._dlg, _ctl_data._x, _ctl_data._y, _ctl_data._width, _ctl_data._height, parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
TWindowed_field::TWindowed_field(TMask* m)
|
|
|
|
: TOperable_field(m), _dlg(0), _win(NULL)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
TWindowed_field::~TWindowed_field()
|
|
|
|
{
|
|
|
|
if (_win)
|
|
|
|
delete _win;
|
|
|
|
}
|
2007-12-12 16:37:46 +00:00
|
|
|
|
|
|
|
#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
|
|
|
|
|
2008-01-31 14:02:52 +00:00
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TControl_host_window
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void TControl_host_window::handler(WINDOW win, EVENT* ep)
|
|
|
|
{
|
|
|
|
switch (ep->type)
|
|
|
|
{
|
|
|
|
case E_SIZE:
|
|
|
|
if (_ctrl != NULL_WIN)
|
|
|
|
{
|
|
|
|
RCT rct;
|
|
|
|
xvt_rect_set(&rct, 0, 0, ep->v.size.width, ep->v.size.height);
|
|
|
|
xvt_vobj_move(_ctrl, &rct);
|
|
|
|
}
|
|
|
|
break;
|
2008-02-14 16:39:04 +00:00
|
|
|
case E_UPDATE:
|
|
|
|
if (_ctrl != NULL_WIN)
|
|
|
|
return; // Inutile disegnare: _ctrl occupa tutta la client area
|
|
|
|
break;
|
2008-01-31 14:02:52 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
TField_window::handler(win, ep);
|
|
|
|
}
|
|
|
|
|
|
|
|
TControl_host_window::TControl_host_window(int x, int y, int dx, int dy,
|
|
|
|
WINDOW parent, TWindowed_field* owner)
|
|
|
|
: TField_window(x, y, dx, dy, parent, owner), _ctrl(NULL_WIN)
|
|
|
|
{
|
|
|
|
set_scroll_max(0, 0); // Get rid of that useless scrollbars
|
|
|
|
}
|
|
|
|
|
2007-12-12 16:37:46 +00:00
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TTree_window
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
2008-01-31 14:02:52 +00:00
|
|
|
class TTree_window : public TControl_host_window
|
2007-12-12 16:37:46 +00:00
|
|
|
{
|
|
|
|
TTree* _tree;
|
|
|
|
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);
|
2008-04-04 16:04:15 +00:00
|
|
|
if (im_nor != NULL)
|
2007-12-12 16:37:46 +00:00
|
|
|
{
|
2008-04-04 16:04:15 +00:00
|
|
|
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();
|
2007-12-12 16:37:46 +00:00
|
|
|
}
|
|
|
|
XVT_TREEVIEW_NODE child = xvt_treeview_add_child_node(_ctrl, parent, type, ii, ic, ie, desc, NULL, id);
|
2008-02-14 16:39:04 +00:00
|
|
|
if (child != NULL && type == XVT_TREEVIEW_NODE_NONTERMINAL && _tree->expanded())
|
|
|
|
{
|
|
|
|
for (bool ok = _tree->goto_firstson(); ok; ok = _tree->goto_rbrother())
|
|
|
|
add_child(child);
|
2007-12-12 16:37:46 +00:00
|
|
|
xvt_treeview_expand_node(_ctrl, child, FALSE);
|
2008-02-14 16:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_tree->goto_node(id);
|
2007-12-12 16:37:46 +00:00
|
|
|
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())
|
|
|
|
{
|
2008-07-11 11:16:52 +00:00
|
|
|
clear(MASK_BACK_COLOR);
|
2007-12-12 16:37:46 +00:00
|
|
|
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;
|
2008-07-11 11:16:52 +00:00
|
|
|
case E_UPDATE:
|
|
|
|
update(); // TControl_host_window non lo fa
|
|
|
|
return;
|
2007-12-12 16:37:46 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2008-01-31 14:02:52 +00:00
|
|
|
TControl_host_window::handler(win, ep);
|
2007-12-12 16:37:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool TTree_window::select_current()
|
|
|
|
{
|
2008-09-29 14:21:49 +00:00
|
|
|
XVT_TREEVIEW_NODE nextsel = NULL; // Nodo da selezionare (se mai lo trovero')
|
2007-12-12 16:37:46 +00:00
|
|
|
|
|
|
|
if (_tree != NULL)
|
|
|
|
{
|
2008-01-17 11:03:22 +00:00
|
|
|
TString id; _tree->curr_id(id); // id del nodo corrente dell'albero
|
|
|
|
|
|
|
|
// Controllo se il tree control e' gia' posizionato bene
|
|
|
|
XVT_TREEVIEW_NODE cursel = xvt_treeview_get_selected_node(_ctrl);
|
2008-09-29 14:21:49 +00:00
|
|
|
nextsel = xvt_treeview_find_node_string(_ctrl, id);
|
|
|
|
if (nextsel != NULL && cursel == nextsel)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (nextsel == NULL)
|
2008-01-17 11:03:22 +00:00
|
|
|
{
|
2008-09-29 14:21:49 +00:00
|
|
|
xvt_treeview_suspend(_ctrl); // Sospendo le notifiche degli eventi
|
|
|
|
TString_array a;
|
|
|
|
a.add(id);
|
|
|
|
// Creo la lista dei progenitori
|
|
|
|
while (_tree->goto_father())
|
2008-01-17 11:03:22 +00:00
|
|
|
{
|
2008-09-29 14:21:49 +00:00
|
|
|
const int i = a.add(EMPTY_STRING);
|
|
|
|
_tree->curr_id(a.row(i));
|
|
|
|
_tree->expand(); // Nel caso non fosse gia' espanso
|
2008-01-17 11:03:22 +00:00
|
|
|
}
|
2007-12-12 16:37:46 +00:00
|
|
|
|
2008-09-29 14:21:49 +00:00
|
|
|
// 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)
|
2007-12-12 16:37:46 +00:00
|
|
|
{
|
2008-09-29 14:21:49 +00:00
|
|
|
if (killed)
|
2007-12-12 16:37:46 +00:00
|
|
|
break;
|
2008-09-29 14:21:49 +00:00
|
|
|
for (int i = 0; ; i++)
|
2007-12-12 16:37:46 +00:00
|
|
|
{
|
2008-09-29 14:21:49 +00:00
|
|
|
XVT_TREEVIEW_NODE child = xvt_treeview_get_child_node(_ctrl, parent, i);
|
|
|
|
if (child == NULL && i == 0) // Forse non c'e' nessun figlio ...
|
2007-12-12 16:37:46 +00:00
|
|
|
{
|
2008-09-29 14:21:49 +00:00
|
|
|
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 = xvt_treeview_get_node_data(_ctrl, child);
|
|
|
|
if (*row == data)
|
|
|
|
{
|
|
|
|
nextsel = child;
|
|
|
|
if (*row == id) // Ho finito
|
|
|
|
killed = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
parent = child;
|
|
|
|
xvt_treeview_expand_node(_ctrl, child, FALSE);
|
|
|
|
}
|
|
|
|
break;
|
2007-12-12 16:37:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-09-29 14:21:49 +00:00
|
|
|
xvt_treeview_resume(_ctrl); // Riattivo le notifiche degli eventi
|
|
|
|
_tree->goto_node(id); // Riposiziono l'albero
|
|
|
|
}
|
|
|
|
if (nextsel != NULL)
|
|
|
|
{
|
|
|
|
xvt_treeview_select_node(_ctrl, nextsel, TRUE);
|
|
|
|
if (_tree->expanded())
|
|
|
|
xvt_treeview_expand_node(_ctrl, nextsel, FALSE);
|
2007-12-12 16:37:46 +00:00
|
|
|
}
|
|
|
|
}
|
2008-09-29 14:21:49 +00:00
|
|
|
return nextsel != NULL;
|
2007-12-12 16:37:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2008-01-31 14:02:52 +00:00
|
|
|
: TControl_host_window(x, y, dx, dy, parent, owner),
|
|
|
|
_tree(NULL), _hide_leaves(false)
|
2007-12-12 16:37:46 +00:00
|
|
|
{
|
|
|
|
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); }
|
2008-01-31 14:02:52 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TOutlook_field
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
class TOutlook_window : public TControl_host_window
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual void handler(WINDOW win, EVENT* ep);
|
|
|
|
|
|
|
|
public:
|
|
|
|
int add_item(short icon, const char* text, int flags);
|
|
|
|
bool select(int item, bool on);
|
|
|
|
int selected() const;
|
|
|
|
TOutlook_window(int x, int y, int dx, int dy, WINDOW parent, TOutlook_field* owner);
|
|
|
|
};
|
|
|
|
|
|
|
|
void TOutlook_window::handler(WINDOW win, EVENT* ep)
|
|
|
|
{
|
|
|
|
switch (ep->type)
|
|
|
|
{
|
|
|
|
case E_CONTROL:
|
|
|
|
if (ep->v.ctl.ci.type == WC_OUTLOOKBAR)
|
|
|
|
{
|
|
|
|
owner().on_key(K_SPACE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
TControl_host_window::handler(win, ep);
|
|
|
|
}
|
|
|
|
|
|
|
|
int TOutlook_window::add_item(short icon, const char* text, int flags)
|
|
|
|
{ return xvt_list_add_item(_ctrl, icon, text, flags); }
|
|
|
|
|
|
|
|
bool TOutlook_window::select(int item, bool on)
|
|
|
|
{ return xvt_list_set_sel(_ctrl, item, on) != FALSE; }
|
|
|
|
|
|
|
|
int TOutlook_window::selected() const
|
|
|
|
{ return xvt_list_get_sel_index(_ctrl); }
|
|
|
|
|
|
|
|
TOutlook_window::TOutlook_window(int x, int y, int dx, int dy, WINDOW parent, TOutlook_field* owner)
|
|
|
|
: TControl_host_window(x, y, dx, dy, parent, owner)
|
|
|
|
{
|
2008-10-08 08:49:04 +00:00
|
|
|
XVT_COLOR_COMPONENT xcc[4]; memset(xcc, 0, sizeof(xcc));
|
|
|
|
xcc[0].type = XVT_COLOR_BACKGROUND;
|
|
|
|
xcc[0].color = BTN_BACK_COLOR;
|
2008-11-11 16:16:48 +00:00
|
|
|
xcc[1].type = XVT_COLOR_FOREGROUND;
|
|
|
|
xcc[1].color = NORMAL_COLOR;
|
2008-10-08 08:49:04 +00:00
|
|
|
|
2008-01-31 14:02:52 +00:00
|
|
|
WIN_DEF wd; memset(&wd, 0, sizeof(wd));
|
|
|
|
wd.wtype = WC_OUTLOOKBAR;
|
|
|
|
wd.v.ctl.ctrl_id = owner->dlg();
|
2008-11-13 12:31:11 +00:00
|
|
|
wd.v.ctl.font_id = xvtil_default_font(true); // Fat font
|
2008-01-31 14:02:52 +00:00
|
|
|
wd.rct = resize_rect(x, y, dx, dy, wd.wtype, parent);
|
2008-10-08 08:49:04 +00:00
|
|
|
wd.ctlcolors = xcc;
|
|
|
|
|
2008-01-31 14:02:52 +00:00
|
|
|
_ctrl = xvt_ctl_create_def(&wd, win(), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
word TOutlook_field::class_id() const
|
|
|
|
{ return CLASS_OUTLOOK_FIELD; }
|
|
|
|
|
|
|
|
bool TOutlook_field::is_kind_of(word cid) const
|
|
|
|
{ return cid == CLASS_OUTLOOK_FIELD || TWindowed_field::is_kind_of(cid); }
|
|
|
|
|
|
|
|
TField_window* TOutlook_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
|
|
|
|
{ return new TOutlook_window(x, y, dx, dy, parent, this); }
|
|
|
|
|
|
|
|
void TOutlook_field::create(short dlg, int x, int y, int dx, int dy, WINDOW parent)
|
|
|
|
{ construct(dlg, "", x, y, dy, parent, "", dx); }
|
|
|
|
|
|
|
|
int TOutlook_field::add_item(short icon, const char* text, int flags)
|
|
|
|
{
|
|
|
|
TOutlook_window& ow = (TOutlook_window&)win();
|
|
|
|
return ow.add_item(icon, text, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TOutlook_field::set_window_data(const char* data)
|
|
|
|
{
|
|
|
|
TOutlook_window& ow = (TOutlook_window&)win();
|
|
|
|
const int sel = atoi(data);
|
|
|
|
_str.cut(0) << sel;
|
|
|
|
ow.select(sel, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
const TString& TOutlook_field::get_window_data()
|
|
|
|
{
|
|
|
|
TOutlook_window& ow = (TOutlook_window&)win();
|
|
|
|
_str.cut(0) << ow.selected();
|
|
|
|
return _str;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TOutlook_field::set(const char* data)
|
|
|
|
{
|
|
|
|
set_window_data(data);
|
|
|
|
set_dirty();
|
|
|
|
}
|
|
|
|
|
|
|
|
const TString& TOutlook_field::get() const
|
|
|
|
{ return _str; }
|
|
|
|
|
|
|
|
bool TOutlook_field::on_key(KEY key)
|
|
|
|
{
|
|
|
|
if (key == K_SPACE)
|
|
|
|
{
|
|
|
|
get_window_data();
|
|
|
|
set_dirty();
|
|
|
|
on_hit();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return TWindowed_field::on_key(key);
|
|
|
|
}
|
2008-05-15 14:59:21 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TSlider_window
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
class TSlider_window : public TField_window
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void set(int pos);
|
|
|
|
int get() const;
|
|
|
|
void set_range(int mi, int ma);
|
|
|
|
TSlider_window(int x, int y, int dx, int dy, WINDOW parent, TSlider_field* owner);
|
|
|
|
};
|
|
|
|
|
|
|
|
void TSlider_window::set_range(int mi, int ma)
|
|
|
|
{
|
|
|
|
if (mi != 0)
|
|
|
|
{
|
|
|
|
ma -= mi;
|
|
|
|
mi = 0;
|
|
|
|
}
|
|
|
|
if (ma < mi)
|
|
|
|
ma = 100;
|
|
|
|
xvt_sbar_set_range(win(), HVSLIDER, mi, ma);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TSlider_window::set(int pos)
|
|
|
|
{ xvt_sbar_set_pos(win(), HVSLIDER, pos); }
|
|
|
|
|
|
|
|
int TSlider_window::get() const
|
|
|
|
{ return xvt_sbar_get_pos(win(), HVSLIDER); }
|
|
|
|
|
|
|
|
TSlider_window::TSlider_window(int x, int y, int dx, int dy, WINDOW parent, TSlider_field* owner)
|
|
|
|
: TField_window(0, 0, 0, 0, NULL, NULL)
|
|
|
|
{
|
2008-10-08 08:49:04 +00:00
|
|
|
XVT_COLOR_COMPONENT xcc[2]; memset(xcc, 0, sizeof(xcc));
|
|
|
|
xcc[0].type = XVT_COLOR_BLEND;
|
|
|
|
xcc[0].color = MASK_BACK_COLOR;
|
|
|
|
|
2008-05-15 14:59:21 +00:00
|
|
|
set_owner(owner);
|
|
|
|
WIN_DEF wd; memset(&wd, 0, sizeof(wd));
|
|
|
|
wd.rct = resize_rect(x, y, dx, dy, wd.wtype, parent);
|
|
|
|
wd.wtype = (wd.rct.right-wd.rct.left) > (wd.rct.bottom-wd.rct.top) ? WC_HSLIDER : WC_VSLIDER;
|
2008-10-08 08:49:04 +00:00
|
|
|
wd.ctlcolors = xcc;
|
2008-05-15 14:59:21 +00:00
|
|
|
wd.v.ctl.ctrl_id = owner->dlg();
|
|
|
|
|
|
|
|
real mi, ma; owner->range(mi, ma);
|
|
|
|
const long limit = ma.integer() - mi.integer();
|
|
|
|
set_win(xvt_ctl_create_def(&wd, parent, limit));
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// TSlider_field
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void TSlider_field::set_window_data(const char* data)
|
|
|
|
{
|
|
|
|
TSlider_window& sw = (TSlider_window&)win();
|
|
|
|
const int sel = atoi(data);
|
|
|
|
sw.set(sel);
|
|
|
|
}
|
|
|
|
|
|
|
|
const TString& TSlider_field::get_window_data()
|
|
|
|
{
|
|
|
|
TSlider_window& sw = (TSlider_window&)win();
|
|
|
|
TString& tmp = get_tmp_string();
|
|
|
|
tmp << sw.get();
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TSlider_field::set(const char* data)
|
|
|
|
{
|
|
|
|
if (!_range_min.is_zero())
|
|
|
|
{
|
|
|
|
real n(data);
|
|
|
|
n -= _range_min;
|
|
|
|
data = n.string();
|
|
|
|
}
|
|
|
|
set_window_data(data);
|
|
|
|
set_dirty();
|
|
|
|
}
|
|
|
|
|
|
|
|
const TString& TSlider_field::get() const
|
|
|
|
{
|
|
|
|
TString& str = (TString&)((TSlider_field*)this)->get_window_data();
|
|
|
|
if (!_range_min.is_zero())
|
|
|
|
{
|
|
|
|
real n(str);
|
|
|
|
n += _range_min;
|
|
|
|
str = n.string();
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* TSlider_field::get_buddy() const
|
|
|
|
{
|
|
|
|
if (_buddy > 0)
|
|
|
|
{
|
|
|
|
const int pos = mask().id2pos(_buddy);
|
|
|
|
if (pos > 0)
|
|
|
|
{
|
|
|
|
real n = mask().fld(pos).get();
|
|
|
|
if (n < _range_min) n = _range_min;
|
|
|
|
if (n > _range_max) n = _range_max;
|
|
|
|
return n.string();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return EMPTY_STRING;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TSlider_field::set_buddy(const char* b) const
|
|
|
|
{
|
|
|
|
if (_buddy > 0)
|
|
|
|
{
|
|
|
|
const int pos = mask().id2pos(_buddy);
|
|
|
|
if (pos > 0)
|
|
|
|
mask().fld(pos).set(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TSlider_field::on_hit()
|
|
|
|
{
|
|
|
|
if (!mask().is_running())
|
|
|
|
{
|
|
|
|
set_range(_range_min, _range_max); // Imposto range dello slider
|
|
|
|
const char* b = get_buddy();
|
|
|
|
if (b && *b)
|
|
|
|
set(b);
|
|
|
|
}
|
|
|
|
return TWindowed_field::on_hit();
|
|
|
|
}
|
|
|
|
|
|
|
|
word TSlider_field::class_id() const
|
|
|
|
{ return CLASS_SLIDER_FIELD; }
|
|
|
|
|
|
|
|
bool TSlider_field::is_kind_of(word cid) const
|
|
|
|
{ return cid == CLASS_SLIDER_FIELD || TWindowed_field::is_kind_of(cid); }
|
|
|
|
|
|
|
|
TField_window* TSlider_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
|
|
|
|
{ return new TSlider_window(x, y, dx, dy, parent, this); }
|
|
|
|
|
|
|
|
void TSlider_field::set_range(const real& mi, const real& ma)
|
|
|
|
{
|
|
|
|
_range_min = mi;
|
|
|
|
_range_max = ma;
|
|
|
|
set_range(mi.integer(), ma.integer());
|
|
|
|
}
|
|
|
|
|
|
|
|
void TSlider_field::set_range(int mi, int ma)
|
|
|
|
{
|
|
|
|
_range_min = mi;
|
|
|
|
_range_max = ma;
|
|
|
|
if (_win != NULL_WIN)
|
|
|
|
{
|
|
|
|
TSlider_window& sw = (TSlider_window&)win();
|
|
|
|
sw.set_range(mi, ma);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TSlider_field::range(real& mi, real& ma)
|
|
|
|
{ mi = _range_min; ma = _range_max; }
|
|
|
|
|
|
|
|
bool TSlider_field::parse_item(TScanner& scanner)
|
|
|
|
{
|
|
|
|
if (scanner.key() == "DR") // DRIVENBY id
|
|
|
|
{
|
|
|
|
_buddy = scanner.integer();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (scanner.key() == "RA") // RANGE min max
|
|
|
|
{
|
|
|
|
const int mi = scanner.integer();
|
|
|
|
const int ma = scanner.integer();
|
|
|
|
set_range(mi, ma);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TWindowed_field::parse_item(scanner);
|
|
|
|
}
|
|
|
|
|
|
|
|
TSlider_field::TSlider_field(TMask* m)
|
|
|
|
: TWindowed_field(m), _buddy(0), _range_min(ZERO), _range_max(CENTO)
|
|
|
|
{ }
|