File: BGUI.C | Size: 67,711 bytes | Download file | Back to directory listing | BWPOW's homepage
/*
File: BGui.c (C) 1998 Dan Huizenga (Skis)
Web: http://www.concentric.net/~skis
E/M: skis@concentric.net
 
BGui -- A win-95 like drop in replacement for the Allegro GUI.
All errors in this file are (C) 1998 Dan Huizenga. If you used these
routines in your program, all that I ask is E-Mail me about what your
program does, and send me a copy if I request it.
*/
 
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
 
#include "allegro.h"
#include "tdgui.h"
 
//(Proc)    (x, y, w, h)    (Dialog) (zorder)  (Flags) (d1, d2) (dp)       
/*
   color constants used to draw billgui routines. Want to change the colors?
   use these, NOT the fg/bg properties of the dialogs
   For slightly more detailed descriptions of what the stuff in this file
   does, look at tdgui.h.
*/
 
float bg_ver = .3;
char bg_ver_str[255] = ".3 BETA";
 
 
RGB bill_light = {224, 224, 224};
RGB bill_hlight = {250, 250, 250};
RGB bill_face = {200, 200, 200};
RGB bill_shadow = {128, 128, 128};
RGB bill_dkshadow = {30, 30, 30};
RGB bill_text = {30, 30, 30};
RGB bill_disabledtext = {128, 128, 128};
RGB bill_activetitle = {0, 0, 128};
RGB bill_titletext = {255, 255, 255};
RGB bill_framebg = {255, 255, 255};
 
PALETTE bill_pal;
 
int bill_appearexact = FALSE;
 
#define GFX_CANCEL         3
#define GFX_DRIVER_LIST    4
#define GFX_MODE_LIST      5
#define GFX_DEPTH_LIST     6
 
#define A_S1  0
#define A_S2  1
#define A_S3  2
#define A_B1  3
#define A_B2  4
#define A_B3  5
 
typedef char *(*getfuncptr)(int, int *);
 
BITMAP *radio_unsel;
BITMAP *radio_sel;
BITMAP *radio_grey;
 
//Unselected
static unsigned char radio_unsel_data[144] =
{
 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0,
 0, 0, 4, 4, 5, 5, 5, 5, 4, 4, 0, 0,
 0, 4, 5, 5, 2, 2, 2, 2, 5, 5, 1, 0,
 0, 4, 5, 2, 2, 2, 2, 2, 2, 3, 1, 0,
 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1,
 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1,
 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1,
 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1,
 0, 4, 5, 2, 2, 2, 2, 2, 2, 3, 1, 0,
 0, 4, 3, 3, 2, 2, 2, 2, 3, 3, 1, 0,
 0, 0, 1, 1, 3, 3, 3, 3, 1, 1, 0, 0,
 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0
};
 
//Selected
static unsigned char radio_sel_data[144] =
{
 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0,
 0, 0, 4, 4, 5, 5, 5, 5, 4, 4, 0, 0,
 0, 4, 5, 5, 2, 2, 2, 2, 5, 5, 1, 0,
 0, 4, 5, 2, 2, 2, 2, 2, 2, 3, 1, 0,
 4, 5, 2, 2, 2, 6, 6, 2, 2, 2, 3, 1,
 4, 5, 2, 2, 6, 6, 6, 6, 2, 2, 3, 1,
 4, 5, 2, 2, 6, 6, 6, 6, 2, 2, 3, 1,
 4, 5, 2, 2, 2, 6, 6, 2, 2, 2, 3, 1,
 0, 4, 5, 2, 2, 2, 2, 2, 2, 3, 1, 0,
 0, 4, 3, 3, 2, 2, 2, 2, 3, 3, 1, 0,
 0, 0, 1, 1, 3, 3, 3, 3, 1, 1, 0, 0,
 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0
};
 
//greyed
static unsigned char radio_grey_data[144] =
{
 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0,
 0, 0, 4, 4, 5, 5, 5, 5, 4, 4, 0, 0,
 0, 4, 5, 5, 7, 7, 7, 7, 5, 5, 1, 0,
 0, 4, 5, 7, 7, 7, 7, 7, 7, 3, 1, 0,
 4, 5, 7, 7, 7, 7, 7, 7, 7, 7, 3, 1,
 4, 5, 7, 7, 7, 7, 7, 7, 7, 7, 3, 1,
 4, 5, 7, 7, 7, 7, 7, 7, 7, 7, 3, 1,
 4, 5, 7, 7, 7, 7, 7, 7, 7, 7, 3, 1,
 0, 4, 5, 7, 7, 7, 7, 7, 7, 3, 1, 0,
 0, 4, 3, 3, 7, 7, 7, 7, 3, 3, 1, 0,
 0, 0, 1, 1, 3, 3, 3, 3, 1, 1, 0, 0,
 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0
};
 
typedef struct GFX_MODE_DATA
{
   int w;
   int h;
   char *s;
} GFX_MODE_DATA;
 
 
typedef struct MENU_INFO            /* information about a popup menu */
{
   MENU *menu;                      /* the menu itself */
   struct MENU_INFO *parent;        /* the parent menu, or NULL for root */
   int bar;                         /* set if it is a top level menu bar */
   int size;                        /* number of items in the menu */
   int sel;                         /* selected item */
   int x, y, w, h;                  /* screen position of the menu */
   int (*proc)();                   /* callback function */
   BITMAP *saved;                   /* saved what was underneath it */
} MENU_INFO;
 
 
static GFX_MODE_DATA gfx_mode_data[] =
{
   { 320,   200,  "320x200"   },
   { 320,   240,  "320x240"   },
   { 640,   400,  "640x400"   },
   { 640,   480,  "640x480"   },
   { 800,   600,  "800x600"   },
   { 1024,  768,  "1024x768"  },
   { 1280,  1024, "1280x1024" },
   { 1600,  1200, "1600x1200" },
   { 256,   200,  "256x200"   },
   { 256,   224,  "256x224"   },
   { 256,   240,  "256x240"   },
   { 256,   256,  "256x256"   },
   { 320,   100,  "320x100"   },
   { 320,   400,  "320x400"   },
   { 320,   480,  "320x480"   },
   { 320,   600,  "320x600"   },
   { 360,   200,  "360x200"   },
   { 360,   240,  "360x240"   },
   { 360,   270,  "360x270"   },
   { 360,   360,  "360x360"   },
   { 360,   400,  "360x400"   },
   { 360,   480,  "360x480"   },
   { 360,   600,  "360x600"   },
   { 376,   282,  "376x282"   },
   { 376,   308,  "376x308"   },
   { 376,   564,  "376x564"   },
   { 400,   150,  "400x150"   },
   { 400,   300,  "400x300"   },
   { 400,   600,  "400x600"   },
   { 0,     0,    NULL        }
};
 
/* The following routines came straight out of Allegro, names and all.
   I hope this doesn't cause any problems, but I wouldn't know, as I
   am realatively new to C programming.  
*/
 
/* gfx_mode_getter:
 *  Listbox data getter routine for the graphics mode list.
 */
static char *gfx_mode_getter(int index, int *list_size)
{
   if (index < 0) {
      if (list_size)
	 *list_size = sizeof(gfx_mode_data) / sizeof(GFX_MODE_DATA) - 1;
      return NULL;
   }
 
   return gfx_mode_data[index].s;
}
 
 
 
/* gfx_card_getter:
 *  Listbox data getter routine for the graphics card list.
 */
static char *gfx_card_getter(int index, int *list_size)
{
   static char *card[] = {
      "Autodetect",
      "VGA mode 13h",
      "Mode-X",
 
   #ifdef DJGPP
	 /* djgpp drivers */
	 "VESA 1.x",
	 "VESA 2.0 (banked)",
	 "VESA 2.0 (linear)",
	 "VBE/AF",
	 "Xtended mode",
	 "ATI 18800/28800",
	 "ATI mach64",
	 "Cirrus 64xx",
	 "Cirrus 54xx",
	 "Paradise",
	 "S3",
	 "Trident",
	 "Tseng ET3000",
	 "Tseng ET4000",
	 "Video-7"
 
   #else
	 /* linux drivers */
	 "SVGALIB"
   #endif
   };
 
   if (index < 0) {
      if (list_size)
	 *list_size = sizeof(card) / sizeof(char *);
      return NULL;
   }
 
   return card[index];
}
 
static void fill_menu_info(MENU_INFO *m, MENU *menu, MENU_INFO *parent, int bar, int x, int y, int minw, int minh)
{
   int c, i;
   int extra = 0;
   char buf[80], *tok;
 
   m->menu = menu;
   m->parent = parent;
   m->bar = bar;
   m->x = x;
   m->y = y;
   m->w = 2;
   m->h = (m->bar) ? (text_height(font)+6) : 3;
   m->proc = NULL;
   m->sel = -1;
 
   /* calculate size of the menu */
   for (m->size=0; m->menu[m->size].text; m->size++) {
      for (i=0; (m->menu[m->size].text[i]) && (m->menu[m->size].text[i] != '\t'); i++)
	 buf[i] = m->menu[m->size].text[i];
      buf[i] = 0;
 
      c = gui_strlen(buf);
 
      if (m->bar) {
	 m->w += c+16;
      }
      else {
	 m->h += text_height(font)+4;
	 m->w = MAX(m->w, c+16);
      }
 
      if (m->menu[m->size].text[i] == '\t') {
	 tok = m->menu[m->size].text+i+1;
	 c = gui_strlen(tok);
	 extra = MAX(extra, c);
      }
   }
 
   if (extra)
      m->w += extra+16;
 
   m->w = MAX(m->w, minw);
   m->h = MAX(m->h, minh);
}
 
static void get_menu_pos(MENU_INFO *m, int c, int *x, int *y, int *w)
{
   int c2;
 
   if (m->bar) {
      *x = m->x+1;
 
      for (c2=0; c2<c; c2++)
	 *x += gui_strlen(m->menu[c2].text) + 16;
 
      *y = m->y+1;
      *w = gui_strlen(m->menu[c].text) + 16;
   }
   else {
      *x = m->x+2;
      *y = m->y+c*(text_height(font)+4)+2;
      *w = m->w-4;
   }
}
 
/* menu_mouse_object:
 *  Returns the index of the object the mouse is currently on top of.
 */
static int menu_mouse_object(MENU_INFO *m)
{
   int c;
   int x, y, w;
 
   for (c=0; c<m->size; c++) {
      get_menu_pos(m, c, &x, &y, &w);
 
      if ((mouse_x >= x) && (mouse_x < x+w) &&
          (mouse_y >= y) && (mouse_y < y+(text_height(font)+4)))
	 return (m->menu[c].text[0]) ? c : -1;
   }
 
   return -1;
}
 
/* mouse_in_parent_menu:
 *  Recursively checks if the mouse is inside a menu or any of its parents.
 */
