/*********************************************************************

	usrintrf.c

	Functions used to handle MAME's user interface.

*********************************************************************/

#include "driver.h"
#include "info.h"
#include "datafile.h"
#include <stdarg.h>
#include <time.h>
#include "ui_text.h"
#include "state.h"
#include "neogeo.h"
#include "video.h"
#include "tsv.h"
#include "jukebox.h"



/***************************************************************************

	Externals

***************************************************************************/

/* Variables for stat menu */
extern char build_version[];
extern unsigned int dispensed_tickets;
extern unsigned int coins[COIN_COUNTERS];
extern unsigned int coinlockedout[COIN_COUNTERS];

/* MARTINEZ.F 990207 Memory Card */
int 		memcard_menu(struct mame_bitmap *bitmap, int);
extern int	mcd_action;
extern int	mcd_number;
extern int	memcard_status;
extern int	memcard_number;
extern int	memcard_manager;
extern struct GameDriver driver_neogeo;

extern int show_input;
extern char command_buf[];
extern int command_counter;

extern int neogeo_memcard_load(int);
extern void neogeo_memcard_save(void);
extern void neogeo_memcard_eject(void);
extern int neogeo_memcard_create(int);
/* MARTINEZ.F 990207 Memory Card End */



/***************************************************************************

	Local variables

***************************************************************************/

struct GfxElement *uirotfont;
struct GfxElement *uirotfont2;

/* raw coordinates, relative to the real scrbitmap */
struct rectangle uirawbounds;
int uirawcharwidth, uirawcharheight;

/* rotated coordinates, easier to deal with */
struct rectangle uirotbounds;
int uirotwidth, uirotheight;
int uirotcharwidth, uirotcharheight;

static int lhw, rhw, uaw, daw, law, raw;
static int scroll_reset;

static char *commandlist_buf = 0;
static int command_scroll = 0;

static int wordwrap_text_buffer(char *buffer, int maxcols);
static int count_lines_in_buffer (char *buffer);
static int display_scroll_message(struct mame_bitmap *bitmap, int *scroll, int width, int height, char *buf, const char *title);

int count_object_number_neogeo(void);
int count_object_number_cps(void);
int count_background_number_cps(void);
void alt_backcolor_exp_neogeo(void);
void alt_backcolor_exp_cps(void);

#define BOXADJUST (uirotcharheight / 2)
#define ROWHEIGHT (uirotcharheight + uirotcharheight / 4)
#define ROWADJUST (uirotcharheight / 8)

static int setup_selected;
static int osd_selected;
static int single_step;
static int command_lastselected;

static int jukebox = 0;

static int object = 0;
static int object_no = 0;
static int background_no = 0;
static int object_selected = 0;

static int command_sc = 0;
static int command_sel = 1;
static int command_load = 1;

static int cheat_sc = 0;
static int cheat_sel = 1;
static int cheat_fe = 0;

static int show_time = 0;

int wave_recording;
int wave_counter = 0;
int wave_seconds = 0;
int wave_minutes = 0;
int skip_object[0x400];
int skip_background[0x400];
int front_layer = 0;
int alt_backcolor = 0;

static int showfps;
static int showfpstemp;



/*-------------------------------------------------
	ui_raw2rot_rect - convert a rect from raw
	coordinates to rotated coordinates
-------------------------------------------------*/

static void ui_raw2rot_rect(struct rectangle *rect)
{
	int temp, w, h;

	w = Machine->drv->screen_width;
	h = Machine->drv->screen_height;

	/* apply X flip */
	if (Machine->ui_orientation & ORIENTATION_FLIP_X)
	{
		temp = w - rect->min_x - 1;
		rect->min_x = w - rect->max_x - 1;
		rect->max_x = temp;
	}

	/* apply Y flip */
	if (Machine->ui_orientation & ORIENTATION_FLIP_Y)
	{
		temp = h - rect->min_y - 1;
		rect->min_y = h - rect->max_y - 1;
		rect->max_y = temp;
	}

	/* apply X/Y swap first */
	if (Machine->ui_orientation & ORIENTATION_SWAP_XY)
	{
		temp = rect->min_x; rect->min_x = rect->min_y; rect->min_y = temp;
		temp = rect->max_x; rect->max_x = rect->max_y; rect->max_y = temp;
	}
}



/*-------------------------------------------------
	ui_rot2raw_rect - convert a rect from rotated
	coordinates to raw coordinates
-------------------------------------------------*/

void ui_rot2raw_rect(struct rectangle *rect)
{
	int temp, w, h;

	w = Machine->drv->screen_width;
	h = Machine->drv->screen_height;

	/* apply X/Y swap first */
	if (Machine->ui_orientation & ORIENTATION_SWAP_XY)
	{
		temp = rect->min_x; rect->min_x = rect->min_y; rect->min_y = temp;
		temp = rect->max_x; rect->max_x = rect->max_y; rect->max_y = temp;
	}

	/* apply X flip */
	if (Machine->ui_orientation & ORIENTATION_FLIP_X)
	{
		temp = w - rect->min_x - 1;
		rect->min_x = w - rect->max_x - 1;
		rect->max_x = temp;
	}

	/* apply Y flip */
	if (Machine->ui_orientation & ORIENTATION_FLIP_Y)
	{
		temp = h - rect->min_y - 1;
		rect->min_y = h - rect->max_y - 1;
		rect->max_y = temp;
	}
}



/*-------------------------------------------------
	set_ui_visarea - called by the OSD code to
	set the UI's domain
-------------------------------------------------*/

void set_ui_visarea (int xmin, int ymin, int xmax, int ymax)
{
	/* fill in the rect */
	uirawbounds.min_x = xmin;
	uirawbounds.min_y = ymin;
	uirawbounds.max_x = xmax;
	uirawbounds.max_y = ymax;

	/* orient it */
	uirotbounds = uirawbounds;
	ui_raw2rot_rect(&uirotbounds);

	/* make some easier-to-access globals */
	uirotwidth = uirotbounds.max_x - uirotbounds.min_x + 1;
	uirotheight = uirotbounds.max_y - uirotbounds.min_y + 1;

	/* remove me */
	Machine->uiwidth = uirotbounds.max_x - uirotbounds.min_x + 1;
	Machine->uiheight = uirotbounds.max_y - uirotbounds.min_y + 1;
	uirotbounds.min_x = uirotbounds.min_x;
	Machine->uiymin = uirotbounds.min_y;

	/* rebuild the font */
	uifont_buildfont();
}



/*-------------------------------------------------
	erase_screen - erase the screen
-------------------------------------------------*/

static void erase_screen(struct mame_bitmap *bitmap)
{
	fillbitmap(bitmap, get_black_pen(), NULL);
	schedule_full_refresh();
}



/*-------------------------------------------------
	ui_plotbox - draw a color box
-------------------------------------------------*/

void ui_plotbox(struct mame_bitmap *bitmap, int leftx, int topy, int width, int height, int color)
{
	struct rectangle bounds;

	/* make a rect and clip it */
	bounds.min_x = uirotbounds.min_x + leftx;
	bounds.min_y = uirotbounds.min_y + topy;
	bounds.max_x = bounds.min_x + width - 1;
	bounds.max_y = bounds.min_y + height - 1;
	sect_rect(&bounds, &uirotbounds);

	ui_rot2raw_rect(&bounds);

	plot_box(bitmap, bounds.min_x, bounds.min_y,
					 bounds.max_x - bounds.min_x + 1, bounds.max_y - bounds.min_y + 1,
					 Machine->uifont->colortable[color]);
}



/*-------------------------------------------------
	ui_transbox - draw a trans box
-------------------------------------------------*/

static void ui_transbox(struct mame_bitmap *bitmap, int leftx, int topy, int width, int height)
{
	struct rectangle bounds;

	/* make a rect and clip it */
	bounds.min_x = uirotbounds.min_x + leftx;
	bounds.min_y = uirotbounds.min_y + topy;
	bounds.max_x = bounds.min_x + width - 1;
	bounds.max_y = bounds.min_y + height - 1;
	sect_rect(&bounds, &uirotbounds);

	ui_rot2raw_rect(&bounds);

	plot_box_trans(bitmap, bounds.min_x, bounds.min_y,
						   bounds.max_x - bounds.min_x + 1, bounds.max_y - bounds.min_y + 1);
}



/*-------------------------------------------------
	ui_text_ex - draw a string to the screen
-------------------------------------------------*/

static void ui_text_ex(struct mame_bitmap *bitmap, const char* buf_begin, const char* buf_end, int x, int y, int color)
{
	int len;
	char buf[256];

	memset(buf, 0, 256);

	len = (buf_end - buf_begin) + 1;
	if (*buf_end == ' ')
		len--;

	memcpy(buf, buf_begin, len);

	uifont_drawfont(bitmap, buf, x, y, color);
}



/*-------------------------------------------------
	ui_text - draw a string to the screen
-------------------------------------------------*/

void ui_text(struct mame_bitmap *bitmap,const char *buf,int x,int y)
{
	ui_text_ex(bitmap, buf, buf + strlen(buf), x, y, UI_COLOR_NORMAL);
}



/*-------------------------------------------------
	ui_text_bk - draw a string to the screen
-------------------------------------------------*/
void ui_text_bk(struct mame_bitmap *bitmap,const char *buf,int x,int y)
{
	ui_transbox(bitmap, x, y, uirotcharwidth * strlen(buf), uirotcharheight);

	ui_text_ex(bitmap, buf, buf + strlen(buf), x, y, UI_COLOR_NORMAL);
}



/*-------------------------------------------------
	displaytext - display a series of text lines
-------------------------------------------------*/

void displaytext(struct mame_bitmap *bitmap, const struct DisplayText *dt)
{
	int next_sy = 0;

	while (dt->text)
	{
		next_sy = uifont_drawfont(bitmap, dt->text, dt->x, dt->y + next_sy, dt->color);
		dt++;

		if (dt->y + next_sy >= uirotheight)
			break;
	}
}



/*-------------------------------------------------
	ui_drawbox - draw a black box with 3d border
-------------------------------------------------*/

void ui_drawbox(struct mame_bitmap *bitmap,int leftx,int topy,int width,int height,int trans)
{
	struct rectangle bounds, tbounds;
	pen_t black;

	/* make a rect and clip it */
	bounds.min_x = uirotbounds.min_x + leftx;
	bounds.min_y = uirotbounds.min_y + topy;
	bounds.max_x = bounds.min_x + width - 1;
	bounds.max_y = bounds.min_y + height - 1;
	sect_rect(&bounds, &uirotbounds);

	/* pick colors from the colortable */
	black = uirotfont->colortable[0];

	/* fill in the middle with black */
	tbounds = bounds;
	ui_rot2raw_rect(&tbounds);

	if (trans)
		plot_box_trans(bitmap, tbounds.min_x, tbounds.min_y, tbounds.max_x - tbounds.min_x, tbounds.max_y - tbounds.min_y);
	else
		plot_box(bitmap, tbounds.min_x, tbounds.min_y, tbounds.max_x - tbounds.min_x, tbounds.max_y - tbounds.min_y, black);

	/* top edge */
	tbounds = bounds;
	tbounds.max_y = tbounds.min_y;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMEMEDIUM], &tbounds);

	tbounds = bounds;
	tbounds.min_x -= 1;
	tbounds.max_x += 1;
	tbounds.min_y -= 1;
	tbounds.max_y = tbounds.min_y;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMELIGHT], &tbounds);

	tbounds = bounds;
	tbounds.min_x += 1;
	tbounds.max_x -= 1;
	tbounds.min_y += 1;
	tbounds.max_y = tbounds.min_y;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMEDARK], &tbounds);

	/* bottom edge */
	tbounds = bounds;
	tbounds.min_y = tbounds.max_y;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMEMEDIUM], &tbounds);

	tbounds = bounds;
	tbounds.min_x -= 1;
	tbounds.max_x += 1;
	tbounds.max_y += 1;
	tbounds.min_y = tbounds.max_y;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMEDARK], &tbounds);

	tbounds = bounds;
	tbounds.min_x += 1;
	tbounds.max_x -= 1;
	tbounds.max_y -= 1;
	tbounds.min_y = tbounds.max_y;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMELIGHT], &tbounds);

	/* left edge */
	tbounds = bounds;
	tbounds.max_x = tbounds.min_x;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMEMEDIUM], &tbounds);

	tbounds = bounds;
	tbounds.min_y -= 1;
	tbounds.max_y += 1;
	tbounds.min_x -= 1;
	tbounds.max_x = tbounds.min_x;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMELIGHT], &tbounds);

	tbounds = bounds;
	tbounds.min_y += 1;
	tbounds.max_y -= 1;
	tbounds.min_x += 1;
	tbounds.max_x = tbounds.min_x;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMEDARK], &tbounds);

	/* right edge */
	tbounds = bounds;
	tbounds.min_x = tbounds.max_x;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMEMEDIUM], &tbounds);

	tbounds = bounds;
	tbounds.min_y -= 1;
	tbounds.max_y += 1;
	tbounds.max_x += 1;
	tbounds.min_x = tbounds.max_x;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMEDARK], &tbounds);

	tbounds = bounds;
	tbounds.min_y += 1;
	tbounds.max_y -= 1;
	tbounds.max_x -= 1;
	tbounds.min_x = tbounds.max_x;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[SYSTEM_COLOR_FRAMELIGHT], &tbounds);
}



/*-------------------------------------------------
	drawbar - draw a thermometer bar
-------------------------------------------------*/

static void drawbar(struct mame_bitmap *bitmap,int leftx,int topy,int width,int height,int percentage,int default_percentage)
{
	struct rectangle bounds, tbounds;
	pen_t white;

	/* make a rect and orient/clip it */
	bounds.min_x = uirotbounds.min_x + leftx;
	bounds.min_y = uirotbounds.min_y + topy;
	bounds.max_x = bounds.min_x + width - 1;
	bounds.max_y = bounds.min_y + height - 1;
	sect_rect(&bounds, &uirotbounds);

	/* pick colors from the colortable */
	white = uirotfont->colortable[1];

	/* draw the top line of the bar */
	tbounds = bounds;
	tbounds.min_y += height / 8;
	tbounds.max_y = tbounds.min_y;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, white, &tbounds);

	/* draw the bottom line of the bar */
	tbounds = bounds;
	tbounds.max_y -= height / 8;
	tbounds.min_y = tbounds.max_y;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, white, &tbounds);

	/* draw the top 3d line of the bar */
	tbounds = bounds;
	tbounds.min_y += height / 8;
	tbounds.max_x -= (width - 1) * (100 - percentage) / 100 + 1;
	tbounds.max_y = tbounds.min_y;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[OSDBAR_COLOR_FRAMEDARK], &tbounds);

	/* draw the left 3d line of the bar */
	tbounds = bounds;
	tbounds.min_y += height / 8 + 1;
	tbounds.max_x = tbounds.min_x;
	tbounds.max_y -= (height / 8);
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[OSDBAR_COLOR_FRAMEDARK], &tbounds);

	/* draw the right 3d line of the bar */
	tbounds = bounds;
	tbounds.min_x += (width - 1) * percentage / 100;
	tbounds.min_y += 1;
	tbounds.max_x = tbounds.min_x;
	tbounds.max_y -= (height / 8 + 1);
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[OSDBAR_COLOR_FRAMELIGHT], &tbounds);

	/* draw the bottom 3d line of the bar */
	tbounds = bounds;
	tbounds.min_x += 1;
	tbounds.max_y -= height / 8;
	tbounds.min_y = tbounds.max_y;
	tbounds.max_x = tbounds.min_x + (width - 1) * percentage / 100 - 2;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[OSDBAR_COLOR_FRAMELIGHT], &tbounds);

	/* fill in the percentage */
	tbounds = bounds;
	tbounds.min_x += 1;
	tbounds.max_x = tbounds.min_x + (width - 1) * percentage / 100 - 2;
	tbounds.min_y += (height / 8 + 1);
	tbounds.max_y -= (height / 8 + 1);
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[OSDBAR_COLOR_FRAMEMEDIUM], &tbounds);

	/* draw the top default percentage marker */
	tbounds = bounds;
	tbounds.min_x += (width - 1) * default_percentage / 100;
	tbounds.max_x = tbounds.min_x;
	tbounds.max_y = tbounds.min_y + height - 1;
	ui_rot2raw_rect(&tbounds);
	fillbitmap(bitmap, Machine->uifont->colortable[OSDBAR_COLOR_DEFAULTBAR], &tbounds);
}



/*-------------------------------------------------
	multiline_extract - extract one line from a
	multiline buffer; return the number of
	characters in the line; pbegin points to the
	start of the next line
-------------------------------------------------*/

static unsigned multiline_extract(const char** pbegin, const char* end, unsigned max)
{
	unsigned mac = 0;
	const char* begin = *pbegin;
	while (begin != end && mac < max)
	{
		if (*begin == '\n')
		{
			*pbegin = begin + 1; /* strip final space */
			return mac;
		}
		else if (*begin == ' ')
		{
			const char* word_end = begin + 1;
			while (word_end != end && *word_end != ' ' && *word_end != '\n')
				++word_end;
			if (mac + word_end - begin > max)
			{
				if (mac)
				{
					*pbegin = begin + 1;
					return mac; /* strip final space */
				} else {
					*pbegin = begin + max;
					return max;
				}
			}
			mac += word_end - begin;
			begin = word_end;
		} else {
			++mac;
			++begin;
		}
	}
	if (begin != end && (*begin == '\n' || *begin == ' '))
		++begin;
	*pbegin = begin;
	return mac;
}



/*-------------------------------------------------
	multiline_size - compute the output size of a
	multiline string
-------------------------------------------------*/

static void multiline_size(int* dx, int* dy, const char* begin, const char* end, unsigned max)
{
	unsigned rows = 0;
	unsigned cols = 0;
	while (begin != end)
	{
		unsigned len;
		len = multiline_extract(&begin,end,max);
		if (len > cols)
			cols = len;
		++rows;
	}
	*dx = cols * uirotcharwidth;
	*dy = (rows-1) * ROWHEIGHT;
}



/*-------------------------------------------------
	multilinebox_size - compute the output size of
	a multiline string with box
-------------------------------------------------*/

static void multilinebox_size(int* dx, int* dy, const char* begin, const char* end, unsigned max)
{
	multiline_size(dx,dy,begin,end,max);
	*dx += uirotcharwidth;
	*dy += ROWHEIGHT;
}



/*-------------------------------------------------
	ui_multitext_ex - display a multiline string
-------------------------------------------------*/

static void ui_multitext_ex(struct mame_bitmap *bitmap, const char* begin, const char* end, unsigned max, int x, int y, int color)
{
	while (begin != end)
	{
		const char* line_begin = begin;
		unsigned len = multiline_extract(&begin,end,max);
		ui_text_ex(bitmap, line_begin, line_begin + len,x,y,color);
		y += ROWHEIGHT;
	}
}



/*-------------------------------------------------
	ui_multitextbox_ex - display a multiline
	string with box
-------------------------------------------------*/

static void ui_multitextbox_ex(struct mame_bitmap *bitmap,const char* begin, const char* end, unsigned max, int x, int y, int dx, int dy, int color)
{
	ui_drawbox(bitmap,x-1,y-BOXADJUST,dx,dy+BOXADJUST*2-2,0);
	x += uirotcharwidth/2-1;
	ui_multitext_ex(bitmap,begin,end,max,x,y,color);
}



