campo-sirio/include/window.cpp
guy 3d6a0f9bae Patch level : 10.0
Files correlati     : agalib.lib
Ricompilazione Demo : [ ]
Commento            :
Aggiunto valore di ritorno agli handler delle finestre
void TWindow::handler(WINDOW win, EVENT* e)
e' diventato
long TWindow::handler(WINDOW win, EVENT* e)


git-svn-id: svn://10.65.10.50/trunk@19478 c028cbd2-c16b-5b4b-a496-9718f37d4682
2009-10-20 15:22:22 +00:00

1187 lines
26 KiB
C++
Executable File

#define XVT_INCL_NATIVE
#define XI_INTERNAL
#include <xinclude.h>
#include <applicat.h>
#include <colors.h>
#include <urldefid.h>
#define __WINDOW_CPP
#include <window.h>
#include <xvtility.h>
///////////////////////////////////////////////////////////
// TRectangle
///////////////////////////////////////////////////////////
void TRectangle::copy(const TRectangle& r)
{
x = r.x; y = r.y;
_size = r._size;
}
void TRectangle::normalize()
{
if (_size.x < 0)
{
x += _size.x;
_size.x = -_size.x;
}
if (_size.y < 0)
{
y += _size.y;
_size.y = -_size.y;
}
}
void TRectangle::set(long cx, long cy, long dx, long dy)
{
x = cx; y = cy;
_size.set(dx, dy);
normalize();
}
void TRectangle::set(const TPoint& pt, const TPoint& sz)
{
set(pt.x, pt.y, sz.x, sz.y);
}
void TRectangle::set_bounds(long left, long top, long right, long bottom)
{
set(left, top, right-left, bottom-top);
}
bool TRectangle::contains(const TPoint& p) const
{
if (p.x < left()) return false;
if (p.y < top()) return false;
if (p.x > right()) return false;
if (p.y > bottom()) return false;
return true;
}
bool TRectangle::contains(const TRectangle& r) const
{
return r.left() >= left() && r.right() <= right() && r.top() >= top() && r.bottom() < bottom();
}
bool TRectangle::intersects(const TRectangle& r) const
{
if (left() > r.right()) return false;
if (right() < r.left()) return false;
if (top() > r.bottom()) return false;
if (bottom() < r.top()) return false;
return true;
}
void TRectangle::merge(const TRectangle& rct)
{
long l = x, t = y, r = right(), b = bottom();
if (rct.x < l) l = rct.x;
if (rct.y < t) t = rct.y;
if (rct.right() > r) r = rct.right();
if (rct.bottom() > b) b = rct.bottom();
set_bounds(l, t, r, b);
}
void TRectangle::inflate(int dx, int dy)
{
x -= dx; y -= dy;
_size.x += 2*dx;
_size.y += 2*dy;
normalize();
}
void TRectangle::deflate(int dx, int dy)
{
inflate(-dx, -dy);
}
///////////////////////////////////////////////////////////
// Utilities
///////////////////////////////////////////////////////////
HIDDEN MENU_ITEM* find_menu_item(MENU_ITEM* menu, MENU_TAG id, bool ismbar)
{
MENU_ITEM* fnd = NULL;
MENU_ITEM* mn = ismbar ? &menu[0] : &menu->child[0];
for (int m = 0; mn != NULL && mn->tag != 0; m++, mn=ismbar?&menu[m]:&menu->child[m])
{
fnd = mn->tag == id ? mn : find_menu_item(mn, id, FALSE);
if (fnd != NULL) break;
}
return fnd;
}
HIDDEN bool remove_menu_item(MENU_ITEM* menu, MENU_TAG id, bool ismbar)
{
MENU_ITEM* mn = ismbar ? &menu[0] : &menu->child[0];
for (int m = 0; mn != NULL && mn->tag != 0; m++, mn=ismbar?&menu[m]:&menu->child[m])
{
if (mn->tag == id)
{
do
{
xvt_mem_rep((DATA_PTR)mn, (DATA_PTR)(mn+1), sizeof(MENU_ITEM), 1);
mn++;
}
while (mn->tag != 0);
return TRUE;
}
else if (remove_menu_item(mn, id, FALSE))
return TRUE;
}
return FALSE;
}
HIDDEN void set_menu_item(MENU_ITEM& m, TToken_string& tt)
{
MENU_TAG tag = tt.get_int(0);
const char* txt = tt.get();
char* text = (txt && *txt) ? xvt_str_duplicate(txt) : NULL;
const TString4 flag = tt.get();
m.tag = tag;
m.text = text;
m.enabled = flag.find('D') < 0;
m.checkable = flag.find('C') >= 0 || flag.find('c') >= 0;
m.checked = flag.find('c') >= 0;
m.separator = text == NULL;
}
///////////////////////////////////////////////////////////
// TWindow_manager
///////////////////////////////////////////////////////////
// @doc INTERNAL
// @class TWindow_manager | Classe per la gestione di un array di finestre modali
class TWindow_manager
{
// @author:(INTERNAL) Guido
// @access:(INTERNAL) Private Member
// @ccost:(INTERNAL) MAX_WIN | 8 | Numero massimo di finestre modali
enum { MAX_WIN = 8 };
// @cmember:(INTERNAL) Stack contenente la finestra attiva
TWindow* _window[MAX_WIN];
// @cmember:(INTERNAL) Stack pointer
short _current;
// @cmember:(INTERNAL) Permette di abilitare/disabilitare il menu' della task window (stesso
// funzionamento della <mf TMask::enable>)
void menu_enable(bool) const;
// @cmember:(INTERNAL) Tiene sempre disponibile un file con un numero di handle inferiore a 20
// (per sopperire ad una mancanza di XVT)
FILE* _lowhandle;
// @access Public Member
public:
// @cmember Costruttore
TWindow_manager();
// @cmember Distruttore
~TWindow_manager();
// @cmember Registra la finestra <p m> corrente
void reg(TWindow* m);
// @cmember De-registra la finestra corrente
void unreg(const TWindow* m);
// @cmember Ritorna il puntatore alla finestra corrente
TWindow* cur_win() const
{ return (_current < 0) ? NULL : _window[_current]; }
// @cmember Chiude tutte le finestre modali aperte
void destroy();
// @cmember Ritorna TRUE se la finestra corrente puo' essere chiusa
bool can_close() const;
} WinManager;
TWindow_manager::TWindow_manager() : _current(-1), _lowhandle(NULL)
{
}
TWindow_manager::~TWindow_manager()
{
destroy();
}
void TWindow_manager::destroy()
{
while (_current >= 0)
{
TWindow* w = cur_win();
w->stop_run(K_FORCE_CLOSE);
w->close_modal();
}
}
bool TWindow_manager::can_close() const
{
bool ok = true;
if (_current >= 0)
ok = cur_win()->can_be_closed();
return ok;
}
// Dis/abilitazione del menu principale
HIDDEN void xvt_menu_enable(MENU_ITEM* m, bool on)
{
while (m->tag)
{
switch(m->tag)
{
case M_FILE: // Leave it as is
case M_EDIT:
case M_FONT:
case M_STYLE:
case M_HELP:
case -1: // Separator
break;
default:
xvt_menu_set_item_enabled(TASK_WIN, m->tag, on);
}
m++;
}
}
void TWindow_manager::menu_enable(bool on) const
{
MENU_ITEM *mi = xvt_menu_get_tree(TASK_WIN);
if (mi)
{
xvt_menu_enable(mi, on);
xvt_menu_update(TASK_WIN);
xvt_res_free_menu_tree(mi);
}
}
void TWindow_manager::reg(TWindow* m)
{
_current++;
CHECK(_current < MAX_WIN, "Too many windows");
switch (_current)
{
case 0 :
menu_enable(FALSE);
{
const bool on = main_app().firm_change_enabled();
xvt_menu_set_item_enabled(TASK_WIN, M_FILE_NEW, on);
}
break;
case 1 :
xvt_menu_set_item_enabled(TASK_WIN, M_FILE_QUIT, FALSE);
xvt_menu_set_item_enabled(TASK_WIN, M_FILE_NEW, FALSE);
default:
_window[_current-1]->deactivate(); break;
}
_window[_current] = m;
}
void TWindow_manager::unreg(const TWindow* m)
{
#ifdef DBG
if (m != cur_win())
{
yesnofatal_box("E' successo un casino nel Window Manager");
return;
}
#endif
_current--;
if (_current < 0)
{
menu_enable(TRUE);
}
else
{
TWindow& w = *cur_win();
w.activate();
xvt_menu_set_item_enabled(TASK_WIN, M_FILE_QUIT, _current == 0);
const bool cf = _current == 0 && main_app().firm_change_enabled();
xvt_menu_set_item_enabled(TASK_WIN, M_FILE_NEW, cf);
xvt_menu_update(TASK_WIN);
w.set_focus();
w.force_update();
}
}
// @func Chiude tutte le finestre aperte
void close_all_dialogs()
{
WinManager.destroy();
}
// @doc EXTERNAL
// @func Indica se l'applicazione puo' essere terminata
//
// @rdesc Ritorna il risultato della ricerca:
//
// @flag TRUE | Se l'aplicazione puo' essere chiusa
// @flag FALSE | Se l'applicazione non puo' essere chiusa
bool can_close()
{
return WinManager.can_close();
}
bool is_valid_window(WINDOW w)
{
bool ok = FALSE;
if (w != NULL_WIN)
ok = (xvt_vobj_get_attr(w, ATTR_NATIVE_WINDOW) != 0L);
return ok;
}
// @func Ritorna l'handle della finestra corrente
//
// @rdesc Restituisce l'handle della finestra corrente.
WINDOW cur_win()
// @comm Se non esiste una finestra corrente allora ritorna NULL_WIN
{
WINDOW win = NULL_WIN;
TWindow* w = WinManager.cur_win();
if (w != NULL)
{
win = w->win();
/*if (!is_valid_window(win))
{
w->stop_run(K_FORCE_CLOSE);
win = NULL_WIN;
}*/
}
return win;
}
///////////////////////////////////////////////////////////
// TWindow
///////////////////////////////////////////////////////////
DRAW_CTOOLS TWindow::_ct;
bool TWindow::_ctools_saved;
TWindow::TWindow()
: _win(NULL_WIN), _lastkey(0),
_base_char_width(0L), _open(FALSE), _modal(FALSE),
_active(TRUE), _running(FALSE), _pixmap(FALSE)
{}
word TWindow::class_id() const
{ return CLASS_WINDOW; }
long TWindow::window_handler(WINDOW win, EVENT* ep)
{
long ret = 0;
TWindow* w = (TWindow*)xvt_vobj_get_data(win);
if (w != NULL)
ret = w->handler(win, ep);
return ret;
}
// @doc EXTERNAL
// @mfunc Crea la finestra
//
// @rdesc Ritorna l'handle della finestra creata
WINDOW TWindow::create(
short x, // @parm Coordinata x della finestra
short y, // @parm Coordinata y della finestra
short dx, // @parm Larghezza della finestra
short dy, // @parm Altezza della finestra
const char* title, // @parm Titolo da assegnare alla finestra (default "")
long flags, // @parm Flag della finestra (default WSF_NONE)
WIN_TYPE wt, // @parm Tipo di finestra da creare (default W_DOC)
WINDOW parent, // @parm Handler della finestra padre (default NULL_WIN)
int menu) // @parm Menu' da assegnare alla finestra (default 0)
{
if (menu == 0) flags |= WSF_NO_MENUBAR;
if (parent == NULL_WIN) parent = TASK_WIN;
if (parent == TASK_WIN) flags |= WSF_INVISIBLE;
_win = xvtil_create_window(
wt,
x, y, dx, dy,
title,
menu, parent,
flags,
window_handler,
PTR_LONG(this)
);
CHECK(_win, "Can't create a window");
return _win;
}
TWindow::~TWindow()
{
if (_win != NULL_WIN)
{
const WINDOW del_win = _win; // Memorizzo l'handle da cancellare
_win = NULL_WIN; // Azzero preventivamente l'handle medesimo
if (is_valid_window(del_win))
xvt_vobj_destroy(del_win);
}
}
void TWindow::open()
{
WINDOW w = win();
CHECK(is_valid_window(w), "Can't open a NULL window");
xvt_vobj_set_visible(w, _open = TRUE);
xvt_scr_set_focus_vobj(w);
xvt_vobj_raise(w);
}
void TWindow::open_modal()
{
set_modal(TRUE);
_open = TRUE;
open();
WinManager.reg(this);
}
void TWindow::close()
{
CHECK(_win != NULL_WIN, "Can't close a NULL window");
if (is_valid_window(_win))
xvt_vobj_set_visible(_win, _open = FALSE);
}
void TWindow::close_modal()
{
if (is_modal())
{
WinManager.unreg(this);
close();
_open = FALSE;
set_modal(FALSE);
}
}
bool TWindow::stop_run(KEY key)
{
_running = FALSE;
_lastkey = key;
return true;
}
bool TWindow::can_be_closed() const
{
const bool ok = !is_modal();
if (!ok)
error_box("Chiudere la finestra attiva prima di uscire dal programma");
return ok;
}
// @doc EXTERNAL
// @mfunc Esegue la finestra
//
// @rdesc Ritorna l'ultimo tasto premuto nella finestra
KEY TWindow::run()
// @comm Se la finestra non era aperta la apre in modo modale
{
const bool was_open = is_open();
start_run();
_running = TRUE;
if (!was_open)
open_modal();
else
open();
while (_running)
{
do_events();
xvt_sys_sleep(50);
}
if (!was_open)
close_modal();
do_events();
return last_key();
}
void TWindow::on_button(short dlg)
{
switch(dlg)
{
case DLG_OK:
stop_run(K_ENTER);
break;
case DLG_CANCEL:
stop_run(K_ESC);
break;
case DLG_QUIT:
stop_run(K_QUIT);
break;
default:
break;
}
}
// @doc EXTERNAL
// @mfunc Gestisce l'handler della finestra
long TWindow::handler(
WINDOW win, // @parm Finestra da gestire
EVENT* ep) // @parm Evento da gestire nella finestra
{
switch(ep->type)
{
case E_CHAR:
on_key(e_char_to_key(ep));
break;
case E_CLOSE:
stop_run(K_ESC);
break;
case E_CREATE:
if (_win == NULL_WIN)
_win = win; // Gestisco meglio gli eventi che avvengono durante la creazione
break;
case E_CONTROL:
if (ep->v.ctl.ci.type == WC_PUSHBUTTON)
on_button(ep->v.ctl.id);
break;
case E_DESTROY:
_win = NULL_WIN;
break;
case E_UPDATE:
update();
break;
default:
break;
}
return 0L;
}
void TWindow::on_idle()
{
// Non c'e' niente da fare qui, ma non si puo' mai sapere
}
TPoint TWindow::size() const
{
RCT r;
xvt_vobj_get_client_rect(win() ? win() : TASK_WIN, &r);
// return TPoint(r.right / CHARX, r.bottom / CHARY);
TPoint pnt;
pnt.x = int(80L * r.right / char2pixel(80));
pnt.y = r.bottom / CHARY;
return pnt;
}
WINDOW TWindow::parent() const
{
return xvt_vobj_get_parent(win());
}
void TWindow::set_focus()
{
WINDOW w = win();
if (w)
{
xvt_scr_set_focus_vobj(w);
xvt_vobj_raise(w);
}
}
void TWindow::maximize() const
{
xvt_vobj_maximize(win());
}
void TWindow::minimize() const
{
xvt_vobj_minimize(win());
}
void TWindow::set_background_color(COLOR col)
{
XI_OBJ* itf = xi_get_itf((XinWindow)win());
itf->v.itf->back_color = col;
force_update();
}
// @doc EXTERNAL
// @mfunc Attiva/disattiva la finestra
void TWindow::activate(
bool on) // @parm Indica l'operazione da svolgere sulla finestra:
//
// @flag TRUE | Abilita la finestra (default)
// @flag FALSE | Disabilita la finestra
{
xvt_vobj_set_enabled(win(), _active = on);
}
void TWindow::set_caption(const char* title)
{
xvt_vobj_set_title(win(), title);
}
const char* TWindow::get_caption(TString& str) const
{
char* title = str.get_buffer(128);
xvt_vobj_get_title(win(), title, str.size());
return title;
}
void TWindow::force_update()
{
if (win() != NULL_WIN)
xvt_dwin_invalidate_rect(win(), NULL);
}
bool TWindow::save_ctools()
{
if (_ctools_saved == FALSE)
{
xvt_dwin_get_draw_ctools(win(), &_ct);
return _ctools_saved = TRUE;
}
return FALSE;
}
bool TWindow::restore_ctools()
{
if (_ctools_saved)
{
xvt_dwin_set_draw_ctools(win(), &_ct);
_ctools_saved = FALSE;
return TRUE;
}
return FALSE;
}
void TWindow::set_color(COLOR fore, COLOR back)
{
WINDOW w = win();
xvt_dwin_set_fore_color(w, fore);
xvt_dwin_set_back_color(w, back);
}
// @doc EXTERNAL
// @mfunc Sceglie la penna da utilizzare nella finestra
void TWindow::set_pen(
COLOR color, // @parm Colore della penna
int width, // @parm Larghezza del tratto (default 1)
PAT_STYLE pat, // @parm Stile del pattern (default PAT_SOLID)
PEN_STYLE style) // @parm Stile della penna (default P_SOLID)
{
CPEN pen;
pen.width = width;
pen.pat = pat;
pen.style = style;
pen.color = color;
xvt_dwin_set_cpen(win(), &pen);
}
void TWindow::hide_pen()
{
xvt_dwin_set_std_cpen(win(), TL_PEN_HOLLOW);
}
void TWindow::set_brush(COLOR color, PAT_STYLE pat)
{
CBRUSH brush = { pat, color };
xvt_dwin_set_cbrush(win(), &brush);
}
void TWindow::hide_brush()
{
CBRUSH brush = { PAT_HOLLOW, COLOR_WHITE };
xvt_dwin_set_cbrush(win(), &brush);
}
HIDDEN void swap(short& a, short& b)
{
short tmp = a;
a = b;
b = tmp;
}
// @doc EXTERNAL
// @mfunc Disegna un rettangolo con la possibilita' di settare la penna e il draw_mode
void TWindow::frame(
short left, // @parm Lato sinistro del rettangolo
short top, // @parm Lato superiore del rettangolo
short right, // @parm Lato destro del rettangolo
short bottom, // @parm Lato inferiore del rettangolo
int flag) // @parm Flag da assegnare per il disegno del rettangolo
// @comm Se <p left> <gt> <p right> oppure <p top> <gt> <p bottom> i valori
// vengono scambiati per permettere il disegno corretto del rettangolo
{
if (left > right) swap(left, right);
if (top > bottom) swap(top, bottom);
const bool saved = flag != 0 && save_ctools();
if (flag & 1) hide_pen();
if (flag & 2) hide_brush();
if (flag & 4)
{
set_mode(M_XOR);
set_brush(COLOR_WHITE);
}
const PNT f = log2dev(left,top);
const PNT t = log2dev(right,bottom);
RCT r;
r.top = f.v; r.left = f.h;
r.bottom = t.v; r.right = t.h;
if (!_pixmap && (flag & 2))
{
r.left += CHARX>>1; r.top += CHARY>>1;
r.right-= CHARX>>1; r.bottom -= CHARY>>1;
}
xvt_dwin_draw_rect(win(), &r);
if (saved) restore_ctools();
}
void TWindow::rect(short left, short top, short right, short bottom)
{
frame(left, top, right, bottom, 2);
}
void TWindow::bar(short left, short top, short right, short bottom)
{
frame(left, top, right, bottom, 1);
}
void TWindow::invert_bar(short left, short top, short right, short bottom)
{
frame(left, top, right, bottom, 5);
}
// @doc EXTERNAL
// @mfunc Setta opaque_text
void TWindow::set_opaque_text(
bool o) // @parm Indica la modalita' di scrittura dell'opaque_text
{
// @comm Quando <p o> e' FALSE il testo viene scritto in modo trasparente
DRAW_CTOOLS ct;
xvt_dwin_get_draw_ctools(win(), &ct);
ct.opaque_text = o;
xvt_dwin_set_draw_ctools(win(), &ct);
}
// @doc EXTERNAL
// @mfunc Sceglie il font da utilizzare nella finestra
void TWindow::set_font(
const char* family, // @parm Famiglia di appartenenza del font (default XVT_FFN_FIXED)
int style, // @parm Stile del font (default 0)
int dim) // @parm Dimensione del font (default 0)
{
xvtil_set_font(win(), family, style, dim);
_base_char_width = 0L;
}
int TWindow::char2pixel(int len) const
{
const int quantem = 80;
if (_base_char_width == 0L)
{
const TString emme(quantem, 'M');
long& bcw = (long&)_base_char_width;
bcw = xvt_dwin_get_text_width(win(), emme, quantem);
}
const int pix = int(len * _base_char_width / quantem);
return pix;
}
PNT TWindow::log2dev(long x, long y) const
{
PNT pnt = { short(y), short(x) };
if (!_pixmap)
{
pnt.h = char2pixel(pnt.h);
pnt.v *= CHARY;
}
return pnt;
}
TPoint TWindow::dev2log(const PNT& p) const
{
TPoint pnt(p.h, p.v);
if (!_pixmap)
{
pnt.x = int(128L * p.h / char2pixel(128));
pnt.y /= CHARY;
}
return pnt;
}
void TWindow::log2dev(const TRectangle& lrct, RCT& drct) const
{
const PNT dp0 = log2dev(lrct.x, lrct.y);
const PNT dp1 = log2dev(lrct.right(), lrct.bottom());
drct.left = dp0.h; drct.top = dp0.v;
drct.right = dp1.h; drct.bottom = dp1.v;
}
void TWindow::dev2log(const RCT& rctd, TRectangle& rctl) const
{
const PNT dp0 = { rctd.top, rctd.left };
const PNT dp1 = { rctd.bottom, rctd.right };
const TPoint lp0 = dev2log(dp0);
const TPoint lp1 = dev2log(dp1);
rctl.set_bounds(lp0.x, lp0.y, lp1.x, lp1.y);
}
void TWindow::stringat(short x, short y, const char* str)
{
PNT pnt = log2dev(x,y);
pnt.v += BASEY;
xvt_dwin_draw_text(win(), pnt.h, pnt.v, str, -1);
}
// @doc EXTERNAL
// @mfunc Scrive il testo formattato nella finestra alla posizione indicata
void TWindow::printat(
short x, // @parm Coordinata x della finestra in cui scrivere il testo
short y, // @parm Coordinata y della finestra in cui scrivere il testo
const char* fmt, // @parm Formato che deve essere dato al testo
...) // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>
{
if (fmt && *fmt)
{
if (strchr(fmt, '%') != NULL)
{
TString256 str; // TString str(256);
char* tmp = str.get_buffer();
va_list argptr;
va_start(argptr, fmt);
vsprintf(tmp, fmt, argptr);
va_end(argptr);
stringat(x, y, tmp);
}
else
stringat(x, y, fmt);
}
}
void TWindow::line(short x0, short y0, short x1, short y1)
{
PNT f = log2dev(x0,y0);
PNT t = log2dev(x1,y1);
if (!_pixmap)
{
if (f.h == 0) f.h = -CHARX; else f.h += CHARX>>1;
if (f.v == 0) f.v = -CHARY; else f.v += CHARY>>1;
if (t.h == 0) t.h = -CHARX; else t.h += CHARX>>1;
if (t.v == 0) t.v = -CHARY; else t.v += CHARY>>1;
}
xvt_dwin_draw_set_pos(win(), f);
xvt_dwin_draw_line(win(), t);
}
void TWindow::icon(short x0, short y0, int iconid)
{
PNT f = log2dev(x0,y0);
if (iconid <= 0)
iconid = ICON_RSRC;
xvt_dwin_draw_icon(win(), f.h, f.v, iconid);
}
void TWindow::clear(COLOR color)
{ xvt_dwin_clear(win(), color); }
void TWindow::set_mode(DRAW_MODE mode)
{ xvt_dwin_set_draw_mode(win(), mode); }
// @doc EXTERNAL
// @mfunc Aggiunge voci di menu' durante l'esecuzione di una finestra
//
// @rdesc Ritorna se e' riuscito ad aggiungere la voce al menu':
//
// @flag TRUE | Se ha ggiunto la voce
// @flag FALSE | Se non ha ggiunto la voce
bool TWindow::add_menu(
TString_array& menu, // @parm Array da aggiungere al menu'
MENU_TAG id, // @parm Identificatore del menu' a cui aggiungere le voci
bool force) // @parm Mai usato
// @comm Nel caso <p id> sia uguale a 0 la voce veine aggiunte nella barra dei menu'
{
CHECK(menu.items() > 0, "TWindow::add_menu: no menus to add");
// get menu tree
MENU_ITEM* menubar = xvt_menu_get_tree(win());
if (id == 0) // add to menubar
{
// count menus
int nmen;
for (nmen = 0; menubar[nmen].tag != 0; nmen++);
menubar = (MENU_ITEM*)xvt_mem_realloc((DATA_PTR)menubar,
sizeof(MENU_ITEM)*(nmen+menu.items()+1));
// zero new
xvt_mem_rep((DATA_PTR)&menubar[nmen], "\0", 1, sizeof(MENU_ITEM)*(menu.items()+1));
// add new menus
for (int i = 0; i < menu.items(); i++)
set_menu_item(menubar[nmen+i], menu.row(i));
}
else // add to menu
{
MENU_ITEM* father = find_menu_item(menubar, id, TRUE);
CHECK(father != NULL, "TWindow::add_menu: you're adding to a NULL menu item");
// count children
int nmen;
for (nmen = 0; father->child != NULL && father->child[nmen].tag != 0; nmen++);
father->child = (MENU_ITEM*)xvt_mem_realloc((DATA_PTR)father->child,
sizeof(MENU_ITEM)*(nmen+menu.items()+1));
// zero new
xvt_mem_rep((DATA_PTR)&(father->child[nmen]), "\0", 1, sizeof(MENU_ITEM)*(menu.items()+1));
// add new menus
for (int i = 0; i < menu.items(); i++)
set_menu_item(father->child[nmen+i], menu.row(i));
}
xvt_menu_set_tree(win(), menubar);
xvt_res_free_menu_tree(menubar);
return TRUE;
}
bool TWindow::remove_menu(MENU_TAG id)
{
MENU_ITEM* menubar = xvt_menu_get_tree(win());
if (remove_menu_item(menubar, id, TRUE))
{
xvt_menu_set_tree(win(),menubar);
xvt_res_free_menu_tree(menubar);
}
return TRUE;
}
///////////////////////////////////////////////////////////
// TTemp_window
///////////////////////////////////////////////////////////
TTemp_window::TTemp_window(WINDOW w)
{
set_win(w);
}
TTemp_window::~TTemp_window()
{
set_win(NULL_WIN); // I don't want to be closed!
}
///////////////////////////////////////////////////////////
// TScroll_window
///////////////////////////////////////////////////////////
TScroll_window::TScroll_window()
: _origin(0, 0), _max(0, 0), _shift(0), _autoscroll(TRUE),
_has_hscroll(TRUE), _has_vscroll(TRUE)
{
}
WINDOW TScroll_window::create(short x, short y, short dx, short dy,
const char* title, long flags, WIN_TYPE wt, WINDOW parent, int menu)
{
_has_hscroll = (flags & WSF_HSCROLL) != 0;
_has_vscroll = (flags & WSF_VSCROLL) != 0 ;
return TWindow::create(x, y, dx, dy, title, flags, wt, parent, menu);
}
PNT TScroll_window::log2dev(long x, long y) const
{
if (_autoscroll)
{
if (_pixmap)
{
x -= _origin.x * CHARX;
y -= (_origin.y >> _shift) * CHARY;
}
else
{
x -= _origin.x;
y -= _origin.y >> _shift;
}
}
return TWindow::log2dev(x,y);
}
void TScroll_window::set_scroll_max(long maxx, long maxy)
{
if (_has_hscroll && maxx >= 0)
{
_max.x = maxx;
xvt_sbar_set_range(win(), HSCROLL, 0, int(maxx));
}
if (_has_vscroll && maxy >= 0)
{
_shift = 0;
while ((maxy >> _shift) > 0x7FFF) _shift++;
_max.y = maxy;
xvt_sbar_set_range(win(), VSCROLL, 0, int(maxy >> _shift));
}
}
void TScroll_window::set_thumb_size(long px, long py)
{
if (_has_hscroll && px >= 0)
xvt_sbar_set_proportion(win(), HSCROLL, int(px));
if (_has_vscroll && py >= 0)
xvt_sbar_set_proportion(win(), VSCROLL, int(py >> _shift));
}
// @doc EXTERNAL
// @mfunc Aggiorna la scrollbar
void TScroll_window::update_thumb(
long x, // @parm Indica la posizione in x in cui spostare la finestra (default -1)
long y) // @parm Indica la posizione in x in cui spostare la finestra (default -1)
// @comm Nel caso si voglia aggiornare solamente una coordinata l'altra dovra' essere
// settata a -1
{
if (x >= 0 && x <= _max.x) _origin.x = x;
if (y >= 0 && y <= _max.y) _origin.y = y;
if (_has_hscroll)
xvt_sbar_set_pos(win(), HSCROLL, int(_origin.x));
if (_has_vscroll)
xvt_sbar_set_pos(win(), VSCROLL, int(_origin.y >> _shift));
}
long TScroll_window::handler(WINDOW win, EVENT* ep)
{
if (ep->type == E_HSCROLL || ep->type == E_VSCROLL)
{
long& pos = (ep->type == E_HSCROLL) ? _origin.x : _origin.y;
const long oldpos = pos;
const long max = (ep->type == E_HSCROLL) ? _max.x : _max.y;
const short pag = (ep->type == E_HSCROLL) ? columns()/2+1 : rows()/2+1;
switch(ep->v.scroll.what)
{
case SC_PAGE_UP:
pos -= pag;
break;
case SC_LINE_UP:
pos--;
break;
case SC_PAGE_DOWN:
pos += pag;
break;
case SC_LINE_DOWN:
pos++;
break;
case SC_THUMB:
pos = ep->v.scroll.pos;
break;
default:
break;
}
if (pos < 0) pos = 0;
if (pos > max) pos = max;
if (pos != oldpos)
{
update_thumb();
force_update();
}
}
return TWindow::handler(win, ep);
}
bool TScroll_window::on_key(KEY key)
{
switch(key)
{
case K_LHOME:
update_thumb(0,0);
force_update();
break;
case K_LEND:
update_thumb(0,range().y);
force_update();
break;
case K_TAB:
update_thumb(origin().x+8);
force_update();
break;
case K_BTAB:
{
long x = origin().x-8;
if (x < 0) x = 0;
update_thumb(x);
force_update();
}
break;
case K_UP:
case K_DOWN:
case K_PREV:
case K_NEXT:
case K_LEFT:
case K_RIGHT:
dispatch_e_scroll(win(), key);
break;
default:
break;
}
return TWindow::on_key(key);
}