static int mouse_in_parent_menu(MENU_INFO *m) 
{
   int c;
 
   if (!m)
      return FALSE;
 
   c = menu_mouse_object(m);
   if ((c >= 0) && (c != m->sel))
      return TRUE;
 
   return mouse_in_parent_menu(m->parent);
}
 
int billmenu_alt_key(int k, MENU *m)
{
   char *s;
   int c;
/*
   if (k & 0xff)
      return 0;
 
   k = key_ascii_table[k>>8];
 
   for (c=0; m[c].text; c++) {
      s = m[c].text;
      while (*s) {
	 if (*s == '&') {
	    s++;
	    if ((*s != '&') && (tolower(*s) == tolower(k)))
	       return k;
	 }
	 s++;
      }
   }
*/
   return 0;
}
 
/* menu_key_shortcut:
 *  Returns true if c is indicated as a keyboard shortcut by a '&' character
 *  in the specified string.
 */
static int menu_key_shortcut(int c, char *s)
{
   while (*s) {
      if (*s == '&') {
	 s++;
	 if ((*s != '&') && (tolower(*s) == tolower(c & 0xff)))
	    return TRUE;
      }
      s++;
   }
 
   return FALSE;
}
 
 
 
 
 
 
 
 
/* Ok, that's the end of the same-name procedures*/
 
 
static DIALOG billgfx_mode_dialog[] =
{
   /* (dialog proc)     (x)   (y)   (w)   (h)   (fg)  (bg)  (key) (flags)  (d1)  (d2)  (dp) */
   { d_billwin_proc,        0,    8,    304,  166,  0,    0,    0,    0,       0,    0,    "Select Graphics Mode" },
   { d_ctext_proc,          0,    0,    0,    0,    0,    0,    0,    0,       0,    0,    "" },
   { d_billbutton_proc,     196,  113,  100,  16,   0,    0,    0,    D_EXIT,  0,    0,    "OK" },
   { d_billbutton_proc,     196,  135,  100,  16,   0,    0,    27,   D_EXIT,  0,    0,    "Cancel" },
   { d_billlist_proc,       16,   28,   164,  123,  0,    0,    0,    D_EXIT,  0,    0,    gfx_card_getter },
   { d_billlist_proc,       196,  28,   100,  75,   0,    0,    0,    D_EXIT,  3,    0,    gfx_mode_getter },
   { NULL }
};
 
static DIALOG billalert_dialog[] =
{
   /* (dialog proc)     (x)   (y)   (w)   (h)   (fg)  (bg)  (key) (flags)  (d1)  (d2)  (dp) */
   { d_billwin_proc,    0,    0,    0,    0,    0,    0,    0,    0,       0,    0,    NULL },
   { d_billctext_proc,      0,    0,    0,    0,    0,    0,    0,    0,       0,    0,    NULL },
   { d_billctext_proc,      0,    0,    0,    0,    0,    0,    0,    0,       0,    0,    NULL },
   { d_billbutton_proc,     0,    0,    0,    0,    0,    0,    0,    D_EXIT,  0,    0,    NULL },
   { d_billbutton_proc,     0,    0,    0,    0,    0,    0,    0,    D_EXIT,  0,    0,    NULL },
   { d_billbutton_proc,     0,    0,    0,    0,    0,    0,    0,    D_EXIT,  0,    0,    NULL },
   { NULL }
};
 
RGB make_8(RGB r)
{
 RGB i;
 i.r = (r.r*63)/255;
 i.g = (r.g*63)/255;
 i.b = (r.b*63)/255;
 return i;
}
 
void set_color8(int idx, RGB *r)
{
 RGB i;
 RGB b;
 b = *r;
 i = make_8(*r);
 set_color(idx, &i);
}
/*
 All of the BGui colors are gotten with this, in case I
 decide to use some twisted color-mapping scheme for 8-Bit.
 I don't think that I'll have to do this anymore, now that
 I figured out what was wrong with the bill_init_smallpall.
*/
int get_bill_color(RGB bc) {
 int i;
 i = makecol(bc.r, bc.g, bc.b);
 return i;
}
 
/*this is a slightly modified version of something
  found in Allegro's mouse.c*/
void data2bmp(unsigned char d[], BITMAP *b, int w, int h)
{
 int pcolor;
 int x, y;
 for (y=0; y<h; y++) {
  for (x=0; x<w; x++) {
   if(d[y*w+x] == 1)
    pcolor = get_bill_color(bill_hlight);
   else if(d[y*w+x] == 2)
    pcolor = get_bill_color(bill_framebg);
   else if(d[y*w+x] == 3)
    pcolor = get_bill_color(bill_light);
   else if(d[y*w+x] == 4)
    pcolor = get_bill_color(bill_shadow);
   else if(d[y*w+x] == 5)
    pcolor = get_bill_color(bill_dkshadow);
   else if(d[y*w+x] == 6)
    pcolor = get_bill_color(bill_dkshadow);
   else if(d[y*w+x] == 7)
    pcolor = get_bill_color(bill_face);
   else
   {
    if (bitmap_color_depth(b) == 8)
     pcolor = 0;
    else 
     pcolor = makecol(255, 0, 255);
   }
   putpixel(b, x, y, pcolor);
  }
 } 
}
 
void bill_init() {
 //billinit_pal();
 radio_unsel = create_bitmap(12, 12);
 radio_sel = create_bitmap(12, 12);
 radio_grey = create_bitmap(12, 12);
 data2bmp(radio_unsel_data, radio_unsel, 12, 12);
 data2bmp(radio_sel_data,   radio_sel,   12, 12);
 data2bmp(radio_grey_data,  radio_grey,  12, 12);
 
 gui_mouse_focus = 0;
}
 
/*Sets up a gray palette w/ blue for the title bars*/
void bill_init_pal() {
 RGB cl = { 0, 0, 0 };
 int count;
 
 for(count = 0; count < 255; count++) {
   cl.r = (63*count)/255;
   cl.g = (63*count)/255;
   cl.b = (63*count)/255;
   set_color(count, &cl);
   bill_pal[count]=cl;
 }
 cl.r = 0;
 cl.g = 0;
 cl.b = 31;
 bill_pal[1]=cl;
 set_color(1, &cl);
 cl.r = 63;
 cl.g = 63;
 cl.b = 63;
 bill_pal[16]=cl;
 set_color(16, &cl);
 data2bmp(radio_unsel_data, radio_unsel, 12, 12);
 data2bmp(radio_sel_data,   radio_sel,   12, 12);
 data2bmp(radio_grey_data,  radio_grey,  12, 12);
}
 
void bill_init_smallpal(int start)
{
set_color8(start, &bill_light);
set_color8(start+1, &bill_hlight);
set_color8(start+2, &bill_face);
set_color8(start+3, &bill_shadow);
set_color8(start+4, &bill_dkshadow);
set_color8(start+5, &bill_text);
set_color8(start+6, &bill_activetitle);
set_color8(start+7, &bill_titletext);
set_color8(start+8, &bill_framebg);
set_color8(start+9, &bill_disabledtext);
 data2bmp(radio_unsel_data, radio_unsel, 12, 12);
 data2bmp(radio_sel_data,   radio_sel,   12, 12);
 data2bmp(radio_grey_data,  radio_grey,  12, 12);
}
 
void bill_init_very_smallpal(int start)
{
set_color8(start, &bill_light);
set_color8(start+1, &bill_hlight);
set_color8(start+2, &bill_face);
set_color8(start+3, &bill_shadow);
set_color8(start+4, &bill_dkshadow);
set_color8(start+5, &bill_activetitle);
set_color8(start+6, &bill_titletext);
 data2bmp(radio_unsel_data, radio_unsel, 12, 12);
 data2bmp(radio_sel_data,   radio_sel,   12, 12);
 data2bmp(radio_grey_data,  radio_grey,  12, 12);
}
 
void set_gui_mode(int mode)
{
 if (mode) {
  bill_appearexact = TRUE;
  gui_mouse_focus = FALSE;
 }
 else {
  bill_appearexact = FALSE;
  gui_mouse_focus = TRUE;
 }
}
/*
 ======================
 =   BILL GUI Helpers =
 ======================
*/
 
/* ALL of the BillGui routines are based on the tdbox routine.
   Styles include:
   STL_IN     (1)        "in" state border (used w/ buttuns and frames)
   STL_OUT    (2)        "out" state border (used w/ buttons)
   STL_FRAME  (8)        used in conjunction w/ STL_IN, it switches the order
                         of the "shadow" lines at the top of a frame, so that
                         the light one is towards the outside
   STL_BUTTONDOWN (64)   used for buttons in appearexact mode 
 
   STL_FACE   (4)        fills the bg w/ bill_face. otherwise bg isn't drawn.
   STL_FLAT   (4)        same as above
   STL_FILLED (4)        same as above
 
   STL_FRAMEFILLED (32)  used for filled frames (white bg).  This DOES NOT include
                         objects drawn w/ draw_scrollable_billframe.  They have
                         to draw their own background.
   STL_DITHERED    (16)  draws a dither of bill_light and bill_hlight as the bg,
                         for scroll bars
   STL_TITLEBAR   (128)  Window titles and menus.
*/
 
