#include <applicat.h>
#include <colors.h>

#include <urldefid.h>
#include <utility.h>

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

#ifdef DBG         
// FATAL_HOOK che intercetta errori fatali XVT
// put breakpoint here
void fatal_hook()
{
  int dummy = 0;
  dummy++;
}
#endif

#if XVTWS == WMWS

short CHARX = 8;
short CHARY = 8;
short BASEY = 8;
short ROWY  = 8;

COLOR MASK_BACK_COLOR = COLOR_WHITE;
COLOR NORMAL_COLOR = COLOR_BLACK;
COLOR NORMAL_BACK_COLOR = COLOR_WHITE;
COLOR DISABLED_COLOR = COLOR_GRAY;
COLOR DISABLED_BACK_COLOR = COLOR_WHITE;
COLOR FOCUS_COLOR = COLOR_BLACK;
COLOR FOCUS_BACK_COLOR = COLOR_WHITE;

#else

#include <windows.h>
#include <config.h>

#ifdef __CTL3D__
#include <ctl3d.h>
#endif

HIDDEN COLORREF COLOR2RGB(COLOR c)
{
  const byte red = byte((c >> 16) & 0xFF);
  const byte gre = byte((c >> 8) & 0xFF);
  const byte blu = byte(c & 0xFF);
  return RGB(red, gre, blu);
}

HIDDEN COLOR RGB2COLOR(COLORREF c)
{
  const byte red = byte(c & 0xFF);
  const byte gre = byte((c >> 8) & 0xFF);
  const byte blu = byte((c >> 16) & 0xFF);
  return MAKE_COLOR(red, gre, blu);
}


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;

HIDDEN HFONT NormalFont = NULL;
HIDDEN LOGFONT LogFont;
HIDDEN int FontWeight;

#ifdef __CTL3D__
COLOR MASK_BACK_COLOR = COLOR_LTGRAY;
#else
COLOR MASK_BACK_COLOR = MAKE_COLOR(0,128,128);
#endif

COLOR NORMAL_COLOR = COLOR_BLACK;
COLOR NORMAL_BACK_COLOR = COLOR_LTGRAY;
COLOR DISABLED_COLOR = COLOR_GRAY;
COLOR DISABLED_BACK_COLOR = MASK_BACK_COLOR;

HIDDEN COLORREF MaskColor = COLOR2RGB(MASK_BACK_COLOR);
HIDDEN HBRUSH MaskBrush = CreateSolidBrush(MaskColor);

HIDDEN COLORREF FocusForeColor = COLOR2RGB(COLOR_BLACK);     
HIDDEN COLORREF FocusBackColor = COLOR2RGB(COLOR_CYAN);      
HIDDEN HBRUSH FocusBrush = CreateSolidBrush(FocusBackColor);

COLOR FOCUS_COLOR = RGB2COLOR(FocusForeColor);
COLOR FOCUS_BACK_COLOR = RGB2COLOR(FocusBackColor);

HIDDEN COLORREF NormalForeColor = COLOR2RGB(NORMAL_COLOR);
HIDDEN COLORREF NormalBackColor = COLOR2RGB(NORMAL_BACK_COLOR);
HIDDEN HBRUSH NormalBrush = CreateSolidBrush(NormalBackColor);

