/* ans.c
 *
 * This file is part of the Allegro GUI Un-uglification Project.
 * It emulates the look of the NeXTstep widget set.
 *
 * Joao Neves <miauz@clix.pt>
 */


#include <allegro.h>
#include "ans.h"
#include "agupitrn.h"


/*----------------------------------------------------------------------*/
/* Recommend fg/bg colors                                               */
/*----------------------------------------------------------------------*/


int ans_fg_color;
int ans_bg_color;
int ans_mg_color;


/*----------------------------------------------------------------------*/
/* Helpers                                                              */
/*----------------------------------------------------------------------*/


static int white, lgrey, dgrey, black, disabled;


#define REDRAW(d)                                               \
do {                                                            \
    scare_mouse_area(d->x, d->y, d->x + d->w, d->y + d->h);     \
    object_message(d, MSG_DRAW, 0);                             \
    unscare_mouse();                                            \
} while (0)


static void ns_bevel(BITMAP *bmp, int x, int y, int w, int h, int state)
{
    w--;
    h--;
    switch (state) {
	case 0:		/* normal */
	    rectfill(bmp, x, y, x + w, y + h, lgrey);
	    rect(bmp, x, y, x + w, y + h, black);
	    line(bmp, x, y, x + w - 1, y, white);
	    line(bmp, x, y, x, y + h - 1, white);
	    line(bmp, x + 1, y + h - 1, x + w - 1, y + h - 1, dgrey);
	    line(bmp, x + w - 1, y + 1, x + w - 1, y + h - 1, dgrey);
	    break;

	case 1:		/* pressed */
	    rectfill(bmp, x, y, x + w, y + h, white);
	    line(bmp, x, y, x, y + h - 1, black);
	    line(bmp, x, y, x + w - 1, y, black);
	    break;

	case 2:		/* focused */
	    rectfill(bmp, x, y, x + w, y + h, white);
	    rect(bmp, x, y, x + w, y + h, black);
	    line(bmp, x, y, x + w - 1, y, white);
	    line(bmp, x, y, x, y + h - 1, white);
	    line(bmp, x + 1, y + h - 1, x + w - 1, y + h - 1, dgrey);
	    line(bmp, x + w - 1, y + 1, x + w - 1, y + h - 1, dgrey);
	    break;
    }
}


static void ns_check(BITMAP *bmp, int x, int y)
{
    line(bmp, x + 4, y + 6, x + 4, y + 10, white);
    line(bmp, x + 4, y + 10, x + 12, y + 2, white);
    line(bmp, x + 5, y + 6, x + 5, y + 7, black);
    line(bmp, x + 5, y + 8, x + 6, y + 7, dgrey);
    line(bmp, x + 4, y + 11, x + 12, y + 3, black);
    line(bmp, x + 5, y + 11, x + 12, y + 4, dgrey);
}


static BITMAP *generate_bitmap(AL_CONST char *templat[], int w, int h)
{
    BITMAP *bmp = create_bitmap(w, h);
    int x, y;

    for (y = 0; y < h; y++)
	for (x = 0; x < w; x++)
	    switch (templat[y][x]) {
		case '.': putpixel(bmp, x, y, white); break;
		case 'X': putpixel(bmp, x, y, black); break;
		case 'a': putpixel(bmp, x, y, lgrey); break;
		case 'x': putpixel(bmp, x, y, dgrey); break;
		case ' ': putpixel(bmp, x, y, lgrey); break;
	    }

    return bmp;
}


/*----------------------------------------------------------------------*/
/* NeXTstep-lookalike procs  						*/
/*----------------------------------------------------------------------*/


int d_ans_box_proc(int msg, DIALOG *d, int c)
{
    (void) c;

    if (msg == MSG_DRAW) {
	ns_bevel(screen, d->x, d->y, d->w, d->h, 0);
    }

    return D_O_K;
}


