#include <applicat.h>
#include <colors.h>
#include <config.h>
#include <date.h>
#include <urldefid.h>
#include <utility.h>
#include <mask.h>

#if XVT_OS == XVT_OS_WIN
#include <windows.h>
#include <string.h>
#include <ctype.h>
#pragma hdrstop
#include "prochook.h"
#define MAX_PATH 260    // This really should be in WINDOWS.H, but is
                        // inexplicably hard-coded into the data structures
int MungeModuleHeader( HINSTANCE hInstance, BOOL fMunge );
#endif

#if XVT_OS == XVT_OS_SCOUNIX
extern "C" { long nap(long period); }
#endif

// ERROR HOOK che intercetta errori XVT
// put breakpoint here

BOOLEAN error_hook(XVT_ERRMSG err, DATA_PTR)
{
  const XVT_ERRSEV sev = xvt_errmsg_get_sev_id(err);
#ifdef DBG
  return FALSE;
#else
  return sev < SEV_ERROR;
#endif
}

#if XVT_OS == XVT_OS_WIN

#define STRICT
#include <windows.h>
#include <ctl3d.h>

extern "C" {
  WINDOW xvtwi_hwnd_to_window(HWND);
#include <statbar.h>
}
#include <controls.h>

short CHARX = 8;
short ROWY = GetSystemMetrics(SM_CYSCREEN) / 25;
short CHARY = 14;
short BASEY = 12;

const word WM_WAKEUP = RegisterWindowMessage("WAKEUP");

// By Matt Pietrek                           
//########################################################################
// Code that does the real work
//########################################################################                          

//
// Central function that modifies a module table to trick the loader
// into letting a second instance of a multiple data segment program run.
//
int MungeModuleHeader( HINSTANCE hInstance, BOOL fMunge )
{ 
    HMODULE hModuleSel;
    LPSTR lpszModName, lpszFileName;
    BYTE cbModuleName;
    static BOOL fResidentNamesMunged = FALSE;
    
    hModuleSel = SELECTOROF(    // Convert the HINSTANCE to an HMODULE
        GlobalLock(GetModuleHandle((LPSTR)MAKELP(0,hInstance))));

    if ( hModuleSel == 0 )      // Make sure we succeeded.
        return 0;

    //
    // First, we'll take care of the resident names table
    //
    if ( FALSE == fResidentNamesMunged )
    {
        // Make pointers to the module name in the resident names table
        lpszModName = (LPSTR)MAKELP(hModuleSel,
                                    *(WORD FAR *)MAKELP(hModuleSel, 0x26) );

        // Get the module name length, and advance to the actual string
        cbModuleName = *lpszModName++;   // First byte is a length byte
        
        // Convert the first uppercase letter of the modulename to lowercase
        while ( cbModuleName )
        {
            if ( isupper(*lpszModName) )
            {
                *lpszModName = tolower(*lpszModName); break;
            }
            cbModuleName--; lpszModName++;
        }
        
        if ( cbModuleName == 0 )    // Make sure we succeeded
            return 0;

        // Remember that we've done this, so that we don't bother doing
        // it in the future.
        fResidentNamesMunged = TRUE;
    }

    //
    // Now, we'll turn our attention to the module file name in the OFSTRUCT
    //
    lpszFileName = (LPSTR)MAKELP(hModuleSel,
                                 *(WORD FAR *)MAKELP(hModuleSel, 0x0A));

    // Position to the end of the filename. First byte is a length byte
    lpszFileName += *lpszFileName - 1;

    // If we're munging, added 0x30 to the last character value, otherwise
    // subtract 0x30.  0x30 is chosen completely at random.
    if ( fMunge )
        *lpszFileName += 0x30;
    else
        *lpszFileName -= 0x30;
    return 1;
}

//########################################################################
// This section watches calls to LoadModule and munges the EXE's module
// database as needed.
//########################################################################

HIDDEN NPHOOKCHILD npHookLoadModule = 0;
HIDDEN char szOurFileName[MAX_PATH];
HIDDEN HINSTANCE HInstance;  