static BOOLEAN event_hook(HWND hwnd,
                          UINT msg,
                          UINT wparam,
                          ULONG lparam,
                          long* ret)
{
  switch(msg)     
  {    
#ifdef __CTL3D__  
  case WM_SYSCOLORCHANGE:
    Ctl3dColorChange();
    break;
#endif    
  case WM_CTLCOLOR:
  {
#ifdef __CTL3D__
    *ret = Ctl3dCtlColorEx(msg, wparam, lparam);
    return TRUE;
#else  
    const word type = HIWORD(lparam);
    if (type == CTLCOLOR_LISTBOX || type == CTLCOLOR_EDIT ||
        type == CTLCOLOR_MSGBOX)
    {
      HWND hwnd = LOWORD(lparam);
      HDC hdc = wparam;

      if (!IsWindowEnabled(hwnd))       // Campo disabilitato
      {
        if (type != CTLCOLOR_MSGBOX)
        {
          SetTextColor(hdc, NormalForeColor);
          SetBkColor(hdc, MaskColor);
        }
        *ret = MaskBrush;
        return TRUE;
      }

      bool focus = GetFocus() == hwnd;
      if (type != CTLCOLOR_MSGBOX)
      {
        SetTextColor(hdc, focus ? FocusForeColor : NormalForeColor);
        SetBkColor(hdc, focus ? FocusBackColor : NormalBackColor);
      }
      *ret = focus ? FocusBrush : NormalBrush;
      return TRUE;
    }
#endif    
  } 
    break;
  case WM_COMMAND:
  {
    const word notify = HIWORD(lparam);
    if (notify == EN_KILLFOCUS || notify == EN_SETFOCUS)
    {
      HWND hwnd = LOWORD(lparam);                      // Ridisegna BENE il campo
      InvalidateRect(hwnd, NULL, TRUE);
    }
  }
    break;
  case WM_KEYDOWN:
    if (wparam == VK_PRIOR || wparam == VK_NEXT ||
        wparam == VK_UP || wparam == VK_DOWN )
    {
      char name[16];
      GetClassName(hwnd, name, 5);
      if (stricmp(name, "Edit") == 0)
      {
        KEY key;
        switch(wparam)
        {
        case VK_PRIOR:
          key = K_PREV; break;
        case VK_NEXT:
          key = K_NEXT; break;
        case VK_UP:
          key = K_UP; break;
        case VK_DOWN:
          key = K_DOWN; break;
        default:
          key = 0; break;
        }
        if (key > 0)
        {
          WINDOW w = cur_win();
          if (w != NULL_WIN)
            dispatch_e_char(w, key);
        }   
      } 
    }
    break;
  case WM_MENUCHAR:
  {
    WINDOW w = cur_win();
    if (w != NULL_WIN)
    {                   
      const KEY key = toupper(wparam)+K_CTRL;
      dispatch_e_char(w, key);
    }  
  }   
    break;
  default:
    break;
  }    

  return FALSE;
}


HIDDEN WIN_TYPE _wc_type = W_NONE;
HIDDEN long _bandiere = 0L;

static void createwindow_hook(DWORD* exstyle, LPCSTR* classname, LPCSTR* windowname, DWORD* styl,
                              int* x, int* y, int* width, int* height, HWND* parent, HMENU* menu,
                              HINSTANCE inst, void **)
{
  if (_wc_type == WC_EDIT)
  {
    if (_bandiere & CTL_FLAG_RIGHT_JUST)
      *exstyle |= ES_MULTILINE | ES_RIGHT;
    if (_bandiere & CTL_FLAG_MAC_GENEVA9)
      *exstyle |= ES_UPPERCASE;
    if (_bandiere & CTL_FLAG_MAC_MONACO9)
      *exstyle |= ES_PASSWORD;
  }
  _wc_type = W_NONE;
}

#endif


RCT& resize_rect(short x, short y, short dx, short dy, WIN_TYPE wt, WINDOW parent)
{
  static RCT r;

  if (parent != TASK_WIN)
  {
    if (get_window_type(parent) == W_PLAIN) // Mask with Toolbar
    {
      if (y >= 0) y++;
      if (x > 0 || (wt != WO_TE && x == 0))
      { 
        RCT pc; 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;
  }

#if XVT_OS == XVT_OS_WIN
  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;
  }
#else
  r.left   = x * CHARX;
  r.top    = y * CHARY;
  r.right  = dx * CHARX;
  r.bottom = dy * CHARY;
#endif

  if (x < 0 || y < 0 || dx <= 0 || dy <= 0)
  {
    RCT pc;
    if (parent == NULL_WIN) parent = TASK_WIN;
    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;
}


void beep()
{ xvt_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;
  _end = (++_end) % MAX;
  CHECKD(_end != _begin, "Too many events queued: max. ", MAX);
}

void TEvent_manager::pop()
{
  if (_begin != _end)
  {
    const int i = _begin;
    _begin = (++_begin) % MAX;                     // Other events may occur!
    dispatch_event(_w[i], &_e[i]);
  }  
}

void do_events()
{
  process_events();
  EM.pop();
#if XVT_OS == XVT_OS_SCOUNIX
  nap(20);
#endif
}

KEY e_char_to_key(const EVENT* ep)
{
  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 && !isprint(key)) key += K_SHIFT;
    if (ep->v.chr.shift && (key < ' ' || key > 'z')) key += K_SHIFT;
    if (key >= ' ' && ep->v.chr.control) key += K_CTRL;
  }
  return key;
}


void dispatch_e_char(WINDOW win, KEY key)
{
  EVENT e;

  e.type = E_CHAR;

  if (key > 10000) { e.v.chr.control = TRUE; key -= K_CTRL; }
  else e.v.chr.control = FALSE;

  if (key >  1000) { e.v.chr.shift   = TRUE; key -= K_SHIFT; }
  else e.v.chr.shift = FALSE;

  e.v.chr.ch = short(key);

  EM.push(win, e);
}