void ui_displaymenu(struct mame_bitmap *bitmap,const char **items,const char **subitems,char *flag,const char *title,int selected,int arrowize_subitem)
{
	struct DisplayText dt[256];
	int curr_dt,curr_y;
//	const char *lefthilight = ui_getstring (UI_lefthilight);
//	const char *righthilight = ui_getstring (UI_righthilight);
	const char *uparrow = ui_getstring (UI_uparrow);
	const char *downarrow = ui_getstring (UI_downarrow);
	const char *leftarrow = ui_getstring (UI_leftarrow);
	const char *rightarrow = ui_getstring (UI_rightarrow);
	int i,count,len,maxlen,highlen;
	int leftoffs,topoffs,visible,topitem;
	int selected_long;


	i = 0;
	maxlen = 0;
	highlen = uirotwidth / uirotcharwidth;
	while (items[i])
	{
		len = (raw+law+1) + strlen(items[i]) + 1;
		if (subitems && subitems[i])
			len += (lhw+rhw) + strlen(subitems[i]);
		if (len > maxlen && len <= highlen)
			maxlen = len;
		i++;
	}
	count = i;

	if (title)
	{
		len = strlen(title) + 2;
		if (len > maxlen && len <= highlen)
			maxlen = len;
		visible = (uirotheight / ROWHEIGHT) - 2;
	}
	else
		visible = (uirotheight / ROWHEIGHT) - 1;

	topitem = 0;
	if (visible > count) visible = count;
	else
	{
		topitem = selected - visible / 2;
		if (topitem < 0) topitem = 0;
		if (topitem > count - visible) topitem = count - visible;
	}

	leftoffs = (uirotwidth - maxlen * uirotcharwidth) / 2;
	if (title)
	{
		topoffs  = (uirotheight - (visible + 1) * ROWHEIGHT) / 2;

		/* black background */
		ui_drawbox(bitmap,leftoffs,topoffs - BOXADJUST,maxlen * uirotcharwidth,(visible + 1) * ROWHEIGHT + BOXADJUST*2,1);
	}
	else
	{
		topoffs  = (uirotheight - visible * ROWHEIGHT) / 2;

		/* black background */
		ui_drawbox(bitmap,leftoffs,topoffs - BOXADJUST,maxlen * uirotcharwidth,visible * ROWHEIGHT + BOXADJUST*2,1);
	}

	if (title)
	{
		ui_plotbox(bitmap, leftoffs + 1, topoffs + ROWHEIGHT - 4, maxlen * uirotcharwidth - 2, 1, SYSTEM_COLOR_FRAMEMEDIUM);
		ui_plotbox(bitmap, leftoffs + 1, topoffs + ROWHEIGHT - 3, maxlen * uirotcharwidth - 3, 1, SYSTEM_COLOR_FRAMEDARK);

		for (i = 0; i < GRADATION_LEVEL; i++)
			ui_plotbox(bitmap, leftoffs + 1 + (int)(i * (maxlen * uirotcharwidth - 2) / GRADATION_LEVEL), topoffs - 5,
							   (int)((maxlen * uirotcharwidth - 2) / GRADATION_LEVEL) + 1, ROWHEIGHT + 1, MAX_COLORTABLE + i);

		dt[0].text = title;
		dt[0].color = UI_COLOR_BOLD;
		dt[0].x = leftoffs + 4;
		dt[0].y = topoffs - BOXADJUST + 3;

		dt[1].text = 0;	/* terminate array */

		displaytext(bitmap,dt);
	}

	selected_long = 0;
	curr_dt = 0;
	for (i = 0;i < visible;i++)
	{
		int item = i + topitem;

		if (title)
			curr_y = topoffs + (i + 1) * ROWHEIGHT + ROWADJUST + 1;
		else
			curr_y = topoffs + i * ROWHEIGHT + ROWADJUST + 1;

		if (i == 0 && item > 0)
		{
			dt[curr_dt].text = uparrow;
			dt[curr_dt].color = UI_COLOR_NORMAL;
			dt[curr_dt].x = (uirotwidth - uirotcharwidth * uaw) / 2;
			dt[curr_dt].y = curr_y;
			curr_dt++;
		}
		else if (i == visible - 1 && item < count - 1)
		{
			dt[curr_dt].text = downarrow;
			dt[curr_dt].color = UI_COLOR_NORMAL;
			dt[curr_dt].x = (uirotwidth - uirotcharwidth * daw) / 2;
			dt[curr_dt].y = curr_y;
			curr_dt++;
		}
		else
		{
			if (subitems && subitems[item])
			{
				int sublen;

				len = strlen(items[item]);
				dt[curr_dt].text = items[item];
				dt[curr_dt].color = UI_COLOR_NORMAL;
				dt[curr_dt].x = leftoffs + uirotcharwidth/2 + uirotcharwidth * raw;
				dt[curr_dt].y = curr_y;
				curr_dt++;

				sublen = strlen(subitems[item]);
				if (sublen > maxlen-(raw+lhw+rhw+2)-len)
				{
					dt[curr_dt].text = "...";
					sublen = strlen(dt[curr_dt].text);
					if (item == selected)
						selected_long = 1;
				} else {
					dt[curr_dt].text = subitems[item];
				}
				/* If this item is flagged, draw it in inverse print */
				dt[curr_dt].color = (flag && flag[item]) ? UI_COLOR_INVERSE : UI_COLOR_NORMAL;
				dt[curr_dt].x = leftoffs + uirotcharwidth * (maxlen-rhw-sublen) - uirotcharwidth/2;
				dt[curr_dt].y = curr_y;
				curr_dt++;
			}
			else
			{
				dt[curr_dt].text = items[item];
				dt[curr_dt].color = UI_COLOR_NORMAL;
				dt[curr_dt].x = (uirotwidth - uirotcharwidth * strlen(items[item])) / 2;
				dt[curr_dt].y = curr_y;
				curr_dt++;
			}
		}
	}

	if (title)
		i = selected - topitem + 1;
	else
		i = selected - topitem;

	curr_y = topoffs + i * ROWHEIGHT + ROWADJUST + 1;

	if (subitems && subitems[selected] && arrowize_subitem)
	{
		if (arrowize_subitem & 1)
		{
			int sublen;

			len = strlen(items[selected]);

			dt[curr_dt].text = leftarrow;
			dt[curr_dt].color = UI_COLOR_NORMAL;

			sublen = strlen(subitems[selected]);
			if (sublen > maxlen-(raw+lhw+rhw+2)-len)
				sublen = strlen("...");

			dt[curr_dt].x = leftoffs + uirotcharwidth * (maxlen-(lhw+law)-sublen) - uirotcharwidth/2 - raw;
			dt[curr_dt].y = curr_y;
			curr_dt++;
		}
		if (arrowize_subitem & 2)
		{
			dt[curr_dt].text = rightarrow;
			dt[curr_dt].color = UI_COLOR_NORMAL;
			dt[curr_dt].x = leftoffs + uirotcharwidth * (maxlen-raw) - uirotcharwidth/2;
			dt[curr_dt].y = curr_y;
			curr_dt++;
		}
	}

	dt[curr_dt].text = 0;	/* terminate array */

	ui_plotbox(bitmap, leftoffs + 2, curr_y - 1, maxlen * uirotcharwidth - 4, ROWHEIGHT - 1, CURSOR_COLOR);

	displaytext(bitmap,dt);

	if (selected_long)
	{
		int long_dx;
		int long_dy;
		int long_x;
		int long_y;
		unsigned long_max;

		long_max = (uirotwidth / uirotcharwidth) - 2;
		multilinebox_size(&long_dx,&long_dy,subitems[selected],subitems[selected] + strlen(subitems[selected]), long_max);

		long_x = uirotwidth - long_dx;
		long_y = topoffs + (i+1) * ROWHEIGHT;

		/* if too low display up */
		if (long_y + long_dy > uirotheight)
			long_y = topoffs + i * ROWHEIGHT - long_dy;

		ui_multitextbox_ex(bitmap,subitems[selected],subitems[selected] + strlen(subitems[selected]), long_max, long_x,long_y,long_dx,long_dy, UI_COLOR_NORMAL);
	}
}


void ui_displaymenu_jukebox(struct mame_bitmap *bitmap,const char **items,char *flag,const char *title,int selected,int notes)
{
	struct DisplayText dt[256];
	int curr_dt,curr_y;
	const char *uparrow = ui_getstring (UI_uparrow);
	const char *downarrow = ui_getstring (UI_downarrow);
	int i,count,len,maxlen,highlen;
	int leftoffs,topoffs,visible,topitem;


	i = 0;
	maxlen = 0;
	highlen = uirotwidth / uirotcharwidth;
	while (items[i])
	{
		len = (raw+law+1) + strlen(items[i]) + 1;
		if (len > maxlen && len <= highlen)
			maxlen = len;
		i++;
	}
	count = i;

	if (title)
	{
		len = strlen(title) + 2;
		if (len > maxlen && len <= highlen)
			maxlen = len;
		visible = (uirotheight / ROWHEIGHT) - 5;
	}
	else
		visible = (uirotheight / ROWHEIGHT) - 4;

	topitem = 0;
	if (visible > count) visible = count;
	else
	{
		topitem = selected - visible / 2;
		if (topitem < 0) topitem = 0;
		if (topitem > count - visible) topitem = count - visible;
	}

	leftoffs = (uirotwidth - maxlen * uirotcharwidth) / 2;
	topoffs  = ROWHEIGHT;

	/* black background */
	if (title)
		ui_drawbox(bitmap,leftoffs,topoffs - BOXADJUST,maxlen * uirotcharwidth,(visible + 1) * ROWHEIGHT + BOXADJUST*2,1);
	else
		ui_drawbox(bitmap,leftoffs,topoffs - BOXADJUST,maxlen * uirotcharwidth,visible * ROWHEIGHT + BOXADJUST*2,1);

	if (title)
	{
		ui_plotbox(bitmap, leftoffs + 1, topoffs + ROWHEIGHT - 4, maxlen * uirotcharwidth - 2, 1, SYSTEM_COLOR_FRAMEMEDIUM);
		ui_plotbox(bitmap, leftoffs + 1, topoffs + ROWHEIGHT - 3, maxlen * uirotcharwidth - 3, 1, SYSTEM_COLOR_FRAMEDARK);

		for (i = 0; i < GRADATION_LEVEL; i++)
			ui_plotbox(bitmap, leftoffs + 1 + (int)(i * (maxlen * uirotcharwidth - 2) / GRADATION_LEVEL), topoffs - 5,
							   (int)((maxlen * uirotcharwidth - 2) / GRADATION_LEVEL) + 1, ROWHEIGHT + 1, MAX_COLORTABLE + i);

		dt[0].text = title;
		dt[0].color = UI_COLOR_BOLD;
		dt[0].x = leftoffs + 4;
		dt[0].y = topoffs - BOXADJUST + 3;

		dt[1].text = 0;	/* terminate array */

		displaytext(bitmap,dt);
	}

	curr_dt = 0;
	for (i = 0;i < visible;i++)
	{
		int item = i + topitem;

		if (title)
			curr_y = topoffs + (i + 1) * ROWHEIGHT + ROWADJUST + 1;
		else
			curr_y = topoffs + i * ROWHEIGHT + ROWADJUST + 1;

		if (i == 0 && item > 0)
		{
			dt[curr_dt].text = uparrow;
			dt[curr_dt].color = UI_COLOR_NORMAL;
			dt[curr_dt].x = (uirotwidth - uirotcharwidth * uaw) / 2;
			dt[curr_dt].y = curr_y;
			curr_dt++;
		}
		else if (i == visible - 1 && item < count - 1)
		{
			dt[curr_dt].text = downarrow;
			dt[curr_dt].color = UI_COLOR_NORMAL;
			dt[curr_dt].x = (uirotwidth - uirotcharwidth * daw) / 2;
			dt[curr_dt].y = curr_y;
			curr_dt++;
		}
		else
		{
			if (flag && flag[item] && notes)
				dt[curr_dt].color = UI_COLOR_INVERSE;
			else
				dt[curr_dt].color = UI_COLOR_NORMAL;

			dt[curr_dt].text = items[item];
			dt[curr_dt].x = (uirotwidth - uirotcharwidth * strlen(items[item])) / 2;
			dt[curr_dt].y = curr_y;
			curr_dt++;
		}
	}

	if (title)
		i = selected - topitem + 1;
	else
		i = selected - topitem;

	curr_y = topoffs + i * ROWHEIGHT + ROWADJUST + 1;

	dt[curr_dt].text = 0;	/* terminate array */

	ui_plotbox(bitmap, leftoffs + 2, curr_y - 1, maxlen * uirotcharwidth - 4, ROWHEIGHT - 1, CURSOR_COLOR);

	displaytext(bitmap,dt);
}


int ui_displaymessagewindow(struct mame_bitmap *bitmap, const char *text, const char *title)
{
	struct DisplayText dt[256];
	char *c, *c2;
	char textcopy[2048];
	int curr_dt;
	int i, lines;
	int leftoffs, topoffs;
	int maxrows, maxcols, maxlen;
	static int scroll = 0;

	maxcols = (uirotwidth / uirotcharwidth) - 2;
	if (title)
		maxrows = (uirotheight / ROWHEIGHT) - 2;
	else
		maxrows = (uirotheight / ROWHEIGHT) - 1;

	strcpy(textcopy, text);
	maxlen = wordwrap_text_buffer(textcopy, maxcols);
	lines  = count_lines_in_buffer(textcopy);

	if (title)
	{
		int len = strlen(title) + 2;
		if (len > maxlen && len <= uirotwidth / uirotcharwidth)
			maxlen = len;
	}

	if (lines >= maxrows)
	{
		if (scroll_reset)
		{
			scroll = 0;
			scroll_reset = 0;
		}

		strcat(textcopy, "\n");
		display_scroll_message(bitmap, &scroll, maxlen, maxrows, textcopy, title);

		if ((scroll > 0) && input_ui_pressed_repeat(IPT_UI_UP,4))
		{
			if (scroll == 2) scroll = 0;	/* 1 would be the same as 0, but with arrow on top */
			else scroll--;
			return -1;
		}
		else if (input_ui_pressed_repeat(IPT_UI_DOWN,4))
		{
			if (scroll == 0) scroll = 2;	/* 1 would be the same as 0, but with arrow on top */
			else scroll++;
			return -1;
		}
		else
		if (input_ui_pressed(IPT_UI_SELECT))
		{
			scroll = 0;
			return 1;
		}
		else
		if (input_ui_pressed(IPT_UI_CANCEL))
		{
			scroll = 0;
			return 2;
		}
		else
		if (input_ui_pressed(IPT_UI_CONFIGURE))
		{
			scroll = 0;
			return 3;
		}
	}
	else
	{
		leftoffs = (uirotwidth - uirotcharwidth * maxlen) / 2;
		if (leftoffs < 0) leftoffs = 0;
		if (title)
		{
			topoffs = (uirotheight - (lines + 2) * ROWHEIGHT) / 2;

			/* black background */
			ui_drawbox(bitmap,leftoffs,topoffs-BOXADJUST,maxlen*uirotcharwidth,(lines+2)*ROWHEIGHT+BOXADJUST*2,1);
		}
		else
		{
			topoffs = (uirotheight - (lines + 1) * ROWHEIGHT) / 2;

			/* black background */
			ui_drawbox(bitmap,leftoffs,topoffs-BOXADJUST,maxlen*uirotcharwidth,(lines+1)*ROWHEIGHT+BOXADJUST*2,1);
		}

		if (title)
		{
			ui_plotbox(bitmap, leftoffs + 1, topoffs + ROWHEIGHT - 4, maxlen * uirotcharwidth - 2, 1, SYSTEM_COLOR_FRAMEMEDIUM);
			ui_plotbox(bitmap, leftoffs + 1, topoffs + ROWHEIGHT - 3, maxlen * uirotcharwidth - 3, 1, SYSTEM_COLOR_FRAMEDARK);

			for (i = 0; i < GRADATION_LEVEL; i++)
				ui_plotbox(bitmap, leftoffs + 1 + (int)(i * (maxlen * uirotcharwidth - 2) / GRADATION_LEVEL), topoffs - 5,
								   (int)((maxlen * uirotcharwidth - 2) / GRADATION_LEVEL) + 1, ROWHEIGHT + 1, MAX_COLORTABLE + i);

			dt[0].text = title;
			dt[0].color = UI_COLOR_BOLD;
			dt[0].x = leftoffs + 4;
			dt[0].y = topoffs - BOXADJUST + 3;

			dt[1].text = 0;	/* terminate array */

			displaytext(bitmap,dt);

			topoffs += ROWHEIGHT;
		}

		curr_dt = 0;
		c = textcopy;
		i = 0;
		while (*c)
		{
			c2 = c;
			while (*c && *c != '\n')
				c++;

			if (*c == '\n')
			{
				*c = '\0';
				c++;
			}

			if (*c2 == '\t')	/* center text */
			{
				c2++;
				dt[curr_dt].x = (uirotwidth - uirotcharwidth * (c - c2)) / 2;
			}
			else
				dt[curr_dt].x = leftoffs + uirotcharwidth/2;

			dt[curr_dt].text = c2;
			dt[curr_dt].color = UI_COLOR_NORMAL;
			dt[curr_dt].y = topoffs + i * ROWHEIGHT + ROWADJUST;
			curr_dt++;

			i++;
		}

		dt[curr_dt].text = 0;	/* terminate array */

		displaytext(bitmap,dt);
	}

	return 0;
}