int d_ans_shadow_box_proc(int msg, DIALOG *d, int c)
{
    return d_ans_box_proc(msg, d, c);
}


int d_ans_button_proc(int msg, DIALOG *d, int c)
{
    if (msg == MSG_DRAW) {
	int s = 0;
	int fg = black;

	if (d->flags & D_SELECTED) {
	    s = 1;
	}
	if (d->flags & D_DISABLED) {
	    fg = disabled;
	}

	ns_bevel(screen, d->x, d->y, d->w, d->h, s);

	if (d->dp) {
	    int rtm = text_mode(-1);
	    if (d->flags & D_SELECTED) {
		gui_textout(screen, (char *)d->dp, d->x + d->w / 2 + 1,
			    d->y + d->h / 2 - text_height(font) / 2 + 1, fg,
			    TRUE);
	    }
	    else {
		gui_textout(screen, (char *)d->dp, d->x + d->w / 2,
			    d->y + d->h / 2 - text_height(font) / 2, fg, TRUE);
	    }
	    text_mode(rtm);
	}

	return D_O_K;
    }

    return d_button_proc(msg, d, c);
}


int d_ans_push_proc(int msg, DIALOG *d, int c)
{
    int ret = D_O_K;

    d->flags |= D_EXIT;

    ret |= d_ans_button_proc(msg, d, c);

    if (ret & D_CLOSE) {
	ret &= ~D_CLOSE;
	REDRAW(d);

	if (d->dp3)
	    ret |= ((int (*)(DIALOG *)) d->dp3) (d);
    }

    return ret;
}


int d_ans_check_proc(int msg, DIALOG *d, int c)
{
    if (msg == MSG_DRAW) {
	int fg = black;
	ns_bevel(screen, d->x, d->y + d->h / 2 - 8, 16, 16, 0);

	if (d->flags & D_SELECTED) {
	    ns_check(screen, d->x, d->y + d->h / 2 - 8);
	}
	if (d->flags & D_DISABLED) {
	    fg = disabled;
	}

	if (d->dp) {
	    int rtm;
	    rtm = text_mode(-1);
	    gui_textout(screen, (char *)d->dp,
			d->x + 20, d->y + d->h / 2 - text_height(font) / 2,
			fg, FALSE);
	    text_mode(rtm);
	}

	return D_O_K;
    }

    return d_button_proc(msg, d, c);
}


static AL_CONST char *radio_up[] =
{
    /* 15 x 15 */
    "     xxxxx     ",
    "   xxXXXXXxx   ",
    "  xXX       x  ",
    " xXx           ",
    " xX            ",
    "xX            .",
    "xX            .",
    "xX            .",
    "xX            .",
    "xX            .",
    " xx          . ",
    " x           . ",
    "  x         .  ",
    "    .     ..   ",
    "     .....     "
};


static AL_CONST char *radio_down[] =
{
    /* 15 x 15 */
    "     xxxxx     ",
    "   xxXXXXXxx   ",
    "  xXX     x x  ",
    " xXx  ....     ",
    " xX ........   ",
    "xX  ........  .",
    "xX .......... .",
    "xX .......... .",
    "xX .......... .",
    "xX .......... .",
    " xx ........ . ",
    " x  ........ . ",
    "  x   ....  .  ",
    "    .     ..   ",
    "     .....     "
};


static AL_CONST char *handle[] =
{
    /* 6 x 6 */
    " xXXX ",
    "xXxxxx",
    "Xxx   ",
    "Xx  ..",
    "Xx ...",
    " x .. "
};


static AL_CONST char *menu_arrow[] =
{
    /* 7 x 7 */
    "Xx     ",
    "X xx   ",
    "X   xx ",
    "X     .",
    "X   .. ",
    "X ..   ",
    "X.     "
};


static AL_CONST char *menu_arrow_sel[] =
{
    /* 7 x 7 */
    "Xx.....",
    "X.xx...",
    "X...xx.",
    "X.....a",
    "X...aa.",
    "X.aa...",
    "Xa....."
};