void tdbox(BITMAP *b, int x, int y, int w, int h, int stl) {
 BITMAP *pattern;
 if (w > 0) {
  if (h > 0) {
  //Draw the frame
   if(stl & STL_OUT) {
    hline(b, x, y, x+w-1, get_bill_color(bill_hlight));
    hline(b, x+1, y+1, x+w-2, get_bill_color(bill_light));
    vline(b, x, y, y+h-1, get_bill_color(bill_hlight));
    vline(b, x+1, y+1, y+h-2, get_bill_color(bill_light));
 
    hline(b, x, y+h, x+w, get_bill_color(bill_dkshadow));
    hline(b, x+1, y+h-1, x+w-1, get_bill_color(bill_shadow));
    vline(b, x+w, y, y+h, get_bill_color(bill_dkshadow));
    vline(b, x+w-1, y+1, y+h-2, get_bill_color(bill_shadow));
   }
   else if(stl & STL_IN) {
    if (!(stl & STL_BUTTONDOWN)) {
     hline(b, x, y+h, x+w, get_bill_color(bill_hlight));
     hline(b, x+1, y+h-1, x+w-1, get_bill_color(bill_light));
     vline(b, x+w, y, y+h, get_bill_color(bill_hlight));
     vline(b, x+w-1, y+1, y+h-2, get_bill_color(bill_light));
 
     if (stl & STL_FRAME) {
      hline(b, x+1, y+1, x+w-1, get_bill_color(bill_dkshadow));
      hline(b, x, y, x+w, get_bill_color(bill_shadow));
      vline(b, x+1, y+1, y+h-1, get_bill_color(bill_dkshadow));
      vline(b, x, y, y+h, get_bill_color(bill_shadow));
     }
     else {
      hline(b, x, y, x+w, get_bill_color(bill_dkshadow));
      hline(b, x+1, y+1, x+w-1, get_bill_color(bill_shadow));
      vline(b, x, y, y+h, get_bill_color(bill_dkshadow));
      vline(b, x+1, y+1, y+h-1, get_bill_color(bill_shadow));
     }
    }
    else {
     rect(b, x, y, x+w, y+h, get_bill_color(bill_dkshadow));
     rect(b, x+1, y+1, x+w-1, y+h-1, get_bill_color(bill_shadow));
    }
   }
 
   //The following HAS to be done AFTER THE FRAME!
   if ((stl & STL_DOWN) || (stl & STL_UP)) {
    x+=2;
    y+=2;
    w-=4;
    h-=4;
   }
   if ((w>0) && (h>0)) 
   {
    //Draw the BackGround
    if (stl & STL_FLAT)
     rectfill(b, x, y, x+w, y+h, get_bill_color(bill_face));
    else if(stl & STL_FRAMEFILLED) 
     rectfill(b, x, y, x+w, y+h, get_bill_color(bill_framebg));
    else if(stl & STL_DITHERED) {
     pattern = create_bitmap(2, 2);
     putpixel(pattern, 0, 1, get_bill_color(bill_light));
     putpixel(pattern, 1, 0, get_bill_color(bill_light));
     putpixel(pattern, 0, 0, get_bill_color(bill_hlight));
     putpixel(pattern, 1, 1, get_bill_color(bill_hlight));
 
     drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0);
     rectfill(b, x, y, x+w, y+h, 0);
     solid_mode();
    }
    else if(stl & STL_TITLEBAR) {
     rectfill(b, x, y, x+w, y+h, get_bill_color(bill_activetitle));
    }
 
   }
  }
 }
}
 
void tdhline(BITMAP *b, int x, int y, int x2)
{
 hline(b, x, y+1, x2, get_bill_color(bill_hlight));
 hline(b, x, y, x2, get_bill_color(bill_shadow));
}
 
 
int is_in(int xa, int ya, int xb, int yb, int w, int h) {
 int in = TRUE;
 if (xa < xb) in = FALSE;
 if (ya < yb) in = FALSE;
 if (xa > xb+w) in = FALSE;
 if (ya > yb+h) in = FALSE;
 return in;
}
 
 
/* Same as the dotted rect in allegro routines, except that it skips
   every other pixel instead of having a fg/bg pixel
*/
static void bill_dotted_rect(int x1, int y1, int x2, int y2, int fg)
{
   int c;
 
   for (c=x1; c<=x2; c+=2) {
      putpixel(screen, c, y1, fg);
      putpixel(screen, c, y2, fg);
   }
 
   for (c=y1; c<y2; c+=2) {
      putpixel(screen, x1, c, fg);
      putpixel(screen, x2, c, fg);
   }
}
 
void _draw_scrollable_billframe(DIALOG *d, int listsize, int offset, int height, int fg_color, int bg)
{
   int i, len;
   int xx, yy;
 
   /* draw frame */
   tdbox(screen, d->x, d->y, d->w, d->h, STL_IN + STL_FRAME);
 
   /* possibly draw scrollbar */
   if (listsize > height) {
      /* create and draw the scrollbar */
      i = ((d->h-4) * height + listsize/2) / listsize;
      xx = d->x+d->w-12;
      yy = d->y+2;
 
 
      if (offset > 0) {
        len = (((d->h-4) * offset) + listsize/2) / listsize;
        //tdbox(screen, xx, yy, (d->x+d->w)-xx-2, (d->y+d->h)-yy-2, STL_DITHERED);
        tdbox(screen, xx, yy, (d->x+d->w)-xx-2, len-1, STL_DITHERED);
        yy += len;
      }
 
      if (yy+i<d->y+d->h-2) {
        tdbox(screen, xx, yy+i, (d->x+d->w)-xx-2, (d->y+d->h)-2-(i+yy), STL_DITHERED);
      }
 
      if (yy+i < d->y+d->h-2) {
       tdbox(screen, xx, yy, 10, i, STL_OUT + STL_FLAT);
      }
      else {
       tdbox(screen, xx, yy, 10, (d->y+d->h)-yy-2, STL_OUT + STL_FLAT);
      }
   }
   else {
      rect(screen, d->x+2, d->y+2, d->x+d->w-2, d->y+d->h-2, get_bill_color(bill_framebg));
   }
}
 
/* draw_listbox:
 *  Helper function to draw a listbox object.
 */
void _draw_billlistbox(DIALOG *d)
{
   int height, listsize, i, len, bar, x, y, w;
   int fg_color, fg, bg;
   char *sel = d->dp2;
   char *s;
   char store;
 
   (*(getfuncptr)d->dp)(-1, &listsize);
   height = (d->h-3) / text_height(font);
   bar = (listsize > height);
   w = (bar ? d->w-14 : d->w-2);
   fg_color = get_bill_color(bill_text);
 
   /* draw box contents */
   for (i=0; i<height; i++) {
      if (d->d2+i < listsize) {
	 if (d->d2+i == d->d1) {
            fg = get_bill_color(bill_framebg);
            bg = get_bill_color(bill_text);
	 } 
	 else if ((sel) && (sel[d->d2+i])) { 
            fg = get_bill_color(bill_framebg);
            bg = get_bill_color(bill_text);
	 }
	 else {
            bg = get_bill_color(bill_framebg);
            fg = get_bill_color(bill_text);
	 }
	 s = (*(getfuncptr)d->dp)(i+d->d2, NULL);
         x = d->x + 3;
         y = d->y + 3 + i*text_height(font);
	 text_mode(bg);
	 rectfill(screen, x, y, x+7, y+text_height(font)-1, bg); 
	 x += 8;
	 len = strlen(s);
	 store = 0;
	 while (text_length(font, s) >= d->w - (bar ? 22 : 10)) {
	    s[len] = store;
	    len--;
	    store = s[len];
	    s[len] = 0;
	 }
         gui_textout(screen, s, x, y, fg, FALSE); 
	 x += text_length(font, s);
	 s[len] = store;
	 if (x <= d->x+w) 
	    rectfill(screen, x, y, d->x+w, y+text_height(font)-1, bg);
      }
      else
	 rectfill(screen, d->x+2,  d->y+2+i*text_height(font), 
                  d->x+w, d->y+1+(i+1)*text_height(font), get_bill_color(bill_framebg));
   }
 
   if (d->y+2+i*text_height(font) <= d->y+d->h-2)
      rectfill(screen, d->x+2, d->y+2+i*text_height(font), 
                                       d->x+w, d->y+d->h-2, get_bill_color(bill_framebg));
 
   /* draw frame, maybe with scrollbar */
   _draw_scrollable_billframe(d, listsize, d->d2, height, fg_color, d->bg);
}
 
 
void _draw_billtextbox(char *thetext, int *listsize, int draw, int offset,
		   int wword, int tabsize, int x, int y, int w, int h,
		   int disabled, int fore, int deselect, int disable)
{
   int fg = fore;
   int y1 = y+4;
   int x1;
   int len;
   int ww = w-4;
 
   char *s = ".";
 
   const char *text = " ";
 
   const char *printed = text;
   const char *scanned = text;
   const char *oldscan = text;
   const char *ignore = NULL;
   int width;
   int line = 0;
 
   int i = 0;
 
   /* find the correct text */
   if (thetext != NULL) {
      printed = thetext;
      scanned = thetext;
   }
 
   /* do some drawing setup */
   if (draw) {
      /* initial start blanking at the top */
      rectfill(screen, x+2, y+2, x+w-1, y1-1, deselect);
   }
 
   /* choose the text color */
   if (disabled) 
      fg = disable;
 
   text_mode(deselect);
 
   /* loop over the entire string */
   while (1) {
      width = 0;
 
      /* find the next break */
      while (scanned[0]) {
	 /* check for a forced break */
	 if (scanned[0] == '\n') {
	    scanned++;
 
	    /* we are done parsing the line end */
	    break;
	 }
 
	 /* the next character length */
	 s[0] = scanned[0];
	 len = text_length(font, s);
 
	 /* modify length if its a tab */
	 if (s[0] == '\t') 
	    len = tabsize * text_length(font, " ");
 
	 /* check for the end of a line by excess width of next char */
	 if (width+len >= ww) {
	    /* we have reached end of line do we go back to find start */
	    if (wword) {
	       /* remember where we were */
	       oldscan = scanned;
 
	       /* go backwards looking for start of word */
	       while (!isspace(scanned[0])) {
		  /* don't wrap too far */
		  if (scanned == printed) {
		     /* the whole line is filled, so stop here */
		     scanned = oldscan;
		     break;
		  }
		  /* look further backwards to wrap */
		  scanned--;
	       }
	       /* put the space at the end of the line */
	       ignore = scanned;
	       scanned++;
 
	       /* check for endline at the convenient place */
	       if (scanned[0] == '\n') 
		  scanned++;
	    }
	    /* we are done parsing the line end */
	    break;
	 }
	 /* the character can be added */
	 scanned++;
	 width += len;
      }
      /* check if we are to print it */
      if ((draw) && (line >= offset) && (y1+text_height(font) < (y+h-1))) {
	 x1 = x+4;
 
	 /* the initial blank bit */
	 rectfill(screen, x+2, y1, x1-1, y1+text_height(font), deselect);
 
	 /* print up to the marked character */
	 while (printed != scanned) {
	    /* do special stuff for each charater */
	    switch (printed[0]) {
 
	       case '\n':
		  /* don't print and endlines in the text, we'll do that ourselves */
		  break;
 
	       /* possibly expand the tabs */
	       case '\t':
		  for (i=0; i<tabsize; i++) {
		     s[0] = ' ';
		     textout(screen, font, s, x1, y1, fg);
		     x1 += text_length(font, s);
		  }
		  break;
 
	       /* print a normal charater */
	       default:
		  if (printed != ignore) {
		     s[0] = printed[0];
		     textout(screen, font, s, x1, y1, fg);
		     x1 += text_length(font, s);
		  }
	    }
	    /* goto the next character */
	    printed++;
	 }
	 /* the last blank bit */
	 if (x1 < x+w-1) 
	    rectfill(screen, x1, y1, x+w-1, y1+text_height(font)-1, deselect);
 
	 /* print the line end */
	 y1 += text_height(font);
      }
      printed = scanned;
 
      /* we have done a line */
      line++;
 
      /* check if we are at the end of the string */
      if (*printed == '\0') {
	 /* the under blank bit */
	 if (draw) 
	    rectfill(screen, x+1, y1, x+w-1, y+h-1, deselect);
 
	 /* tell how many lines we found */
	 *listsize = line;
	 return;
      }
   }
}
 