static void showcharset(struct mame_bitmap *bitmap)
{
	int i;
	char buf[80];
	int mode,bank,color,firstdrawn;
	int palpage;
	int changed;
	int total_colors = 0;
	pen_t *colortable = NULL;
	int cpx=0,cpy,skip_chars=0,skip_tmap=0;
	int tilemap_xpos = 0;
	int tilemap_ypos = 0;

	mode = 0;
	bank = 0;
	color = 0;
	firstdrawn = 0;
	palpage = 0;

	changed = 1;

	do
	{
		switch (mode)
		{
			case 0: /* palette or clut */
			{
				if (bank == 0)	/* palette */
				{
					total_colors = Machine->drv->total_colors;
					colortable = Machine->pens;
					strcpy(buf,"PALETTE");
				}
				else if (bank == 1)	/* clut */
				{
					total_colors = Machine->drv->color_table_len;
					colortable = Machine->remapped_colortable;
					strcpy(buf,"CLUT");
				}
				else
				{
					buf[0] = 0;
					total_colors = 0;
					colortable = 0;
				}

				/*if (changed) -- temporary */
				{
					erase_screen(bitmap);

					if (total_colors)
					{
						int sx,sy,colors;
						int column_heading_max;
						struct bounds;

						colors = total_colors - 256 * palpage;
						if (colors > 256) colors = 256;

						/* min(colors, 16) */
						if (colors < 16)
							column_heading_max = colors;
						else
							column_heading_max = 16;

						for (i = 0;i < column_heading_max;i++)
						{
							char bf[40];

							sx = 3*uirotcharwidth + (uirotcharwidth*4/3)*(i % 16);
							sprintf(bf,"%X",i);
							ui_text(bitmap,bf,sx,2*uirotcharheight);
							if (16*i < colors)
							{
								sy = 3*uirotcharheight + (uirotcharheight)*(i % 16);
								sprintf(bf,"%3X",i+16*palpage);
								ui_text(bitmap,bf,0,sy);
							}
						}

						for (i = 0;i < colors;i++)
						{
							struct rectangle bounds;
							bounds.min_x = uirotbounds.min_x + 3*uirotcharwidth + (uirotcharwidth*4/3)*(i % 16);
							bounds.min_y = uirotbounds.min_y + 2*uirotcharheight + (uirotcharheight)*(i / 16) + uirotcharheight;
							bounds.max_x = bounds.min_x + uirotcharwidth*4/3 - 1;
							bounds.max_y = bounds.min_y + uirotcharheight - 1;
							ui_rot2raw_rect(&bounds);
							fillbitmap(bitmap, colortable[i + 256*palpage], &bounds);
						}
					}
					else
						ui_text(bitmap,"N/A",3*uirotcharwidth,2*uirotcharheight);

					ui_text(bitmap,buf,0,0);
					changed = 0;
				}

				break;
			}
			case 1: /* characters */
			{
				int crotwidth = (Machine->ui_orientation & ORIENTATION_SWAP_XY) ? Machine->gfx[bank]->height : Machine->gfx[bank]->width;
				int crotheight = (Machine->ui_orientation & ORIENTATION_SWAP_XY) ? Machine->gfx[bank]->width : Machine->gfx[bank]->height;
				cpx = uirotwidth / crotwidth;
				cpy = (uirotheight - uirotcharheight) / crotheight;
				skip_chars = cpx * cpy;
				/*if (changed) -- temporary */
				{
					int flipx,flipy;
					int lastdrawn=0;

					erase_screen(bitmap);

					/* validity check after char bank change */
					if (firstdrawn >= Machine->gfx[bank]->total_elements)
					{
						firstdrawn = Machine->gfx[bank]->total_elements - skip_chars;
						if (firstdrawn < 0) firstdrawn = 0;
					}

					flipx = 0;
					flipy = 0;

					for (i = 0; i+firstdrawn < Machine->gfx[bank]->total_elements && i<cpx*cpy; i++)
					{
						struct rectangle bounds;
						bounds.min_x = (i % cpx) * crotwidth + uirotbounds.min_x;
						bounds.min_y = uirotcharheight + (i / cpx) * crotheight + uirotbounds.min_y;
						bounds.max_x = bounds.min_x + crotwidth - 1;
						bounds.max_y = bounds.min_y + crotheight - 1;
						ui_rot2raw_rect(&bounds);

						drawgfx(bitmap,Machine->gfx[bank],
								i+firstdrawn,color,  /*sprite num, color*/
								flipx,flipy,bounds.min_x,bounds.min_y,
								0,Machine->gfx[bank]->colortable ? TRANSPARENCY_NONE : TRANSPARENCY_NONE_RAW,0);

						lastdrawn = i+firstdrawn;
					}

					sprintf(buf,"GFXSET %d COLOR %2X CODE %X-%X",bank,color,firstdrawn,lastdrawn);
					ui_text(bitmap,buf,0,0);
					changed = 0;
				}

				break;
			}
			case 2: /* Tilemaps */
			{
				/*if (changed) -- temporary */
				{
					UINT32 tilemap_width, tilemap_height;
					tilemap_nb_size (bank, &tilemap_width, &tilemap_height);
					while (tilemap_xpos < 0)
						tilemap_xpos += tilemap_width;
					tilemap_xpos %= tilemap_width;

					while (tilemap_ypos < 0)
						tilemap_ypos += tilemap_height;
					tilemap_ypos %= tilemap_height;

					erase_screen(bitmap);
					tilemap_nb_draw (bitmap, bank, tilemap_xpos, tilemap_ypos);
					sprintf(buf, "TILEMAP %d (%dx%d)  X:%d  Y:%d", bank, tilemap_width, tilemap_height, tilemap_xpos, tilemap_ypos);
					ui_text(bitmap,buf,0,0);
					changed = 0;
					skip_tmap = 0;
				}
				break;
			}
		}

		update_video_and_audio();

		if (code_pressed(KEYCODE_LCONTROL) || code_pressed(KEYCODE_RCONTROL))
		{
			skip_chars = cpx;
			skip_tmap = 8;
		}
		if (code_pressed(KEYCODE_LSHIFT) || code_pressed(KEYCODE_RSHIFT))
		{
			skip_chars = 1;
			skip_tmap = 1;
		}


		if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
		{
			int next_bank, next_mode;
			int jumped;

			next_mode = mode;
			next_bank = bank+1;
			do {
				jumped = 0;
				switch (next_mode)
				{
					case 0:
						if (next_bank == 2 || Machine->drv->color_table_len == 0)
						{
							jumped = 1;
							next_mode++;
							next_bank = 0;
						}
						break;
					case 1:
						if (next_bank == MAX_GFX_ELEMENTS || !Machine->gfx[next_bank])
						{
							jumped = 1;
							next_mode++;
							next_bank = 0;
						}
						break;
					case 2:
						if (next_bank == tilemap_count())
							next_mode = -1;
						break;
				}
			}	while (jumped);
			if (next_mode != -1 )
			{
				bank = next_bank;
				mode = next_mode;
//				firstdrawn = 0;
				changed = 1;
			}
		}

		if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
		{
			int next_bank, next_mode;

			next_mode = mode;
			next_bank = bank-1;
			while(next_bank < 0 && next_mode >= 0)
			{
				next_mode = next_mode - 1;
				switch (next_mode)
				{
					case 0:
						if (Machine->drv->color_table_len == 0)
							next_bank = 0;
						else
							next_bank = 1;
						break;
					case 1:
						next_bank = MAX_GFX_ELEMENTS-1;
						while (next_bank >= 0 && !Machine->gfx[next_bank])
							next_bank--;
						break;
					case 2:
						next_bank = tilemap_count() - 1;
						break;
				}
			}
			if (next_mode != -1 )
			{
				bank = next_bank;
				mode = next_mode;
//				firstdrawn = 0;
				changed = 1;
			}
		}

		if (code_pressed_memory_repeat(KEYCODE_PGDN,4))
		{
			switch (mode)
			{
				case 0:
				{
					if (256 * (palpage + 1) < total_colors)
					{
						palpage++;
						changed = 1;
					}
					break;
				}
				case 1:
				{
					if (firstdrawn + skip_chars < Machine->gfx[bank]->total_elements)
					{
						firstdrawn += skip_chars;
						changed = 1;
					}
					break;
				}
				case 2:
				{
					if (skip_tmap)
						tilemap_ypos -= skip_tmap;
					else
						tilemap_ypos -= bitmap->height;
					changed = 1;
					break;
				}
			}
		}

		if (code_pressed_memory_repeat(KEYCODE_PGUP,4))
		{
			switch (mode)
			{
				case 0:
				{
					if (palpage > 0)
					{
						palpage--;
						changed = 1;
					}
					break;
				}
				case 1:
				{
					firstdrawn -= skip_chars;
					if (firstdrawn < 0) firstdrawn = 0;
					changed = 1;
					break;
				}
				case 2:
				{
					if (skip_tmap)
						tilemap_ypos += skip_tmap;
					else
						tilemap_ypos += bitmap->height;
					changed = 1;
					break;
				}
			}
		}

		if (code_pressed_memory_repeat(KEYCODE_D,4))
		{
			switch (mode)
			{
				case 2:
				{
					if (skip_tmap)
						tilemap_xpos -= skip_tmap;
					else
						tilemap_xpos -= bitmap->width;
					changed = 1;
					break;
				}
			}
		}

		if (code_pressed_memory_repeat(KEYCODE_G,4))
		{
			switch (mode)
			{
				case 2:
				{
					if (skip_tmap)
						tilemap_xpos += skip_tmap;
					else
						tilemap_xpos += bitmap->width;
					changed = 1;
					break;
				}
			}
		}

		if (input_ui_pressed_repeat(IPT_UI_UP,6))
		{
			switch (mode)
			{
				case 1:
				{
					if (color < Machine->gfx[bank]->total_colors - 1)
					{
						color++;
						changed = 1;
					}
					break;
				}
			}
		}

		if (input_ui_pressed_repeat(IPT_UI_DOWN,6))
		{
			switch (mode)
			{
				case 0:
					break;
				case 1:
				{
					if (color > 0)
					{
						color--;
						changed = 1;
					}
				}
			}
		}

		if (input_ui_pressed(IPT_UI_SNAPSHOT))
			osd_save_snapshot(bitmap, &Machine->visible_area);
	} while (!input_ui_pressed(IPT_UI_SHOW_GFX) &&
			!input_ui_pressed(IPT_UI_CANCEL));

	schedule_full_refresh();
}



static int setdipswitches(struct mame_bitmap *bitmap,int selected)
{
	const char *menu_item[128];
	const char *menu_subitem[128];
	struct InputPort *entry[128];
	char flag[40];
	int i,sel;
	struct InputPort *in;
	int total;
	int arrowize;


	sel = selected - 1;


	in = Machine->input_ports;

	total = 0;
	while (in->type != IPT_END)
	{
		if ((in->type & ~IPF_MASK) == IPT_DIPSWITCH_NAME && input_port_name(in) != 0 &&
				(in->type & IPF_UNUSED) == 0 &&
				!(!options.cheat && (in->type & IPF_CHEAT)))
		{
			entry[total] = in;
			menu_item[total] = input_port_name(in);

			total++;
		}

		in++;
	}

	if (total == 0)
	{
		char msg[80];

		strcpy(msg,"\t");
		strcat(msg,ui_getstring(UI_dipswitchmissing));
		strcat(msg,"\n\n\t");
		strcat(msg,ui_getstring (UI_lefthilight));
		strcat(msg," ");
		strcat(msg,ui_getstring (UI_returntomain));
		strcat(msg," ");
		strcat(msg,ui_getstring (UI_righthilight));
		ui_displaymessagewindow(bitmap,msg,ui_getstring(UI_dipswitches));

		if (input_ui_pressed(IPT_UI_SELECT))
			sel = -1;

		if (input_ui_pressed(IPT_UI_CANCEL))
			sel = -1;

		if (input_ui_pressed(IPT_UI_CONFIGURE))
			sel = -2;
	}
	else
	{
		menu_item[total] = ui_getstring (UI_returntomain);
		menu_item[total + 1] = 0;	/* terminate array */
		total++;

		for (i = 0;i < total;i++)
		{
			flag[i] = 0; /* TODO: flag the dip if it's not the real default */
			if (i < total - 1)
			{
				in = entry[i] + 1;
				while ((in->type & ~IPF_MASK) == IPT_DIPSWITCH_SETTING &&
						in->default_value != entry[i]->default_value)
					in++;

				if ((in->type & ~IPF_MASK) != IPT_DIPSWITCH_SETTING)
					menu_subitem[i] = ui_getstring (UI_INVALID);
				else menu_subitem[i] = input_port_name(in);
			}
			else menu_subitem[i] = 0;	/* no subitem */
		}

		arrowize = 0;
		if (sel < total - 1)
		{
			in = entry[sel] + 1;
			while ((in->type & ~IPF_MASK) == IPT_DIPSWITCH_SETTING &&
					in->default_value != entry[sel]->default_value)
				in++;

			if ((in->type & ~IPF_MASK) != IPT_DIPSWITCH_SETTING)
				/* invalid setting: revert to a valid one */
				arrowize |= 1;
			else
			{
				if (((in-1)->type & ~IPF_MASK) == IPT_DIPSWITCH_SETTING &&
						!(!options.cheat && ((in-1)->type & IPF_CHEAT)))
					arrowize |= 1;
			}
		}
		if (sel < total - 1)
		{
			in = entry[sel] + 1;
			while ((in->type & ~IPF_MASK) == IPT_DIPSWITCH_SETTING &&
					in->default_value != entry[sel]->default_value)
				in++;

			if ((in->type & ~IPF_MASK) != IPT_DIPSWITCH_SETTING)
				/* invalid setting: revert to a valid one */
				arrowize |= 2;
			else
			{
				if (((in+1)->type & ~IPF_MASK) == IPT_DIPSWITCH_SETTING &&
						!(!options.cheat && ((in+1)->type & IPF_CHEAT)))
					arrowize |= 2;
			}
		}

		ui_displaymenu(bitmap,menu_item,menu_subitem,flag,ui_getstring(UI_dipswitches),sel,arrowize);

		if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
			sel = (sel + 1) % total;

		if (input_ui_pressed_repeat(IPT_UI_UP,8))
			sel = (sel + total - 1) % total;

		if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
		{
			if (sel < total - 1)
			{
				in = entry[sel] + 1;
				while ((in->type & ~IPF_MASK) == IPT_DIPSWITCH_SETTING &&
						in->default_value != entry[sel]->default_value)
					in++;

				if ((in->type & ~IPF_MASK) != IPT_DIPSWITCH_SETTING)
					/* invalid setting: revert to a valid one */
					entry[sel]->default_value = (entry[sel]+1)->default_value & entry[sel]->mask;
				else
				{
					if (((in+1)->type & ~IPF_MASK) == IPT_DIPSWITCH_SETTING &&
							!(!options.cheat && ((in+1)->type & IPF_CHEAT)))
						entry[sel]->default_value = (in+1)->default_value & entry[sel]->mask;
				}

				/* tell updatescreen() to clean after us (in case the window changes size) */
				schedule_full_refresh();
			}
		}

		if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
		{
			if (sel < total - 1)
			{
				in = entry[sel] + 1;
				while ((in->type & ~IPF_MASK) == IPT_DIPSWITCH_SETTING &&
						in->default_value != entry[sel]->default_value)
					in++;

				if ((in->type & ~IPF_MASK) != IPT_DIPSWITCH_SETTING)
					/* invalid setting: revert to a valid one */
					entry[sel]->default_value = (entry[sel]+1)->default_value & entry[sel]->mask;
				else
				{
					if (((in-1)->type & ~IPF_MASK) == IPT_DIPSWITCH_SETTING &&
							!(!options.cheat && ((in-1)->type & IPF_CHEAT)))
						entry[sel]->default_value = (in-1)->default_value & entry[sel]->mask;
				}

				/* tell updatescreen() to clean after us (in case the window changes size) */
				schedule_full_refresh();
			}
		}

		if (input_ui_pressed(IPT_UI_SELECT))
		{
			if (sel == total - 1) sel = -1;
		}

		if (input_ui_pressed(IPT_UI_CANCEL))
			sel = -1;

		if (input_ui_pressed(IPT_UI_CONFIGURE))
			sel = -2;
	}

	if (sel == -1 || sel == -2)
	{
		schedule_full_refresh();
	}

	return sel + 1;
}

/* This flag is used for record OR sequence of key/joy */
/* when is !=0 the first sequence is record, otherwise the first free */
/* it's used byt setdefkeysettings, setdefjoysettings, setkeysettings, setjoysettings */
static int record_first_insert = 1;

static char menu_subitem_buffer[400][96];

static int setdefcodesettings(struct mame_bitmap *bitmap,int selected)
{
	const char *menu_item[400];
	const char *menu_subitem[400];
	struct ipd *entry[400];
	char flag[400];
	int i,sel,visible;
	struct ipd *in;
	int total;
	extern struct ipd inputport_defaults[];

	sel = selected - 1;
	visible = (uirotheight / ROWHEIGHT) - 3;


	if (Machine->input_ports == 0)
		return 0;

	in = inputport_defaults;

	total = 0;
	while (in->type != IPT_END)
	{
		if (in->name != 0  && (in->type & ~IPF_MASK) != IPT_UNKNOWN && (in->type & ~IPF_MASK) != IPT_OSD_RESERVED && (in->type & IPF_UNUSED) == 0
			&& !(!options.cheat && (in->type & IPF_CHEAT)))
		{
			entry[total] = in;
			menu_item[total] = in->name;

			total++;
		}

		in++;
	}

	if (total == 0) return 0;

	menu_item[total] = ui_getstring (UI_returntomain);
	menu_item[total + 1] = 0;	/* terminate array */
	total++;

	for (i = 0;i < total;i++)
	{
		if (i < total - 1)
		{
			seq_name(&entry[i]->seq,menu_subitem_buffer[i],sizeof(menu_subitem_buffer[0]));
			menu_subitem[i] = menu_subitem_buffer[i];
		} else
			menu_subitem[i] = 0;	/* no subitem */
		flag[i] = 0;
	}

	if (sel > SEL_MASK)   /* are we waiting for a new key? */
	{
		int ret;

		menu_subitem[sel & SEL_MASK] = "    ";
		ui_displaymenu(bitmap,menu_item,menu_subitem,flag,ui_getstring(UI_inputgeneral),sel & SEL_MASK,3);

		ret = seq_read_async(&entry[sel & SEL_MASK]->seq,record_first_insert);

		if (ret >= 0)
		{
			sel &= 0xff;

			if (ret > 0 || seq_get_1(&entry[sel]->seq) == CODE_NONE)
			{
				seq_set_1(&entry[sel]->seq,CODE_NONE);
				ret = 1;
			}

			/* tell updatescreen() to clean after us (in case the window changes size) */
			schedule_full_refresh();

			record_first_insert = ret != 0;
		}

		init_analog_seq();

		return sel + 1;
	}


	ui_displaymenu(bitmap,menu_item,menu_subitem,flag,ui_getstring(UI_inputgeneral),sel,0);

	if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
	{
		sel = (sel + 1) % total;
		record_first_insert = 1;
	}

	if (input_ui_pressed_repeat(IPT_UI_UP,8))
	{
		sel = (sel + total - 1) % total;
		record_first_insert = 1;
	}

	if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
	{
		sel -= visible;
		if (sel < 0)	sel = 0;
		record_first_insert = 1;
	}

	if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
	{
		sel += visible;
		if (sel >= total)	sel = total - 1;
		record_first_insert = 1;
	}

	if (input_ui_pressed(IPT_UI_SELECT))
	{
		if (sel == total - 1) sel = -1;
		else
		{
			seq_read_async_start();

			sel |= 1 << SEL_BITS;	/* we'll ask for a key */

			/* tell updatescreen() to clean after us (in case the window changes size) */
			schedule_full_refresh();
		}
	}

	if (input_ui_pressed(IPT_UI_CANCEL))
		sel = -1;

	if (input_ui_pressed(IPT_UI_CONFIGURE))
		sel = -2;

	if (sel == -1 || sel == -2)
	{
		/* tell updatescreen() to clean after us */
		schedule_full_refresh();

		record_first_insert = 1;
	}

	return sel + 1;
}