static BITMAP *radio_down_bmp, *radio_up_bmp;
static BITMAP *handle_bmp;
static BITMAP *menu_arrow_bmp, *menu_arrow_sel_bmp;


int d_ans_radio_proc(int msg, DIALOG *d, int c)
{
    if (msg == MSG_DRAW) {
	int fg = black;
	draw_sprite(screen,
		    (d->flags & D_SELECTED) ? radio_down_bmp : radio_up_bmp,
		    d->x, d->y + d->h / 2 - 7);
	if (d->flags & D_DISABLED) {
	    fg = disabled;
	}

	if (d->dp) {
	    int rtm;
	    rtm = text_mode(-1);
	    gui_textout(screen, (char *)d->dp,
			d->x + 20, d->y + d->h / 2 - text_height(font) / 2,
			fg, FALSE);
	    text_mode(rtm);
	}

	return D_O_K;
    }

    return d_radio_proc(msg, d, c);
}


int d_ans_icon_proc(int msg, DIALOG *d, int c)
{
    if (msg == MSG_DRAW) {
	BITMAP *img = (BITMAP *)d->dp;
	int x = 0;

	if (d->flags & D_SELECTED) {
	    x = 1;
	}

	ns_bevel(screen, d->x, d->y, d->w, d->h, x);

	stretch_sprite(screen, img, d->x + 2, d->y + 2, d->w - 4, d->h - 4);

	return D_O_K;
    }

    return d_button_proc(msg, d, c);
}


int d_ans_edit_proc(int msg, DIALOG *d, int c)
{
    if (msg == MSG_DRAW) {
	int l, x, b, f, p, w, rtm;
	int fg = (d->flags & D_DISABLED) ? disabled : black;
	char *s = (char *)d->dp;
	char buf[16];
	int fonth;

        agup_edit_adjust_position (d);

	fonth = text_height(font);

	l = ustrlen(s);
	/* set cursor pos */
	if (d->d2 >= l) {
	    d->d2 = l;
	    usetc(buf + usetc(buf, ' '), 0);
	    x = text_length(font, buf) + 2;
	}
	else
	    x = 2;

	b = 0;			/* num of chars to be blitted */
	/* get the part of the string to be blitted */
	for (p = d->d2; p >= 0; p--) {
	    usetc(buf + usetc(buf, ugetat(s, p)), 0);
	    x += text_length(font, buf);
	    b++;

	    if (x > d->w - 4)
		break;
	}

	/* see if length of text is too wide */
	if (x <= d->w - 2) {
	    b = l;
	    p = 0;
	}
	else {
	    b--;
	    p = d->d2 - b + 1;
	    b = d->d2;
	}

	rectfill(screen, d->x, d->y, d->x + d->w - 1, d->y + fonth + 5, lgrey);
	rect(screen, d->x, d->y, d->x + d->w - 1, d->y + fonth + 5, white);
	line(screen, d->x, d->y, d->x + d->w - 2, d->y, dgrey);
	line(screen, d->x, d->y, d->x, d->y + fonth + 4, dgrey);
	line(screen, d->x + 1, d->y + 1, d->x + d->w - 3, d->y + 1, dgrey);
	line(screen, d->x + 1, d->y + 1, d->x + 1, d->y + fonth + 3, dgrey);

	rectfill(screen, d->x + 2, d->y + 2, d->x + d->w - 3, d->y + fonth + 3, white);
	for (x = 4; p <= b; p++) {
	    f = ugetat(s, p);
	    usetc(buf + usetc(buf, (f) ? f : ' '), 0);
	    w = text_length(font, buf);
	    f = ((p == d->d2) && (d->flags & D_GOTFOCUS));
	    rtm = text_mode(white);
	    textout(screen, font, buf, d->x + x, d->y + 4, fg);
	    text_mode(rtm);
	    if (f)
		vline(screen, d->x + x - 1, d->y + 3, d->y + fonth + 3, black);
	    if ((x += w) + w > d->w - 4)
		break;
	}

        agup_edit_restore_position (d);

	return D_O_K;
    }

    return d_agup_adjusted_edit_proc(msg, d, c);
}