static void draw_billmenu_item(MENU_INFO *m, int c)
{
 int fg, bg;
 int i, x, y, w;
 char buf[80], *tok;
 int stl;
 
 if (m->menu[c].flags & D_DISABLED) {
  fg = get_bill_color(bill_disabledtext);
  bg = get_bill_color(bill_face);
  stl = STL_FACE;
 }
 else {
  if (c == m->sel) {
   fg = get_bill_color(bill_titletext);;
   bg = get_bill_color(bill_activetitle);
   stl = STL_TITLEBAR;
  }
  else {
   fg = get_bill_color(bill_text);
   bg = get_bill_color(bill_face);
   stl = STL_FACE;
  }
 }
 
 get_menu_pos(m, c, &x, &y, &w);
 
 tdbox(screen, x, y, w, text_height(font)+3, stl);
 
 text_mode(bg);
 
 if (m->menu[c].text[0]) {
  for (i=0; (m->menu[c].text[i]) && (m->menu[c].text[i] != '\t'); i++)
   buf[i] = m->menu[c].text[i];
  buf[i] = 0;
 
  gui_textout(screen, buf, x+8, y+1, fg, FALSE);
 
  if (m->menu[c].text[i] == '\t') {
   tok = m->menu[c].text+i+1;
   gui_textout(screen, tok, x+w-gui_strlen(tok)-8, y+1, fg, FALSE);
  }
 }
 else
  tdhline(screen, x, y+text_height(font)/2+2, x+w);
 
 if (m->menu[c].flags & D_SELECTED) {
  line(screen, x+1, y+text_height(font)/2+1, x+3, y+text_height(font)+1, fg);
  line(screen, x+3, y+text_height(font)+1, x+6, y+2, fg);
 }
}
 
static void draw_billmenu(MENU_INFO *m)
{
 int c;
 
 for (c=0; m->menu[c].text; c++)
  draw_billmenu_item(m, c);
 
 if(!m->bar) tdbox(screen, m->x, m->y, m->w, m->h, STL_OUT);
}
 
int _do_billmenu(MENU *menu, MENU_INFO *parent, int bar, int x, int y, int repos, int *dret, int minw, int minh)
{
   MENU_INFO m;
   MENU_INFO *i;
   int c, c2;
   int ret = -1;
   int mouse_on = mouse_b;
   int old_sel;
   int mouse_sel;
   int _x, _y;
   int redraw = TRUE;
 
   show_mouse(NULL);
 
   fill_menu_info(&m, menu, parent, bar, x, y, minw, minh);
 
   if (repos) {
      m.x = MID(0, m.x, SCREEN_W-m.w-1);
      m.y = MID(0, m.y, SCREEN_H-m.h-1);
   }
 
   /* save screen under the menu */
   m.saved = create_bitmap(m.w+1, m.h+1); 
 
   if (m.saved)
      blit(screen, m.saved, m.x, m.y, 0, 0, m.w+1, m.h+1);
   else
      errno = ENOMEM;
 
   m.sel = mouse_sel = menu_mouse_object(&m);
   if ((m.sel < 0) && (!mouse_on) && (!bar))
      m.sel = 0;
 
   show_mouse(screen);
 
   do {
      old_sel = m.sel;
 
      c = menu_mouse_object(&m);
      if ((mouse_b) || (c != mouse_sel))
	 m.sel = mouse_sel = c;
 
      if (mouse_b) {                            /* if button pressed */
         if ((mouse_x < m.x) || (mouse_x > m.x+m.w) ||
             (mouse_y < m.y) || (mouse_y > m.y+m.h)) {
	    if (!mouse_on)                            /* dismiss menu? */
	       break;
 
	    if (mouse_in_parent_menu(m.parent))       /* back to parent? */
	       break;
	 }
 
	 if ((m.sel >= 0) && (m.menu[m.sel].child))   /* bring up child? */
	    ret = m.sel;
 
	 mouse_on = TRUE;
	 clear_keybuf();
      }
      else {                                          /* button not pressed */
	 if (mouse_on)                                /* selected an item? */
	    ret = m.sel;
 
	 mouse_on = FALSE;
 
	 if (keypressed()) {                          /* keyboard input */
	    c = readkey();
 
	    if ((c & 0xff) == 27) {
	       ret = -1;
	       goto getout;
	    }
 
	    switch (c >> 8) {
 
	       case KEY_LEFT:
		  if (m.parent) {
		     if (m.parent->bar) {
			simulate_keypress(KEY_LEFT<<8);
			simulate_keypress(KEY_DOWN<<8);
		     }
		     ret = -1;
		     goto getout;
		  }
		  /* fall through */
 
	       case KEY_UP:
		  if ((((c >> 8) == KEY_LEFT) && (m.bar)) ||
		      (((c >> 8) == KEY_UP) && (!m.bar))) {
		     c = m.sel;
		     do {
			c--;
			if (c < 0)
			   c = m.size - 1;
		     } while ((!(m.menu[c].text[0])) && (c != m.sel));
		     m.sel = c;
		  }
		  break;
 
	       case KEY_RIGHT:
		  if (((m.sel < 0) || (!m.menu[m.sel].child)) &&
		      (m.parent) && (m.parent->bar)) {
		     simulate_keypress(KEY_RIGHT<<8);
		     simulate_keypress(KEY_DOWN<<8);
		     ret = -1;
		     goto getout;
		  }
		  /* fall through */
 
	       case KEY_DOWN:
		  if ((m.sel >= 0) && (m.menu[m.sel].child) &&
		      ((((c >> 8) == KEY_RIGHT) && (!m.bar)) ||
		       (((c >> 8) == KEY_DOWN) && (m.bar)))) {
		     ret = m.sel;
		  }
		  else if ((((c >> 8) == KEY_RIGHT) && (m.bar)) ||
			   (((c >> 8) == KEY_DOWN) && (!m.bar))) {
		     c = m.sel;
		     do {
			c++;
			if (c >= m.size)
			   c = 0;
		     } while ((!(m.menu[c].text[0])) && (c != m.sel));
		     m.sel = c;
		  }
		  break;
 
	       case KEY_SPACE:
	       case KEY_ENTER:
		  if (m.sel >= 0)
		     ret = m.sel;
		  break;
 
	       default:
		  if ((!m.parent) && ((c & 0xff) == 0))
                     c = billmenu_alt_key(c, m.menu);
		  for (c2=0; m.menu[c2].text; c2++) {
		     if (menu_key_shortcut(c, m.menu[c2].text)) {
			ret = m.sel = c2;
			break;
		     }
		  }
		  if (m.parent) {
		     i = m.parent;
		     for (c2=0; i->parent; c2++)
			i = i->parent;
                     c = billmenu_alt_key(c, i->menu);
		     if (c) {
			while (c2-- > 0)
			   simulate_keypress(27);
			simulate_keypress(c);
			ret = -1;
			goto getout;
		     }
		  }
		  break;
	    }
	 }
      }
 
      if ((redraw) || (m.sel != old_sel)) {           /* selection changed? */
	 show_mouse(NULL);
 
	 if (redraw) {
            draw_billmenu(&m);
	    redraw = FALSE;
	 }
	 else {
	    if (old_sel >= 0)
               draw_billmenu_item(&m, old_sel);
 
	    if (m.sel >= 0)
               draw_billmenu_item(&m, m.sel);
	 }
 
	 show_mouse(screen);
      }
 
      if ((ret >= 0) && (m.menu[ret].flags & D_DISABLED))
	 ret = -1;
 
      if (ret >= 0) {                                 /* child menu? */
	 if (m.menu[ret].child) {
	    if (m.bar) {
	       get_menu_pos(&m, ret, &_x, &_y, &c);
	       _x += 6;
	       _y += text_height(font)+7;
	    }
	    else {
	       _x = m.x+m.w*2/3;
	       _y = m.y + (text_height(font)+4)*ret + text_height(font)/4+2;
	    }
            c = _do_billmenu(m.menu[ret].child, &m, FALSE, _x, _y, TRUE, NULL, 0, 0);
	    if (c < 0) {
	       ret = -1;
	       mouse_on = FALSE;
	       mouse_sel = menu_mouse_object(&m);
	    }
	 }
      }
 
      if ((m.bar) && (!mouse_b) && (!keypressed()) &&
          ((mouse_x < m.x) || (mouse_x > m.x+m.w) ||
           (mouse_y < m.y) || (mouse_y > m.y+m.h)))
	 break;
 
   } while (ret < 0);
 
   getout:
 
   if (dret)
      *dret = 0;
 
   /* callback function? */
   if ((!m.proc) && (ret >= 0)) {
      active_menu = &m.menu[ret];
      m.proc = active_menu->proc;
   }
 
   if (ret >= 0) {
      if (parent)
	 parent->proc = m.proc;
      else  {
	 if (m.proc) {
	    c = m.proc();
	    if (dret)
	       *dret = c;
	 }
      }
   }
 
   /* restore screen */
   if (m.saved) {
      show_mouse(NULL);
      blit(m.saved, screen, 0, 0, m.x, m.y, m.w+1, m.h+2);
      destroy_bitmap(m.saved);
   }
 
   show_mouse(screen);
 
   return ret;
}
 
int do_billmenu(MENU *menu, int x, int y)
{
   int ret = _do_billmenu(menu, NULL, FALSE, x, y, TRUE, NULL, 0, 0);
 
   do {
   } while (mouse_b);
 
   return ret;
}
 
/*
  ==============================
  = BILL GUI dialogs           =
  ==============================
*/
 
int billgfx_mode_select(int *card, int *w, int *h)
{
   int ret;
 
   clear_keybuf();
 
   do {
   } while (mouse_b);
 
   centre_dialog(billgfx_mode_dialog);
   ret = moveable_do_dialog(billgfx_mode_dialog, GFX_DRIVER_LIST);
 
   *card = billgfx_mode_dialog[GFX_DRIVER_LIST].d1;
 
   *w = gfx_mode_data[billgfx_mode_dialog[GFX_MODE_LIST].d1].w;
   *h = gfx_mode_data[billgfx_mode_dialog[GFX_MODE_LIST].d1].h;
 
   if (ret == GFX_CANCEL)
      return FALSE;
   else 
      return TRUE;
}
 