static int setcodesettings(struct mame_bitmap *bitmap,int selected)
{
	const char *menu_item[400];
	const char *menu_subitem[400];
	struct InputPort *entry[400];
	char flag[400];
	int i,sel,visible;
	struct InputPort *in;
	int total;


	sel = selected - 1;
	visible = (uirotheight / ROWHEIGHT) - 3;


	if (Machine->input_ports == 0)
		return 0;

	in = Machine->input_ports;

	total = 0;
	while (in->type != IPT_END)
	{
		if (input_port_name(in) != 0 && seq_get_1(&in->seq) != CODE_NONE && (in->type & ~IPF_MASK) != IPT_UNKNOWN && (in->type & ~IPF_MASK) != IPT_OSD_RESERVED)
		{
			entry[total] = in;
			menu_item[total] = input_port_name(in);

			total++;
		}

		in++;
	}

	if (total == 0) return 0;

	menu_item[total] = ui_getstring (UI_returntomain);
	menu_item[total + 1] = 0;	/* terminate array */
	total++;

	for (i = 0;i < total;i++)
	{
		if (i < total - 1)
		{
			seq_name(input_port_seq(entry[i]),menu_subitem_buffer[i],sizeof(menu_subitem_buffer[0]));
			menu_subitem[i] = menu_subitem_buffer[i];

			/* If the key isn't the default, flag it */
			if (seq_get_1(&entry[i]->seq) != CODE_DEFAULT)
				flag[i] = 1;
			else
				flag[i] = 0;

		} else
			menu_subitem[i] = 0;	/* no subitem */
	}

	if (sel > SEL_MASK)   /* are we waiting for a new key? */
	{
		int ret;

		menu_subitem[sel & SEL_MASK] = "    ";
		ui_displaymenu(bitmap,menu_item,menu_subitem,flag,ui_getstring(UI_inputspecific),sel & SEL_MASK,3);

		ret = seq_read_async(&entry[sel & SEL_MASK]->seq,record_first_insert);

		if (ret >= 0)
		{
			sel &= 0xff;

			if (ret > 0 || seq_get_1(&entry[sel]->seq) == CODE_NONE)
			{
				seq_set_1(&entry[sel]->seq, CODE_DEFAULT);
				ret = 1;
			}

			/* tell updatescreen() to clean after us (in case the window changes size) */
			schedule_full_refresh();

			record_first_insert = ret != 0;
		}

		init_analog_seq();

		return sel + 1;
	}


	ui_displaymenu(bitmap,menu_item,menu_subitem,flag,ui_getstring(UI_inputspecific),sel,0);

	if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
	{
		sel = (sel + 1) % total;
		record_first_insert = 1;
	}

	if (input_ui_pressed_repeat(IPT_UI_UP,8))
	{
		sel = (sel + total - 1) % total;
		record_first_insert = 1;
	}

	if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
	{
		sel -= visible;
		if (sel < 0)	sel = 0;
		record_first_insert = 1;
	}

	if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
	{
		sel += visible;
		if (sel >= total)	sel = total - 1;
		record_first_insert = 1;
	}

	if (input_ui_pressed(IPT_UI_SELECT))
	{
		if (sel == total - 1) sel = -1;
		else
		{
			seq_read_async_start();

			sel |= 1 << SEL_BITS;	/* we'll ask for a key */

			/* tell updatescreen() to clean after us (in case the window changes size) */
			schedule_full_refresh();
		}
	}

	if (input_ui_pressed(IPT_UI_CANCEL))
		sel = -1;

	if (input_ui_pressed(IPT_UI_CONFIGURE))
		sel = -2;

	if (sel == -1 || sel == -2)
	{
		schedule_full_refresh();

		record_first_insert = 1;
	}

	return sel + 1;
}


static int setcustombutton(struct mame_bitmap *bitmap, int selected)
{
	const char *menu_item[10];
	const char *menu_subitem[10];
	int i, j, n, player, button, sel, val;
	int total, num;
	char buf[8][32], buf2[8][32];
	extern UINT16 custom_button[2][4];
	extern int button_number;

	sel = selected - 1;

	total = 0;
	for (player = 0; player < 2; player++)
	{
		for (button = 0; button < 4; button++)
		{
			i = player * 4 + button;
			val = custom_button[player][button];

			sprintf(buf[i], "P%d %s%d", player + 1, ui_getstring(UI_custombutton), button + 1);

			if (val == 0)
				sprintf(buf2[i], "%s", ui_getstring(UI_custombutton_notuse));
			else
			{
				num = 0;
				n = 1;
				for (j = 0; j < button_number; j++)
				{
					if (val & n)
					{
						if (num)
						{
							buf2[i][num++] = (char)0x81;
							buf2[i][num++] = (char)0xc4;
						}

						buf2[i][num++] = (char)0x81;
						if (Machine->gamedrv->system == SYSTEM_NEOGEO)
							buf2[i][num++] = (char)(0xc0 + j);
						else
							buf2[i][num++] = (char)(0xe9 + j);

						buf2[i][num] = '\0';
					}
					n <<= 1;
				}
			}

			menu_item[i] = buf[i];
			menu_subitem[i] = buf2[i];

			total++;
		}
	}

	menu_item[total] = ui_getstring(UI_returntomain);
	menu_subitem[total]  = 0;
	menu_item[total + 1] = 0;	/* terminate array */
	total++;

	ui_displaymenu(bitmap, menu_item,menu_subitem,0,ui_getstring(UI_custombuttons),sel,0);

	if (input_ui_pressed_repeat(IPT_UI_DOWN,4))
		sel = (sel + 1) % total;

	if (input_ui_pressed_repeat(IPT_UI_UP,4))
		sel = (sel + total - 1) % total;

	player = sel / 4;
	button = sel % 4;

	if (sel != total - 1)
	{
		if (code_pressed_memory(KEYCODE_1) && button_number > 0)
			custom_button[player][button] ^= 0x01;

		if (code_pressed_memory(KEYCODE_2) && button_number > 1)
			custom_button[player][button] ^= 0x02;

		if (code_pressed_memory(KEYCODE_3) && button_number > 2)
			custom_button[player][button] ^= 0x04;

		if (code_pressed_memory(KEYCODE_4) && button_number > 3)
			custom_button[player][button] ^= 0x08;

		if (code_pressed_memory(KEYCODE_5) && button_number > 4)
			custom_button[player][button] ^= 0x10;

		if (code_pressed_memory(KEYCODE_6) && button_number > 5)
			custom_button[player][button] ^= 0x20;
	}

	if (input_ui_pressed(IPT_UI_SELECT))
		if (sel == total - 1)
			sel = -1;

	if (input_ui_pressed(IPT_UI_CANCEL))
		sel = -1;

	if (input_ui_pressed(IPT_UI_CONFIGURE))
		sel = -2;

	if (sel == -1 || sel == -2)
	{
		schedule_full_refresh();
	}

	return sel + 1;
}


static int setautofiresettings(struct mame_bitmap *bitmap,int selected)
{
	const char *menu_item[400];
	const char *menu_subitem[400];
	struct InputPort *entry[400];
	struct InputPort *in;
	char flag[400];
	char delay[4];
	int sel;
	int total;
	int autofire_delay;
	int value = 0;
	int changed = 0;

	sel = selected - 1;

	if (sel < 0) sel = 0;

	total = 0;

	if (Machine->input_ports)
	{
		in = Machine->input_ports;

		while (in->type != IPT_END)
		{
			if (input_port_name(in)
			&&  (in->type & ~IPF_MASK) > IPT_PORT
			&&  (in->type & ~IPF_MASK) < IPT_ANALOG_START)
			{
				int v;

				entry[total] = in;

				v = (in->type & IPF_AUTOFIRE_MASK) >> IPF_AUTOFIRE_SHIFT;
				menu_item[total] = input_port_name(in);
				menu_subitem[total] = ui_getstring(UI_autofireoff + v);
				if (v)
					flag[total] = 1;
				else
					flag[total] = 0;
				if (total == sel)
					value = v;
				total++;
			}
			in++;
		}
	}

	if (total == 0)
		return 0;

	sprintf(delay, "%d", options.autofiredelay);
	autofire_delay = total;

	menu_item[total] = ui_getstring (UI_autofiredelay);
	menu_subitem[total] = delay;
	if (options.autofiredelay > 1)
		flag[total++] = 1;
	else
		flag[total++] = 0;
	menu_item[total] = ui_getstring (UI_returntomain);
	menu_subitem[total++] = 0;
	menu_item[total] = 0;

	ui_displaymenu(bitmap,menu_item,menu_subitem,flag,ui_getstring(UI_autofire),sel,0);

	if (sel == autofire_delay)
	{
		if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
		{
			options.autofiredelay++;
			if (options.autofiredelay > 99)
				options.autofiredelay = 99;
			changed = 1;
		}
		if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
		{
			options.autofiredelay--;
			if (options.autofiredelay < 1)
				options.autofiredelay = 1;
			changed = 1;
		}
	}
	else if (sel < autofire_delay)
	{
		UINT32 type = entry[sel]->type & ~IPF_AUTOFIRE_MASK;

		if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
		{
			if (++value > 2) value = 0;
			changed = 1;
		}
		if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
		{
			if (--value < 0) value = 2;
			changed = 1;
		}
		entry[sel]->type = type | (value << IPF_AUTOFIRE_SHIFT);
	}

	if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
		sel = (sel + 1) % total;

	if (input_ui_pressed_repeat(IPT_UI_UP,8))
		sel = (sel + total - 1) % total;

	if (input_ui_pressed(IPT_UI_SELECT))
	{
		if (sel == total - 1) sel = -1;
		else sel = 0;
	}

	if (input_ui_pressed(IPT_UI_CANCEL))
 		sel = -1;

	if (input_ui_pressed(IPT_UI_CONFIGURE))
		sel = -2;

	if (sel == -1 || sel == -2 || changed)
		schedule_full_refresh();

	return sel + 1;
}


static int settraksettings(struct mame_bitmap *bitmap,int selected)
{
	const char *menu_item[40];
	const char *menu_subitem[40];
	struct InputPort *entry[40];
	int i,sel;
	struct InputPort *in;
	int total,total2;
	int arrowize;


	sel = selected - 1;


	if (Machine->input_ports == 0)
		return 0;

	in = Machine->input_ports;

	/* Count the total number of analog controls */
	total = 0;
	while (in->type != IPT_END)
	{
		if (((in->type & 0xff) > IPT_ANALOG_START) && ((in->type & 0xff) < IPT_ANALOG_END)
				&& !(!options.cheat && (in->type & IPF_CHEAT)))
		{
			entry[total] = in;
			total++;
		}
		in++;
	}

	if (total == 0) return 0;

	/* Each analog control has 3 entries - key & joy delta, reverse, sensitivity */

#define ENTRIES 3

	total2 = total * ENTRIES;

	menu_item[total2] = ui_getstring (UI_returntomain);
	menu_item[total2 + 1] = 0;	/* terminate array */
	total2++;

	arrowize = 0;
	for (i = 0;i < total2;i++)
	{
		if (i < total2 - 1)
		{
			char label[30][40];
			char setting[30][40];
			int sensitivity,delta;
			int reverse;

			strcpy (label[i], input_port_name(entry[i/ENTRIES]));
			sensitivity = IP_GET_SENSITIVITY(entry[i/ENTRIES]);
			delta = IP_GET_DELTA(entry[i/ENTRIES]);
			reverse = (entry[i/ENTRIES]->type & IPF_REVERSE);

			strcat (label[i], " ");
			switch (i%ENTRIES)
			{
				case 0:
					strcat (label[i], ui_getstring (UI_keyjoyspeed));
					sprintf(setting[i],"%d",delta);
					if (i == sel) arrowize = 3;
					break;
				case 1:
					strcat (label[i], ui_getstring (UI_reverse));
					if (reverse)
						sprintf(setting[i],ui_getstring (UI_on));
					else
						sprintf(setting[i],ui_getstring (UI_off));
					if (i == sel) arrowize = 3;
					break;
				case 2:
					strcat (label[i], ui_getstring (UI_sensitivity));
					sprintf(setting[i],"%3d%%",sensitivity);
					if (i == sel) arrowize = 3;
					break;
			}

			menu_item[i] = label[i];
			menu_subitem[i] = setting[i];

			in++;
		}
		else menu_subitem[i] = 0;	/* no subitem */
	}

	ui_displaymenu(bitmap,menu_item,menu_subitem,0,ui_getstring(UI_analogcontrols),sel,arrowize);

	if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
		sel = (sel + 1) % total2;

	if (input_ui_pressed_repeat(IPT_UI_UP,8))
		sel = (sel + total2 - 1) % total2;

	if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
	{
		if(sel != total2 - 1)
		{
			if ((sel % ENTRIES) == 0)
			/* keyboard/joystick delta */
			{
				int val = IP_GET_DELTA(entry[sel/ENTRIES]);

				val --;
				if (val < 1) val = 1;
				IP_SET_DELTA(entry[sel/ENTRIES],val);
			}
			else if ((sel % ENTRIES) == 1)
			/* reverse */
			{
				int reverse = entry[sel/ENTRIES]->type & IPF_REVERSE;
				if (reverse)
					reverse=0;
				else
					reverse=IPF_REVERSE;
				entry[sel/ENTRIES]->type &= ~IPF_REVERSE;
				entry[sel/ENTRIES]->type |= reverse;
			}
			else if ((sel % ENTRIES) == 2)
			/* sensitivity */
			{
				int val = IP_GET_SENSITIVITY(entry[sel/ENTRIES]);

				val --;
				if (val < 1) val = 1;
				IP_SET_SENSITIVITY(entry[sel/ENTRIES],val);
			}
		}
	}

	if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
	{
		if(sel != total2 - 1)
		{
			if ((sel % ENTRIES) == 0)
			/* keyboard/joystick delta */
			{
				int val = IP_GET_DELTA(entry[sel/ENTRIES]);

				val ++;
				if (val > 255) val = 255;
				IP_SET_DELTA(entry[sel/ENTRIES],val);
			}
			else if ((sel % ENTRIES) == 1)
			/* reverse */
			{
				int reverse = entry[sel/ENTRIES]->type & IPF_REVERSE;
				if (reverse)
					reverse=0;
				else
					reverse=IPF_REVERSE;
				entry[sel/ENTRIES]->type &= ~IPF_REVERSE;
				entry[sel/ENTRIES]->type |= reverse;
			}
			else if ((sel % ENTRIES) == 2)
			/* sensitivity */
			{
				int val = IP_GET_SENSITIVITY(entry[sel/ENTRIES]);

				val ++;
				if (val > 255) val = 255;
				IP_SET_SENSITIVITY(entry[sel/ENTRIES],val);
			}
		}
	}

	if (input_ui_pressed(IPT_UI_SELECT))
	{
		if (sel == total2 - 1) sel = -1;
	}

	if (input_ui_pressed(IPT_UI_CANCEL))
		sel = -1;

	if (input_ui_pressed(IPT_UI_CONFIGURE))
		sel = -2;

	if (sel == -1 || sel == -2)
	{
		schedule_full_refresh();
	}

	return sel + 1;
}

static int mame_stats(struct mame_bitmap *bitmap,int selected)
{
	char temp[10];
	char buf[2048];
	int sel, i;


	sel = selected - 1;

	buf[0] = 0;

	if (dispensed_tickets)
	{
		strcat(buf, ui_getstring (UI_tickets));
		strcat(buf, ": ");
		sprintf(temp, "%d\n\n", dispensed_tickets);
		strcat(buf, temp);
	}

	for (i=0; i<COIN_COUNTERS; i++)
	{
		strcat(buf, ui_getstring (UI_coin));
		sprintf(temp, " %c: ", i+'A');
		strcat(buf, temp);
		if (!coins[i])
			strcat (buf, ui_getstring (UI_NA));
		else
		{
			sprintf (temp, "%d", coins[i]);
			strcat (buf, temp);
		}
		if (coinlockedout[i])
		{
			strcat(buf, " ");
			strcat(buf, ui_getstring (UI_locked));
			strcat(buf, "\n");
		}
		else
		{
			strcat(buf, "\n");
		}
	}

	{
		int res;

		/* menu system, use the normal menu keys */
		strcat(buf,"\n\t");
		strcat(buf,ui_getstring (UI_lefthilight));
		strcat(buf," ");
		strcat(buf,ui_getstring (UI_returntomain));
		strcat(buf," ");
		strcat(buf,ui_getstring (UI_righthilight));

		res = ui_displaymessagewindow(bitmap,buf,ui_getstring(UI_bookkeeping));
		if (res != -1)
		{
			if (res == 1 || input_ui_pressed(IPT_UI_SELECT))
				sel = -1;

			if (res == 2 || input_ui_pressed(IPT_UI_CANCEL))
				sel = -1;

			if (res == 3 || input_ui_pressed(IPT_UI_CONFIGURE))
				sel = -2;
		}
	}

	if (sel == -1 || sel == -2)
	{
		scroll_reset = 1;
		schedule_full_refresh();
	}

	return sel + 1;
}

int showcopyright(struct mame_bitmap *bitmap)
{
	int done, res;
	char buf[1000];
	char buf2[256];

	strcpy (buf, ui_getstring(UI_copyright1));
	strcat (buf, "\n\n");
#ifdef BUILD_ENGLISH
	sprintf(buf2, ui_getstring(UI_copyright2), Machine->gamedrv->description);
#else
	sprintf(buf2, ui_getstring(UI_copyright2), GetDescriptionByName(Machine->gamedrv->name, options.use_japaneselist));
#endif
	strcat (buf, buf2);
	strcat (buf, "\n\n");
	strcat (buf, ui_getstring(UI_copyright3));

	setup_selected = -1;////
	done = 0;

	do
	{
		erase_screen(bitmap);
		res = ui_displaymessagewindow(bitmap,buf,ui_getstring(UI_copyright));

		update_video_and_audio();
		if (res != -1)
		{
			if (res == 2 || input_ui_pressed(IPT_UI_CANCEL))
			{
				setup_selected = 0;////
				return 1;
			}
			if (keyboard_pressed_memory(KEYCODE_O) ||
					input_ui_pressed(IPT_UI_LEFT))
				done = 1;
			if (done == 1 && (keyboard_pressed_memory(KEYCODE_K) ||
					input_ui_pressed(IPT_UI_RIGHT)))
				done = 2;
		}
	} while (done < 2);

	scroll_reset = 1;

	setup_selected = 0;////
	erase_screen(bitmap);
	update_video_and_audio();

	return 0;
}

