#include #include #include #include #include #include #include #include #include #include short CHARX = 8; short CHARY = 14; short ROWY = -CHARY; // Not so good! short BASEY = 12; // ERROR HOOK che intercetta errori XVT // put breakpoint here HIDDEN bool _ignore_xvt_errors = FALSE; void ignore_xvt_errors(bool ixe) { _ignore_xvt_errors = ixe; } HIDDEN BOOLEAN error_hook(XVT_ERRMSG err, DATA_PTR) { if (_ignore_xvt_errors) return TRUE; const XVT_ERRSEV sev = xvt_errmsg_get_sev_id(err); #ifdef DBG return sev == 0 ? FALSE : FALSE; #else return sev < SEV_ERROR; #endif } // @doc INTERNAL // @func Calcola dimensioni e posizione di un controllo contenuto nella finestra // // @rdesc Ritorna il rettangolo RCT& resize_rect( short x, // @parm Coordinata x del controllo (espresso in caratteri) short y, // @parm Coordinata y del controllo (espresso in caratteri) short dx, // @parm Larghezza del controllo (espresso in caratteri) short dy, // @parm Altezza del controllo (espresso in caratteri) WIN_TYPE wt, // @parm Tipo di controllo da creare WINDOW parent) // @parm Identificatore della finestra padre { static RCT r; if (parent != TASK_WIN) { if (xvt_vobj_get_type(parent) == W_PLAIN) // Mask with Toolbar { /* if (y >= 0) { const TWindow* w = (const TWindow*)xvt_vobj_get_data(parent); if (w->is_kind_of(CLASS_MASK)) { const TMask* m = (const TMask*)w; if (parent != m->toolwin()) y++; } } */ if (x > 0 || (wt != WO_TE && wt != W_PLAIN && x == 0)) { RCT pc; xvt_vobj_get_client_rect(parent, &pc); // Get parent window size const int width = pc.right; const int tot = 80*CHARX; if (width > tot) x += (width-tot) / (CHARX<<1); } } wt = WC_TEXTEDIT; // Campo di maschera } else { if (ROWY <= 0) // Not yet initialized { RCT pc; xvt_vobj_get_client_rect(parent, &pc); ROWY = (pc.bottom - pc.top) / 23; } } switch (wt) { case WC_TEXTEDIT : if (x == 0 && dx == 0 && y == 0 && dy == 0) // Campo a tutta pagina! { xvt_vobj_get_client_rect(parent, &r); } else { r.left = (x+1)*CHARX; r.top = y*ROWY; r.right = dx*CHARX; r.bottom = (CHARY << 1) - BASEY; if (dy > 1) r.bottom += ROWY*(dy-1); } break; case W_DOC: r.left = x * CHARX; r.top = y * ROWY; r.right = dx * CHARX; r.bottom = dy * CHARY; break; default: r.left = x * CHARX; r.top = y * ROWY; r.right = (dx+2)*CHARX; r.bottom = dy*ROWY-1; break; } if (x < 0 || y < 0 || dx <= 0 || dy <= 0) { RCT pc; if (parent == NULL_WIN) parent = TASK_WIN; xvt_vobj_get_client_rect(parent, &pc); // Get parent window size if (parent == TASK_WIN) pc.bottom -= 26; const short MAXX = pc.right; const short MAXY = pc.bottom; if (x < 0) { x = -x; if (wt != WC_TEXTEDIT && x == 1) x = 11; if (x > 10) { const int num = x/10 -1; const int tot = x%10; const int spc = (MAXX - tot*r.right) / (tot+1); r.left = spc + num*(spc+r.right); } else r.left = MAXX - r.right - x*CHARX; } if (y < 0) { y = -y; if (wt != WC_TEXTEDIT && y == 1) y = 11; if (y > 10) { const int num = y/10 -1; const int tot = y%10; const int spc = (MAXY - tot*r.bottom) / (tot+1); r.top = spc + num*(spc+r.bottom); } else r.top = MAXY - r.bottom - (y-1)*ROWY; } if (dx <= 0) r.right = MAXX + dx*CHARX; else r.right += r.left; if (dy <= 0) r.bottom = MAXY + dy*ROWY; else r.bottom += r.top; } else { r.right += r.left; r.bottom += r.top; } return r; } // @doc EXTERNAL // @func Emette un suono di default void beep(int severity) { xvt_sys_beep(severity); } /////////////////////////////////////////////////////////// // Event Handling /////////////////////////////////////////////////////////// class TEvent_manager { enum { MAX = 16 }; WINDOW _w[MAX]; EVENT _e[MAX]; int _begin, _end; public: TEvent_manager() : _begin(0), _end(0) {} void push(WINDOW win, const EVENT& event); void pop(); }; HIDDEN TEvent_manager EM; void TEvent_manager::push(WINDOW w, const EVENT& e) { CHECK(w, "You shouldn't send events to NULL_WIN!"); _w[_end] = w; _e[_end] = e; const int next = (_end+1) % MAX; if (next == _begin) warning_box(FR("Hey %s, clicca piu' piano!"), (const char*)user()); else _end = next; } void TEvent_manager::pop() { if (_begin != _end) { const int i = _begin; _begin = (++_begin) % MAX; // Other events may occur! xvt_win_dispatch_event(_w[i], &_e[i]); } WINDOW cw = cur_win(); if (cw != NULL_WIN) { TWindow* w = (TWindow*)xvt_vobj_get_data(cw); CHECK(w != NULL, "Can't idle NULL window"); w->on_idle(); } } // @doc EXTERNAL // @func Processa tutti gli eventi rimasti in coda void do_events() { xvt_app_process_pending_events(); EM.pop(); } // @doc EXTERNAL // @func Permette di convertire un evento carattere in un codice carattere premuto // // @rdesc Ritorna il codice del carattere corrispondente all'evento KEY e_char_to_key( const EVENT* ep) // @parm Evento da codificare // @comm Viene controllato se l'evento e' un e_car e viene tradotto, in caso // controrio viene emesso un segnale d'errore. { CHECK(ep->type == E_CHAR, "I can't convert a Non-E_CHAR event to a key"); KEY key = ep->v.chr.ch; if (key < K_INS || key > K_HELP) { if (ep->v.chr.shift && (key < ' ' || key >= K_UP)) key += K_SHIFT; //if (ep->v.chr.control && key >= ' ') key += K_CTRL; if (ep->v.chr.control && (key > K_SHIFT || (key >= K_F1 && key <= K_F12) || xvt_chr_is_alnum(key) || strchr("\r+-*/",key) != NULL)) key += K_CTRL; } return key; } // @doc EXTERNAL // @func Simula un evento void dispatch_event( WINDOW win, // @parm Finestra destinataria dell'evento const EVENT& e, // @parm Evento da generare bool post) { if (post) EM.push(win, e); else xvt_win_dispatch_event(win, (EVENT*)&e); } // @doc EXTERNAL // @func Simula la scelta di una voce di menu void dispatch_e_menu( WINDOW win, // @parm Finestra che contiene il menu MENU_TAG item) // @parm Voce del menu da selezionare // @xref { EVENT e; memset(&e, 0, sizeof(e)); e.type = E_COMMAND; e.v.cmd.tag = item; dispatch_event(win, e, true); } // @doc EXTERNAL // @func Simula la scelta di una combinazione di caratteri void dispatch_e_char( WINDOW win, // @parm Finestra che contiene il menu KEY key) // @parm Combinazione di caratteri da utilizzare // @xref { EVENT e; memset(&e, 0, sizeof(e)); e.type = E_CHAR; if (key > K_CTRL) { e.v.chr.control = TRUE; key -= K_CTRL; } if (key > K_SHIFT) { e.v.chr.shift = TRUE; key -= K_SHIFT; } e.v.chr.ch = short(key); dispatch_event(win, e, TRUE); } // @doc EXTERNAL // @func Simula uno scroll all'interno di una finestra void dispatch_e_scroll( WINDOW win, // @parm Finestra nella quale operare KEY key) // @parm Tasto utilizzato per lo scroll nella finestra // @xref { EVENT e; memset(&e, 0, sizeof(e)); EVENT_TYPE& t = e.type; SCROLL_CONTROL& w = e.v.scroll.what; short& p = e.v.scroll.pos; w = SC_NONE; switch(key) { case K_HOME: t = E_HSCROLL; w = SC_THUMB; p = 0; break; case K_LHOME: t = E_VSCROLL; w = SC_THUMB; p = 0; break; case K_UP: t = E_VSCROLL; w = SC_LINE_UP; break; case K_DOWN: t = E_VSCROLL; w = SC_LINE_DOWN; break; case K_BTAB: t = E_HSCROLL; w = SC_PAGE_UP; break; case K_TAB: t = E_HSCROLL; w = SC_PAGE_DOWN; break; case K_PREV: t = E_VSCROLL; w = SC_PAGE_UP; break; case K_NEXT: t = E_VSCROLL; w = SC_PAGE_DOWN; break; case K_LEFT: t = E_HSCROLL; w = SC_LINE_UP; break; case K_RIGHT: t = E_HSCROLL; w = SC_LINE_DOWN; break; default: break; }; if (w != SC_NONE) dispatch_event(win, e, FALSE); } void set_xvt_hooks() { xvt_vobj_set_attr(NULL_WIN,ATTR_ERRMSG_HANDLER, (long)error_hook); xvt_vobj_set_attr(NULL_WIN,ATTR_WIN_PM_DRAWABLE_TWIN, TRUE); long twin_style = xvt_vobj_get_attr(NULL_WIN,ATTR_WIN_PM_TWIN_STARTUP_STYLE); twin_style |= WSF_ICONIZABLE | WSF_CLOSE; // WSF_SIZE pare azzardato TConfig cfg(CONFIG_GUI, "Colors"); const int res = cfg.get_int("Resolution"); const int scx = xvt_vobj_get_attr(NULL_WIN, ATTR_SCREEN_WIDTH); const int scy = xvt_vobj_get_attr(NULL_WIN, ATTR_SCREEN_HEIGHT); if (res >= 640 && res < scx) { const int fx = xvt_vobj_get_attr(NULL_WIN, ATTR_FRAME_WIDTH); const int fy = xvt_vobj_get_attr(NULL_WIN, ATTR_FRAME_HEIGHT); const int cy = xvt_vobj_get_attr(NULL_WIN, ATTR_TITLE_HEIGHT); const int width = res + 2*fx; const int height = (res * scy) / scx + 2*fy + cy; const int deltax = (scx - width) / 2; const int deltay = (scy - height) / 2; RCT rct; rct.left = deltax; rct.top = deltay; rct.right = deltax + width; rct.bottom = deltay + height; xvt_vobj_set_attr(NULL_WIN, ATTR_WIN_PM_TWIN_STARTUP_RCT, long(&rct)); } else twin_style |= WSF_MAXIMIZED; xvt_vobj_set_attr(NULL_WIN,ATTR_WIN_PM_TWIN_STARTUP_STYLE, twin_style); } // @doc INTERNAL // @func Stabilisce i parametri standard dei controlli void customize_controls( bool on) // @parm Permette di inizializzare (TRUE) o scaricare (FALSE) i parametri { if (on) { customize_colors(); init_controls(); } else { free_controls(); } } // @doc INTERNAL // @func Permette di settare il font attivo nella finestra void xvtil_set_font( WINDOW win, // @parm Finestra nella quale settare il font const char* family, // @parm Nome del font da settare int style, // @parm Stile da applicare al font int dim) // @parm Dimensione del font { CHECK(win != NULL_WIN, "Can't set the font in a NULL window"); if ((family == NULL || *family == '\0') && (style == XVT_FS_NONE || style == XVT_FS_BOLD) && dim == 0) { xvt_dwin_set_font(win, xvtil_default_font(style == XVT_FS_BOLD)); } else { XVT_FNTID font = xvt_dwin_get_font(TASK_WIN); if (family && *family) xvt_font_set_family(font, family); if (dim != 0) xvt_font_set_size(font, dim); if (style != XVT_FS_NONE) xvt_font_set_style(font, style); if (!xvt_font_is_mapped(font)) xvt_font_map(font, win); xvt_dwin_set_font(win, font); xvt_font_destroy(font); } } // @doc INTERNAL // @func Permette di creare una finestra // // @rdesc Ritorna l'identificatore della finestra creata WINDOW xvtil_create_window( WIN_TYPE wt, // @parm Tipo di finestra da creare short x, // @parm Coordinata x della finestra (espresso in caratteri) short y, // @parm Coordinata y della finestra (espresso in caratteri) short dx, // @parm Larghezza della finestra (espresso in caratteri) short dy, // @parm Altezza della finestra (espresso in caratteri) const char* caption, // @parm Titolo da assegnare alla finestra int menu, // @parm Menu della finestra (definito nelle risorse, 0=senza) WINDOW parent, // @parm Identificatore della finestra padre long flags, // @parm Attributi della finestra EVENT_HANDLER eh, // @parm Funzioni per la gestione degli eventi diretti alla finestra long app_data) // @parm Puntatore alla classe C++ che gestisce la finestra { RCT& rect = resize_rect(x, y, dx, dy, wt, parent); if (wt == WD_MODAL) wt = W_DOC; WINDOW win = xvt_win_create(wt, &rect, (char*)caption, menu, parent, flags, EM_ALL, eh, app_data); // Utile per migliorare il calcolo delle dimensioni dei caratteri xvt_dwin_set_font(win, xvtil_default_font()); CHECK(win, "Can't create a window: XVT error"); return win; } /////////////////////////////////////////////////////////// // Gestione Status bar /////////////////////////////////////////////////////////// HIDDEN WINDOW _statbar = NULL_WIN; // @doc INTERNAL // @func Permette di creare la barra di stato del programma // // @rdesc Ritorna l'identificatore della barra di stato creata WINDOW xvtil_create_statbar() // @xref { CHECK(_statbar == NULL_WIN, "Onli uan statbar, plis"); if (TASK_WIN != NULL_WIN) // Puo' succedere in chiusura menu { const int prop_count = 4; char* prop_list[prop_count+1] = { "Status bar", "HEIGHT=24", "TASK_WIN", "FIELD_OFFSET=24", NULL }; _statbar = statbar_create(0, 0, 600, 1024, 800, prop_count, prop_list, TASK_WIN, 0, 0, ""); CHECK(_statbar, "Can't create the status bar"); statbar_set_fontid(_statbar, xvtil_default_font()); } return _statbar; } // @doc INTERNAL // @func Permette di settare una finestra con la barra di stato void xvtil_statbar_set( const char* text, // @parm Testo da inserire nella barra di stato bool def) // @parm (default FALSE) // @comm Nella barra di stato vi e' sempre presente la data del sistema // // @xref { if (_statbar != NULL_WIN) { TToken_string t(80, '\t'); t.add(text); if (prefix_valid() && main_app().get_firm() > 0) { t.add(prefix().firm().get(NDT_RAGSOC)); } else { TString80 ragsoc; xvt_sys_get_profile_string(NULL, "Main", "Company", "", ragsoc.get_buffer(), ragsoc.size()); t.add(ragsoc); } t.add(main_app().title()); if (def) statbar_set_default_title(_statbar, t); statbar_set_title(_statbar, t); } } // @doc INTERNAL // @func Setta il testo standard della barra di stato void xvtil_statbar_refresh() // @xref { if (_statbar) statbar_set_title(_statbar, NULL); } void xvtil_statbar_destroy() { if (_statbar != NULL_WIN && statbar_destroy(_statbar)) _statbar = NULL; } /////////////////////////////////////////////////////////// // Test menu /////////////////////////////////////////////////////////// HIDDEN bool test_menu_tag(MENU_ITEM* mi, MENU_TAG tag) { while (mi->tag) { if (mi->tag == tag) return TRUE; if (mi->child != NULL) { const bool ok = test_menu_tag(mi->child, tag); if (ok) return TRUE; } mi++; } return FALSE; } // @doc INTERNAL // @func Controlla se e' esiste una voce del menu' // // @rdesc Ritorna i seguenti valori // // @flag TRUE | Se esiste la voce di menu' // @flag FALSE | Se non esiste la voce di menu' bool xvtil_test_menu_tag( MENU_TAG tag) // @parm Menu' nel quale cercare la voce { bool ok = FALSE; MENU_ITEM *mi = xvt_menu_get_tree(TASK_WIN); if (mi) { ok = test_menu_tag(mi, tag); xvt_res_free_menu_tree(mi); } return ok; } // @doc INTERNAL // @func Permette di convertire in attributi grafici i codici caratteri usati // dalle funzioni di stampa // // @rdesc Ritorna il codice del colore convertito in attributo grafico COLOR trans_color( char c) // @parm Codice carattere da convertire { COLOR col = COLOR_WHITE; switch (c) { case 'b': col = COLOR_BLUE; break; case 'c': col = COLOR_CYAN; break; case 'd': col = COLOR_DKGRAY; break; case 'g': col = COLOR_GREEN; break; case 'k': col = COLOR_GRAY; break; case 'l': col = COLOR_LTGRAY; break; case 'm': col = MASK_BACK_COLOR; break; case 'n': col = COLOR_BLACK; break; case 'r': col = COLOR_RED; break; case 'v': col = COLOR_MAGENTA; break; case 'w': col = COLOR_WHITE; break; case 'y': col = COLOR_YELLOW; break; default : NFCHECK("trans_color: Undefined color '%c'", c); break; } return col; } // @doc INTERNAL // @func HIDDEN void | set_cursor | Cambia il cursore del mouse HIDDEN void set_cursor( bool w) // @parm Indica il tipo di cursore da utilizzare: // // @flag TRUE | Cursore a clessidra per le wait // @flag FALSE | Cursore a frecca normale { static int _count = 0; static WINDOW _win = NULL_WIN; if (w) { if (_count == 0) { _win = cur_win(); if (_win == NULL_WIN) _win = TASK_WIN; xvt_win_set_cursor(_win, CURSOR_WAIT); } _count++; } else { _count--; CHECK(_count >= 0, "end_wait without matching begin_wait"); if (_count == 0) { WINDOW cur = cur_win(); if (cur == _win) xvt_win_set_cursor(_win, CURSOR_ARROW); else xvt_win_set_cursor(TASK_WIN, CURSOR_ARROW); } } } void begin_wait() { set_cursor(TRUE); } void end_wait() { set_cursor(FALSE); } // @doc INTERNAL // @func Permette di converitire lo stile del pattern in attributi grafici da // codici carattere. // // @rdesc Ritorna il pattern convertito PAT_STYLE trans_brush( char p) // @parm Codice carattere da convertire { switch (p) { case 'n' : return PAT_NONE; case 'h' : return PAT_HOLLOW; case 's' : return PAT_SOLID; case '-' : return PAT_HORZ; case '|' : return PAT_VERT; case '/' : return PAT_FDIAG; case '\\': return PAT_BDIAG; case 'X' : return PAT_DIAGCROSS; case '+' : return PAT_CROSS; default : CHECK(0,"trans_brush: Undefined pattern"); break; } return PAT_NONE; } // @doc INTERNAL // @func Permette di convertire lo stile della penna da codice carattere // // @rdesc Ritorna lo stilo convertito PEN_STYLE trans_pen( char p) // @parm Codice carattere da convertire { PEN_STYLE ps = P_SOLID; switch (p) { case 'n' : ps = P_SOLID; break; case '.' : ps = P_DOT; break; case '-' : ps = P_DASH; break; default: CHECK(0, "trans_pen: Undefined pattern"); break; } return ps; }