void dispatch_e_scroll(WINDOW win, KEY key)
{
  EVENT 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);
}

void customize_controls(bool on)
{
#if XVTWS == WMWS
  if (on)
  {
    // set_value(NULL_WIN,ATTR_CH_SHADOW,XVT_CH_SHADOW_WINDOW|XVT_CH_SHADOW_DIALOG);
    set_value(NULL_WIN, ATTR_CH_TOGGLE_COMBO, (long)K_F9);
  }
#endif

#if XVT_OS == XVT_OS_WIN
  if (on)
  {
    set_value(NULL_WIN,ATTR_WIN_PM_DRAWABLE_TWIN, TRUE);
    set_value(NULL_WIN,ATTR_EVENT_HOOK, (long)event_hook); 
    set_value(NULL_WIN,ATTR_WIN_CREATEWINDOW_HOOK, (long)createwindow_hook); 
#ifdef __CTL3D__  
    HINSTANCE _hInstance = (HINSTANCE)get_value(NULL_WIN, ATTR_WIN_INSTANCE);
    Ctl3dRegister(_hInstance);
    Ctl3dAutoSubclass(_hInstance);
#endif    
  }
  else
  {
#ifdef __CTL3D__  
    HINSTANCE _hInstance = (HINSTANCE)get_value(NULL_WIN, ATTR_WIN_INSTANCE);
    Ctl3dUnregister(_hInstance);
#endif  
    DeleteObject(NormalFont);
    DeleteObject(MaskBrush);
    DeleteObject(NormalBrush);
    DeleteObject(FocusBrush);
    free_controls_bmp();
  }
#endif

#ifdef DBG  
  if (on) set_value(NULL_WIN,ATTR_FATAL_ERR_HANDLER, (long)fatal_hook);
#endif
}

#if XVT_OS == XVT_OS_WIN
void xvt_init_font()
{
  NormalFont = GetStockObject(ANSI_FIXED_FONT);
  GetObject(NormalFont, sizeof(LOGFONT), &LogFont);

  TConfig font(CONFIG_GENERAL, "Font");
  CHARY = (int)font.get_long("Height");
  if (CHARY > 0)
  {
    LogFont.lfHeight = CHARY;
    LogFont.lfWidth  = (int)font.get_long("Width");
    LogFont.lfWeight = FontWeight = (int)font.get_long("Weight");
    LogFont.lfCharSet = (int)font.get_long("CharSet");
    LogFont.lfClipPrecision = (int)font.get_long("Clip");
    LogFont.lfOutPrecision = (int)font.get_long("Precision");
    LogFont.lfQuality = (int)font.get_long("Quality");;
    LogFont.lfPitchAndFamily = (int)font.get_long("Pitch");
    strcpy(LogFont.lfFaceName, font.get("Name"));
  }
  else
  {
    LogFont.lfHeight = CHARY = 10;
    FontWeight = 400;
  }
  NormalFont = CreateFontIndirect(&LogFont);
  xvt_set_font(TASK_WIN, FF_FIXED, 0);

  // Get true text size              
  TEXTMETRIC tm;                    
  HWND hwnd = (HWND)get_value(TASK_WIN, ATTR_NATIVE_WINDOW);
  HDC hdc = GetDC(hwnd);
  GetTextMetrics(hdc, &tm);
  ReleaseDC(hwnd, hdc);
  
  const int COLX = GetSystemMetrics(SM_CXSCREEN) / 80;
  CHARX = tm.tmAveCharWidth+1;
  if (CHARX > COLX) CHARX = COLX;

  CHARY = tm.tmHeight;
  BASEY = tm.tmAscent;
  if (CHARY > ROWY-2) CHARY = ROWY-2;
}
#endif

void xvt_set_font(WINDOW win, int family, int style, int dim)
{
  CHECK(win != NULL_WIN, "Can't set the font in a NULL window");

#if XVT_OS == XVT_OS_WIN 
  if (dim < 1)
  {
    // LogFont.lfWidth  = CHARX - (style & FS_BOLD) ? 2 : 1;
    // LogFont.lfHeight = CHARY - ((style & FS_BOLD) ? 4 : 2);
    LogFont.lfWeight = FontWeight + ((style & FS_BOLD) ?  300 : 0);
    LogFont.lfItalic = (style & FS_ITALIC) ? TRUE : FALSE;
    set_value(NULL_WIN, ATTR_WIN_PM_LOGFONT, (long)&LogFont);
    set_value(NULL_WIN, ATTR_WIN_PM_USERFONT, TRUE);
    win_set_font(win, NULL, FALSE);
    set_value(NULL_WIN, ATTR_WIN_PM_USERFONT, FALSE);
    return;
  }
#endif

  FONT font;
  select_font(family, style, dim < 1 ? CHARY : dim, &font);
  win_set_font(win, &font, FALSE);
}