static int displaygameinfo(struct mame_bitmap *bitmap,int selected)
{
	int i, res;
	char buf[2048];
	char buf2[64];
	int sel;


	if (options.jukebox)
		return -1;

	sel = selected - 1;


#ifdef BUILD_ENGLISH
	sprintf(buf,"%s\n%s %s\n\n%s:\n",Machine->gamedrv->description,Machine->gamedrv->year,Machine->gamedrv->manufacturer,
		ui_getstring (UI_cpu));
#else
	sprintf(buf,"%s\n%s %s\n\n%s:\n",GetDescriptionByName(Machine->gamedrv->name, options.use_japaneselist),Machine->gamedrv->year,Machine->gamedrv->manufacturer,
		ui_getstring (UI_cpu));
#endif
	i = 0;
	while (i < MAX_CPU && Machine->drv->cpu[i].cpu_type)
	{

		if (Machine->drv->cpu[i].cpu_clock >= 1000000)
			sprintf(&buf[strlen(buf)],"%s %d.%06d MHz",
					cputype_name(Machine->drv->cpu[i].cpu_type),
					Machine->drv->cpu[i].cpu_clock / 1000000,
					Machine->drv->cpu[i].cpu_clock % 1000000);
		else
			sprintf(&buf[strlen(buf)],"%s %d.%03d kHz",
					cputype_name(Machine->drv->cpu[i].cpu_type),
					Machine->drv->cpu[i].cpu_clock / 1000,
					Machine->drv->cpu[i].cpu_clock % 1000);

		if (Machine->drv->cpu[i].cpu_type & CPU_AUDIO_CPU)
		{
			sprintf (buf2, " (%s)", ui_getstring (UI_sound_lc));
			strcat(buf, buf2);
		}

		strcat(buf,"\n");

		i++;
	}

	sprintf (buf2, "\n%s", ui_getstring (UI_sound));
	strcat (buf, buf2);
	if (Machine->drv->sound_attributes & SOUND_SUPPORTS_STEREO)
		sprintf(&buf[strlen(buf)]," (%s)", ui_getstring (UI_stereo));
	strcat(buf,":\n");

	i = 0;
	while (i < MAX_SOUND && Machine->drv->sound[i].sound_type)
	{
		if (sound_num(&Machine->drv->sound[i]))
			sprintf(&buf[strlen(buf)],"%dx",sound_num(&Machine->drv->sound[i]));

		sprintf(&buf[strlen(buf)],"%s",sound_name(&Machine->drv->sound[i]));

		if (sound_clock(&Machine->drv->sound[i]))
		{
			if (sound_clock(&Machine->drv->sound[i]) >= 1000000)
				sprintf(&buf[strlen(buf)]," %d.%06d MHz",
						sound_clock(&Machine->drv->sound[i]) / 1000000,
						sound_clock(&Machine->drv->sound[i]) % 1000000);
			else
				sprintf(&buf[strlen(buf)]," %d.%03d kHz",
						sound_clock(&Machine->drv->sound[i]) / 1000,
						sound_clock(&Machine->drv->sound[i]) % 1000);
		}

		strcat(buf,"\n");

		i++;
	}

	sprintf(&buf[strlen(buf)],"\n%s:\n", ui_getstring (UI_screenres));
	sprintf(&buf[strlen(buf)],"%d x %d (%s) %f Hz\n",
			Machine->visible_area.max_x - Machine->visible_area.min_x + 1,
			Machine->visible_area.max_y - Machine->visible_area.min_y + 1,
			(Machine->gamedrv->flags & ORIENTATION_SWAP_XY) ? "V" : "H",
			Machine->drv->frames_per_second);
#if 0
		{
			int pixelx,pixely,tmax,tmin,rem;

			pixelx = 4 * (Machine->visible_area.max_y - Machine->visible_area.min_y + 1);
			pixely = 3 * (Machine->visible_area.max_x - Machine->visible_area.min_x + 1);

			/* calculate MCD */
			if (pixelx >= pixely)
			{
				tmax = pixelx;
				tmin = pixely;
			}
			else
			{
				tmax = pixely;
				tmin = pixelx;
			}
			while ( (rem = tmax % tmin) )
			{
				tmax = tmin;
				tmin = rem;
			}
			/* tmin is now the MCD */

			pixelx /= tmin;
			pixely /= tmin;

			sprintf(&buf[strlen(buf)],"pixel aspect ratio %d:%d\n",
					pixelx,pixely);
		}
		sprintf(&buf[strlen(buf)],"%d colors ",Machine->drv->total_colors);
#endif


	if (sel == -1)
	{
		/* startup info, print MAME version and ask for any key */

		sprintf (buf2, "\n\t%s ", ui_getstring (UI_mame));	/* \t means that the line will be centered */
		strcat(buf, buf2);

		strcat(buf,build_version);
		sprintf(buf2, "\n\t%s", ui_getstring(UI_selectkey));
		strcat(buf,buf2);
		sel = 0;

		res = ui_displaymessagewindow(bitmap,buf,ui_getstring(UI_gameinfo));
		if (res >= 0)
		{
			if (res == 1 || input_ui_pressed(IPT_UI_SELECT))
				sel = -1;

			if (res == 2 || input_ui_pressed(IPT_UI_CANCEL))
				sel = -1;

			if (res == 3 || input_ui_pressed(IPT_UI_CONFIGURE))
				sel = -2;
		}
	}
	else
	{
		/* menu system, use the normal menu keys */
		strcat(buf,"\n\t");
		strcat(buf,ui_getstring (UI_lefthilight));
		strcat(buf," ");
		strcat(buf,ui_getstring (UI_returntomain));
		strcat(buf," ");
		strcat(buf,ui_getstring (UI_righthilight));

		res = ui_displaymessagewindow(bitmap,buf,ui_getstring(UI_gameinfo));
		if (res >= 0)
		{
			if (res == 1 || input_ui_pressed(IPT_UI_SELECT))
				sel = -1;

			if (res == 2 || input_ui_pressed(IPT_UI_CANCEL))
				sel = -1;

			if (res == 3 || input_ui_pressed(IPT_UI_CONFIGURE))
				sel = -2;
		}
	}

	if (sel == -1 || sel == -2)
	{
		scroll_reset = 1;
		schedule_full_refresh();
	}

	return sel + 1;
}


int showgamewarnings(struct mame_bitmap *bitmap)
{
	int i;
	char buf[2048];

	if (Machine->gamedrv->flags &
			(GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_WRONG_COLORS | GAME_IMPERFECT_COLORS |
			  GAME_NO_SOUND | GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS | GAME_NO_COCKTAIL))
	{
		int done, res;

		strcpy(buf, ui_getstring (UI_knownproblems));
		strcat(buf, "\n\n");

		if (Machine->gamedrv->flags & GAME_IMPERFECT_COLORS)
		{
			strcat(buf, ui_getstring (UI_imperfectcolors));
			strcat(buf, "\n");
		}

		if (Machine->gamedrv->flags & GAME_WRONG_COLORS)
		{
			strcat(buf, ui_getstring (UI_wrongcolors));
			strcat(buf, "\n");
		}

		if (Machine->gamedrv->flags & GAME_IMPERFECT_GRAPHICS)
		{
			strcat(buf, ui_getstring (UI_imperfectgraphics));
			strcat(buf, "\n");
		}

		if (Machine->gamedrv->flags & GAME_IMPERFECT_SOUND)
		{
			strcat(buf, ui_getstring (UI_imperfectsound));
			strcat(buf, "\n");
		}

		if (Machine->gamedrv->flags & GAME_NO_SOUND)
		{
			strcat(buf, ui_getstring (UI_nosound));
			strcat(buf, "\n");
		}

		if (Machine->gamedrv->flags & GAME_NO_COCKTAIL)
		{
			strcat(buf, ui_getstring (UI_nococktail));
			strcat(buf, "\n");
		}

		if (Machine->gamedrv->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION))
		{
			const struct GameDriver *maindrv;
			int foundworking;

			if (Machine->gamedrv->flags & GAME_NOT_WORKING)
			{
				strcpy(buf, ui_getstring (UI_brokengame));
				strcat(buf, "\n");
			}
			if (Machine->gamedrv->flags & GAME_UNEMULATED_PROTECTION)
			{
				strcat(buf, ui_getstring (UI_brokenprotection));
				strcat(buf, "\n");
			}

			if (Machine->gamedrv->clone_of && !(Machine->gamedrv->clone_of->flags & NOT_A_DRIVER))
				maindrv = Machine->gamedrv->clone_of;
			else maindrv = Machine->gamedrv;

			foundworking = 0;
			i = 0;
			while (drivers[i])
			{
				if (drivers[i] == maindrv || drivers[i]->clone_of == maindrv)
				{
					if ((drivers[i]->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION)) == 0)
					{
						if (foundworking == 0)
						{
							strcat(buf,"\n\n");
							strcat(buf, ui_getstring (UI_workingclones));
							strcat(buf,"\n\n");
						}
						foundworking = 1;

						sprintf(&buf[strlen(buf)],"%s\n",drivers[i]->name);
					}
				}
				i++;
			}
		}

		strcat(buf,"\n\n");
		strcat(buf,ui_getstring (UI_typeok));

		done = 0;
		res = 0;
		do
		{
			erase_screen(bitmap);
			res = ui_displaymessagewindow(bitmap,buf,0);

			update_video_and_audio();
			if (res == 2) // canceled
			{
				return 1;
			}
			else if (res >= 0)
			{
				if (code_pressed_memory(KEYCODE_O)
				||  input_ui_pressed(IPT_UI_LEFT))
					done = 1;
				if (done == 1 && (code_pressed_memory(KEYCODE_K)
				||  input_ui_pressed(IPT_UI_RIGHT)))
					done = 2;
			}
		} while (done < 2);
	}


	erase_screen(bitmap);

	/* clear the input memory */
	while (code_read_async() != CODE_NONE) {};

	while (displaygameinfo(bitmap,0) == 1)
	{
		update_video_and_audio();
	}

	erase_screen(bitmap);
	/* make sure that the screen is really cleared, in case autoframeskip kicked in */
	update_video_and_audio();
	update_video_and_audio();
	update_video_and_audio();
	update_video_and_audio();

	return 0;
}

/* Word-wraps the text in the specified buffer to fit in maxwidth characters per line.
   The contents of the buffer are modified.
   Known limitations: Words longer than maxwidth cause the function to fail. */
static int wordwrap_text_buffer(char *buffer, int maxcols)
{
	char *c, *c2;
	char textcopy[8192+256];
	unsigned short code;
	int i, increment, wrapped;
	int len, maxlen;

	/* copy text, calculate max len, wrap long lines to fit */
	len    = 0;
	maxlen = 0;
	c = buffer;
	c2 = textcopy;
	memset(textcopy, 0, 8192+256);

	while (*c)
	{
		wrapped = 0;
		increment = uifont_decodechar((unsigned char *)c, &code);

		if (*c == '\n')
		{
			*c2++ = *c++;
			wrapped = 1;
		}
		else if (*c == ' ')
		{
			if (len != 0)
			{
				int nextlen = 0;
				char *nc;

				nc = c + 1;
				while (*nc && *nc != ' ' && *nc != '\n')
				{
					nextlen++;
					nc++;
				}

				/* word wrap */
				if (len + nextlen + 1 >= maxcols)
				{
					c++;
					*c2++ = '\n';
					wrapped = 1;
				}
				else
				{
					*c2++ = *c++;
					len++;
				}
			}
			else
			{
				*c2++ = *c++;
				len++;
			}
		}
		else
		{
			i = (code < 256) ? 1 : 2;

			if (len + i >= maxcols)
			{
				*c2++ = '\n';
				wrapped = 1;
			}
			else
			{
				len += i;

				while (increment)
				{
					*c2++ = *c++;
					increment--;
				}
			}
		}

		if (len > maxlen)
			maxlen = len;

		if (wrapped)
			len = 0;
	}

	*c2 = '\0';

	maxlen++;

	strcpy(buffer, textcopy);

	return maxlen;
}

static int count_lines_in_buffer (char *buffer)
{
	int lines = 0;
	char c;

	while ( (c = *buffer++) )
		if (c == '\n') lines++;

	return lines;
}

/* Display lines from buffer, starting with line 'scroll', in a width x height text window */
static int display_scroll_message (struct mame_bitmap *bitmap, int *scroll, int width, int height, char *buf, const char *title)
{
	struct DisplayText dt[256];
	int curr_dt = 0;
	const char *uparrow = ui_getstring (UI_uparrow);
	const char *downarrow = ui_getstring (UI_downarrow);
	char textcopy[8192];
	char *copy;
	int leftoffs,topoffs;
	int first = *scroll;
	int buflines,showlines;
	int i, ret;


	/* draw box */
	leftoffs = (uirotwidth - uirotcharwidth * width) / 2;
	if (leftoffs < 0) leftoffs = 0;
	if (title)
	{
		topoffs = (uirotheight - (height + 1) * ROWHEIGHT) / 2;
		ui_drawbox(bitmap,leftoffs,topoffs-BOXADJUST,width*uirotcharwidth,(height+1)*ROWHEIGHT+BOXADJUST*2,1);
	}
	else
	{
		topoffs = (uirotheight - height * ROWHEIGHT) / 2;
		ui_drawbox(bitmap,leftoffs,topoffs-BOXADJUST,width*uirotcharwidth,height*ROWHEIGHT+BOXADJUST*2,1);
	}

	if (title)
	{
		ui_plotbox(bitmap, leftoffs + 1, topoffs + ROWHEIGHT - 4, width * uirotcharwidth - 2, 1, SYSTEM_COLOR_FRAMEMEDIUM);
		ui_plotbox(bitmap, leftoffs + 1, topoffs + ROWHEIGHT - 3, width * uirotcharwidth - 3, 1, SYSTEM_COLOR_FRAMEDARK);

		for (i = 0; i < GRADATION_LEVEL; i++)
			ui_plotbox(bitmap, leftoffs + 1 + (int)(i * (width * uirotcharwidth - 2) / GRADATION_LEVEL), topoffs - 5,
							   (int)((width * uirotcharwidth - 2) / GRADATION_LEVEL) + 1, ROWHEIGHT + 1, MAX_COLORTABLE + i);

		dt[0].text = title;
		dt[0].color = UI_COLOR_BOLD;
		dt[0].x = leftoffs + 4;
		dt[0].y = topoffs - BOXADJUST + 3;

		dt[1].text = 0;	/* terminate array */

		displaytext(bitmap,dt);

		topoffs += ROWHEIGHT;
	}

	buflines = count_lines_in_buffer (buf);
	if (first > 0)
	{
		if (buflines <= height)
			first = 0;
		else
		{
			height--;
			if (first > (buflines - height))
				first = buflines - height;
		}
		*scroll = first;
	}

	if (first != 0)
	{
		/* indicate that scrolling upward is possible */
		dt[curr_dt].text = uparrow;
		dt[curr_dt].color = UI_COLOR_NORMAL;
		dt[curr_dt].x = (uirotwidth - uirotcharwidth * uaw) / 2;
		dt[curr_dt].y = topoffs + curr_dt * ROWHEIGHT + 1;
		curr_dt++;
	}

	if ((buflines - first) > height)
		showlines = height - 1;
	else
		showlines = height;

	ret = buflines;

	if (first)
		ret |= SCR_PREV_PAGE;

	if (showlines == (height - 1))
		ret |= SCR_NEXT_PAGE;

	/* skip to first line */
	while (first > 0)
	{
		char c;

		while ( (c = *buf++) )
		{
			if (c == '\n')
			{
				first--;
				break;
			}
		}
	}

	/* copy 'showlines' lines from buffer, starting with line 'first' */
	copy = textcopy;
	for (i = 0; i < showlines; i++)
	{
		char *copystart = copy;

		while (*buf && *buf != '\n')
		{
			*copy = *buf;
			copy++;
			buf++;
		}
		*copy = '\0';
		copy++;
		if (*buf == '\n')
			buf++;

		if (*copystart == '\t') /* center text */
		{
			copystart++;
			dt[curr_dt].x = (uirotwidth - uirotcharwidth * (copy - copystart)) / 2;
		}
		else
			dt[curr_dt].x = leftoffs + uirotcharwidth/2 + 1;

		dt[curr_dt].text = copystart;
		dt[curr_dt].color = UI_COLOR_NORMAL;
		dt[curr_dt].y = topoffs + curr_dt*ROWHEIGHT + 1;
		curr_dt++;
	}

	if (showlines == (height - 1))
	{
		/* indicate that scrolling downward is possible */
		dt[curr_dt].text = downarrow;
		dt[curr_dt].color = UI_COLOR_NORMAL;
		dt[curr_dt].x = (uirotwidth - uirotcharwidth * daw) / 2;
		dt[curr_dt].y = topoffs + curr_dt*ROWHEIGHT + 1;
		curr_dt++;
	}

	dt[curr_dt].text = 0;	/* terminate array */

	displaytext(bitmap,dt);

	return ret;
}


/* Display text entry for current driver from history.dat and mameinfo.dat. */
static int displayhistory (struct mame_bitmap *bitmap, int selected)
{
	static int scroll = 0;
	static char *buf = 0;
	int maxcols,maxrows,maxlen;
	static int lines = 0;
	int sel;


	sel = selected - 1;


	maxcols = (uirotwidth / uirotcharwidth) - 2;
	maxrows = (uirotheight / ROWHEIGHT) - 2;

	if (!buf)
	{
		/* allocate a buffer for the text */
		buf = malloc (8192);
		if (buf)
		{
			/* try to load entry */
			if (load_driver_history (Machine->gamedrv, buf, 8192) == 0)
			{
				scroll = 0;
				maxlen = wordwrap_text_buffer(buf, maxcols);
				lines  = count_lines_in_buffer(buf);
				strcat(buf,"\n\t");
				strcat(buf,ui_getstring (UI_lefthilight));
				strcat(buf," ");
				strcat(buf,ui_getstring (UI_returntomain));
				strcat(buf," ");
				strcat(buf,ui_getstring (UI_righthilight));
				strcat(buf,"\n");
			}
			else
			{
				free (buf);
				buf = 0;
			}
		}
	}

	{
		if (buf)
		{
			if (lines < maxrows)
				maxrows = lines;
			display_scroll_message (bitmap, &scroll, maxcols, maxrows, buf, ui_getstring(UI_history));
		}
		else
		{
			char msg[80];

			strcpy(msg,"\t");
			strcat(msg,ui_getstring(UI_historymissing));
			strcat(msg,"\n\n\t");
			strcat(msg,ui_getstring (UI_lefthilight));
			strcat(msg," ");
			strcat(msg,ui_getstring (UI_returntomain));
			strcat(msg," ");
			strcat(msg,ui_getstring (UI_righthilight));
			ui_displaymessagewindow(bitmap,msg,ui_getstring(UI_history));
		}

		if ((scroll > 0) && input_ui_pressed_repeat(IPT_UI_UP,4))
		{
			if (scroll == 2) scroll = 0;	/* 1 would be the same as 0, but with arrow on top */
			else scroll--;
		}

		if (input_ui_pressed_repeat(IPT_UI_DOWN,4))
		{
			if (scroll == 0) scroll = 2;	/* 1 would be the same as 0, but with arrow on top */
			else scroll++;
		}

		if (input_ui_pressed(IPT_UI_SELECT))
			sel = -1;

		if (input_ui_pressed(IPT_UI_CANCEL))
			sel = -1;

		if (input_ui_pressed(IPT_UI_CONFIGURE))
			sel = -2;
	}

	if (sel == -1 || sel == -2)
	{
		schedule_full_refresh();

		/* force buffer to be recreated */
		if (buf)
		{
			free (buf);
			buf = 0;
		}
	}

	return sel + 1;

}


static void convert_command_move(char *buf)
{
	unsigned char *c = (unsigned char *)buf;

	while (*c)
	{
		if (iszen1(*c) && iszen2(*(c+1)))
		{
			c+=2;
		}
		else
		{
			if (*c == '_')
			{
				switch(*(c+1))
				{
					case '1':
					case '2':
					case '3':
					case '4':
					case '6':
					case '7':
					case '8':
					case '9':
						*c     = 0x81;
						*(c+1) = 0xd0 + (*(c+1) - '0');
						c+=2;
						break;

					case 'N':
						*c     = 0x81;
						*(c+1) = 0xd5;
						c+=2;
						break;

					case 'A':
					case 'B':
					case 'C':
					case 'D':
						*c     = 0x81;
						*(c+1) = 0xc0 + (*(c+1) - 'A');
						c+=2;
						break;

					case 'a':
					case 'b':
					case 'c':
					case 'd':
					case 'e':
					case 'f':
						*c     = 0x81;
						*(c+1) = 0xe9 + (*(c+1) - 'a');
						c+=2;
						break;

					case '+':
						*c     = 0x81;
						*(c+1) = 0xc4;
						c+=2;
						break;

					case 'P':
						*c     = 0x81;
						*(c+1) = 0xc5;
						c+=2;
						break;

					case 'K':
						*c     = 0x81;
						*(c+1) = 0xc6;
						c+=2;
						break;

					case 'S':
						*c     = 0x81;
						*(c+1) = 0xef;
						c+=2;
						break;

					default:
						c++;
						break;
				}
			}
			else if (*c == '\\' && *(c+1) == 'n')
			{
				*c     = ' ';
				*(c+1) = '\n';
				c+=2;
			}
			else
				c++;
		}
	}
}