typedef char *(*getfuncptr) (int, int *);


static void ns_draw_scrollable_frame(DIALOG *d, int listsize, int offset, int height)
{
    int i, len, c;
    int xx, yy;

    /* draw frame */
    hline(screen, d->x, d->y, d->x + d->w - 1, dgrey);
    vline(screen, d->x, d->y, d->y + d->h - 1, dgrey);

    hline(screen, d->x + 1, d->y + 1, d->x + d->w - 2, black);
    vline(screen, d->x + 1, d->y + 1, d->y + d->h - 2, black);
    hline(screen, d->x + 2, d->y + d->h - 2, d->x + d->w - 2, black);
    vline(screen, d->x + d->w - 2, d->y + 2, d->y + d->h - 3, black);

    hline(screen, d->x + 1, d->y + d->h - 1, d->x + d->w - 1, white);
    vline(screen, d->x + d->w - 1, d->y + 1, d->y + d->h - 2, white);

    /* possibly draw scrollbar */
    if (listsize > height) {
	if (d->flags & D_GOTFOCUS)
	    c = 1;
	else if (d->flags & D_SELECTED)
	    c = 2;
	else
	    c = 0;

	xx = d->x + d->w - 11;
	yy = d->y;
	len = (((d->h - 2) * offset) + listsize / 2) / listsize;
	rectfill(screen, xx - 2, yy + 1, xx - 2 + 12 - 1, yy + d->h - 1 - 1, lgrey);
	vline(screen, xx - 2, yy + 1, yy + d->h - 1 - 1, black);

	i = ((d->h - 5) * height + listsize / 2) / listsize;
	xx = d->x + d->w - 12;
	yy = d->y + 2;

	if (offset > 0) {
	    len = (((d->h - 5) * offset) + listsize / 2) / listsize;
	    rectfill(screen, xx, yy, xx + 10, yy + len, lgrey);
	    yy += len;
	}
	if (yy + i < d->y + d->h - 3) {
	    ns_bevel(screen, xx, yy-1, 11, i+1, 0);
	    if (i > 10) {
		draw_sprite(screen, handle_bmp, xx + 11 / 2 - 3, yy + i / 2 - 3);
	    }
	    yy += i + 1;
	}
	else {
	    ns_bevel(screen, xx, yy-1, 11, d->h  - yy + d->y, 0);
	    if (i > 10) {
		draw_sprite(screen, handle_bmp, xx + 11 / 2 - 3, yy + i / 2 - 3);
	    }
	}
    }
}