WINDOW xvt_create_window(WIN_TYPE wt,
                         short x, short y, short dx, short dy,
                         const char* caption, WINDOW parent,
                         long flags, EVENT_HANDLER eh, long app_data
                         )
{
  RCT& rect = resize_rect(x, y, dx, dy, wt, parent);

  if (wt == WD_MODAL) wt = W_DOC;
  WINDOW win = create_window(wt,
                             &rect,
                             (char*)caption,
                             0, parent,
                             flags,
                             EM_ALL, eh,
                             app_data);

  CHECKD(win, "Can't create a window: XVT error ", get_xvterrno());

#if XVT_OS == XVT_OS_WIN
  static bool to_set = TRUE;
  HWND hwnd = (HWND)get_value(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;
}

WINDOW xvt_create_control(WIN_TYPE wt,
                          short x, short y, short dx, short dy,
                          const char* caption,
                          WINDOW parent,
                          long flags,
                          long app_data,
                          int id)
{
  RCT r = resize_rect(x, y, dx, dy, wt, parent);
  WINDOW win = NULL_WIN;

#if XVT_OS == XVT_OS_WIN
  _wc_type = wt;
  _bandiere = flags;
  flags &= ~(CTL_FLAG_MAC_MONACO9 | CTL_FLAG_MAC_GENEVA9);

  if (wt == WC_PUSHBUTTON)
    win = xvt_create_pushbutton(r.left, r.top, r.right, r.bottom,
                                caption, parent, flags, app_data, id);

#ifndef __CTL3D__
  if (wt == WC_CHECKBOX)
    win = xvt_create_checkbox(r.left, r.top, r.right, r.bottom,
                              caption, parent, flags, app_data, id);

  if (wt == WC_RADIOBUTTON)
    win = xvt_create_radiobutton(r.left, r.top, r.right, r.bottom,
                                 caption, parent, flags, app_data, id);

  if (wt == WC_GROUPBOX)
  {
    win = xvt_create_groupbox(r.left, r.top, r.right, r.bottom,
                              caption, parent, flags, app_data, id);
  }

  if (wt == WC_TEXT)
  {
    win = xvt_create_text(r.left, r.top, r.right, r.bottom,
                          caption, parent, flags, app_data, id);
  }
#else  
  if (wt == WC_GROUPBOX)
  {
    win = xvt_create_text(r.left, r.top, r.right, r.top+CHARY,
                          caption, parent, flags, app_data, id);
  }
#endif
  
#endif

  if (win == NULL_WIN)
  {
    if (wt == WC_PUSHBUTTON)
    {
      if (dy == 2) r.bottom -= ROWY;
      if (id == DLG_F9)
      { wt = WC_TEXT;   r.right = r.left+CHARX; caption = "*"; }
      else if (*caption == '*') caption = "";
    }

    while (*caption == '@') caption += 2;
    win = create_control(wt, &r, (char*)caption, parent,
                         flags, app_data, id);
    
    if (win == NULL_WIN)
      fatal_box("Can't create control %d: XVT error %d", id, get_xvterrno());
  }


#if XVT_OS == XVT_OS_WIN
#ifdef __CTL3D__  
  if (wt != WC_PUSHBUTTON)
#else
    if (wt == WC_EDIT || wt == WC_LISTBUTTON)
#endif  
    {
      HWND hwnd = (HWND)get_value(win, ATTR_NATIVE_WINDOW);
      SendMessage(hwnd, WM_SETFONT, NormalFont, FALSE);
      if (_bandiere & CTL_FLAG_MAC_MONACO9)
        SendMessage(hwnd, EM_SETPASSWORDCHAR, (WORD)'#', 0);
#ifdef DBG
      DWORD stylecheck = GetWindowLong(hwnd, GWL_STYLE);
      stylecheck |= 0;
#endif        
#ifdef __CTL3D__  
      Ctl3dSubclassCtl(hwnd);
#endif    
    }
#endif

  return win;
}


const char* xvt_get_title(WINDOW win)
{
#if XVT_OS == XVT_OS_WIN && !defined(__CTL3D__)
  const TControl* c = TControl::WINDOW2TControl(win);
  return c->caption();
#else
  get_title(win, __tmp_string, 80);
  return __tmp_string;
#endif
}

void xvt_set_front_control(WINDOW win)
{
#if XVT_OS == XVT_OS_WIN && !defined(__CTL3D__)
  TControl* c = TControl::WINDOW2TControl(win);
  c->focus(TRUE);
#endif
  set_front_window(win);
}


void xvt_enable_control(WINDOW win, bool on)
{
#if XVT_OS == XVT_OS_WIN && !defined(__CTL3D__)
  TControl* c = TControl::WINDOW2TControl(win);
  c->enable(on);
#else
  enable_window(win, on);
#endif
}


void xvt_check_box(WINDOW win, bool on)
{
#if XVT_OS == XVT_OS_WIN && !defined(__CTL3D__)
  TControl* c = (TControl*)TControl::WINDOW2TControl(win);
  c->check(on);
#else
  win_check_box(win, on);
#endif
}


bool xvt_get_checked_state(WINDOW win)
{
#if XVT_OS == XVT_OS_WIN && !defined(__CTL3D__)
  TControl* c = TControl::WINDOW2TControl(win);
  return c->checked();
#else
  return get_checked_state(win) ? TRUE : FALSE;
#endif
}


void xvt_check_radio_button(WINDOW win, const WINDOW* ctls, int count)
{
#if XVT_OS == XVT_OS_WIN && !defined(__CTL3D__)
  for (int i = 0; i < count; i++)
    xvt_check_box(ctls[i], ctls[i] == win);
#else
  win_check_radio_button(win, (WINDOW*)ctls, count);
#endif
}


int xvt_get_checked_radio(const WINDOW* ctls, int count)
{
  for (int i = 0; i < count; i++)
    if (xvt_get_checked_state(ctls[i])) return i;

#ifdef DBG
  error_box("Accendi la tua radio per favore!");
#endif

  return 0;
}


///////////////////////////////////////////////////////////
// Gestione Status bar
///////////////////////////////////////////////////////////

HIDDEN WINDOW statbar = NULL_WIN;

WINDOW xvt_create_statbar()
{
  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, "");
  
  xvt_init_font();                          
  DRAW_CTOOLS ct; win_get_draw_ctools(TASK_WIN, &ct);
  statbar_set_font(statbar, &ct.font);
#endif

  return statbar;
}