/* Display text entry for current driver from command.dat. */
static int displaycommand(struct mame_bitmap *bitmap, int selected, int shortcut)
{
	int sel, ret = 0, buflines = 0, visible = 0;
	static int maxcols = 0, maxrows = 0;

	sel = selected - 1;

	if (!commandlist_buf)
	{
		maxcols = (uirotwidth / uirotcharwidth) - 2;
		maxrows = (uirotheight / ROWHEIGHT) - 2;

		/* allocate a buffer for the text */
		if ((commandlist_buf = malloc(65536)))
		{
			memset(commandlist_buf, 0, 65536);

			/* try to load entry */
			if (!load_driver_command_ex (Machine->gamedrv, commandlist_buf, 65536, sel))
			{
				int height = 1;
				int count = 0;
				static int presel = -1;
				char *c;

				if( presel != sel )
				{
					command_scroll = 0;
					presel = sel;
				}

				convert_command_move(commandlist_buf);

				c = commandlist_buf;

				while(*c)
				{
					if (count < 2)
					{
						commandlist_buf++;
						if (*c++ == '\n')
							count++;
					}
					else
						if (*c++ == '\n') 
							height++;
				}

				if (height <= maxrows)
					maxrows = height - 1;
			}
			else
			{
				free(commandlist_buf);
				commandlist_buf = 0;
			}
		}
	}

	if (commandlist_buf)
	{
		const char *items[64];
		command_sub_menu(Machine->gamedrv, items);
		ret = display_scroll_message(bitmap, &command_scroll, maxcols, maxrows, commandlist_buf, items[selected - 1]);

		buflines = ret & SCR_PAGE_MASK;
		visible  = maxrows - ((ret & SCR_PREV_PAGE) != 0) - ((ret & SCR_NEXT_PAGE) != 0);
	}
	else
	{
		char msg[80];

		strcpy(msg, "\t");
		strcat(msg, ui_getstring(UI_commandmissing));
		strcat(msg, "\n\n\t");
		strcat(msg, ui_getstring(UI_lefthilight));
		strcat(msg, " ");
		if (shortcut)
			strcat(msg, ui_getstring(UI_returntogame));
		else
			strcat(msg, ui_getstring(UI_returntomain));
		strcat(msg, " ");
		strcat(msg, ui_getstring(UI_righthilight));
		ui_displaymessagewindow(bitmap, msg, ui_getstring(UI_command));
	}

	if ((command_scroll > 0) && input_ui_pressed_repeat(IPT_UI_UP,4))
	{
		if (command_scroll == 2) command_scroll = 0;	/* 1 would be the same as 0, but with arrow on top */
		else command_scroll--;
	}

	if (input_ui_pressed_repeat(IPT_UI_DOWN,4))
	{
		if (command_scroll == 0) command_scroll = 2;	/* 1 would be the same as 0, but with arrow on top */
		else command_scroll++;
	}

	if ((ret & SCR_PREV_PAGE) && input_ui_pressed_repeat(IPT_UI_LEFT,4))
	{
		if (command_scroll == maxrows - 1)
			command_scroll = 0;
		else if (command_scroll - visible < 0)
			command_scroll = 0;
		else
			command_scroll -= visible;
	}

	if ((ret & SCR_NEXT_PAGE) && input_ui_pressed_repeat(IPT_UI_RIGHT,4))
	{
		if (command_scroll >= buflines - visible)
			command_scroll = buflines - visible;
		else
			command_scroll += visible;
	}

	if (input_ui_pressed(IPT_UI_SELECT))
		sel = -1;

	if (input_ui_pressed(IPT_UI_CANCEL))
		sel = -1;

	if (input_ui_pressed(IPT_UI_CONFIGURE) && shortcut == 0)
		sel = -2;

	if (sel == -1 || sel == -2)
	{
		schedule_full_refresh();

		/* force buffer to be recreated */
		if (commandlist_buf)
		{
			free(commandlist_buf);
			commandlist_buf = 0;
		}
	}

	return sel + 1;
}


static int displaycommand_ex(struct mame_bitmap *bitmap, int selected, int shortcut)
{
	static const char *menu_item[64];
	static int total = 0;
	int sel, visible;

	sel = selected - 1;
	visible = (uirotheight / ROWHEIGHT) - 3;

	/* If a submenu has been selected, go there */
	if (command_lastselected)
	{
		command_lastselected = displaycommand(bitmap, (sel + 1), shortcut);

		if (command_lastselected == -1)
		{
			sel = -2;
			command_lastselected = 1;
			schedule_full_refresh();
		}

		return sel + 1;
	}

	/* No submenu active, display the main command index menu */
	if (total == -1)
	{
		char msg[80];

		strcpy(msg, "\t");
		strcat(msg, ui_getstring(UI_commandmissing));
		strcat(msg, "\n\n\t");
		strcat(msg, ui_getstring(UI_lefthilight));
		strcat(msg, " ");
		if (shortcut)
			strcat(msg, ui_getstring(UI_returntogame));
		else
			strcat(msg, ui_getstring(UI_returntomain));
		strcat(msg, " ");
		strcat(msg, ui_getstring(UI_righthilight));
		ui_displaymessagewindow(bitmap, msg, ui_getstring(UI_command));
	}
	else
	{
		if (total == 0 || command_load)
		{
			total = command_sub_menu(Machine->gamedrv, menu_item);
			command_load = 0;

			if (total > 0)
			{
				if (shortcut)
					menu_item[total++] = ui_getstring(UI_returntogame);
				else
					menu_item[total++] = ui_getstring(UI_returntomain);
				menu_item[total] = 0;
			}
			else
			{
				char msg[80];

				total = -1;
				strcpy(msg, "\t");
				strcat(msg, ui_getstring(UI_commandmissing));
				strcat(msg, "\n\n\t");
				strcat(msg, ui_getstring(UI_lefthilight));
				strcat(msg, " ");
				if (shortcut)
					strcat(msg, ui_getstring(UI_returntogame));
				else
					strcat(msg, ui_getstring(UI_returntomain));
				strcat(msg, " ");
				strcat(msg, ui_getstring(UI_righthilight));
				ui_displaymessagewindow(bitmap, msg, ui_getstring(UI_command));
			}
		}
		else
		{
			if (shortcut)
				menu_item[total - 1] = ui_getstring(UI_returntogame);
			else
				menu_item[total - 1] = ui_getstring(UI_returntomain);

			ui_displaymenu(bitmap,menu_item,0,0,ui_getstring(UI_command),sel,0);
		}

		if (total > 0)
		{
			if (input_ui_pressed_repeat(IPT_UI_DOWN,4))
				sel = (sel + 1) % total;

			if (input_ui_pressed_repeat(IPT_UI_UP,4))
				sel = (sel + total - 1) % total;

			if (input_ui_pressed_repeat(IPT_UI_LEFT,4))
			{
				sel -= visible;
				if (sel < 0)	sel = 0;
			}

			if (input_ui_pressed_repeat(IPT_UI_RIGHT,4))
			{
				sel += visible;
				if (sel >= total)	sel = total - 1;
			}
		}
	}

	if (input_ui_pressed(IPT_UI_SELECT))
	{
		if (sel == (total - 1) || total == -1) // return to main
		{
			command_lastselected = 0;
			sel = -1;
		}
		else
		{
			command_lastselected = 1;
			schedule_full_refresh();
		}
	}

	/* Cancel pops us up a menu level */
	if (input_ui_pressed(IPT_UI_CANCEL))
		sel = -1;

	/* The UI key takes us all the way back out */
	if (input_ui_pressed(IPT_UI_CONFIGURE) && shortcut == 0)
		sel = -2;

	if (sel == -1 || sel == -2)
	{
		schedule_full_refresh();
		total = 0;
	}

	return sel + 1;
}


int memcard_menu(struct mame_bitmap *bitmap, int selection)
{
	int sel;
	int menutotal = 0;
	const char *menuitem[10];
	char buf[256];
	char buf2[256];

	sel = selection - 1 ;

	sprintf(buf, "%s %03d", ui_getstring (UI_loadcard), mcd_number);
	menuitem[menutotal++] = buf;
	menuitem[menutotal++] = ui_getstring (UI_ejectcard);
	menuitem[menutotal++] = ui_getstring (UI_createcard);
	menuitem[menutotal++] = ui_getstring (UI_resetcard);
	menuitem[menutotal++] = ui_getstring (UI_returntomain);
	menuitem[menutotal] = 0;

	if (mcd_action!=0)
	{
		strcpy (buf2, "\n");

		switch(mcd_action)
		{
			case 1:
				strcat (buf2, ui_getstring (UI_loadfailed));
				break;
			case 2:
				strcat (buf2, ui_getstring (UI_loadok));
				break;
			case 3:
				strcat (buf2, ui_getstring (UI_cardejected));
				break;
			case 4:
				strcat (buf2, ui_getstring (UI_cardcreated));
				break;
			case 5:
				strcat (buf2, ui_getstring (UI_cardcreatedfailed));
				strcat (buf2, "\n");
				strcat (buf2, ui_getstring (UI_cardcreatedfailed2));
				break;
			default:
				strcat (buf2, ui_getstring (UI_carderror));
				break;
		}

		strcat (buf2, "\n\n");
		ui_displaymessagewindow(bitmap,buf2,ui_getstring(UI_memorycard));
		if (input_ui_pressed(IPT_UI_SELECT))
			mcd_action = 0;
	}
	else
	{
		ui_displaymenu(bitmap,menuitem,0,0,ui_getstring(UI_memorycard),sel,0);

		if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
			mcd_number = (mcd_number + 1) % 1000;

		if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
			mcd_number = (mcd_number + 999) % 1000;

		if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
			sel = (sel + 1) % menutotal;

		if (input_ui_pressed_repeat(IPT_UI_UP,8))
			sel = (sel + menutotal - 1) % menutotal;

		if (input_ui_pressed(IPT_UI_SELECT))
		{
			switch(sel)
			{
			case 0:
				neogeo_memcard_eject();
				if (neogeo_memcard_load(mcd_number))
				{
					memcard_status=1;
					memcard_number=mcd_number;
					mcd_action = 2;
				}
				else
					mcd_action = 1;
				break;
			case 1:
				neogeo_memcard_eject();
				mcd_action = 3;
				break;
			case 2:
				if (neogeo_memcard_create(mcd_number))
					mcd_action = 4;
				else
					mcd_action = 5;
				break;
			case 3:
				memcard_manager=1;
				sel=-2;
				machine_reset();
				break;
			case 4:
				sel=-1;
				break;
			}
		}

		if (input_ui_pressed(IPT_UI_CANCEL))
			sel = -1;

		if (input_ui_pressed(IPT_UI_CONFIGURE))
			sel = -2;

		if (sel == -1 || sel == -2)
		{
			schedule_full_refresh();
		}
	}

	return sel + 1;
}


enum { UI_SWITCH = 0,UI_DEFCODE,UI_CODE,UI_ANALOG,
		UI_CUSTOM,UI_AUTOFIRE,UI_STATS,UI_GAMEINFO, UI_HISTORY,
		UI_CHEAT,UI_RESET,UI_MEMCARD,UI_COMMAND,UI_EXIT };


#define MAX_SETUPMENU_ITEMS 20
static const char *menu_item[MAX_SETUPMENU_ITEMS];
static int menu_action[MAX_SETUPMENU_ITEMS];
static int menu_total;


static void setup_menu_init(void)
{
	menu_total = 0;

	menu_item[menu_total] = ui_getstring (UI_inputgeneral); menu_action[menu_total++] = UI_DEFCODE;
	menu_item[menu_total] = ui_getstring (UI_inputspecific); menu_action[menu_total++] = UI_CODE;
	menu_item[menu_total] = ui_getstring (UI_dipswitches); menu_action[menu_total++] = UI_SWITCH;

	/* Determine if there are any analog controls */
	{
		struct InputPort *in;
		int num;

		in = Machine->input_ports;

		num = 0;
		while (in->type != IPT_END)
		{
			if (((in->type & 0xff) > IPT_ANALOG_START) && ((in->type & 0xff) < IPT_ANALOG_END)
					&& !(!options.cheat && (in->type & IPF_CHEAT)))
				num++;
			in++;
		}

		if (num != 0)
		{
			menu_item[menu_total] = ui_getstring (UI_analogcontrols); menu_action[menu_total++] = UI_ANALOG;
		}
	}

	menu_item[menu_total] = ui_getstring (UI_bookkeeping); menu_action[menu_total++] = UI_STATS;
	menu_item[menu_total] = ui_getstring (UI_gameinfo); menu_action[menu_total++] = UI_GAMEINFO;
	menu_item[menu_total] = ui_getstring (UI_history); menu_action[menu_total++] = UI_HISTORY;
	menu_item[menu_total] = ui_getstring (UI_command); menu_action[menu_total++] = UI_COMMAND;
	menu_item[menu_total] = ui_getstring (UI_custombuttons); menu_action[menu_total++] = UI_CUSTOM;
	menu_item[menu_total] = ui_getstring (UI_autofire); menu_action[menu_total++] = UI_AUTOFIRE;

	if (options.cheat)
	{
		menu_item[menu_total] = ui_getstring (UI_cheat); menu_action[menu_total++] = UI_CHEAT;
	}

	if (options.bios_type == NEOGEOBIOS_STANDARD)
	{
		if (Machine->gamedrv->clone_of == &driver_neogeo ||
				(Machine->gamedrv->clone_of &&
					Machine->gamedrv->clone_of->clone_of == &driver_neogeo))
		{
			menu_item[menu_total] = ui_getstring (UI_memorycard); menu_action[menu_total++] = UI_MEMCARD;
		}
	}

	menu_item[menu_total] = ui_getstring (UI_resetgame); menu_action[menu_total++] = UI_RESET;
	menu_item[menu_total] = ui_getstring (UI_returntogame); menu_action[menu_total++] = UI_EXIT;
	menu_item[menu_total] = 0; /* terminate array */
}


static int setup_menu(struct mame_bitmap *bitmap, int selected)
{
	int sel,res=-1;
	static int menu_lastselected = 0;


	if (selected == -1)
		sel = menu_lastselected;
	else sel = selected - 1;

	if (sel > SEL_MASK)
	{
		switch (menu_action[sel & SEL_MASK])
		{
			case UI_SWITCH:
				res = setdipswitches(bitmap, sel >> SEL_BITS);
				break;
			case UI_DEFCODE:
				res = setdefcodesettings(bitmap, sel >> SEL_BITS);
				break;
			case UI_CODE:
				res = setcodesettings(bitmap, sel >> SEL_BITS);
				break;
			case UI_ANALOG:
				res = settraksettings(bitmap, sel >> SEL_BITS);
				break;
			case UI_CUSTOM:
				res = setcustombutton(bitmap, sel >> SEL_BITS);
				break;
			case UI_AUTOFIRE:
				res = setautofiresettings(bitmap, sel >> SEL_BITS);
				break;
			case UI_STATS:
				res = mame_stats(bitmap, sel >> SEL_BITS);
				break;
			case UI_GAMEINFO:
				res = displaygameinfo(bitmap, sel >> SEL_BITS);
				break;
			case UI_HISTORY:
				res = displayhistory(bitmap, sel >> SEL_BITS);
				break;
			case UI_COMMAND:
				res = displaycommand_ex(bitmap, sel >> SEL_BITS, 0);
				break;
			case UI_CHEAT:
				res = cheat_menu(bitmap, sel >> SEL_BITS);
				break;
			case UI_MEMCARD:
				res = memcard_menu(bitmap, sel >> SEL_BITS);
				break;
		}

		if (res == -1)
		{
			menu_lastselected = sel;
			sel = -1;
		}
		else
			sel = (sel & SEL_MASK) | (res << SEL_BITS);

		return sel + 1;
	}


	ui_displaymenu(bitmap,menu_item,0,0,ui_getstring(UI_menu),sel,0);

	if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
		sel = (sel + 1) % menu_total;

	if (input_ui_pressed_repeat(IPT_UI_UP,8))
		sel = (sel + menu_total - 1) % menu_total;

	if (input_ui_pressed(IPT_UI_SELECT))
	{
		switch (menu_action[sel])
		{
			case UI_SWITCH:
			case UI_DEFCODE:
			case UI_CODE:
			case UI_ANALOG:
			case UI_CUSTOM:
			case UI_AUTOFIRE:
			case UI_STATS:
			case UI_GAMEINFO:
			case UI_HISTORY:
			case UI_COMMAND:
			case UI_CHEAT:
			case UI_MEMCARD:
				sel |= 1 << SEL_BITS;
				schedule_full_refresh();
				break;

			case UI_RESET:
				machine_reset();
				break;

			case UI_EXIT:
				menu_lastselected = 0;
				sel = -1;
				break;
		}
	}

	if (input_ui_pressed(IPT_UI_CANCEL) ||
			input_ui_pressed(IPT_UI_CONFIGURE))
	{
		menu_lastselected = sel;
		sel = -1;
	}

	if (sel == -1)
	{
		schedule_full_refresh();
	}

	return sel + 1;
}



/*********************************************************************

  start of On Screen Display handling

*********************************************************************/

static void displayosd(struct mame_bitmap *bitmap,const char *text,int percentage,int default_percentage)
{
	struct DisplayText dt[2];
	int avail;


	avail = (uirotwidth / uirotcharwidth) * 19 / 20;

	ui_drawbox(bitmap,(uirotwidth - uirotcharwidth * avail) / 2,
			(uirotheight - 7*uirotcharheight/2),
			avail * uirotcharwidth,
			3*uirotcharheight,1);

	avail--;

	drawbar(bitmap,(uirotwidth - uirotcharwidth * avail) / 2,
			(uirotheight - 3*uirotcharheight),
			avail * uirotcharwidth,
			uirotcharheight,
			percentage,default_percentage);

	dt[0].text = text;
	dt[0].color = UI_COLOR_NORMAL;
	dt[0].x = (uirotwidth - uirotcharwidth * strlen(text)) / 2;
	dt[0].y = (uirotheight - 2*uirotcharheight) + 2;
	dt[1].text = 0; /* terminate array */
	displaytext(bitmap,dt);
}



static void onscrd_volume(struct mame_bitmap *bitmap,int increment,int arg)
{
	char buf[20];
	int attenuation;

	if (increment)
	{
		attenuation = osd_get_mastervolume();
		attenuation += increment;
		if (attenuation > 0) attenuation = 0;
		if (attenuation < -32) attenuation = -32;
		osd_set_mastervolume(attenuation);
	}
	attenuation = osd_get_mastervolume();

	sprintf(buf,"%s %3ddB", ui_getstring (UI_volume), attenuation);
	displayosd(bitmap,buf,100 * (attenuation + 32) / 32,100);
}