HINSTANCE
WINAPI
__export MultInst95LoadModule( LPCSTR lpszModuleName,
                               LPVOID lpvParameterBlock )
{
    HINSTANCE retValue;

    // Uppercase the name of the module name that was passed to LoadModule
    char szNewFileName[MAX_PATH];
    lstrcpy( szNewFileName, lpszModuleName );
    strupr( szNewFileName );

    // Compare the incoming filename to our EXE's module name.  If they
    // don't match, we don't need to bother munging the module database
    BOOL fSecondInstance = strstr(szOurFileName, szNewFileName) ? TRUE:FALSE;

    // Unhook our LoadModule hook so that we can call the real LoadModule
    ProcUnhook( npHookLoadModule );

    // Munge module database if needed
    if ( fSecondInstance )
        MungeModuleHeader( HInstance, TRUE );

    // Call the original LoadModule code
    retValue = LoadModule( lpszModuleName, lpvParameterBlock );

    // Unmunge module database if needed
    if ( fSecondInstance )
        MungeModuleHeader( HInstance, FALSE );

    // Reinstall our LoadModule hook so that we see future loads
    ProcHook( npHookLoadModule );
    
    return retValue;
}

BOOL deny_another_instance()
{ 
  if ( !npHookLoadModule )
      return FALSE;

  SetProcRelease( npHookLoadModule );
  npHookLoadModule = 0;
    
  return TRUE;
}

BOOL allow_another_instance()
{ 
#ifdef __NOMUNGE__        
  return FALSE;
#endif
          
  if ( npHookLoadModule )
      return TRUE;

  // Get the EXE's filename into a global string variable and uppercase it
  GetModuleFileName( HInstance, szOurFileName, sizeof(szOurFileName) );
  strupr( szOurFileName );

  // Create a MakeProcInstance thunk so that our callback function
  // will always be using the correct DS selector
  FARPROC lpfnMPI
      = MakeProcInstance( (FARPROC)MultInst95LoadModule, HInstance );

  if ( !lpfnMPI )
      return FALSE;

  // Call PROCHOOK.DLL to hook calls to LoadModule
  npHookLoadModule = SetProcAddress(  (FARPROC)LoadModule,
                                      lpfnMPI, FALSE );
    
  return (BOOL)npHookLoadModule;
}

static BOOLEAN event_hook(HWND hwnd,
                          UINT msg,
                          UINT wparam,
                          ULONG lparam,
                          long* ret)
{
  switch(msg)     
  {            
  case WM_SYSCOLORCHANGE:
    Ctl3dColorChange();
    break;
  case WM_MENUCHAR:
    if (wparam > ' ' && wparam <= 'z')
    {
      WINDOW win = cur_win();
      if (win != NULL_WIN)
      {      
//        TWindow* w = (TWindow*)xvt_vobj_get_data(win);
        const KEY key = toupper(wparam)+K_CTRL;
//        w->on_key(key);
        dispatch_e_char(win, key);
        *ret = 2 << 8;
      }  
    }   
    break;  
  case WM_KEYDOWN:
    if (wparam == VK_F1)
    {    
      if ((lparam & (1<<29)) == 0)             // Il tasto alt non e' premuto
      {      
        KEY k = K_F1;
        int sc = GetAsyncKeyState(VK_CONTROL); // Stato del tasto control 
        if (sc & 1) k += K_CTRL;
        
        int ss = GetAsyncKeyState(VK_SHIFT);   // Stato del tasto shift 
        if (ss & 1) k += K_SHIFT;

        WINDOW win = cur_win();
        if (win != NULL_WIN)
          dispatch_e_char(win, k);
      }  
    }
    break;  
  default:  
    if (msg == WM_WAKEUP && wparam == main_app().waiting())
      main_app().wake_up();
    break;
  }    

  return TRUE; // Continua col processo normale
}

#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 TMask* m = (const TMask*)xvt_vobj_get_data(parent);
        if (parent != m->toolwin())
          y++;
      }  
      if (x > 0 || (wt != WO_TE && 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_EDIT;
  }

  switch (wt)
  {
  case WC_EDIT :
    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
    const short MAXX = pc.right;
    const short MAXY = pc.bottom;

    if (x < 0)
    {
      x = -x;
      if (wt != WC_EDIT && 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_EDIT && 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()
{ xvt_scr_beep(); }


///////////////////////////////////////////////////////////
// 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("Hey, clicca piu' piano!");
  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();
#if XVT_OS == XVT_OS_SCOUNIX
  nap(20);
#endif
}

// @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;
  }
  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;
  e.v.cmd.shift = e.v.cmd.control = 0;
  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);
}

// @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)
  {
#if XVT_OS == XVT_OS_WIN
    long old_hook = xvt_vobj_get_attr(NULL_WIN,ATTR_EVENT_HOOK); 
    if (old_hook == 0)
      xvt_vobj_set_attr(NULL_WIN,ATTR_EVENT_HOOK, (long)event_hook); 
    
    xvt_vobj_set_attr(NULL_WIN,ATTR_ERRMSG_HANDLER, (long)error_hook);
    HInstance = (HINSTANCE)xvt_vobj_get_attr(NULL_WIN, ATTR_WIN_INSTANCE);

    Ctl3dRegister(HInstance);
    Ctl3dAutoSubclass(HInstance);
#endif    
    customize_colors();
    init_controls();
  }
  else
  {       
#if XVT_OS == XVT_OS_WIN
//    HINSTANCE _hInstance = (HINSTANCE)xvt_vobj_get_attr(NULL_WIN, ATTR_WIN_INSTANCE);
    Ctl3dUnregister(HInstance);
    deny_another_instance();
#endif      
    free_controls();
  }
}

