#include <applicat.h>
#include <colors.h>
#include <config.h>
#include <controls.h>
#include <mask.h>
#include <prefix.h>
#include <statbar.h> 
#include <urldefid.h>
#include <utility.h>     
 
#include <nditte.h>     

short CHARX = 8;
short CHARY = 14;
short ROWY = -CHARY;    // Not so good!

// 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
}

PNT xvtil_taskwin_size()
{
  RCT max_rct; xvt_vobj_get_client_rect(TASK_WIN, &max_rct);
  PNT pnt = { max_rct.bottom, max_rct.right };

  int sbh = xvtil_statbar_height(); 
  if (sbh <= 0) sbh = 24;
  pnt.v -= sbh;                    // Tolgo lo spazio occupato dalla status bar
  pnt.v -= sbh;                    // Tolgo lo spazio occupato dai tab buttons
  pnt.v -= TOOL_SIZE + 8;          // Tolgo lo spazio occupato dalle icone della toolbar
  pnt.v -= TOOL_TEXT ? 12 : 0;     // Tolgo lo spazio occupato dal testo della toolbar
  return pnt;
}


// @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 (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
    {
      const PNT tws = xvtil_taskwin_size();
      ROWY = tws.v / min(MAX_MASK_ROWS, tws.v / CHARY);
    }  
  }

  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
    {
      int BASEY; xvt_dwin_get_font_metrics(parent, NULL, &BASEY, NULL);
      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 * ROWY;
    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)
    {
      int sbh = xvtil_statbar_height(); 
      if (sbh <= 0) sbh = 22;
      pc.bottom -= (sbh+2);
    }
    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;
        int height = r.bottom;
        if (wt == W_DOC)
        {
          height += short(xvt_vobj_get_attr(parent, ATTR_TITLE_HEIGHT));
          height += short(2*xvt_vobj_get_attr(parent, ATTR_DOCFRAME_HEIGHT));
        }
        const int spc = (MAXY - tot*height) / (tot+1);
        r.top = spc + num*(spc+height);
      }
      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;
}

RCT& xvtil_align_rect(const RCT& inner, const RCT& outer, char halign, char valign, char grow)
{
  static RCT r;      

  const int ow = xvt_rect_get_width(&outer);
  const int oh = xvt_rect_get_height(&outer);
  int iw = xvt_rect_get_width(&inner);
  int ih = xvt_rect_get_height(&inner);
  int ix = outer.left, iy = outer.top;
  if (iw > ow || ih > oh)
  {
    if (grow == '-' || grow == '*')
    {
      const double rx = double(ow)/iw;
      const double ry = double(oh)/ih;
      const double r = rx < ry ? rx : ry;
      ih = int(ih*r);
      iw = int(iw*r);
    }
  } else
  if (iw < ow && ih < oh)
  {
    if (grow == '+' || grow == '*')
    {
      const double rx = double(ow)/iw;
      const double ry = double(oh)/ih;
      if (rx < ry)
        ih = int(ih*rx);
      else
        iw = int(iw*ry);
    }
  }
  switch (halign)
  {
  case 'R': ix = outer.right-iw; break;
  case 'C': ix = (outer.left + outer.right - iw) / 2; break;
  default : break;
  }
  switch (valign)
  {
  case 'B': iy = outer.bottom-ih; break;
  case 'C': iy = (outer.top + outer.bottom - ih) / 2; break;
  default : break;
  }
  xvt_rect_set(&r, ix, iy, ix+iw, iy+ih);
  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)
  {
    TString msg; msg.format(FR("Hey %s, clicca piu' piano!"), (const char*)user());
    xvt_dm_popup_message(msg);
  }
  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);
    if (w != NULL)
      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 <f dispatch_e_char> <f dispatch_e_scroll>
{
  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 <f dispatch_e_menu> <f dispatch_e_scroll>
{
  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 <f dispatch_e_menu> <f dispatch_e_char>
{
  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

  const int scx = xvt_vobj_get_attr(NULL_WIN, ATTR_SCREEN_WIDTH);
  const int scy = xvt_vobj_get_attr(NULL_WIN, ATTR_SCREEN_HEIGHT);

  TToken_string stres(ini_get_string(CONFIG_GUI, "Colors", "Resolution"), 'x');
  const int resx = stres.get_int(0);
  int resy = stres.get_int();
  if (resy <= 0)
    resy = scy*resx/scx;

  if (resx >= 240 && resx < 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 = resx + 2*fx;
    const int height = resy+ 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);
  CHECK(win, "Can't create a window: XVT error");

  if (x == 0 && y == 0 && dx == 0 && dy == 0)
    xvt_vobj_maximize(win); // Molto piu' preciso di resize_rect(0,0,0,0,parent)
  
	// Utile per migliorare il calcolo delle dimensioni dei caratteri
  xvt_dwin_set_font(win, xvtil_default_font());

  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 <f xvt_statbar_set> <f xvt_statbar_refresh>
{
  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 <f xvt_create_statbar> <f xvt_statbar_refresh>
{                    
  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 <f xvt_create_statbar> <f xvt_statbar_set>
{
  if (_statbar)
    statbar_set_title(_statbar, NULL);
}

void xvtil_statbar_destroy()
{
  if (_statbar != NULL_WIN && statbar_destroy(_statbar))
    _statbar = NULL;
}

int xvtil_statbar_height()
{
  int h = 0;
  if (_statbar != NULL_WIN)
  {
    RCT rct; xvt_vobj_get_outer_rect(_statbar, &rct);
    h = rct.bottom - rct.top;
  }
  return h;
}

static bool xvtil_popup_something(int severity, const char* msg)
{
  if (ADVANCED_GRAPHICS && ANIMATED_BOXES && is_power_reseller())
  {
    switch (severity)
    {
    case  1: xvt_dm_popup_warning(msg); break;
    case  2: xvt_dm_popup_error(msg); break;
    default: xvt_dm_popup_message(msg); break;
    }
  }
  else
  {
    beep(severity);
    xvtil_statbar_set(msg);
  }
  return false;
}

bool xvtil_popup_message(const char* msg)
{ return xvtil_popup_something(0, msg); }

bool xvtil_popup_warning(const char* msg)
{ return xvtil_popup_something(1, msg); }

bool xvtil_popup_error(const char* msg)
{ return xvtil_popup_something(2, msg); }

///////////////////////////////////////////////////////////                      
// 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;
}