int d_ans_list_proc(int msg, DIALOG *d, int c)
{
    if (msg == MSG_DRAW) {
	int height, listsize, i, len, bar, x, y, w;
	int fg_color, fg, bg;
	char *sel = (char *)d->dp2;
	char s[1024];
	int rtm;

	rectfill(screen, d->x, d->y, d->x + d->w - 1, d->y + d->h - 1, lgrey);

	(*(getfuncptr) d->dp) (-1, &listsize);
	height = (d->h - 4) / text_height(font);
	bar = (listsize > height);
	w = (bar ? d->w - 14 : d->w - 3);
	fg_color = (d->flags & D_DISABLED) ? disabled : d->fg;

	/* draw box contents */
	for (i = 0; i < height; i++) {
	    if (d->d2 + i < listsize) {
		if (d->d2 + i == d->d1) {
		    fg = black;
		    bg = white;
		}
		else if ((sel) && (sel[d->d2 + i])) {
		    fg = white;
		    bg = dgrey;
		}
		else {
		    fg = black;
		    bg = lgrey;
		}
		usetc(s, 0);
		ustrncat(s, (*(getfuncptr) d->dp) (i + d->d2, NULL),
			 sizeof(s) - ucwidth(0));
		x = d->x + 2;
		y = d->y + 2 + i * text_height(font);
		rtm = text_mode(bg);
		rectfill(screen, x, y, x + 7, y + text_height(font) - 1, bg);
		x += 8;
		len = ustrlen(s);
		while (text_length(font, s) >=
		       MAX(d->w - 1 - (bar ? 22 : 10), 1)) {
		    len--;
		    usetat(s, len, 0);
		}
		textout(screen, font, s, x, y, fg);
		text_mode(rtm);
		x += text_length(font, s);

		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),
			 lgrey);
	    }
	}

	if (d->y + 2 + i * text_height(font) <= d->y + d->h - 3)
	    rectfill(screen, d->x + 2, d->y + 2 + i * text_height(font),
		     d->x + w, d->y + d->h - 3, lgrey);

	/* draw frame, maybe with scrollbar */
	ns_draw_scrollable_frame(d, listsize, d->d2, height);

	return D_O_K;
    }

    return d_list_proc(msg, d, c);
}


int d_ans_text_list_proc(int msg, DIALOG *d, int c)
{
    if (msg == MSG_DRAW)
	return d_ans_list_proc(msg, d, c);
    return d_text_list_proc(msg, d, c);
}


int d_ans_textbox_proc(int msg, DIALOG *d, int c)
{
    if (msg == MSG_DRAW) {
	int height, bar;
	int fg_color = (d->flags & D_DISABLED) ? disabled : black;

	height = (d->h - 8) / text_height(font);

	/* tell the object to sort of draw, but only calculate the listsize */
	_draw_textbox((char *)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 = 11;
	}
	else {
	    bar = 0;
	    d->d2 = 0;
	}

	/* now do the actual drawing */
	_draw_textbox((char *)d->dp, &d->d1, 1, d->d2,
		      !(d->flags & D_SELECTED), 8, d->x, d->y, d->w - bar, d->h,
		      (d->flags & D_DISABLED), fg_color, white, ans_mg_color);

	/* draw the frame around */
	ns_draw_scrollable_frame(d, d->d1, d->d2, height);
	return D_O_K;
    }

    return d_textbox_proc(msg, d, c);
}


int d_ans_slider_proc(int msg, DIALOG *d, int c)
{
    if (msg == MSG_DRAW) {
	int vert = TRUE;	/* flag: is slider vertical? */
	int slp;		/* slider position */
	int irange, inmark = 1, ismark;
	fixed slratio, slmax, slpos;

	/* check for slider direction */
	if (d->h < d->w)
	    vert = FALSE;

	irange = (vert ? d->h - 2 : d->w - 2);
	ismark = irange / inmark;
	slmax = itofix(irange - 19);
	slratio = slmax / (d->d1);
	slpos = slratio * d->d2;
	slp = 1 + fixtoi(slpos);

	rectfill(screen, d->x, d->y, d->x + d->w - 1, d->y + d->h - 1, dgrey);
	line(screen, d->x, d->y, d->x, d->y + d->h - 1, black);
	line(screen, d->x, d->y, d->x + d->w - 1, d->y, black);
	line(screen, d->x, d->y + d->h - 1, d->x + d->w - 1, d->y + d->h - 1, white);
	line(screen, d->x + d->w - 1, d->y, d->x + d->w - 1, d->y + d->h - 1, white);

	if (vert) {
	    ns_bevel(screen, d->x + 1, d->y + d->h - slp - 19, d->w - 2, 10, 0);
	    ns_bevel(screen, d->x + 1, d->y + d->h - slp - 10, d->w - 2, 10, 0);
	    line(screen, d->x + 2, d->y + d->h - slp - 19, d->x + 2,
		 d->y + d->h - slp - 12, white);
	    line(screen, d->x + 2, d->y + d->h - slp - 10, d->x + 2,
		 d->y + d->h - slp - 3, white);
	    putpixel(screen, d->x + d->w - 3, d->y + d->h - slp - 10, lgrey);
	    putpixel(screen, d->x + 1, d->y + d->h - slp - 2, dgrey);
	}
	else {
	    ns_bevel(screen, d->x + slp, d->y + 1, 10, d->h - 2, 0);
	    ns_bevel(screen, d->x + slp + 9, d->y + 1, 10, d->h - 2, 0);
	    line(screen, d->x + slp + 1, d->y + 2, d->x + slp + 1,
		 d->y + d->h - 2 - 2, white);
	    putpixel(screen, d->x + slp + 9, d->y + 1 + d->h - 2 - 2, lgrey);
	    putpixel(screen, d->x + slp + 9 + 8, d->y + 1, dgrey);
	}
	return D_O_K;
    }

    return d_slider_proc(msg, d, c);
}