static void onscrd_mixervol(struct mame_bitmap *bitmap,int increment,int arg)
{
	static void *driver = 0;
	char buf[40];
	int volume,ch;
	int doallchannels = 0;
	int proportional = 0;


	if (code_pressed(KEYCODE_LSHIFT) || code_pressed(KEYCODE_RSHIFT))
		doallchannels = 1;
	if (!code_pressed(KEYCODE_LCONTROL) && !code_pressed(KEYCODE_RCONTROL))
		increment *= 5;
	if (code_pressed(KEYCODE_LALT) || code_pressed(KEYCODE_RALT))
		proportional = 1;

	if (increment)
	{
		if (proportional)
		{
			static int old_vol[MIXER_MAX_CHANNELS];
			float ratio = 1.0;
			int overflow = 0;

			if (driver != Machine->drv)
			{
				driver = (void *)Machine->drv;
				for (ch = 0; ch < MIXER_MAX_CHANNELS; ch++)
					old_vol[ch] = mixer_get_mixing_level(ch);
			}

			volume = mixer_get_mixing_level(arg);
			if (old_vol[arg])
				ratio = (float)(volume + increment) / (float)old_vol[arg];

			for (ch = 0; ch < MIXER_MAX_CHANNELS; ch++)
			{
				if (mixer_get_name(ch) != 0)
				{
					volume = ratio * old_vol[ch];
					if (volume < 0 || volume > 200)
						overflow = 1;
				}
			}

			if (!overflow)
			{
				for (ch = 0; ch < MIXER_MAX_CHANNELS; ch++)
				{
					volume = ratio * old_vol[ch];
					mixer_set_mixing_level(ch,volume);
				}
			}
		}
		else
		{
			driver = 0; /* force reset of saved volumes */

			volume = mixer_get_mixing_level(arg);
			volume += increment;
			if (volume > 200) volume = 200;
			if (volume < 0) volume = 0;

			if (doallchannels)
			{
				for (ch = 0;ch < MIXER_MAX_CHANNELS;ch++)
					mixer_set_mixing_level(ch,volume);
			}
			else
				mixer_set_mixing_level(arg,volume);
		}
	}
	volume = mixer_get_mixing_level(arg);

	if (proportional)
		sprintf(buf,"%s %s %3d%%", ui_getstring (UI_allchannels), ui_getstring (UI_relative), volume);
	else if (doallchannels)
		sprintf(buf,"%s %s %3d%%", ui_getstring (UI_allchannels), ui_getstring (UI_volume), volume);
	else
		sprintf(buf,"%s %s %3d%%",mixer_get_name(arg), ui_getstring (UI_volume), volume);
	displayosd(bitmap,buf,volume / 2,mixer_get_default_mixing_level(arg) / 2);
}

static void onscrd_brightness(struct mame_bitmap *bitmap,int increment,int arg)
{
	char buf[20];
	double brightness;


	if (increment)
	{
		brightness = palette_get_global_brightness();
		brightness += 0.05 * increment;
		if (brightness < 0.1) brightness = 0.1;
		if (brightness > 2.0) brightness = 2.0;
		palette_set_global_brightness(brightness);
	}
	brightness = palette_get_global_brightness();

	sprintf(buf,"%s %3d%%", ui_getstring (UI_brightness), (int)(brightness * 100));
	displayosd(bitmap,buf,brightness*50,100/2);
}

static void onscrd_gamma(struct mame_bitmap *bitmap,int increment,int arg)
{
	char buf[20];
	double gamma_correction;

	if (increment)
	{
		gamma_correction = palette_get_global_gamma();

		gamma_correction += 0.05 * increment;
		if (gamma_correction < 0.5) gamma_correction = 0.5;
		if (gamma_correction > 2.0) gamma_correction = 2.0;

		palette_set_global_gamma(gamma_correction);
	}
	gamma_correction = palette_get_global_gamma();

	sprintf(buf,"%s %1.2f", ui_getstring (UI_gamma), gamma_correction);
	displayosd(bitmap,buf,100*(gamma_correction-0.5)/(2.0-0.5),100*(1.0-0.5)/(2.0-0.5));
}

static void onscrd_overclock(struct mame_bitmap *bitmap,int increment,int arg)
{
	char buf[30];
	double overclock;
	int cpu, doallcpus = 0, oc;
	extern short cpu_clocks[MAX_CPU];

	if (code_pressed(KEYCODE_LSHIFT) || code_pressed(KEYCODE_RSHIFT))
		doallcpus = 1;
	if (!code_pressed(KEYCODE_LCONTROL) && !code_pressed(KEYCODE_RCONTROL))
		increment *= 5;
	if( increment )
	{
		overclock = timer_get_overclock(arg);
		overclock += 0.01 * increment;
		if (overclock < 0.01) overclock = 0.01;
		if (overclock > 3.0) overclock = 3.0;
		if( doallcpus )
			for( cpu = 0; cpu < cpu_gettotalcpu(); cpu++ )
				timer_set_overclock(cpu, overclock);
		else
			timer_set_overclock(arg, overclock);
	}

	oc = 100 * timer_get_overclock(arg) + 0.5;

	if( doallcpus )
	{
		sprintf(buf,"%s %s %3d%%", ui_getstring (UI_allcpus), ui_getstring (UI_overclock), oc);
		for (cpu = 0; cpu < cpu_gettotalcpu(); cpu++)
			cpu_clocks[cpu] = oc;
	}
	else
	{
		sprintf(buf,"%s %s%d %3d%%", ui_getstring (UI_overclock), ui_getstring (UI_cpu), arg, oc);
		cpu_clocks[arg] = oc;
	}
	displayosd(bitmap,buf,oc/3,100/3);
}

#define MAX_OSD_ITEMS 30
static void (*onscrd_fnc[MAX_OSD_ITEMS])(struct mame_bitmap *bitmap,int increment,int arg);
static int onscrd_arg[MAX_OSD_ITEMS];
static int onscrd_total_items;

static void onscrd_init(void)
{
	int item,ch;


	item = 0;

	if (Machine->sample_rate)
	{
		onscrd_fnc[item] = onscrd_volume;
		onscrd_arg[item] = 0;
		item++;

		for (ch = 0;ch < MIXER_MAX_CHANNELS;ch++)
		{
			if (mixer_get_name(ch) != 0)
			{
				onscrd_fnc[item] = onscrd_mixervol;
				onscrd_arg[item] = ch;
				item++;
			}
		}
	}

	if (options.cheat)
	{
		for (ch = 0;ch < cpu_gettotalcpu();ch++)
		{
			onscrd_fnc[item] = onscrd_overclock;
			onscrd_arg[item] = ch;
			item++;
		}
	}

	onscrd_fnc[item] = onscrd_brightness;
	onscrd_arg[item] = 0;
	item++;

	onscrd_fnc[item] = onscrd_gamma;
	onscrd_arg[item] = 0;
	item++;

	onscrd_total_items = item;
}

static int on_screen_display(struct mame_bitmap *bitmap, int selected)
{
	int increment,sel;
	static int lastselected = 0;


	if (selected == -1)
		sel = lastselected;
	else sel = selected - 1;

	increment = 0;
	if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
		increment = -1;
	if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
		increment = 1;
	if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
		sel = (sel + 1) % onscrd_total_items;
	if (input_ui_pressed_repeat(IPT_UI_UP,8))
		sel = (sel + onscrd_total_items - 1) % onscrd_total_items;

	(*onscrd_fnc[sel])(bitmap,increment,onscrd_arg[sel]);

	lastselected = sel;

	if (input_ui_pressed(IPT_UI_ON_SCREEN_DISPLAY))
	{
		sel = -1;

		schedule_full_refresh();
	}

	return sel + 1;
}

/*********************************************************************

  end of On Screen Display handling

*********************************************************************/


void displaymessage(struct mame_bitmap *bitmap,const char *text,int trans)
{
	struct DisplayText dt[2];
	int avail;


	if (uirotwidth < uirotcharwidth * strlen(text))
	{
		ui_displaymessagewindow(bitmap,text,0);
		return;
	}

	avail = strlen(text)+2;

	ui_drawbox(bitmap,(uirotwidth - uirotcharwidth * avail) / 2,
			uirotheight - 3*uirotcharheight,
			avail * uirotcharwidth,
			2*uirotcharheight,trans);

	dt[0].text = text;
	dt[0].color = UI_COLOR_NORMAL;
	dt[0].x = (uirotwidth - uirotcharwidth * strlen(text)) / 2;
	dt[0].y = uirotheight - 5*uirotcharheight/2;
	dt[1].text = 0; /* terminate array */
	displaytext(bitmap,dt);
}


static char messagetext[200];
static int messagecounter;

void CLIB_DECL usrintf_showmessage(const char *text,...)
{
	va_list arg;
	va_start(arg,text);
	vsprintf(messagetext,text,arg);
	va_end(arg);
	messagecounter = 2 * Machine->drv->frames_per_second;
}

void CLIB_DECL usrintf_showmessage_secs(int seconds, const char *text,...)
{
	va_list arg;
	va_start(arg,text);
	vsprintf(messagetext,text,arg);
	va_end(arg);
	messagecounter = seconds * Machine->drv->frames_per_second;
}

static void flash_all_values_and_buffers(void)
{
	int i;

	setup_selected    = 0;
	osd_selected      = 0;
	single_step       = 0;
	show_input        = 0;

	if (wave_recording)
	{
		osd_stop_log_wave();
		wave_recording = 0;
	}
	wave_recording    = 0;
	wave_counter      = 0;
	wave_seconds      = 0;
	wave_minutes      = 0;
	scroll_reset      = 1;

	command_counter   = 0;
	memset(command_buf, 0, COMMAND_LOG_BUFSIZE);

	if (commandlist_buf)
	{
		free(commandlist_buf);
		commandlist_buf = 0;
	}
	command_scroll = 0;
	command_lastselected = 0;

	command_sc = 0;
	command_sel = 1;
	command_load = 1;

	jukebox = 0;

	for (i = 0 ; i < 0x400 ; i++)
		skip_object[i] = 0;

	for (i = 0 ; i < 0x400 ; i++)
		skip_background[i] = 0;

	front_layer = 0;
	alt_backcolor = 0;
	object_no = 0;
	background_no = 0;
	object_selected = 0;
	object = 0;

	cheat_sc = 0;
	cheat_sel = 1;
	cheat_fe = 0;

	show_time = 0;

	lhw = strlen(ui_getstring(UI_lefthilight));
	rhw = strlen(ui_getstring(UI_righthilight));
	uaw = strlen(ui_getstring(UI_uparrow));
	daw = strlen(ui_getstring(UI_downarrow));
	law = strlen(ui_getstring(UI_leftarrow));
	raw = strlen(ui_getstring(UI_rightarrow));
}

void do_loadsave(struct mame_bitmap *bitmap, int request_loadsave)
{
	int file = 0;

	mame_pause(1);

	do
	{
		InputCode code;

		if (request_loadsave == LOADSAVE_SAVE)
			displaymessage(bitmap, ui_getstring(UI_saveselect), 1);
		else
			displaymessage(bitmap, ui_getstring(UI_loadselect), 1);

		update_video_and_audio();
		reset_partial_updates();

		if (input_ui_pressed(IPT_UI_CANCEL))
			break;

		code = code_read_async();
		if (code != CODE_NONE)
		{
			if (code >= KEYCODE_A && code <= KEYCODE_Z)
				file = 'a' + (code - KEYCODE_A);
			else if (code >= KEYCODE_0 && code <= KEYCODE_9)
				file = '0' + (code - KEYCODE_0);
			else if (code >= KEYCODE_0_PAD && code <= KEYCODE_9_PAD)
				file = '0' + (code - KEYCODE_0);
		}
	}
	while (!file);

	mame_pause(0);

	if (file > 0)
	{
		if (request_loadsave == LOADSAVE_SAVE)
			usrintf_showmessage(ui_getstring(UI_saveposition), file);
		else
			usrintf_showmessage(ui_getstring(UI_loadposition), file);
		cpu_loadsave_schedule(request_loadsave, file);
	}
	else
	{
		if (request_loadsave == LOADSAVE_SAVE)
			usrintf_showmessage(ui_getstring(UI_savecancel));
		else
			usrintf_showmessage(ui_getstring(UI_loadcancel));
	}
}


void ui_show_fps_temp(double seconds)
{
	if (!showfps)
		showfpstemp = (int)(seconds * Machine->drv->frames_per_second);
}


static void display_fps(struct mame_bitmap *bitmap)
{
	const char *text, *end;
	char textbuf[256];
	int done = 0;
	int y = 0;

	/* if we're not currently displaying, skip it */
	if (!showfps && !showfpstemp)
		return;

	/* get the current FPS text */
	text = osd_get_fps_text(mame_get_performance_info());

	/* loop over lines */
	while (!done)
	{
		/* find the end of this line and copy it to the text buf */
		end = strchr(text, '\n');
		if (end)
		{
			memcpy(textbuf, text, end - text);
			textbuf[end - text] = 0;
			text = end + 1;
		}
		else
		{
			strcpy(textbuf, text);
			done = 1;
		}

		/* render */
		ui_text_bk(bitmap, textbuf, uirotwidth - strlen(textbuf) * uirotcharwidth, y);
		y += uirotcharheight;
	}

	/* update the temporary FPS display state */
	if (showfpstemp)
	{
		showfpstemp--;
		if (!showfps && showfpstemp == 0)
			schedule_full_refresh();
	}
}


static void object_operation_start(void)
{
	object_selected = 0;
}

static void object_operation_end(void)
{
	object = 0;
}

static void object_operation_neogeo(struct mame_bitmap *bitmap)
{
	int i, sel, object_number = 0, arrowise = 0;
	static const char *menu_items[8];
	static const char *menu_subitem[10];
	char buf[4][5];

	menu_items[0] = ui_getstring(UI_object_number);
	menu_items[1] = ui_getstring(UI_object_exp);
	menu_items[2] = ui_getstring(UI_frontlayer);
	menu_items[3] = ui_getstring(UI_altbackcolor);
	menu_items[4] = ui_getstring(UI_object_clear);
	menu_items[5] = ui_getstring(UI_object_def);
	menu_items[6] = ui_getstring(UI_returntogame);
	menu_items[7] = 0;	/* terminate array */

	for (i = 0; i < 10; i++)
		menu_subitem[i] = 0;

	object_number = count_object_number_neogeo();

	if (object_no > object_number)	object_no = object_number;

	sprintf(buf[0], "%d", object_no);
	menu_subitem[0] = (const char *)buf[0];

	sprintf(buf[1], "%s", skip_object[object_no] ? ui_getstring(UI_object_off) : ui_getstring(UI_object_on));
	menu_subitem[1] = (const char *)buf[1];

	sprintf(buf[2], "%s", front_layer ? ui_getstring(UI_object_off) : ui_getstring(UI_object_on));
	menu_subitem[2] = (const char *)buf[2];

	sprintf(buf[3], "%s", alt_backcolor ? ui_getstring(UI_object_on) : ui_getstring(UI_object_off));
	menu_subitem[3] = (const char *)buf[3];

	sel = object_selected;

	switch (sel)
	{
		case 0:
			if (object_no > 0)
				arrowise |= 1;
			if (object_no < object_number)
				arrowise |= 2;
			if (object_number == 0)
				arrowise = 0;
			break;

		case 1:
			if (skip_object[object_no] == 0)
				arrowise = 2;
			if (skip_object[object_no] == 1)
				arrowise = 1;
			if (object_number == 0)
				arrowise = 0;
			break;

		case 2:
			if (front_layer == 0)
				arrowise = 2;
			if (front_layer == 1)
				arrowise = 1;
			break;

		case 3:
			if (alt_backcolor == 0)
				arrowise = 2;
			if (alt_backcolor == 1)
				arrowise = 1;
			break;

		default:
			break;
	}

	ui_displaymenu(bitmap, menu_items, menu_subitem, 0, ui_getstring(UI_object_operation), sel, arrowise);

//	erase_screen(bitmap);

	if (input_ui_pressed_repeat(IPT_UI_SELECT, 8))
	{
		switch (sel)
		{
			case 0:
			case 1:
				if (object_number == 0)	break;
				skip_object[object_no] ^= 1;
				break;

			case 2:
				front_layer ^= 1;
				break;

			case 3:
				alt_backcolor ^= 1;
				alt_backcolor_exp_neogeo();
				break;

			case 4:
				for (i = 0 ; i < 0x400 ; i++)	skip_object[i] = 1;
				front_layer = 1;
				object_no = 0;
				break;

			case 5:
				for (i = 0 ; i < 0x400 ; i++)	skip_object[i] = 0;
				front_layer = 0;
				alt_backcolor = 0;
				object_no = 0;
				alt_backcolor_exp_neogeo();
				break;

			case 6:
				sel = -1;
				break;

			default:
				break;
		}
	}

	if (input_ui_pressed_repeat(IPT_UI_LEFT, 8))
	{
		switch (sel)
		{
			case 0:
				if (object_number == 0)	break;
				if (object_no > 0)	object_no--;
				break;

			case 1:
				if (object_number == 0)	break;
				if (skip_object[object_no] == 1)	skip_object[object_no] = 0;
				break;

			case 2:
				if (front_layer == 1)	front_layer = 0;
				break;

			case 3:
				if (alt_backcolor == 1)
				{
					alt_backcolor = 0;
					alt_backcolor_exp_neogeo();
				}
				break;

			default:
				break;
		}
	}

	if (input_ui_pressed_repeat(IPT_UI_RIGHT, 8))
	{
		switch (sel)
		{
			case 0:
				if (object_number == 0)	break;
				if (object_no < object_number)	object_no++;
				break;

			case 1:
				if (object_number == 0)	break;
				if (skip_object[object_no] == 0)	skip_object[object_no] = 1;
				break;

			case 2:
				if (front_layer == 0)	front_layer = 1;
				break;

			case 3:
				if (alt_backcolor == 0)
				{
					alt_backcolor = 1;
					alt_backcolor_exp_neogeo();
				}
				break;

			default:
				break;
		}
	}

	if (sel == 0 && object_number)
	{
		if (code_pressed_memory_repeat(KEYCODE_PGDN, 8))
		{
			object_no -= 10;
			if (object_no < 0)	object_no = 0;
		}

		if (code_pressed_memory_repeat(KEYCODE_PGUP, 8))
		{
			object_no += 10;
			if (object_no > object_number)	object_no = object_number;
		}
	}

	if (input_ui_pressed_repeat(IPT_UI_UP, 8))
	{
		sel--;
		if (sel == -1) sel = 6;
	}

	if (input_ui_pressed_repeat(IPT_UI_DOWN, 8))
	{
		sel++;
		if (sel == 7) sel = 0;
	}

	if (input_ui_pressed(IPT_UI_CANCEL) || input_ui_pressed(IPT_UI_OPERATION_OBJ))
	{
		sel = -1;
	}

	object_selected = sel;

	update_video_and_audio();

	if (sel == -1)	object_operation_end();
}