void xvt_statbar_set(const char* text, bool def)
{                    
#if XVT_OS == XVT_OS_WIN
  const TDate oggi(TODAY);
  TString t(80);
  t << text << '\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
}

void xvt_statbar_refresh()
{
#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;
}


bool xvt_test_menu_tag(MENU_TAG tag)
{                      
  MENU_ITEM *mi = win_menu_fetch(TASK_WIN);
  const bool ok = test_menu_tag(mi, tag);
  menu_free(mi);
  return ok;
}


// translation of graphics attributes from codes chars  
// used by print functions

COLOR trans_color(char c)
{
  switch (c) 
  {
  case 'n': return COLOR_BLACK;     break;
          case 'r': return COLOR_RED;       break;
          case 'g': return COLOR_GREEN;     break;
          case 'b': return COLOR_BLUE;      break;
          case 'c': return COLOR_CYAN;      break;
          case 'y': return COLOR_YELLOW;    break;
          case 'v': return COLOR_MAGENTA;   break;
          case 'w': return COLOR_WHITE;     break;
          case 'm': return MASK_BACK_COLOR; break;
          case 'd': return COLOR_DKGRAY;    break;
          case 'l': return COLOR_LTGRAY;    break;
          case 'k': return COLOR_GRAY;      break;
          default: CHECK(0,"trans_color: Undefined color"); break;
          }
  return -1; 
}

PAT_STYLE trans_brush(char p)
{
  switch (p)
  {
  case 'n' :  return PAT_NONE;      break;
            case 'h' :  return PAT_HOLLOW;    break;
            case 's' :  return PAT_SOLID;     break;
            case '-' :  return PAT_HORZ;      break;
            case '|' :  return PAT_VERT;      break;
            case '/' :  return PAT_FDIAG;     break;
            case '\\':  return PAT_BDIAG;     break;
            case 'X' :  return PAT_DIAGCROSS; break;
            case '+' :  return PAT_CROSS;     break;
              default  : CHECK(0,"trans_brush: Undefined pattern"); break;
            }
  return PAT_NONE; 
}

PEN_STYLE trans_pen(char p)
{
  switch (p)
  {
  case 'n' : return P_SOLID; break;
           case '.' : return P_DOT;   break;
           case '-' : return P_DASH;  break;
           default: CHECK(0,"trans_pen: Undefined pattern"); break;
           }
  return P_SOLID;
}                          