// @doc INTERNAL

// @func Permette di settare il font attivo nella finestra
void xvt_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, xvt_default_font(style != XVT_FS_NONE));
  }
  else
  {
    XVT_FNTID font = xvt_dwin_get_font(TASK_WIN);                     
    if (family && *family)    xvt_font_set_family(font, (char*)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);
  }  
}

void xvt_draw_rect(WINDOW win, const RCT& rect, COLOR lt, COLOR rb, short depth)
{
  RCT r = rect;

  CPEN pen;
  pen.width = 1;
  pen.pat = PAT_SOLID;
  pen.style = P_SOLID;
  pen.color = lt;

  for (short d = 0; d < depth;)
  {
    xvt_dwin_set_cpen(win, &pen);

    PNT p;      // Current vertex of the rectangle

    bool drawn = FALSE;
    if (lt != MASK_BACK_COLOR)
    {
      p.h = r.left; p.v = r.bottom;
      xvt_dwin_draw_set_pos(win, p);

      p.v = r.top;
      xvt_dwin_draw_line(win, p);
      p.h = r.right;
      xvt_dwin_draw_line(win, p);
      drawn = TRUE;
    }

    if (rb != MASK_BACK_COLOR)
    {
      if (pen.color != rb)
      {
        pen.color = rb;
        xvt_dwin_set_cpen(win, &pen);
      }
      if (!drawn)
      {
        p.h = r.right; p.v = r.top;
        xvt_dwin_draw_set_pos(win, p);
      }
      p.v = r.bottom;
      xvt_dwin_draw_line(win, p);
      p.h = r.left;
      xvt_dwin_draw_line(win, p);
    }

    if (++d < depth)
    {
      r.left++; r.top++;
      r.right--; r.bottom--;
    }
  }
}


// @doc INTERNAL

// @func Permette di creare una finestra
//
// @rdesc Ritorna l'identificatore della finestra creata
WINDOW xvt_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 XVT_OS == XVT_OS_WIN
  static bool to_set = TRUE;
  HWND hwnd = (HWND)xvt_vobj_get_attr(win, ATTR_NATIVE_WINDOW);
  if (to_set)
  {
    word style = GetClassWord(hwnd, GCW_STYLE);
    style |= CS_BYTEALIGNCLIENT;
    SetClassWord(hwnd, GCW_STYLE, style);
    to_set = FALSE;
  }
#endif

  return win;
}

// @doc INTERNAL

// @func Permette di creare i controlli all'interno di una finestra
//
// @rdesc Ritorna la finestra del controllo
WINDOW xvt_create_control(
  WIN_TYPE wt,          // @parm Tipo di controllo da creare
  short x,              // @parm Coordinata x del control
  short y,              // @parm Coordinata y del control
  short dx,             // @parm Larghezza della control
  short dy,             // @parm Altezza della control
  const char* caption,  // @parm Titolo da assegnare alla control
  WINDOW parent,        // @parm Identificatore della finestra padre
  long flags,           // @parm Attributi della finestra
  long app_data,        // @parm Puntatore alla classe C++ che gestisce la finestra
  int id)               // @parm Indentificatore del controlllo
{
  RCT r = resize_rect(x, y, dx, dy, wt, parent);
  while (*caption == '@') caption += 2;
  WINDOW win = xvt_ctl_create(wt, &r, (char*)caption, parent,
                              flags, app_data, id);
  if (win == NULL_WIN)
    fatal_box("Can't create control %d: '%s'", id, caption);

  return win;
}

// @doc INTERNAL

// @func Restituisce il titolo della finestra
//
// @rdesc Stringa contenente il titolo della finestra
const char* xvt_get_title(
  WINDOW win) // @parm Finestra della quale si vuole conoscere il titolo

  // @xref <f xvt_set_title>
{
  xvt_vobj_get_title(win, __tmp_string, 80);
  return __tmp_string;
}

// @doc INTERNAL

// @func Permette di assegnare il titolo ad una finestra
void xvt_set_title(
  WINDOW win,      // @parm Finestra a cui assegnare il titolo
  const char* cap) // @parm Titolo da assegnare

  // @xref <f xvt_get_title>
{
  xvt_vobj_set_title(win, (char*)cap);
}