int
d_ans_clear_proc (int msg, DIALOG *d, int c)
{
    if (msg == MSG_DRAW)
    {
        clear_to_color (screen, ans_bg_color);
        return D_O_K;
    }
    return d_clear_proc (msg, d, c);
}


/*----------------------------------------------------------------------*/
/* Menus                                                                */
/*----------------------------------------------------------------------*/


/* These menus don't look much like NeXTstep menus.  Unfortunately, it's
   probably about as good as we can do without reimplementing menus
   for ourselves.  */


static void ns_draw_menu(int x, int y, int w, int h)
{
    ns_bevel(screen, x, y, w, h, 0);
}


static void ns_draw_menu_item(MENU * m, int x, int y, int w, int h, int bar, int sel)
{
    int fg, bg;
    int i, j;
    char buf[256], *tok;
    int rtm;

    if (m->flags & D_DISABLED) {
	fg = disabled;
	bg = lgrey;
    }
    else {
	fg = black;
	bg = (sel) ? white : lgrey;
    }

    if (sel && (!(m->flags & D_DISABLED))) {
	ns_bevel(screen, x, y, w, h, 2);
    }
    else {
	ns_bevel(screen, x, y, w, h, 0);
    }
    rtm = text_mode(bg);

    if (ugetc(m->text)) {
	i = 0;
	j = ugetc(m->text);

	while ((j) && (j != '\t')) {
	    i += usetc(buf + i, j);
	    j = ugetc(m->text + i);
	}

	usetc(buf + i, 0);

	gui_textout(screen, buf, x + 8, y + 1, fg, FALSE);

	if (j == '\t') {
	    tok = m->text + i + uwidth(m->text + i);
	    gui_textout(screen, tok, x + w - gui_strlen(tok) - 10, y + 1, fg,
			FALSE);
	}

	if ((m->child) && (!bar)) {
	    if (sel) {
		draw_sprite(screen, menu_arrow_sel_bmp, x + w - 12,
			    y + (h - menu_arrow_sel_bmp->h) / 2);
	    }
	    else {
		draw_sprite(screen, menu_arrow_bmp, x + w - 12,
			    y + (h - menu_arrow_bmp->h) / 2);
	    }
	}
    }
    else {
	hline(screen, x + 4, y + text_height(font) / 2 + 2, x + w - 4, dgrey);
	hline(screen, x + 4, y + text_height(font) / 2 + 3, x + w - 4, white);
    }

    if (m->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);
    }

    text_mode(rtm);
}


int d_ans_menu_proc(int msg, DIALOG *d, int c)
{
    return d_menu_proc(msg, d, c);
}


/*----------------------------------------------------------------------*/
/* Window frames							*/
/*----------------------------------------------------------------------*/