static void object_operation_cps(struct mame_bitmap *bitmap)
{
	int i, sel, object_number = 0, background_number = 0, arrowise = 0;
	static const char *menu_items[9];
	static const char *menu_subitem[10];
	char buf[5][5];

	menu_items[0] = ui_getstring(UI_object_number);
	menu_items[1] = ui_getstring(UI_object_exp);
	menu_items[2] = ui_getstring(UI_background_number);
	menu_items[3] = ui_getstring(UI_background_exp);
	menu_items[4] = ui_getstring(UI_altbackcolor);
	menu_items[5] = ui_getstring(UI_object_clear);
	menu_items[6] = ui_getstring(UI_object_def);
	menu_items[7] = ui_getstring(UI_returntogame);
	menu_items[8] = 0;	/* terminate array */

	for (i = 0; i < 10; i++)
		menu_subitem[i] = 0;

	object_number     = count_object_number_cps();
	background_number = count_background_number_cps();

	if (object_no > object_number)	object_no = object_number;
	if (background_no > background_number)	background_no = background_number;

	sprintf(buf[0], "%d", object_no);
	menu_subitem[0] = (const char *)buf[0];

	sprintf(buf[1], "%s", skip_object[object_no] ? ui_getstring(UI_object_off) : ui_getstring(UI_object_on));
	menu_subitem[1] = (const char *)buf[1];

	sprintf(buf[2], "%d", background_no);
	menu_subitem[2] = (const char *)buf[2];

	sprintf(buf[3], "%s", skip_background[background_no] ? ui_getstring(UI_object_off) : ui_getstring(UI_object_on));
	menu_subitem[3] = (const char *)buf[3];

	sprintf(buf[4], "%s", alt_backcolor ? ui_getstring(UI_object_on) : ui_getstring(UI_object_off));
	menu_subitem[4] = (const char *)buf[4];

	sel = object_selected;

	switch (sel)
	{
		case 0:
			if (object_no > 0)
				arrowise |= 1;
			if (object_no < object_number)
				arrowise |= 2;
			if (object_number == 0)
				arrowise = 0;
			break;

		case 1:
			if (skip_object[object_no] == 0)
				arrowise = 2;
			if (skip_object[object_no] == 1)
				arrowise = 1;
			if (object_number == 0)
				arrowise = 0;
			break;

		case 2:
			if (background_no > 0)
				arrowise |= 1;
			if (background_no < background_number)
				arrowise |= 2;
			if (background_number == 0)
				arrowise = 0;
			break;

		case 3:
			if (skip_background[background_no] == 0)
				arrowise = 2;
			if (skip_background[background_no] == 1)
				arrowise = 1;
			if (background_number == 0)
				arrowise = 0;
			break;

		case 4:
			if (alt_backcolor == 0)
				arrowise = 2;
			if (alt_backcolor == 1)
				arrowise = 1;
			break;

		default:
			break;
	}

	ui_displaymenu(bitmap, menu_items, menu_subitem, 0, ui_getstring(UI_object_operation), sel, arrowise);

//	erase_screen(bitmap);

	if (input_ui_pressed_repeat(IPT_UI_SELECT, 8))
	{
		switch (sel)
		{
			case 0:
			case 1:
				if (object_number == 0)	break;
				skip_object[object_no] ^= 1;
				break;

			case 2:
			case 3:
				if (background_number == 0)	break;
				skip_background[background_no] ^= 1;
				break;

			case 4:
				alt_backcolor ^= 1;
				alt_backcolor_exp_cps();
				break;

			case 5:
				for (i = 0 ; i < 0x400 ; i++)	skip_object[i] = 1;
				for (i = 0 ; i < 0x400 ; i++)	skip_background[i] = 1;
				object_no = 0;
				background_no = 0;
				break;

			case 6:
				for (i = 0 ; i < 0x400 ; i++)	skip_object[i] = 0;
				for (i = 0 ; i < 0x400 ; i++)	skip_background[i] = 0;
				alt_backcolor = 0;
				object_no = 0;
				background_no = 0;
				alt_backcolor_exp_cps();
				break;

			case 7:
				sel = -1;
				break;

			default:
				break;
		}
	}

	if (input_ui_pressed_repeat(IPT_UI_LEFT, 8))
	{
		switch (sel)
		{
			case 0:
				if (object_number == 0)	break;
				if (object_no > 0)	object_no--;
				break;

			case 1:
				if (object_number == 0)	break;
				if (skip_object[object_no] == 1)	skip_object[object_no] = 0;
				break;

			case 2:
				if (background_number == 0)	break;
				if (background_no > 0)	background_no--;
				break;

			case 3:
				if (background_number == 0)	break;
				if (skip_background[background_no] == 1)	skip_background[background_no] = 0;
				break;

			case 4:
				if (alt_backcolor == 1)
				{
					alt_backcolor = 0;
					alt_backcolor_exp_cps();
				}
				break;

			default:
				break;
		}
	}

	if (input_ui_pressed_repeat(IPT_UI_RIGHT, 8))
	{
		switch (sel)
		{
			case 0:
				if (object_number == 0)	break;
				if (object_no < object_number)	object_no++;
				break;

			case 1:
				if (object_number == 0)	break;
				if (skip_object[object_no] == 0)	skip_object[object_no] = 1;
				break;

			case 2:
				if (background_number == 0)	break;
				if (background_no < background_number)	background_no++;
				break;

			case 3:
				if (background_number == 0)	break;
				if (skip_background[background_no] == 0)	skip_background[background_no] = 1;
				break;

			case 4:
				if (alt_backcolor == 0)
				{
					alt_backcolor = 1;
					alt_backcolor_exp_cps();
				}
				break;

			default:
				break;
		}
	}

	if (sel == 0 && object_number)
	{
		if (code_pressed_memory_repeat(KEYCODE_PGDN, 8))
		{
			object_no -= 10;
			if (object_no < 0)	object_no = 0;
		}

		if (code_pressed_memory_repeat(KEYCODE_PGUP, 8))
		{
			object_no += 10;
			if (object_no > object_number)	object_no = object_number;
		}
	}

	if (sel == 2 && background_number)
	{
		if (code_pressed_memory_repeat(KEYCODE_PGDN, 8))
		{
			background_no -= 10;
			if (background_no < 0)	background_no = 0;
		}

		if (code_pressed_memory_repeat(KEYCODE_PGUP, 8))
		{
			background_no += 10;
			if (background_no > background_number)	background_no = background_number;
		}
	}

	if (input_ui_pressed_repeat(IPT_UI_UP, 8))
	{
		sel--;
		if (sel == -1) sel = 7;
	}

	if (input_ui_pressed_repeat(IPT_UI_DOWN, 8))
	{
		sel++;
		if (sel == 8) sel = 0;
	}

	if (input_ui_pressed(IPT_UI_CANCEL) || input_ui_pressed(IPT_UI_OPERATION_OBJ))
	{
		sel = -1;
	}

	object_selected = sel;

	update_video_and_audio();

	if (sel == -1)	object_operation_end();
}

static void recording_counter(struct mame_bitmap *bitmap)
{
	char buf[8];
	int width;

	if (++wave_counter == 60)
	{
		wave_counter = 0;
		wave_seconds++;

		if (wave_seconds == 60)
		{
			wave_seconds = 0;
			wave_minutes++;
		}
	}

	if (wave_counter < 40)
		ui_text_bk(bitmap, ui_getstring(UI_waverecording), 0, uirotheight - uirotcharheight);

	sprintf(buf, "%02d:%02d", wave_minutes, wave_seconds);
	width = strlen(buf) * uirotcharwidth;

	ui_text_bk(bitmap, buf, uirotwidth - width, uirotheight - uirotcharheight);
}



int handle_user_interface(struct mame_bitmap *bitmap)
{
	static int show_profiler;

	if (options.jukebox)
	{
		if (jukebox)
		{
			if (Machine->gamedrv->system == SYSTEM_NEOGEO)
			{
				jukebox_play(bitmap, JUKEBOX_NEOGEO);
			}
			else if (strcmp(Machine->gamedrv->sound, "qsound") && strcmp(Machine->gamedrv->sound, "cps2"))
			{
				jukebox_play(bitmap, JUKEBOX_CPS);
			}
			else
			{
				jukebox_play(bitmap, JUKEBOX_QSOUND);
			}
		}
		else
		{
			cpu_set_halt_line(0, 1);
			palette_set_rgb(0x0fff, ui_colortable[JUKEBOX_BACKGROUND]);
			jukebox = 1;
		}

		if (input_ui_pressed(IPT_UI_CLOSE))
		{
			flash_all_values_and_buffers();
			return 1;
		}

		if (wave_recording)
			recording_counter(bitmap);

		return 0;
	}

	if (wave_recording)
		recording_counter(bitmap);

	/* if the user pressed F12, save the screen to a file */
	if (input_ui_pressed(IPT_UI_SNAPSHOT))
		osd_save_snapshot(bitmap, &Machine->visible_area);

	/* This call is for the cheat, it must be called once a frame */
	if (options.cheat) DoCheat(bitmap);

	/* if the user pressed ESC, stop the emulation */
	/* but don't quit if the setup menu is on screen */
	if (setup_selected == 0 && input_ui_pressed(IPT_UI_CLOSE))
	{
		flash_all_values_and_buffers();
		return 1;
	}

	if (setup_selected == 0 && command_sc == 0 &&
		cheat_sc == 0 && input_ui_pressed(IPT_UI_CONFIGURE))
	{
		setup_selected = -1;

		if (osd_selected != 0)
		{
			osd_selected = 0;	/* disable on screen display */
			schedule_full_refresh();
		}
	}
	if (setup_selected != 0) setup_selected = setup_menu(bitmap, setup_selected);

	if (!mame_debug && osd_selected == 0 && command_sc == 0 &&
		cheat_sc == 0 && input_ui_pressed(IPT_UI_ON_SCREEN_DISPLAY))
	{
		osd_selected = -1;

		if (setup_selected != 0)
		{
			setup_selected = 0; /* disable setup menu */
			schedule_full_refresh();
		}
	}
	if (osd_selected != 0) osd_selected = on_screen_display(bitmap, osd_selected);

	if (setup_selected == 0 && cheat_sc == 0 && input_ui_pressed(IPT_UI_COMMAND))
	{
		command_sc ^= 1;

		if (osd_selected != 0)
		{
			osd_selected = 0;	/* disable on screen display */
			schedule_full_refresh();
		}
	}

	if (command_sc && setup_selected == 0)
	{
		static int res;
		res = displaycommand_ex(bitmap, command_sel, 1);
		command_sel = res++;

		if (command_sel == 0)
		{
			command_sc = 0;
			command_sel = 1;
		}
	}

	if (setup_selected == 0 && command_sc == 0 && input_ui_pressed(IPT_UI_CHEAT))
	{
		cheat_sc ^= 1;
		cheat_fe = 1;

		if (osd_selected != 0)
		{
			osd_selected = 0;	/* disable on screen display */
			schedule_full_refresh();
		}
	}

	if (cheat_sc && setup_selected == 0)
	{
		static int res;
		res = EnableDisableCheatMenu(bitmap, cheat_sel, cheat_fe, 1);
		cheat_sel = res++;
		cheat_fe = 0;

		if (cheat_sel == 0)
		{
			cheat_sc = 0;
			cheat_sel = 1;
		}
	}

	if (input_ui_pressed(IPT_UI_TIME))
	{
		show_time ^= 1;
	}

	if (show_time && wave_recording == 0 && show_input == 0)
	{
		char buf[20];
		int width;
		time_t ltime;
		struct tm *today;

		time(&ltime);
		today = localtime(&ltime);

		sprintf(buf, "%02d:%02d", today->tm_hour, today->tm_min);
		width = strlen(buf) * uirotcharwidth;
		ui_text_bk(bitmap, buf, uirotwidth - width, uirotheight - uirotcharheight);
	}

	/* if the user pressed F3, reset the emulation */
	if (input_ui_pressed(IPT_UI_RESET_MACHINE))
		machine_reset();

	if (input_ui_pressed(IPT_UI_SAVE_STATE))
		do_loadsave(bitmap, LOADSAVE_SAVE);

	if (input_ui_pressed(IPT_UI_LOAD_STATE))
		do_loadsave(bitmap, LOADSAVE_LOAD);

	if (single_step || input_ui_pressed(IPT_UI_PAUSE)) /* pause the game */
	{
/*		osd_selected = 0;	   disable on screen display, since we are going   */
							/* to change parameters affected by it */

		single_step = 0;

		if (single_step == 0)
			mame_pause(1);

		while (!input_ui_pressed(IPT_UI_PAUSE) || object == 1)
		{
			profiler_mark(PROFILER_VIDEO);
			if (osd_skip_this_frame() == 0)
			{
				/* keep calling vh_screenrefresh() while paused so we can stuff */
				/* debug code in there */
				draw_screen();
			}
			profiler_mark(PROFILER_END);

			if (input_ui_pressed(IPT_UI_SNAPSHOT))
				osd_save_snapshot(bitmap, &Machine->visible_area);

			if (input_ui_pressed(IPT_UI_SAVE_STATE))
				do_loadsave(bitmap, LOADSAVE_SAVE);

			if (input_ui_pressed(IPT_UI_LOAD_STATE))
				do_loadsave(bitmap, LOADSAVE_LOAD);

			/* if the user pressed F4, show the character set */
			if (input_ui_pressed(IPT_UI_SHOW_GFX))
				showcharset(bitmap);

			if (input_ui_pressed_repeat(IPT_UI_SINGLE_STEP, 8))
			{
				single_step = 1;
				break;
			}

			if (setup_selected == 0 && command_sc == 0 &&
				cheat_sc == 0 && input_ui_pressed(IPT_UI_OPERATION_OBJ))
			{
				object ^= 1;

				if (osd_selected != 0)
				{
					osd_selected = 0;	/* disable on screen display */
					schedule_full_refresh();
				}

				if (object)
				{
					object_operation_start();
				}
				else
				{
					object_operation_end();
				}
			}

			if (object)
			{
				if (input_ui_pressed(IPT_UI_CANCEL))
				{
					object_operation_end();
				}
				else
				{
					if (Machine->gamedrv->system == SYSTEM_NEOGEO)
						object_operation_neogeo(bitmap);
					else
						object_operation_cps(bitmap);
				}
			}

			if (setup_selected == 0 && object == 0 && input_ui_pressed(IPT_UI_CLOSE))
			{
				flash_all_values_and_buffers();
				return 1;
			}

			if (setup_selected == 0 && object == 0 &&
				cheat_sc == 0 && input_ui_pressed(IPT_UI_COMMAND))
			{
				command_sc ^= 1;

				if (osd_selected != 0)
				{
					osd_selected = 0;	/* disable on screen display */
					schedule_full_refresh();
				}
			}

			if (command_sc && setup_selected == 0)
			{
				static int res;
				res = displaycommand_ex(bitmap, command_sel, 1);
				command_sel = res++;

				if (command_sel == 0)
				{
					command_sc = 0;
					command_sel = 1;
				}
			}

			if (setup_selected == 0 && object == 0 &&
				command_sc == 0 && input_ui_pressed(IPT_UI_CHEAT))
			{
				cheat_sc ^= 1;
				cheat_fe = 1;

				if (osd_selected != 0)
				{
					osd_selected = 0;	/* disable on screen display */
					schedule_full_refresh();
				}
			}

			if (cheat_sc && setup_selected == 0)
			{
				static int res;
				res = EnableDisableCheatMenu(bitmap, cheat_sel, cheat_fe, 1);
				cheat_sel = res++;
				cheat_fe = 0;

				if (cheat_sel == 0)
				{
					cheat_sc = 0;
					cheat_sel = 1;
				}
			}

			if (input_ui_pressed(IPT_UI_TIME))
			{
				show_time ^= 1;
			}

			if (show_time)
			{
				char buf[20];
				int width;
				time_t ltime;
				struct tm *today;

				time(&ltime);
				today = localtime(&ltime);

				sprintf(buf, "%02d:%02d", today->tm_hour, today->tm_min);
				width = strlen(buf) * uirotcharwidth;
				ui_text_bk(bitmap, buf, uirotwidth - width, uirotheight - uirotcharheight);
			}

			if (setup_selected == 0 && object == 0 && command_sc == 0 &&
				cheat_sc == 0 && input_ui_pressed(IPT_UI_CONFIGURE))
			{
				setup_selected = -1;

				if (osd_selected != 0)
				{
					osd_selected = 0;	/* disable on screen display */
					schedule_full_refresh();
				}
			}
			if (setup_selected != 0) setup_selected = setup_menu(bitmap, setup_selected);

			if (!mame_debug && osd_selected == 0 && object == 0 &&
				command_sc == 0 && cheat_sc == 0 && input_ui_pressed(IPT_UI_ON_SCREEN_DISPLAY))
			{
				osd_selected = -1;

				if (setup_selected != 0)
				{
					setup_selected = 0; /* disable setup menu */
					schedule_full_refresh();
				}
			}
			if (osd_selected != 0) osd_selected = on_screen_display(bitmap, osd_selected);

			if (options.cheat) DisplayWatches(bitmap);

			/* show popup message if any */
			if (messagecounter > 0)
			{
				displaymessage(bitmap, messagetext, 1);

				if (--messagecounter == 0)
					schedule_full_refresh();
			}

			update_video_and_audio();
			reset_partial_updates();
		}

		if (single_step == 0)
		{
			mame_pause(0);
		}

		schedule_full_refresh();
	}

	if (input_ui_pressed(IPT_UI_SHOW_INPUT_LOG))
	{
		show_input ^= 1;
		memset(command_buf, 0, COMMAND_LOG_BUFSIZE);
	}

	if (show_input && command_counter)
	{
		ui_transbox(bitmap, 0, uirotheight - uirotcharheight, uirotwidth, uirotcharheight);

		ui_text(bitmap, command_buf, 0, uirotheight - uirotcharheight);
		
		if (--command_counter == 0)
			memset(command_buf, 0, COMMAND_LOG_BUFSIZE);
	}

	/* show popup message if any */
	if (messagecounter > 0)
	{
		displaymessage(bitmap, messagetext, 1);

		if (--messagecounter == 0)
			schedule_full_refresh();
	}


	if (input_ui_pressed(IPT_UI_SHOW_PROFILER))
	{
		show_profiler ^= 1;
		if (show_profiler)
			profiler_start();
		else
		{
			profiler_stop();
			schedule_full_refresh();
		}
	}

	if (show_profiler) profiler_show(bitmap);


	/* show FPS display? */
	if (input_ui_pressed(IPT_UI_SHOW_FPS))
	{
		/* if we're temporarily on, turn it off immediately */
		if (showfpstemp)
		{
			showfpstemp = 0;
			schedule_full_refresh();
		}

		/* otherwise, just toggle; force a refresh if going off */
		else
		{
			showfps ^= 1;
			if (!showfps)
				schedule_full_refresh();
		}
	}


	/* if the user pressed F4, show the character set */
	if (input_ui_pressed(IPT_UI_SHOW_GFX))
	{
		osd_sound_enable(0);

		showcharset(bitmap);

		osd_sound_enable(1);
	}

	if (input_ui_pressed(IPT_UI_TOGGLE_AUTOFIRE))
	{
		extern int toggle_autofire(void);
		int autofire_enable = toggle_autofire();

		usrintf_showmessage(ui_getstring(UI_autofiretoggle_message), (autofire_enable ? ui_getstring(UI_on) : ui_getstring(UI_off)));
	}

	if (input_ui_pressed(IPT_UI_TOGGLE_LOGWAVE))
	{
		if (wave_recording == 0)
		{
			osd_start_log_wave();
			wave_recording = 1;
			wave_counter   = 0;
			wave_seconds   = 0;
			wave_minutes   = 0;
		}
		else
		{
			osd_stop_log_wave();
			wave_recording = 0;
		}
	}

	/* add the FPS counter */
	display_fps(bitmap);

	return 0;
}


void init_user_interface(void)
{
	extern int snapno;	/* in common.c */

	snapno = 0; /* reset snapshot counter */

	setup_menu_init();
	onscrd_init();
	flash_all_values_and_buffers();
}

int onscrd_active(void)
{
	return osd_selected;
}

int setup_active(void)
{
	return setup_selected;
}