// @doc INTERNAL

// @func Permette di abilitare il focus su un controllo
void xvt_set_front_control(
  WINDOW win)  // @parm Finestra nella quale abilitare il focus
{
  xvt_scr_set_focus_vobj(win);
}

// @doc INTERNAL

// @func Permette di togliere il focus da un controllo
void xvt_kill_focus(
  WINDOW win)  // @parm Finestra nella quale togliere il focus
{
}

// @doc INTERNAL

// @func Permette di abilitare o disabilitare un controllo
void xvt_enable_control(
  WINDOW win, // @parm Finestra all'interno della quale abilitare il controllo
  bool on)    // @parm Abilita (TRUE) o disabilita (FALSE) il controllo
{
  xvt_vobj_set_enabled(win, on);
}

// @doc INTERNAL

// @func Permette di gestire un check box all'interno di una finestra
void xvt_check_box(
  WINDOW win, // @parm Finestra all'interno della quale abilitare il check box
  bool on)    // @parm Permette di inizializzare (TRUE) o scaricare (FALSE) i parametri
{
  xvt_ctl_set_checked(win, on);
}

// @doc INTERNAL

// @func Permette di controllare se un controllo e' stato selezionato
//
// @rdesc Ritorna i seguenti valori:
//
// @flag TRUE | Se il controllo e' stato selezionato
// @flag FALSE | Se il controllo non e' stato selezionato
bool xvt_get_checked_state(
  WINDOW win) // @parm Finestra di cui si vuole conoscere lo stato
{
  return xvt_ctl_is_checked(win) ? TRUE : FALSE;
}

// @doc INTERNAL

// @func Permette di gestire un radio button all'interno di una finestra
void xvt_check_radio_button(
  WINDOW win,         // @parm Finestra all'interno della quale abilitare il radio button
  const WINDOW* ctls, // @parm Array di stringhe contenenti le scelte del radiobutton
  int count)          // @parm Numero di elementi del radiobutton
{
  xvt_ctl_check_radio_button(win, (WINDOW*)ctls, count);
}

// @doc INTERNAL

// @func Permette di controllare lo stato di un radiobutton
//
// @rdesc Ritorna il numero dell'elemento del radiobutton selezionato
int xvt_get_checked_radio(
  const WINDOW* ctls, // @parm Array di stringhe contenenti le scelte del radiobutton
  int count)          // @parm Numero di elemnti del radiobutton

{
  return 0;
}


// @doc INTERNAL

// @func Permette di cambiare il colore di sfondo di un controllo
void xvt_set_ctrl_back_color(
  WINDOW win, // @parm Finestra di cui si vuole cambiare lo sfondo
  COLOR col)  // @parm Colore dello sfondo
{
}



///////////////////////////////////////////////////////////
// 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 xvt_create_statbar()

  // @xref <f xvt_statbar_set> <f xvt_statbar_refresh>
{
  CHECK(_statbar == NULL_WIN, "Onli uan stabar, plis");

#if XVT_OS == XVT_OS_WIN
  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, xvt_default_font());

#endif

  return _statbar;
}

// @doc INTERNAL

// @func Permette di settare una finestra con la barra di stato
void xvt_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 XVT_OS == XVT_OS_WIN
  const TDate oggi(TODAY);
  TString256 t(text);
  t << '\t' << oggi.string() << " - " << main_app().title();
  if (def)                                          
    statbar_set_default_title(_statbar, (char*)(const char*)t);
  statbar_set_title(_statbar, (char*)(const char*)t);
#endif
}

// @doc INTERNAL

// @func Permette di cambiare il titolo alla barra di stato presente
void xvt_statbar_refresh()

  // @xref <f xvt_create_statbar> <f xvt_statbar_set>
{
#if XVT_OS == XVT_OS_WIN
  statbar_set_title(_statbar, NULL);
#endif
}

///////////////////////////////////////////////////////////                      
// 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 xvt_test_menu_tag(
  MENU_TAG tag) // @parm Menu' nel quale cercare la voce

{                      
  MENU_ITEM *mi = xvt_menu_get_tree(TASK_WIN);
  const bool 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;
  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: 
    CHECK(0,"trans_color: Undefined color"); 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; 
  
  if (w) 
  {
    if (_count == 0)
      xvt_win_set_cursor(TASK_WIN, CURSOR_WAIT);
    _count++; 
  }     
  else 
  {
    _count--;
    CHECK(_count >= 0, "end_wait without matching begin_wait");
    if (_count == 0)
      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;
}                          