int d_ans_window_proc(int msg, DIALOG *d, int c)
{
    (void)c;

    if (msg == MSG_DRAW) {
	rectfill(screen, d->x, d->y, d->x + d->w - 1, d->y + d->h - 1, lgrey);
	rect(screen, d->x, d->y, d->x + d->w - 1, d->y + d->h - 1, black);
	rectfill(screen, d->x, d->y, d->x + d->w - 1, d->y + text_height(font) + 6 + 1, black);

	hline(screen, d->x + 1, d->y + text_height(font) + 6, d->x + d->w - 1 - 2, dgrey);
	vline(screen, d->x + d->w - 1 - 1, d->y + 2, d->y + text_height(font) + 6, dgrey);
	hline(screen, d->x + 1, d->y + 1, d->x + d->w - 2, lgrey);
	vline(screen, d->x + 1, d->y + 1, d->y + text_height(font) + 6, lgrey);

	if (d->dp) {
	    int rtm = text_mode(-1);
	    int cl = screen->cl, ct = screen->ct;
	    int cr = screen->cr, cb = screen->cb;
	    set_clip(screen, d->x, d->y, d->x + d->w - 1, d->y + d->h - 1);

	    textout_centre(screen, font, (char *)d->dp, d->x + d->w / 2, d->y + 3 + 2, white);

	    set_clip(screen, cl, ct, cr, cb);
	    text_mode(rtm);
	}
    }

    return D_O_K;
}


/*----------------------------------------------------------------------*/
/* Initialisation                                                       */
/*----------------------------------------------------------------------*/


void ans_init(void)
{
    white = makecol(0xff, 0xff, 0xff);
    lgrey = makecol(0xbd, 0xbd, 0xbd);
    dgrey = makecol(0x7b, 0x7b, 0x7b);
    black = makecol(0, 0, 0);
    disabled = makecol(0x7f, 0x7f, 0x7f);

    ans_fg_color = black;
    ans_bg_color = lgrey;
    ans_mg_color = disabled;

    radio_up_bmp = generate_bitmap(radio_up, 15, 15);
    radio_down_bmp = generate_bitmap(radio_down, 15, 15);
    handle_bmp = generate_bitmap(handle, 6, 6);
    menu_arrow_bmp = generate_bitmap(menu_arrow, 7, 7);
    menu_arrow_sel_bmp = generate_bitmap(menu_arrow_sel, 7, 7);

    gui_menu_draw_menu = ns_draw_menu;
    gui_menu_draw_menu_item = ns_draw_menu_item;
}

void ans_shutdown(void)
{
    destroy_bitmap(radio_up_bmp);
    destroy_bitmap(radio_down_bmp);
    destroy_bitmap(handle_bmp);
    destroy_bitmap(menu_arrow_bmp);
    destroy_bitmap(menu_arrow_sel_bmp);
    gui_menu_draw_menu_item = NULL;
    gui_menu_draw_menu = NULL;
}

/*----------------------------------------------------------------------*/
/* Theme                                                                */
/*----------------------------------------------------------------------*/

static struct AGUP_THEME the_theme = {
    "NeXTStep",
    &ans_fg_color,
    &ans_bg_color,
    &ans_mg_color,
    ans_init,
    ans_shutdown,
    d_ans_box_proc,
    d_ans_shadow_box_proc,
    d_ans_button_proc,
    d_ans_push_proc,
    d_ans_check_proc,
    d_ans_radio_proc,
    d_ans_icon_proc,
    d_ans_edit_proc,
    d_ans_list_proc,
    d_ans_text_list_proc,
    d_ans_textbox_proc,
    d_ans_slider_proc,
    d_ans_menu_proc,
    d_ans_window_proc,
    d_ans_clear_proc,
    d_agup_common_text_proc,
    d_agup_common_ctext_proc,
    d_agup_common_rtext_proc
};


AL_CONST struct AGUP_THEME *ans_theme = &the_theme;

/*
                white
        #bdbdbd light grey
        #7b7b7b dark grey
        #7f7f7f disabled
                black
*/