int billalert3(char *s1, char *s2, char *s3, char *b1, char *b2, char *b3, int c1, int c2, int c3)
{
   int maxlen = 0;
   int len1, len2, len3;
   int avg_w = text_length(font, " ");
   int avg_h = text_height(font);
   int buttons = 0;
   int b[3];
   int c;
 
   #define SORT_OUT_BUTTON(x) {                                            \
      if (b##x) {                                                          \
         billalert_dialog[A_B##x].flags &= ~D_HIDDEN;                          \
         billalert_dialog[A_B##x].key = c##x;                                  \
         billalert_dialog[A_B##x].dp = b##x;                                   \
	 len##x = gui_strlen(b##x);                                        \
	 b[buttons++] = A_B##x;                                            \
      }                                                                    \
      else {                                                               \
         billalert_dialog[A_B##x].flags |= D_HIDDEN;                           \
	 len##x = 0;                                                       \
      }                                                                    \
   }
 
   billalert_dialog[A_S1].dp = billalert_dialog[A_S2].dp = billalert_dialog[A_S3].dp = 
                           billalert_dialog[A_B1].dp = billalert_dialog[A_B2].dp = "";
 
   if (s1) {
      billalert_dialog[A_S1].dp = s1;
      maxlen = text_length(font, s1);
   }
 
   if (s2) {
      billalert_dialog[A_S2].dp = s2;
      len1 = text_length(font, s2);
      if (len1 > maxlen)
	 maxlen = len1;
   }
 
   if (s3) {
      billalert_dialog[A_S3].dp = s3;
      len1 = text_length(font, s3);
      if (len1 > maxlen)
	 maxlen = len1;
   }
 
   SORT_OUT_BUTTON(1);
   SORT_OUT_BUTTON(2);
   SORT_OUT_BUTTON(3);
 
   len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
   if (len1*buttons > maxlen)
      maxlen = len1*buttons;
 
   maxlen += avg_w*4;
   billalert_dialog[0].w = maxlen;
   billalert_dialog[A_S2].x = billalert_dialog[A_S3].x = 
                                                billalert_dialog[0].x + maxlen/2;
 
   billalert_dialog[A_B1].w = billalert_dialog[A_B2].w = billalert_dialog[A_B3].w = len1;
 
   billalert_dialog[A_B1].x = billalert_dialog[A_B2].x = billalert_dialog[A_B3].x = 
                                       billalert_dialog[0].x + maxlen/2 - len1/2;
 
   if (buttons == 3) {
      billalert_dialog[b[0]].x = billalert_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
      billalert_dialog[b[2]].x = billalert_dialog[0].x + maxlen/2 + len1/2 + avg_w;
   }
   else if (buttons == 2) {
      billalert_dialog[b[0]].x = billalert_dialog[0].x + maxlen/2 - len1 - avg_w;
      billalert_dialog[b[1]].x = billalert_dialog[0].x + maxlen/2 + avg_w;
   }
 
   billalert_dialog[0].h = avg_h*8;
   billalert_dialog[A_S2].y = billalert_dialog[0].y + avg_h*2;
   billalert_dialog[A_S3].y = billalert_dialog[0].y + avg_h*3;
   billalert_dialog[A_S2].h = avg_h;
 
   billalert_dialog[A_B1].y = billalert_dialog[A_B2].y = billalert_dialog[A_B3].y = 
                                                billalert_dialog[0].y + avg_h*5;
 
   billalert_dialog[A_B1].h = billalert_dialog[A_B2].h = billalert_dialog[A_B3].h = avg_h*2;
 
   centre_dialog(billalert_dialog);
 
   clear_keybuf();
 
   do {
   } while (mouse_b);
 
   c = moveable_do_dialog(billalert_dialog, A_B1);
 
   if (c == A_B1)
      return 1;
   else if (c == A_B2)
      return 2;
   else
      return 3;
}
 
int billalert(char *s1, char *s2, char *s3, char *b1, char *b2, int c1, int c2)
{
   int ret;
 
   ret = billalert3(s1, s2, s3, b1, b2, NULL, c1, c2, 0);
 
   if (ret > 2)
      ret = 2;
 
   return ret;
}
 
void _draw_arrow(int x, int y, int basew, int colr, int stl) {
 int sx;
 int sy;
 int xp;
 int yp;
 int h;
 int w;
 
 if (stl == SCL_LEFTARROW) {
  sx = x + basew/2;
  h=basew;
  if (h % 2 > 0) h--;
  for(xp = sx, yp = y; h>=0; xp--, yp++, h-=2) {
   vline(screen, xp, yp, yp+h, colr); 
  }
 }
 else if (stl == SCL_RIGHTARROW) {
  sx = x;
  h=basew;
  if (h % 2 > 0) h--;
  for(xp = sx, yp = y; h>=0; xp++, yp++, h-=2) {
   vline(screen, xp, yp, yp+h, colr); 
  }
 }
 else if (stl == SCL_UPARROW) {
  sy = y;
  w=0;
  if (h % 2 > 0) h--;
  for(yp = sy, xp = x+basew/2; w<=basew; yp++, xp--, w+=2) {
   hline(screen, xp, yp, xp+w, colr); 
  }
 }
 else if (stl == SCL_DOWNARROW) {
  sy = y;
  w=basew;
  if (h % 2 > 0) h--;
  for(yp = sy, xp = x; w>=0; yp++, xp++, w-=2) {
   hline(screen, xp, yp, xp+w, colr); 
  }
 }
}
 
 
void bill_fade_bmp(BITMAP *bmp, int clr) {
 int yoff;
 int ysub;
 int xoff;
 int xadd;
 
 for(yoff=0; yoff<=SCREEN_H; yoff +=2) {
  for(ysub=0; ((yoff-ysub)>=0);ysub++)
   putpixel(bmp, ysub, yoff-ysub, clr);
 }
 
 for(xoff=0; xoff<=SCREEN_W; xoff +=2) {
  for(xadd=0; ((xoff+xadd)<=SCREEN_W); xadd++)
   putpixel(bmp, xoff+xadd, SCREEN_H-xadd, clr);
 }
}
 
void bill_slowfade_bmp(BITMAP *bmp, int clr) {
 int yoff;
 int ysub;
 int xoff;
 int xadd;
 
 for(yoff=0; yoff<=SCREEN_H; yoff +=2) {
 vsync();
  for(ysub=0; ((yoff-ysub)>=0);ysub++)
   putpixel(bmp, ysub, yoff-ysub, clr);
 }
 
 for(xoff=0; xoff<=SCREEN_W; xoff +=2) {
 vsync();
  for(xadd=0; ((xoff+xadd)<=SCREEN_W); xadd++)
   putpixel(bmp, xoff+xadd, SCREEN_H-xadd, clr);
 }
}
 
 
void replace_col(BITMAP *b, int oc, int nc)
{
 int x;
 int y;
 for (y=0; y<=b->h; y++) {
  for (x=0; x<=b->w; x++) {
   if (getpixel(b, x, y) == oc)
    putpixel(b, x, y, nc);
  }
 }
}
 
void make_solid_pal(PALETTE pal, int start, int stop, int r, int g, int b)
{
 int counter;
 RGB color = {r, g, b};
 for (counter=start; counter<=stop; counter++) {
  pal[counter] = color;
 }
}
/*
  ==============================
  =  Stuff that didn't fit in  =
  ==============================
*/
int init_moveable(DIALOG *dialog)
{
 BITMAP *bmp;
 bmp = create_bitmap(dialog->w+1, dialog->h+1); 
 
 if (bmp) {
  show_mouse(NULL);
  blit(screen, bmp, dialog->x, dialog->y, 0, 0, dialog->w+1, dialog->h+1);
 }
 
 dialog->dp3 = bmp;
 
 
 return 0;
}
 
int shutdown_moveable(DIALOG *dialog)
{
 if (dialog->dp3) {
  show_mouse(NULL);
  blit(dialog->dp3, screen, 0, 0, dialog->x, dialog->y, dialog->w+1, dialog->h+1);
  destroy_bitmap(dialog->dp3);
 }
 
 
 return 0;
}
 
int moveable_do_dialog(DIALOG *dialog, int focus_obj)
{
   int ret;
   init_moveable(dialog);
   ret = do_dialog(dialog, focus_obj);
   shutdown_moveable(dialog);
   return ret;
}
 
/*
  ==============================
  = BILL GUI Procs             =
  ==============================
*/
int d_billmenu_proc(int msg, DIALOG *d, int c)
{ 
  MENU_INFO m;
  int x;
  int ret = D_O_K;
 
  switch (msg) {
   case MSG_DRAW:
    fill_menu_info(&m, d->dp, NULL, TRUE, d->x-1, d->y-1, d->w+2, d->h+2);
    draw_billmenu(&m);
    break;
 
   case MSG_XCHAR: 
    x = billmenu_alt_key(c, d->dp);
    if (!x)
     break;
    ret |= D_USED_CHAR;
    simulate_keypress(x);
    SEND_MESSAGE(d, MSG_CLICK, 0);
    /*No break, keep right on going*/
 
   case MSG_CLICK:
   case MSG_GOTMOUSE:
    _do_billmenu(d->dp, NULL, TRUE, d->x-1, d->y-1, FALSE, &x, d->w+2, d->h+2);
    ret |= x;
    do {
    } while (mouse_b);
    break;
 
   default:
    ret = d_menu_proc(msg, d, c);
    break;
  }
  return ret;
}
 
 
 
 
 
int d_hbillscrollbar_proc(int msg, DIALOG *d, int c)
{
 int retval = D_O_K;
 float rngl;
 float rngr;
 float rngw;
 int newval;
 int msx, msy;
 int objd1 = d->d1;
 int lastclock;
 int hpos;
 int tmp;
 void (*proc)(int d2value);
 
 rngl = d->x+d->h+1;
 rngr = d->x+d->w-(d->h*2)-1;
 rngw = rngr - rngl;
 
 if (msg==MSG_DRAW)
 {
  //Left buttun w/ arrow
  show_mouse(NULL);
 
  if (d->flags & SCL_DOWNBUTTON_DOWN)
   tdbox(screen, d->x, d->y, d->h, d->h, STL_DOWN + STL_FACE);
  else
   tdbox(screen, d->x, d->y, d->h, d->h, STL_UP + STL_FACE);
  _draw_arrow(d->x+4, d->y+3, d->h-6, get_bill_color(bill_text), SCL_LEFTARROW);
  //Handle
  if (d->d1 < 1)
   d->d1 = 5;
 
  hpos = rngl + ((d->d2*rngw)/objd1);
 
  tdbox(screen, hpos, d->y, d->h, d->h, STL_UP + STL_FACE);
  //tdbox(screen, rngl +20, d->y, d->h, d->h, STL_UP + STL_FACE);
  //Dithered(Left)part
  tdbox(screen, rngl, d->y, hpos-(rngl+1), d->h, STL_DITHERED);
  //Dithered(right)part
  tdbox(screen, hpos+d->h+1, d->y, rngr+d->h-(hpos+d->h), d->h, STL_DITHERED);
  //Rbuttun w/ arrow
  if (d->flags & SCL_UPBUTTON_DOWN)
   tdbox(screen, d->x+d->w-d->h, d->y, d->h, d->h, STL_DOWN + STL_FACE);
  else
   tdbox(screen, d->x+d->w-d->h, d->y, d->h, d->h, STL_UP + STL_FACE);
  _draw_arrow(d->x+d->w-2-d->h/2, d->y+3, d->h-6, get_bill_color(bill_text), SCL_RIGHTARROW);
  show_mouse(screen);
 }
 else if(msg == MSG_CLICK)
 {
  msx = mouse_x;
  msy = mouse_y;
  /* Check for mouse button */
  if (mouse_b) {
   /*Check for Left Arrow*/
   if (is_in(msx, msy, d->x, d->y, d->h, d->h))
   {
    /* Mark the arrow as down */
    d->flags += SCL_DOWNBUTTON_DOWN;
    /* Loop until the mouse button is released*/
    while (mouse_b) {
     /* Keep everyting animating nicely */
     broadcast_dialog_message(MSG_IDLE, 0);
     /* This copies the mouse position into a couple of
        variabls for me, so it won't change half way
        through this.
      */
     msx = mouse_x;
     msy = mouse_y;
     /* Only move the slider if the mouse is still over the
        button
     */
     if (is_in(msx, msy, d->x, d->y, d->h, d->h))
     {
      /* Mark button as down if it is up*/
      if(!(d->flags & SCL_DOWNBUTTON_DOWN))
       d->flags += SCL_DOWNBUTTON_DOWN;
      /* Only move the slider after 5 clock ticks have gone by, this
         keeps it from jumping from one end to another
      */
      if( ((clock() - lastclock) > 5) || ((clock() - lastclock) < 0) )
      {
       d->d2--;
       if (d->d2 < 0) d->d2 = 0;
       SEND_MESSAGE(d, MSG_DRAW, 0);
       lastclock = clock();
       if (d->dp) {
        proc = d->dp;
        (*proc)(d->d2);
       }
      }
     }
     else
     {
     /*If the mouse isn't in the button, mark it as up*/
      if(d->flags & SCL_DOWNBUTTON_DOWN)
      {
       d->flags -= SCL_DOWNBUTTON_DOWN;
       SEND_MESSAGE(d, MSG_DRAW, 0);
      }
     }
    }
    /* if the button is still down, put it up */
    if(d->flags & SCL_DOWNBUTTON_DOWN)
    {
     d->flags -= SCL_DOWNBUTTON_DOWN;
     SEND_MESSAGE(d, MSG_DRAW, 0);
    }
   }
 
   /*Check for Right Arrow*/
   else if (is_in(msx, msy, d->x+d->w-d->h, d->y, d->h, d->h))
   {
    d->flags += SCL_UPBUTTON_DOWN;
    while (mouse_b)
    {
     broadcast_dialog_message(MSG_IDLE, 0);
     msx = mouse_x;
     msy = mouse_y;
     if (is_in(msx, msy, d->x+d->w-d->h, d->y, d->h, d->h))
     {
      if(!(d->flags & SCL_UPBUTTON_DOWN))
       d->flags += SCL_UPBUTTON_DOWN;
      if( ((clock() - lastclock) > 5) || ((clock() - lastclock) < 0) )
      {
       d->d2++;
       if (d->d2 > d->d1) d->d2 = d->d1;
       SEND_MESSAGE(d, MSG_DRAW, 0);
       lastclock = clock();
       if (d->dp) {
        proc = d->dp;
        (*proc)(d->d2);
       }
      }
     }
     else
     {
     /*If the mouse isn't in the button, mark it as up*/
      if(d->flags & SCL_UPBUTTON_DOWN)
      {
       d->flags -= SCL_UPBUTTON_DOWN;
       SEND_MESSAGE(d, MSG_DRAW, 0);
      }
     }
    }
    if(d->flags & SCL_UPBUTTON_DOWN)
    {
     d->flags -= SCL_UPBUTTON_DOWN;
     SEND_MESSAGE(d, MSG_DRAW, 0);
    }
   }
   /*Check for other..*/
   else if (is_in(msx, msy, d->x+d->h, d->y, d->w-d->h*2, d->h))
   {
    while(mouse_b)
    {
     msx = mouse_x;
     msy = mouse_y;
     hpos = msx;
     newval = (objd1*(hpos-rngl))/rngw;
     if (newval < 0) newval = 0;
     if (newval > objd1) newval = objd1;
     d->d2 = newval;
     if (newval != tmp)
     {
      SEND_MESSAGE(d, MSG_DRAW, 0);
      tmp = newval;
      if (d->dp) {
       proc = d->dp;
       (*proc)(d->d2);
      }
     }
    }
   }
  }
  else {
   if (d->flags & SCL_UPBUTTON_DOWN) {
    d->flags -= SCL_UPBUTTON_DOWN;
    SEND_MESSAGE(d, MSG_DRAW, 0);
   }
   if (d->flags & SCL_DOWNBUTTON_DOWN) {
     d->flags -= SCL_DOWNBUTTON_DOWN;
     SEND_MESSAGE(d, MSG_DRAW, 0);
   }
  }
 
  if (d->d2 < 0) d->d2 = 0;
  if (d->d2 > d->d1) d->d2 = d->d1;
  SEND_MESSAGE(d, MSG_DRAW, 0);
 }
 else if(msg == MSG_IDLE)
 {
  if (!(mouse_b))
  {
   if (d->flags & SCL_UPBUTTON_DOWN) {
    d->flags -= SCL_UPBUTTON_DOWN;
    SEND_MESSAGE(d, MSG_DRAW, 0);
   }
   if (d->flags & SCL_DOWNBUTTON_DOWN) {
    d->flags -= SCL_DOWNBUTTON_DOWN;
    SEND_MESSAGE(d, MSG_DRAW, 0);
   }
  }
 }
 //if (redraw == TRUE)
 return retval;
}
 
int d_vbillscrollbar_proc(int msg, DIALOG *d, int c)
{
 int retval = D_O_K;
 float rngt;
 float rngb;
 float rngh;
 int newval;
 int msx, msy;
 int objd1 = d->d1;
 int lastclock;
 int hpos;
 int tmp;
 void (*proc)(int d2value);
 
 rngt = d->y+d->w+1;
 rngb = d->y+d->h-(d->w*2)-1;
 rngh = rngb - rngt;
 
 if (msg==MSG_DRAW)
 {
  //Left buttun w/ arrow
  show_mouse(NULL);
 
  if (d->flags & SCL_DOWNBUTTON_DOWN)
   tdbox(screen, d->x, d->y, d->w, d->w, STL_DOWN + STL_FACE);
  else
   tdbox(screen, d->x, d->y, d->w, d->w, STL_UP + STL_FACE);
  _draw_arrow(d->x+3, d->y+4, d->w-6, get_bill_color(bill_text), SCL_UPARROW);
  //Handle
  if (d->d1 < 1)
   d->d1 = 5;
 
  hpos = rngt + ((d->d2*rngh)/objd1);
 
  tdbox(screen, d->x, hpos, d->w, d->w, STL_UP + STL_FACE);
  //tdbox(screen, rngl +20, d->y, d->h, d->h, STL_UP + STL_FACE);
  //Dithered(Left)part
  tdbox(screen, d->x, rngt, d->w, hpos-(rngt+1), STL_DITHERED);
  //Dithered(right)part
  tdbox(screen, d->x, hpos+d->w+1, d->w, rngb-hpos, STL_DITHERED);
  //Rbuttun w/ arrow
  if (d->flags & SCL_UPBUTTON_DOWN)
   tdbox(screen, d->x, d->y+d->h-d->w, d->w, d->w, STL_DOWN + STL_FACE);
  else
   tdbox(screen, d->x, d->y+d->h-d->w, d->w, d->w, STL_UP + STL_FACE);
  _draw_arrow (d->x+3, d->y+d->h-2-d->w/2, d->w-6, get_bill_color(bill_text), SCL_DOWNARROW);
  show_mouse(screen);
 }
 else if(msg == MSG_CLICK)
 {
  msx = mouse_x;
  msy = mouse_y;
  /* Check for mouse button */
  if (mouse_b) {
   /*Check for Left Arrow*/
   if (is_in(msx, msy, d->x, d->y, d->w, d->w))
   {
    /* Mark the arrow as down */
    d->flags += SCL_DOWNBUTTON_DOWN;
    /* Loop until the mouse button is released*/
    while (mouse_b) {
     /* Keep everyting animating nicely */
     broadcast_dialog_message(MSG_IDLE, 0);
     /* This copies the mouse position into a couple of
        variabls for me, so it won't change half way
        through this.
      */
     msx = mouse_x;
     msy = mouse_y;
     /* Only move the slider if the mouse is still over the
        button
     */
     if (is_in(msx, msy, d->x, d->y, d->w, d->w))
     {
      /* Mark button as down if it is up*/
      if(!(d->flags & SCL_DOWNBUTTON_DOWN))
       d->flags += SCL_DOWNBUTTON_DOWN;
      /* Only move the slider after 5 clock ticks have gone by, this
         keeps it from jumping from one end to another
      */
      if( ((clock() - lastclock) > 5) || ((clock() - lastclock) < 0) )
      {
       d->d2--;
       if (d->d2 < 0) d->d2 = 0;
       SEND_MESSAGE(d, MSG_DRAW, 0);
       lastclock = clock();
       if (d->dp) {
        proc = d->dp;
        (*proc)(d->d2);
       }
      }
     }
     else
     {
     /*If the mouse isn't in the button, mark it as up*/
      if(d->flags & SCL_DOWNBUTTON_DOWN)
      {
       d->flags -= SCL_DOWNBUTTON_DOWN;
       SEND_MESSAGE(d, MSG_DRAW, 0);
      }
     }
    }
    /* if the button is still down, put it up */
    if(d->flags & SCL_DOWNBUTTON_DOWN)
    {
     d->flags -= SCL_DOWNBUTTON_DOWN;
     SEND_MESSAGE(d, MSG_DRAW, 0);
    }
   }
 
   /*Check for Right Arrow*/
   else if (is_in(msx, msy, d->x, d->y+d->h-d->w, d->w, d->w))
   {
    d->flags += SCL_UPBUTTON_DOWN;
    while (mouse_b)
    {
     broadcast_dialog_message(MSG_IDLE, 0);
     msx = mouse_x;
     msy = mouse_y;
     if (is_in(msx, msy, d->x, d->y+d->h-d->w, d->w, d->w))
     {
      if(!(d->flags & SCL_UPBUTTON_DOWN))
       d->flags += SCL_UPBUTTON_DOWN;
      if( ((clock() - lastclock) > 5) || ((clock() - lastclock) < 0) )
      {
       d->d2++;
       if (d->d2 > d->d1) d->d2 = d->d1;
       SEND_MESSAGE(d, MSG_DRAW, 0);
       lastclock = clock();
       if (d->dp) {
        proc = d->dp;
        (*proc)(d->d2);
       }
      }
     }
     else
     {
     /*If the mouse isn't in the button, mark it as up*/
      if(d->flags & SCL_UPBUTTON_DOWN)
      {
       d->flags -= SCL_UPBUTTON_DOWN;
       SEND_MESSAGE(d, MSG_DRAW, 0);
      }
     }
    }
    if(d->flags & SCL_UPBUTTON_DOWN)
    {
     d->flags -= SCL_UPBUTTON_DOWN;
     SEND_MESSAGE(d, MSG_DRAW, 0);
    }
   }
   /*Check for other..*/
   else if (is_in(msx, msy, d->x, d->y+d->w, d->w, d->h-d->w*2))
   {
    while(mouse_b)
    {
     msx = mouse_x;
     msy = mouse_y;
     hpos = msy;
     newval = (objd1*(hpos-rngt))/rngh;
     if (newval < 0) newval = 0;
     if (newval > objd1) newval = objd1;
     d->d2 = newval;
     if (newval != tmp)
     {
      SEND_MESSAGE(d, MSG_DRAW, 0);
      tmp = newval;
      if (d->dp) {
       proc = d->dp;
       (*proc)(d->d2);
      }
     }
    }
   }
  }
  else {
   if (d->flags & SCL_UPBUTTON_DOWN) {
    d->flags -= SCL_UPBUTTON_DOWN;
    SEND_MESSAGE(d, MSG_DRAW, 0);
   }
   if (d->flags & SCL_DOWNBUTTON_DOWN) {
     d->flags -= SCL_DOWNBUTTON_DOWN;
     SEND_MESSAGE(d, MSG_DRAW, 0);
   }
  }
 
  if (d->d2 < 0) d->d2 = 0;
  if (d->d2 > d->d1) d->d2 = d->d1;
  SEND_MESSAGE(d, MSG_DRAW, 0);
 }
 else if(msg == MSG_IDLE)
 {
  if (!(mouse_b))
  {
   if (d->flags & SCL_UPBUTTON_DOWN) {
    d->flags -= SCL_UPBUTTON_DOWN;
    SEND_MESSAGE(d, MSG_DRAW, 0);
   }
   if (d->flags & SCL_DOWNBUTTON_DOWN) {
    d->flags -= SCL_DOWNBUTTON_DOWN;
    SEND_MESSAGE(d, MSG_DRAW, 0);
   }
  }
 }
 //if (redraw == TRUE)
 return retval;
}
 
 
 
int d_billtextbox_proc(int msg, DIALOG *d, int c)
{
   int height, bar;
   int fg_color = get_bill_color(bill_text);
 
   /* calculate the actual height */
   height = (d->h-4) / text_height(font);
 
   if(msg == MSG_DRAW) {
	 /* tell the object to sort of draw, but only calculate the listsize */
         _draw_billtextbox(d->dp, &d->d1, 
		       0, /* DONT DRAW anything */
		       d->d2, !(d->flags & D_SELECTED), 8,
		       d->x, d->y, d->w, d->h,
		       (d->flags & D_DISABLED),
		       0, 0, 0);
 
	 if (d->d1 > height) {
	    bar = 12;
	 }
	 else {
	    bar = 0;
	    d->d2 = 0;
	 }
 
	 /* now do the actual drawing */
         _draw_billtextbox(d->dp, &d->d1, 1, d->d2,
		       !(d->flags & D_SELECTED), 8,
		       d->x, d->y, d->w-bar-1, d->h,
		       (d->flags & D_DISABLED),
                       fg_color, get_bill_color(bill_framebg), get_bill_color(bill_framebg));
 
	 /* draw the frame around */
         _draw_scrollable_billframe(d, d->d1, d->d2, height, fg_color, d->bg);
         return D_O_K;
   }
   else
    return d_textbox_proc(msg, d, c);
}
 
 
int d_billedit_proc(int msg, DIALOG *d, int c)
{
   int f, l, p, w, x, fg;
   int b; 
   int scroll; 
   char *s;
   char buf[2];
 
 if(msg == MSG_DRAW) {
   s = d->dp;
   l = strlen(s);
   if (d->d2 > l) 
      d->d2 = l;
 
  /* calculate maximal number of displayable characters */
   b = x = 0;
   if (d->d2 == l)  {
      buf[0] = ' ';
      buf[1] = 0;
      x = text_length(font, buf);
   }
 
   buf[1] = 0;
   for (p=d->d2; p>=0; p--) {
      buf[0] = s[p];
      b++;
      x += text_length(font, buf);
      if (x > d->w) 
         break;
   }
 
   if (x <= d->w) {
      b = l; 
      scroll = FALSE;
   }
   else {
      b--; 
      scroll = TRUE;
   }
 
   /* Actual drawing begins here*/
 
         fg = get_bill_color(bill_text);
	 x = 0;
 
	 if (scroll) {
	    p = d->d2-b+1; 
	    b = d->d2; 
	 }
	 else 
	    p = 0; 
 
         tdbox(screen, d->x+2, d->y+2, d->w-4, d->h-4, STL_FRAMEFILLED);
         for (; p<=b; p++) {
	    buf[0] = s[p] ? s[p] : ' ';
	    w = text_length(font, buf);
            if (x+w > d->w-4) 
              break;
 
            f = ((p == d->d2) && (d->flags & D_GOTFOCUS));
            text_mode(f ? fg : get_bill_color(bill_framebg));
            textout(screen, font, buf, d->x+x+3, d->y+3, f ? get_bill_color(bill_framebg) : fg);
	    x += w;
	 }
 
         tdbox(screen, d->x, d->y, d->w, d->h, STL_IN+STL_FRAME);
         return D_O_K;
 }
 else
  return d_edit_proc(msg, d, c);
}
 
int d_billtext_proc(int msg, DIALOG *d, int c)
{
 int fg = get_bill_color(bill_text);
   if (msg==MSG_DRAW) {
      if (d->fg == BILL_TITLE)
       fg = get_bill_color(bill_titletext);
      else
       fg = get_bill_color(bill_text);
 
      if (d->bg == BILL_CLEAR)
       text_mode(-1);
      else if (d->bg == BILL_TITLE)
       text_mode(get_bill_color(bill_activetitle));
      else
       text_mode(get_bill_color(bill_face));
 
      gui_textout(screen, d->dp, d->x, d->y, fg, FALSE);
   }
 
   return D_O_K;
}
 
 
int d_billctext_proc(int msg, DIALOG *d, int c)
{
 int fg = get_bill_color(bill_text);
   if (msg==MSG_DRAW) {
      if (d->fg == BILL_TITLE)
       fg = get_bill_color(bill_titletext);
      else
       fg = get_bill_color(bill_text);
 
      if (d->bg == BILL_CLEAR)
       text_mode(-1);
      else if (d->bg == BILL_TITLE)
       text_mode(get_bill_color(bill_activetitle));
      else
       text_mode(get_bill_color(bill_face));
 
      gui_textout(screen, d->dp, d->x, d->y, fg, TRUE);
   }
 
   return D_O_K;
}
 
int d_billcheck_proc(int msg, DIALOG *d, int c)
{
   int x;
   int fg;
 
   if (msg==MSG_DRAW) {
      fg = get_bill_color(bill_text);
      text_mode(get_bill_color(bill_face));
      x = d->x + gui_textout(screen, d->dp, d->x, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, fg, FALSE) + text_height(font)/2;
      tdbox(screen, x, d->y, d->h, d->h, STL_IN + STL_FRAME + STL_FRAMEFILLED);
      if (d->flags & D_SELECTED) {
         line(screen, x+2, d->y+2, x+d->h-2, d->y+d->h-2, get_bill_color(bill_text));
         line(screen, x+2, d->y+d->h-2, x+d->h-2, d->y+2, get_bill_color(bill_text)); 
      }
      return D_O_K;
   } 
   return d_button_proc(msg, d, c);
}
 
 
int d_billslider_proc(int msg, DIALOG *d, int c)
{
   BITMAP *slhan = NULL;
   int sfg;                /* slider foreground color */
   int vert = TRUE;        /* flag: is slider vertical? */
   int hh = 10;             /* handle height (width for horizontal sliders) */
   int hmar;               /* handle margin */
   int slp;                /* slider position */
   int irange;
   int slx, sly, slh, slw;
   int ret;
   fixed slratio, slmax, slpos;
 
 
   if (msg == MSG_DRAW) {
      /* check for slider direction */
      if (d->h < d->w)
       vert = FALSE;
 
     /* set up the metrics for the control */
     if (d->dp != NULL) {
      slhan = (BITMAP *)d->dp;
      if (vert)
       hh = slhan->h;
      else
       hh = slhan->w;
     }
 
         hmar = hh/2;
         irange = (vert) ? d->h : d->w;
         slmax = itofix(irange-hh);
         slratio = slmax / (d->d1);
         slpos = slratio * d->d2;
         slp = fixtoi(slpos);
 
	 sfg = (d->flags & D_DISABLED) ? gui_mg_color : d->fg;
 
	 if (vert) {
            rectfill(screen, d->x, d->y, d->x+d->w, d->y+d->h, get_bill_color(bill_face));
            tdbox(screen, d->x+d->w/2-2, d->y, 3, d->h, STL_IN + STL_FRAME + STL_FLAT);
	 }
	 else {
            rectfill(screen, d->x, d->y, d->x+d->w, d->y+d->h, get_bill_color(bill_face));
            tdbox(screen, d->x, d->y+d->h/2-2, d->w, 3, STL_IN + STL_FRAME + STL_FLAT);
	 }
 
	 /* okay, background and slot are drawn, now draw the handle */
	 if (slhan) {
	    if (vert) {
	       slx = d->x+(d->w/2)-(slhan->w/2);
	       sly = d->y+d->h-(hh+slp);
	    } 
	    else {
	       slx = d->x+slp;
	       sly = d->y+(d->h/2)-(slhan->h/2);
	    }
	    draw_sprite(screen, slhan, slx, sly);
	 } 
	 else {
	    /* draw default handle */
	    if (vert) {
	       slx = d->x;
	       sly = d->y+d->h-(hh+slp);
	       slw = d->w;
	       slh = hh;
              /* draw body */
              tdbox(screen, slx, sly+2, (slw), slh-2, STL_OUT + STL_FACE);
	    } else {
	       slx = d->x+slp;
	       sly = d->y;
	       slw = hh;
	       slh = d->h;
              /* draw body */
              tdbox(screen, slx+2, sly, (slw-2), slh, STL_OUT + STL_FACE);
	    }
 
	 }
 
      //   if (d->flags & D_GOTFOCUS)
      //      dotted_rect(d->x, d->y, d->x+d->w, d->y+d->h, sfg, d->bg);
   ret=D_O_K;
   }
   else {
    ret = d_slider_proc(msg, d, c);
   }
 return ret;
}
 
int d_billwin_proc(int msg, DIALOG *d, int c)
{
 int msx;
 int msy;
 int ymv, xmv;
 DIALOG *origd;
 BITMAP *tmp;
 BITMAP *screenptr;
 
 if (msg==MSG_DRAW) {
  tdbox(screen, d->x, d->y, d->w, d->h, STL_OUT + STL_FLAT);
  if (strlen(d->dp)) {
   rectfill(screen, d->x+3, d->y+3, d->x+d->w-3, d->y+4+text_height(font), get_bill_color(bill_activetitle));
   text_mode(-1);
   gui_textout(screen, d->dp, d->x+4, d->y+4, get_bill_color(bill_titletext), FALSE);
  }
 }
 else if (msg==MSG_CLICK)
 {
  broadcast_dialog_message(MSG_IDLE, 0);
  if (d->dp3)
  {
   msx = mouse_x;
   msy = mouse_y;
   if ((is_in(msx, msy, d->x+2, d->y+2, d->w-2, 3+text_height(font))) && (mouse_b))
   {
    show_mouse(NULL);
    d->d1 = mouse_x - d->x;
    d->d2 = mouse_y - d->y;
    tmp = create_bitmap(SCREEN_W, SCREEN_H);
    blit(screen, tmp, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
    blit(d->dp3, tmp, 0, 0, d->x, d->y, d->w+1, d->h+1);
    screenptr = screen;
    screen = tmp;
    while (mouse_b)
    {
     msx = mouse_x;
     msy = mouse_y;
     xmv = (msx - d->x) - d->d1;
     ymv = (msy - d->y) - d->d2;
     blit(d->dp3, screen, 0, 0, d->x, d->y, d->w+1, d->h+1);
     origd = d;
     while(d->proc)
     {
      d->x += xmv;
      d->y += ymv;
      d++;
     }
     d = origd;
     blit(screen, d->dp3, d->x, d->y, 0, 0, d->w+1, d->h+1);
     /* let other objects continue to animate */
     broadcast_dialog_message(MSG_IDLE, 0);
     broadcast_dialog_message(MSG_DRAW, 0);
     show_mouse(NULL);
     blit(screen, screenptr, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
    }
    screen = screenptr;
    destroy_bitmap(tmp);
    broadcast_dialog_message(MSG_DRAW, 0);
    show_mouse(screen);
   }
  }
 }
 return D_O_K;
}
 
 
int d_billclear_proc(int msg, DIALOG *d, int c)
{
   if (msg == MSG_DRAW) {
      tdbox(screen, d->x, d->y, d->w, d->h, STL_FACE);
   }
   return D_O_K;
}
 
 
int d_billlist_proc(int msg, DIALOG *d, int c)
{
int ret;
 if (msg == MSG_DRAW) {
  _draw_billlistbox(d);
  ret = D_O_K;
 }
 else {
  ret = d_list_proc(msg, d, c);
 }
 return ret;
}
 
int d_billradio_proc(int msg, DIALOG *d, int c)
{
 int ret;
 int fg;
 int x;
 if (msg == MSG_DRAW) {
  fg = get_bill_color(bill_text);
  text_mode(get_bill_color(bill_face));
  gui_textout(screen, d->dp, d->x+15, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, fg, FALSE);
 
  x = d->x;
  //rectfill(screen, x, d->y, x+12, d->y+12, get_bill_color(bill_face));
 
  if (d->flags & D_DISABLED)
   masked_blit(radio_grey, screen, 0, 0, x, d->y, 12, 12);
  else if (d->flags & D_SELECTED)
   masked_blit(radio_sel, screen, 0, 0, x, d->y, 12, 12);
  else
   masked_blit(radio_unsel, screen, 0, 0, x, d->y, 12, 12);
 
  ret = D_O_K;
 
 }
 else {
  ret = d_radio_proc(msg, d, c);
 }
 return ret;
}
 
 
int d_billbutton_proc(int msg, DIALOG *d, int c)
{
 int state;
 int ret;
 int txoff = 0;
 
 if (msg == MSG_DRAW) {
  if (d->flags & D_SELECTED) {
   state = STL_IN;
   if (bill_appearexact) {
    txoff = 1;
    state += STL_BUTTONDOWN;
   }
  }
  else {
   state = STL_OUT;
  }
 
  if (bill_appearexact) {
   if ((d->flags & D_GOTFOCUS) && (!(d->flags & D_SELECTED))) {
    tdbox(screen, d->x+1, d->y+1, d->w-2, d->h-2, state + STL_FLAT);
    rect(screen, d->x, d->y, d->x+d->w, d->y+d->h, get_bill_color(bill_dkshadow));
   }
   else
    tdbox(screen, d->x, d->y, d->w, d->h, state + STL_FLAT);
  }
  else
   tdbox(screen, d->x, d->y, d->w, d->h, state + STL_FLAT);
 
  text_mode(-1);
  gui_textout(screen, d->dp, d->x+d->w/2+txoff, d->y+d->h/2-text_height(font)/2+1+txoff, get_bill_color(bill_text), TRUE);
 
  if ((d->flags & D_GOTFOCUS) && (!(d->flags & D_SELECTED) || !(d->flags & D_EXIT)))
    bill_dotted_rect(d->x+3, d->y+3, d->x+d->w - 3, d->y+d->h - 3, get_bill_color(bill_shadow));
 ret = D_O_K;
 }
 else {
  ret = d_button_proc(msg, d, c);
 }
 return ret;
}
 
int d_ex_billbutton_proc(int msg, DIALOG *d, int c)
{
 int ret;
 int (*proc)(void *cbpointer, int d2value);
 ret = d_billbutton_proc(msg, d, c);
 
 if (ret == D_CLOSE) {
  ret = D_REDRAW;
  if (d->dp2) {
   proc = d->dp2;
   (*proc)(d->dp3, d->d2);
   return D_REDRAW;
  }
 }
 return ret;
}
 
int d_samplex_billbutton_proc(int msg, DIALOG *d, int c)
{
 int ret;
 int (*proc)();
 ret = d_billbutton_proc(msg, d, c);
 
 if (ret == D_CLOSE) {
  ret = D_REDRAW;
  if (d->dp3) {
   play_sample(d->dp3, 255, 128, 1000, FALSE);
  }
  if (d->dp2) {
   proc = d->dp2;
   (*proc)();
   return D_REDRAW;
  }
 }
 return ret;
}
 
int d_billhline_proc(int msg, DIALOG *d, int c)
{
   if (msg == MSG_DRAW) {
    tdhline(screen, d->x, d->y, d->x+d->w);
   }
   return D_O_K;
}
 
 
/*
I hope that you're using a fixed-width font.. ;-).
 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!| None of the stuff below this line works,|!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!| So don't try to use it.                 |!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!|_________________________________________|!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! Following is the beginning of a windowing system, currently one that     !!
!! crashes, in which each window will be able to contain a standard         !!
!! Allegro dialog. The idea is that you CAN have multiple "open" dialogs,   !!
!! all of which are accessable by the user, but only the one on top recieves!!
!! most of the messages (draw will ocasionally be sent to the bottum ones). !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
 
Did that get your attention?
*/
 
/*
  ==============================
  = Winsystem helpers/procs    =
  ==============================
*/
void _move_dialog(DIALOG *d, int x, int y)
{
 int i;
 for (i=0; d[i].proc; i++)
 {
  d[i].x += x;
  d[i].y += y;
 }
}
 
int ws_window_proc(int wm, WS *w, int msg)
{
 int i;
 if (wm==WM_START) {
  _move_dialog(w->dlg, w->x, w->y);
  w->dlg_player = init_dialog(w->dlg, 0);
 }
 else if (wm==WM_DRAW) {
  tdbox(screen, w->x, w->y, w->w, w->h, STL_OUT + STL_FLAT);
  if (strlen(w->dp)) {
   rectfill(screen, w->x+3, w->y+3, w->x+w->w-3, w->y+4+text_height(font), get_bill_color(bill_activetitle));
   text_mode(-1);
   gui_textout(screen, w->dp, w->x+4, w->y+4, get_bill_color(bill_titletext), FALSE);
  }
  dialog_message(w->dlg, MSG_DRAW, 0, &i);
 }
 else if (wm==WM_CLICK) {
  if (w->z<1)
   return W_WANTACTIVATE+W_REDRAW;
 }
 else if (wm==WM_END) {
  shutdown_dialog(w->dlg_player);
 }
 
 
 return 0;
}
 
int w_message(WS *w, int wm)
{
  w->proc(wm, w, -1);
 
 
 return 0;
}
 
int ws_message(WS *w, int wm)
{
 int i;
 for(i = 0; w[i].proc; i++)
 {
  w_message((w+i), wm);
 }
 
 
 return 0;
}
 
int number_of_windows(WS *w)
{
 int i;
 for(i = 0; w[i].proc; i++);
 return i;
}
 
int w_from_z(WS *w, int z)
{
 int i;
 for(i = 0; w[i].proc; i++)
  if(w[i].z == z) return i;
 return -1;
}
 
int w_make_top(WS *w, int wn)
{
 int origz = w[wn].z;
 int i;
 int cwin;
 for(i=origz; i<=1; i++)
 {
  cwin = w_from_z(w, i);
  w[cwin].z--;
 }
 w[wn].z = 1;
 
 
 return 0;
}
/*
  ==============================
  = Winsystem player           =
  ==============================
*/
int mstatus, mx, my, oldmx, oldmy;
 
int do_winsystem(WS *w)
{
 int i;
 int go;
 int ret, wsreturn;
 int now;         //(Number Of Windows)
 int wn;          /* Stores results of w_from_z, which returns the
                     array position of a window with a specific Z
                     order
                  */
 BITMAP *oldscreen, *newscreen;
 int clicks;
 
 go = TRUE;
 wsreturn = ws_message(w, WM_START);
 now = number_of_windows(w);
 newscreen = create_bitmap(SCREEN_W, SCREEN_H);
 oldscreen = screen;
 screen = newscreen;
 while (go)
 {
  mx = mouse_x;
  my = mouse_y;
  ws_message(w, WM_IDLE);
  if (mouse_b)
  {
   if(!(mstatus))
   {
    mstatus = mouse_b;
    clicks++;
   }
  }
 
  for (i=0; i<= now; i++)
  {
   ret = 0;
   wn = w_from_z(w, i);
    if(clicks>0)
    {
     if(is_in(mx, my, w[i].x, w[i].y, w[i].w, w[i].h))
     {
      ret = w_message(&w[wn], WM_CLICK);
      if (ret & W_USEDCLICK)
       clicks--;
     }
    }
 
    if(ret & W_WANTACTIVATE)
     w_make_top(w, wn);
  }
  blit(newscreen, oldscreen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
 }
 i = ws_message(w, WM_END);
 screen = oldscreen;
 destroy_bitmap(newscreen);
 
 
 return 0;
}