summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/ui.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/ui.c')
-rw-r--r--trunk/src/emu/ui.c2252
1 files changed, 2252 insertions, 0 deletions
diff --git a/trunk/src/emu/ui.c b/trunk/src/emu/ui.c
new file mode 100644
index 00000000000..56817e9190e
--- /dev/null
+++ b/trunk/src/emu/ui.c
@@ -0,0 +1,2252 @@
+/*********************************************************************
+
+ ui.c
+
+ Functions used to handle MAME's user interface.
+
+ Copyright Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "video/vector.h"
+#include "machine/laserdsc.h"
+#include "profiler.h"
+#include "render.h"
+#include "cheat.h"
+#include "rendfont.h"
+#include "ui.h"
+#include "uiinput.h"
+#include "uimenu.h"
+#include "uigfx.h"
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+enum
+{
+ LOADSAVE_NONE,
+ LOADSAVE_LOAD,
+ LOADSAVE_SAVE
+};
+
+
+/***************************************************************************
+ LOCAL VARIABLES
+***************************************************************************/
+
+/* list of natural keyboard keys that are not associated with UI_EVENT_CHARs */
+static const input_item_id non_char_keys[] =
+{
+ ITEM_ID_ESC,
+ ITEM_ID_F1,
+ ITEM_ID_F2,
+ ITEM_ID_F3,
+ ITEM_ID_F4,
+ ITEM_ID_F5,
+ ITEM_ID_F6,
+ ITEM_ID_F7,
+ ITEM_ID_F8,
+ ITEM_ID_F9,
+ ITEM_ID_F10,
+ ITEM_ID_F11,
+ ITEM_ID_F12,
+ ITEM_ID_NUMLOCK,
+ ITEM_ID_0_PAD,
+ ITEM_ID_1_PAD,
+ ITEM_ID_2_PAD,
+ ITEM_ID_3_PAD,
+ ITEM_ID_4_PAD,
+ ITEM_ID_5_PAD,
+ ITEM_ID_6_PAD,
+ ITEM_ID_7_PAD,
+ ITEM_ID_8_PAD,
+ ITEM_ID_9_PAD,
+ ITEM_ID_DEL_PAD,
+ ITEM_ID_PLUS_PAD,
+ ITEM_ID_MINUS_PAD,
+ ITEM_ID_INSERT,
+ ITEM_ID_DEL,
+ ITEM_ID_HOME,
+ ITEM_ID_END,
+ ITEM_ID_PGUP,
+ ITEM_ID_PGDN,
+ ITEM_ID_UP,
+ ITEM_ID_DOWN,
+ ITEM_ID_LEFT,
+ ITEM_ID_RIGHT,
+ ITEM_ID_PAUSE,
+ ITEM_ID_CANCEL
+};
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* font for rendering */
+static render_font *ui_font;
+
+/* current UI handler */
+static UINT32 (*ui_handler_callback)(running_machine &, render_container *, UINT32);
+static UINT32 ui_handler_param;
+
+/* flag to track single stepping */
+static int single_step;
+
+/* FPS counter display */
+static int showfps;
+static osd_ticks_t showfps_end;
+
+/* profiler display */
+static int show_profiler;
+
+/* popup text display */
+static osd_ticks_t popup_text_end;
+
+/* messagebox buffer */
+static astring messagebox_text;
+static rgb_t messagebox_backcolor;
+
+/* slider info */
+static slider_state *slider_list;
+static slider_state *slider_current;
+
+/* natural keyboard info */
+static int ui_use_natural_keyboard;
+static UINT8 non_char_keys_down[(ARRAY_LENGTH(non_char_keys) + 7) / 8];
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void ui_exit(running_machine &machine);
+
+/* text generators */
+static astring &disclaimer_string(running_machine &machine, astring &buffer);
+static astring &warnings_string(running_machine &machine, astring &buffer);
+
+/* UI handlers */
+static UINT32 handler_messagebox(running_machine &machine, render_container *container, UINT32 state);
+static UINT32 handler_messagebox_ok(running_machine &machine, render_container *container, UINT32 state);
+static UINT32 handler_messagebox_anykey(running_machine &machine, render_container *container, UINT32 state);
+static UINT32 handler_ingame(running_machine &machine, render_container *container, UINT32 state);
+static UINT32 handler_load_save(running_machine &machine, render_container *container, UINT32 state);
+static UINT32 handler_confirm_quit(running_machine &machine, render_container *container, UINT32 state);
+
+/* slider controls */
+static slider_state *slider_alloc(running_machine &machine, const char *title, INT32 minval, INT32 defval, INT32 maxval, INT32 incval, slider_update update, void *arg);
+static slider_state *slider_init(running_machine &machine);
+static INT32 slider_volume(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_mixervol(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_adjuster(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_overclock(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_refresh(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_brightness(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_contrast(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_gamma(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_xscale(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_yscale(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_xoffset(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_yoffset(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_overxscale(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_overyscale(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_overxoffset(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_overyoffset(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_flicker(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_beam(running_machine &machine, void *arg, astring *string, INT32 newval);
+static char *slider_get_screen_desc(screen_device &screen);
+static char *slider_get_laserdisc_desc(device_t *screen);
+#ifdef MAME_DEBUG
+static INT32 slider_crossscale(running_machine &machine, void *arg, astring *string, INT32 newval);
+static INT32 slider_crossoffset(running_machine &machine, void *arg, astring *string, INT32 newval);
+#endif
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ ui_set_handler - set a callback/parameter
+ pair for the current UI handler
+-------------------------------------------------*/
+
+INLINE UINT32 ui_set_handler(UINT32 (*callback)(running_machine &, render_container *, UINT32), UINT32 param)
+{
+ ui_handler_callback = callback;
+ ui_handler_param = param;
+ return param;
+}
+
+
+/*-------------------------------------------------
+ is_breakable_char - is a given unicode
+ character a possible line break?
+-------------------------------------------------*/
+
+INLINE int is_breakable_char(unicode_char ch)
+{
+ /* regular spaces and hyphens are breakable */
+ if (ch == ' ' || ch == '-')
+ return TRUE;
+
+ /* In the following character sets, any character is breakable:
+ Hiragana (3040-309F)
+ Katakana (30A0-30FF)
+ Bopomofo (3100-312F)
+ Hangul Compatibility Jamo (3130-318F)
+ Kanbun (3190-319F)
+ Bopomofo Extended (31A0-31BF)
+ CJK Strokes (31C0-31EF)
+ Katakana Phonetic Extensions (31F0-31FF)
+ Enclosed CJK Letters and Months (3200-32FF)
+ CJK Compatibility (3300-33FF)
+ CJK Unified Ideographs Extension A (3400-4DBF)
+ Yijing Hexagram Symbols (4DC0-4DFF)
+ CJK Unified Ideographs (4E00-9FFF) */
+ if (ch >= 0x3040 && ch <= 0x9fff)
+ return TRUE;
+
+ /* Hangul Syllables (AC00-D7AF) are breakable */
+ if (ch >= 0xac00 && ch <= 0xd7af)
+ return TRUE;
+
+ /* CJK Compatibility Ideographs (F900-FAFF) are breakable */
+ if (ch >= 0xf900 && ch <= 0xfaff)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ ui_init - set up the user interface
+-------------------------------------------------*/
+
+int ui_init(running_machine &machine)
+{
+ /* make sure we clean up after ourselves */
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(ui_exit), &machine));
+
+ /* initialize the other UI bits */
+ ui_menu_init(machine);
+ ui_gfx_init(machine);
+
+ /* reset globals */
+ single_step = FALSE;
+ ui_set_handler(handler_messagebox, 0);
+ /* retrieve options */
+ ui_use_natural_keyboard = machine.options().natural_keyboard();
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ ui_exit - clean up ourselves on exit
+-------------------------------------------------*/
+
+static void ui_exit(running_machine &machine)
+{
+ /* free the font */
+ machine.render().font_free(ui_font);
+ ui_font = NULL;
+}
+
+
+/*-------------------------------------------------
+ ui_display_startup_screens - display the
+ various startup screens
+-------------------------------------------------*/
+
+int ui_display_startup_screens(running_machine &machine, int first_time, int show_disclaimer)
+{
+ const int maxstate = 3;
+ int str = machine.options().seconds_to_run();
+ int show_gameinfo = !machine.options().skip_gameinfo();
+ int show_warnings = TRUE;
+ int state;
+
+ /* disable everything if we are using -str for 300 or fewer seconds, or if we're the empty driver,
+ or if we are debugging */
+ if (!first_time || (str > 0 && str < 60*5) || &machine.system() == &GAME_NAME(___empty) || (machine.debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ show_gameinfo = show_warnings = show_disclaimer = FALSE;
+
+ /* initialize the on-screen display system */
+ slider_list = slider_current = slider_init(machine);
+
+ /* loop over states */
+ ui_set_handler(handler_ingame, 0);
+ for (state = 0; state < maxstate && !machine.scheduled_event_pending() && !ui_menu_is_force_game_select(); state++)
+ {
+ /* default to standard colors */
+ messagebox_backcolor = UI_BACKGROUND_COLOR;
+
+ /* pick the next state */
+ switch (state)
+ {
+ case 0:
+ if (show_disclaimer && disclaimer_string(machine, messagebox_text).len() > 0)
+ ui_set_handler(handler_messagebox_ok, 0);
+ break;
+
+ case 1:
+ if (show_warnings && warnings_string(machine, messagebox_text).len() > 0)
+ {
+ ui_set_handler(handler_messagebox_ok, 0);
+ if (machine.system().flags & (GAME_WRONG_COLORS | GAME_IMPERFECT_COLORS | GAME_REQUIRES_ARTWORK | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND | GAME_NO_SOUND))
+ messagebox_backcolor = UI_YELLOW_COLOR;
+ if (machine.system().flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_MECHANICAL))
+ messagebox_backcolor = UI_RED_COLOR;
+ }
+ break;
+
+ case 2:
+ if (show_gameinfo && game_info_astring(machine, messagebox_text).len() > 0)
+ ui_set_handler(handler_messagebox_anykey, 0);
+ break;
+ }
+
+ /* clear the input memory */
+ machine.input().reset_polling();
+ while (machine.input().poll_switches() != INPUT_CODE_INVALID) ;
+
+ /* loop while we have a handler */
+ while (ui_handler_callback != handler_ingame && !machine.scheduled_event_pending() && !ui_menu_is_force_game_select())
+ machine.video().frame_update();
+
+ /* clear the handler and force an update */
+ ui_set_handler(handler_ingame, 0);
+ machine.video().frame_update();
+ }
+
+ /* if we're the empty driver, force the menus on */
+ if (ui_menu_is_force_game_select())
+ ui_set_handler(ui_menu_ui_handler, 0);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ ui_set_startup_text - set the text to display
+ at startup
+-------------------------------------------------*/
+
+void ui_set_startup_text(running_machine &machine, const char *text, int force)
+{
+ static osd_ticks_t lastupdatetime = 0;
+ osd_ticks_t curtime = osd_ticks();
+
+ /* copy in the new text */
+ messagebox_text.cpy(text);
+ messagebox_backcolor = UI_BACKGROUND_COLOR;
+
+ /* don't update more than 4 times/second */
+ if (force || (curtime - lastupdatetime) > osd_ticks_per_second() / 4)
+ {
+ lastupdatetime = curtime;
+ machine.video().frame_update();
+ }
+}
+
+
+/*-------------------------------------------------
+ ui_update_and_render - update the UI and
+ render it; called by video.c
+-------------------------------------------------*/
+
+void ui_update_and_render(running_machine &machine, render_container *container)
+{
+ /* always start clean */
+ container->empty();
+
+ /* if we're paused, dim the whole screen */
+ if (machine.phase() >= MACHINE_PHASE_RESET && (single_step || machine.paused()))
+ {
+ int alpha = (1.0f - machine.options().pause_brightness()) * 255.0f;
+ if (ui_menu_is_force_game_select())
+ alpha = 255;
+ if (alpha > 255)
+ alpha = 255;
+ if (alpha >= 0)
+ container->add_rect(0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(alpha,0x00,0x00,0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
+
+ /* render any cheat stuff at the bottom */
+ if (machine.phase() >= MACHINE_PHASE_RESET)
+ machine.cheat().render_text(*container);
+
+ /* call the current UI handler */
+ assert(ui_handler_callback != NULL);
+ ui_handler_param = (*ui_handler_callback)(machine, container, ui_handler_param);
+
+ /* display any popup messages */
+ if (osd_ticks() < popup_text_end)
+ ui_draw_text_box(container, messagebox_text, JUSTIFY_CENTER, 0.5f, 0.9f, messagebox_backcolor);
+ else
+ popup_text_end = 0;
+
+ /* cancel takes us back to the ingame handler */
+ if (ui_handler_param == UI_HANDLER_CANCEL)
+ ui_set_handler(handler_ingame, 0);
+}
+
+
+/*-------------------------------------------------
+ ui_get_font - return the UI font
+-------------------------------------------------*/
+
+render_font *ui_get_font(running_machine &machine)
+{
+ /* allocate the font and messagebox string */
+ if (ui_font == NULL)
+ ui_font = machine.render().font_alloc(machine.options().ui_font());
+ return ui_font;
+}
+
+
+/*-------------------------------------------------
+ ui_get_line_height - return the current height
+ of a line
+-------------------------------------------------*/
+
+float ui_get_line_height(running_machine &machine)
+{
+ INT32 raw_font_pixel_height = ui_get_font(machine)->pixel_height();
+ render_target &ui_target = machine.render().ui_target();
+ INT32 target_pixel_height = ui_target.height();
+ float one_to_one_line_height;
+ float scale_factor;
+
+ /* compute the font pixel height at the nominal size */
+ one_to_one_line_height = (float)raw_font_pixel_height / (float)target_pixel_height;
+
+ /* determine the scale factor */
+ scale_factor = UI_TARGET_FONT_HEIGHT / one_to_one_line_height;
+
+ /* if our font is small-ish, do integral scaling */
+ if (raw_font_pixel_height < 24)
+ {
+ /* do we want to scale smaller? only do so if we exceed the threshhold */
+ if (scale_factor <= 1.0f)
+ {
+ if (one_to_one_line_height < UI_MAX_FONT_HEIGHT || raw_font_pixel_height < 12)
+ scale_factor = 1.0f;
+ }
+
+ /* otherwise, just ensure an integral scale factor */
+ else
+ scale_factor = floor(scale_factor);
+ }
+
+ /* otherwise, just make sure we hit an even number of pixels */
+ else
+ {
+ INT32 height = scale_factor * one_to_one_line_height * (float)target_pixel_height;
+ scale_factor = (float)height / (one_to_one_line_height * (float)target_pixel_height);
+ }
+
+ return scale_factor * one_to_one_line_height;
+}
+
+
+/*-------------------------------------------------
+ ui_get_char_width - return the width of a
+ single character
+-------------------------------------------------*/
+
+float ui_get_char_width(running_machine &machine, unicode_char ch)
+{
+ return ui_get_font(machine)->char_width(ui_get_line_height(machine), machine.render().ui_aspect(), ch);
+}
+
+
+/*-------------------------------------------------
+ ui_get_string_width - return the width of a
+ character string
+-------------------------------------------------*/
+
+float ui_get_string_width(running_machine &machine, const char *s)
+{
+ return ui_get_font(machine)->utf8string_width(ui_get_line_height(machine), machine.render().ui_aspect(), s);
+}
+
+
+/*-------------------------------------------------
+ ui_draw_outlined_box - add primitives to draw
+ an outlined box with the given background
+ color
+-------------------------------------------------*/
+
+void ui_draw_outlined_box(render_container *container, float x0, float y0, float x1, float y1, rgb_t backcolor)
+{
+ container->add_rect(x0, y0, x1, y1, backcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ container->add_line(x0, y0, x1, y0, UI_LINE_WIDTH, UI_BORDER_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ container->add_line(x1, y0, x1, y1, UI_LINE_WIDTH, UI_BORDER_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ container->add_line(x1, y1, x0, y1, UI_LINE_WIDTH, UI_BORDER_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ container->add_line(x0, y1, x0, y0, UI_LINE_WIDTH, UI_BORDER_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+}
+
+
+/*-------------------------------------------------
+ ui_draw_text - simple text renderer
+-------------------------------------------------*/
+
+void ui_draw_text(render_container *container, const char *buf, float x, float y)
+{
+ ui_draw_text_full(container, buf, x, y, 1.0f - x, JUSTIFY_LEFT, WRAP_WORD, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, NULL, NULL);
+}
+
+
+/*-------------------------------------------------
+ ui_draw_text_full - full featured text
+ renderer with word wrapping, justification,
+ and full size computation
+-------------------------------------------------*/
+
+void ui_draw_text_full(render_container *container, const char *origs, float x, float y, float origwrapwidth, int justify, int wrap, int draw, rgb_t fgcolor, rgb_t bgcolor, float *totalwidth, float *totalheight)
+{
+ running_machine &machine = container->manager().machine();
+ float lineheight = ui_get_line_height(machine);
+ const char *ends = origs + strlen(origs);
+ float wrapwidth = origwrapwidth;
+ const char *s = origs;
+ const char *linestart;
+ float cury = y;
+ float maxwidth = 0;
+
+ /* if we don't want wrapping, guarantee a huge wrapwidth */
+ if (wrap == WRAP_NEVER)
+ wrapwidth = 1000000.0f;
+ if (wrapwidth <= 0)
+ return;
+
+ /* loop over lines */
+ while (*s != 0)
+ {
+ const char *lastbreak = NULL;
+ int line_justify = justify;
+ unicode_char schar;
+ int scharcount;
+ float lastbreak_width = 0;
+ float curwidth = 0;
+ float curx = x;
+
+ /* get the current character */
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+
+ /* if the line starts with a tab character, center it regardless */
+ if (schar == '\t')
+ {
+ s += scharcount;
+ line_justify = JUSTIFY_CENTER;
+ }
+
+ /* remember the starting position of the line */
+ linestart = s;
+
+ /* loop while we have characters and are less than the wrapwidth */
+ while (*s != 0 && curwidth <= wrapwidth)
+ {
+ float chwidth;
+
+ /* get the current chcaracter */
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+
+ /* if we hit a newline, stop immediately */
+ if (schar == '\n')
+ break;
+
+ /* get the width of this character */
+ chwidth = ui_get_char_width(machine, schar);
+
+ /* if we hit a space, remember the location and width *without* the space */
+ if (schar == ' ')
+ {
+ lastbreak = s;
+ lastbreak_width = curwidth;
+ }
+
+ /* add the width of this character and advance */
+ curwidth += chwidth;
+ s += scharcount;
+
+ /* if we hit any non-space breakable character, remember the location and width
+ *with* the breakable character */
+ if (schar != ' ' && is_breakable_char(schar) && curwidth <= wrapwidth)
+ {
+ lastbreak = s;
+ lastbreak_width = curwidth;
+ }
+ }
+
+ /* if we accumulated too much for the current width, we need to back off */
+ if (curwidth > wrapwidth)
+ {
+ /* if we're word wrapping, back up to the last break if we can */
+ if (wrap == WRAP_WORD)
+ {
+ /* if we hit a break, back up to there with the appropriate width */
+ if (lastbreak != NULL)
+ {
+ s = lastbreak;
+ curwidth = lastbreak_width;
+ }
+
+ /* if we didn't hit a break, back up one character */
+ else if (s > linestart)
+ {
+ /* get the previous character */
+ s = (const char *)utf8_previous_char(s);
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+
+ curwidth -= ui_get_char_width(machine, schar);
+ }
+ }
+
+ /* if we're truncating, make sure we have enough space for the ... */
+ else if (wrap == WRAP_TRUNCATE)
+ {
+ /* add in the width of the ... */
+ curwidth += 3.0f * ui_get_char_width(machine, '.');
+
+ /* while we are above the wrap width, back up one character */
+ while (curwidth > wrapwidth && s > linestart)
+ {
+ /* get the previous character */
+ s = (const char *)utf8_previous_char(s);
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+
+ curwidth -= ui_get_char_width(machine, schar);
+ }
+ }
+ }
+
+ /* align according to the justfication */
+ if (line_justify == JUSTIFY_CENTER)
+ curx += (origwrapwidth - curwidth) * 0.5f;
+ else if (line_justify == JUSTIFY_RIGHT)
+ curx += origwrapwidth - curwidth;
+
+ /* track the maximum width of any given line */
+ if (curwidth > maxwidth)
+ maxwidth = curwidth;
+
+ /* if opaque, add a black box */
+ if (draw == DRAW_OPAQUE)
+ container->add_rect(curx, cury, curx + curwidth, cury + lineheight, bgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ /* loop from the line start and add the characters */
+ while (linestart < s)
+ {
+ /* get the current character */
+ unicode_char linechar;
+ int linecharcount = uchar_from_utf8(&linechar, linestart, ends - linestart);
+ if (linecharcount == -1)
+ break;
+
+ if (draw != DRAW_NONE)
+ {
+ container->add_char(curx, cury, lineheight, machine.render().ui_aspect(), fgcolor, *ui_get_font(machine), linechar);
+ curx += ui_get_char_width(machine, linechar);
+ }
+ linestart += linecharcount;
+ }
+
+ /* append ellipses if needed */
+ if (wrap == WRAP_TRUNCATE && *s != 0 && draw != DRAW_NONE)
+ {
+ container->add_char(curx, cury, lineheight, machine.render().ui_aspect(), fgcolor, *ui_get_font(machine), '.');
+ curx += ui_get_char_width(machine, '.');
+ container->add_char(curx, cury, lineheight, machine.render().ui_aspect(), fgcolor, *ui_get_font(machine), '.');
+ curx += ui_get_char_width(machine, '.');
+ container->add_char(curx, cury, lineheight, machine.render().ui_aspect(), fgcolor, *ui_get_font(machine), '.');
+ curx += ui_get_char_width(machine, '.');
+ }
+
+ /* if we're not word-wrapping, we're done */
+ if (wrap != WRAP_WORD)
+ break;
+
+ /* advance by a row */
+ cury += lineheight;
+
+ /* skip past any spaces at the beginning of the next line */
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+
+ if (schar == '\n')
+ s += scharcount;
+ else
+ while (*s && isspace(schar))
+ {
+ s += scharcount;
+ scharcount = uchar_from_utf8(&schar, s, ends - s);
+ if (scharcount == -1)
+ break;
+ }
+ }
+
+ /* report the width and height of the resulting space */
+ if (totalwidth)
+ *totalwidth = maxwidth;
+ if (totalheight)
+ *totalheight = cury - y;
+}
+
+
+/*-------------------------------------------------
+ ui_draw_text_box - draw a multiline text
+ message with a box around it
+-------------------------------------------------*/
+
+void ui_draw_text_box(render_container *container, const char *text, int justify, float xpos, float ypos, rgb_t backcolor)
+{
+ float line_height = ui_get_line_height(container->manager().machine());
+ float max_width = 2.0f * ((xpos <= 0.5f) ? xpos : 1.0f - xpos) - 2.0f * UI_BOX_LR_BORDER;
+ float target_width = max_width;
+ float target_height = line_height;
+ float target_x = 0, target_y = 0;
+ float last_target_height = 0;
+
+ // limit this iteration to a finite number of passes
+ for (int pass = 0; pass < 5; pass++)
+ {
+ /* determine the target location */
+ target_x = xpos - 0.5f * target_width;
+ target_y = ypos - 0.5f * target_height;
+
+ /* make sure we stay on-screen */
+ if (target_x < UI_BOX_LR_BORDER)
+ target_x = UI_BOX_LR_BORDER;
+ if (target_x + target_width + UI_BOX_LR_BORDER > 1.0f)
+ target_x = 1.0f - UI_BOX_LR_BORDER - target_width;
+ if (target_y < UI_BOX_TB_BORDER)
+ target_y = UI_BOX_TB_BORDER;
+ if (target_y + target_height + UI_BOX_TB_BORDER > 1.0f)
+ target_y = 1.0f - UI_BOX_TB_BORDER - target_height;
+
+ /* compute the multi-line target width/height */
+ ui_draw_text_full(container, text, target_x, target_y, target_width + 0.00001f,
+ justify, WRAP_WORD, DRAW_NONE, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &target_width, &target_height);
+ if (target_height > 1.0f - 2.0f * UI_BOX_TB_BORDER)
+ target_height = floor((1.0f - 2.0f * UI_BOX_TB_BORDER) / line_height) * line_height;
+
+ /* if we match our last value, we're done */
+ if (target_height == last_target_height)
+ break;
+ last_target_height = target_height;
+ }
+
+ /* add a box around that */
+ ui_draw_outlined_box(container, target_x - UI_BOX_LR_BORDER,
+ target_y - UI_BOX_TB_BORDER,
+ target_x + target_width + UI_BOX_LR_BORDER,
+ target_y + target_height + UI_BOX_TB_BORDER, backcolor);
+ ui_draw_text_full(container, text, target_x, target_y, target_width + 0.00001f,
+ justify, WRAP_WORD, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, NULL, NULL);
+}
+
+
+/*-------------------------------------------------
+ ui_popup_time - popup a message for a specific
+ amount of time
+-------------------------------------------------*/
+
+void CLIB_DECL ui_popup_time(int seconds, const char *text, ...)
+{
+ va_list arg;
+
+ /* extract the text */
+ va_start(arg,text);
+ messagebox_text.vprintf(text, arg);
+ messagebox_backcolor = UI_BACKGROUND_COLOR;
+ va_end(arg);
+
+ /* set a timer */
+ popup_text_end = osd_ticks() + osd_ticks_per_second() * seconds;
+}
+
+
+/*-------------------------------------------------
+ ui_show_fps_temp - show the FPS counter for
+ a specific period of time
+-------------------------------------------------*/
+
+void ui_show_fps_temp(double seconds)
+{
+ if (!showfps)
+ showfps_end = osd_ticks() + seconds * osd_ticks_per_second();
+}
+
+
+/*-------------------------------------------------
+ ui_set_show_fps - show/hide the FPS counter
+-------------------------------------------------*/
+
+void ui_set_show_fps(int show)
+{
+ showfps = show;
+ if (!show)
+ {
+ showfps = 0;
+ showfps_end = 0;
+ }
+}
+
+
+/*-------------------------------------------------
+ ui_get_show_fps - return the current FPS
+ counter visibility state
+-------------------------------------------------*/
+
+int ui_get_show_fps(void)
+{
+ return showfps || (showfps_end != 0);
+}
+
+
+/*-------------------------------------------------
+ ui_set_show_profiler - show/hide the profiler
+-------------------------------------------------*/
+
+void ui_set_show_profiler(int show)
+{
+ show_profiler = show;
+ g_profiler.enable(show);
+}
+
+
+/*-------------------------------------------------
+ ui_get_show_profiler - return the current
+ profiler visibility state
+-------------------------------------------------*/
+
+int ui_get_show_profiler(void)
+{
+ return show_profiler;
+}
+
+
+/*-------------------------------------------------
+ ui_show_menu - show the menus
+-------------------------------------------------*/
+
+void ui_show_menu(void)
+{
+ ui_set_handler(ui_menu_ui_handler, 0);
+}
+
+
+/*-------------------------------------------------
+ ui_is_menu_active - return TRUE if the menu
+ UI handler is active
+-------------------------------------------------*/
+
+int ui_is_menu_active(void)
+{
+ return (ui_handler_callback == ui_menu_ui_handler);
+}
+
+
+
+/***************************************************************************
+ TEXT GENERATORS
+***************************************************************************/
+
+/*-------------------------------------------------
+ disclaimer_string - print the disclaimer
+ text to the given buffer
+-------------------------------------------------*/
+
+static astring &disclaimer_string(running_machine &machine, astring &string)
+{
+ string.cpy("Usage of emulators in conjunction with ROMs you don't own is forbidden by copyright law.\n\n");
+ string.catprintf("IF YOU ARE NOT LEGALLY ENTITLED TO PLAY \"%s\" ON THIS EMULATOR, PRESS ESC.\n\n", machine.system().description);
+ string.cat("Otherwise, type OK or move the joystick left then right to continue");
+ return string;
+}
+
+
+/*-------------------------------------------------
+ warnings_string - print the warning flags
+ text to the given buffer
+-------------------------------------------------*/
+
+static astring &warnings_string(running_machine &machine, astring &string)
+{
+#define WARNING_FLAGS ( GAME_NOT_WORKING | \
+ GAME_UNEMULATED_PROTECTION | \
+ GAME_MECHANICAL | \
+ GAME_WRONG_COLORS | \
+ GAME_IMPERFECT_COLORS | \
+ GAME_REQUIRES_ARTWORK | \
+ GAME_NO_SOUND | \
+ GAME_IMPERFECT_SOUND | \
+ GAME_IMPERFECT_GRAPHICS | \
+ GAME_NO_COCKTAIL)
+
+ string.reset();
+
+ /* if no warnings, nothing to return */
+ if (rom_load_warnings(machine) == 0 && rom_load_knownbad(machine) == 0 && !(machine.system().flags & WARNING_FLAGS))
+ return string;
+
+ /* add a warning if any ROMs were loaded with warnings */
+ if (rom_load_warnings(machine) > 0)
+ {
+ string.cat("One or more ROMs/CHDs for this game are incorrect. The " GAMENOUN " may not run correctly.\n");
+ if (machine.system().flags & WARNING_FLAGS)
+ string.cat("\n");
+ }
+
+ /* if we have at least one warning flag, print the general header */
+ if ((machine.system().flags & WARNING_FLAGS) || rom_load_knownbad(machine) > 0)
+ {
+ string.cat("There are known problems with this " GAMENOUN "\n\n");
+
+ /* add a warning if any ROMs are flagged BAD_DUMP/NO_DUMP */
+ if (rom_load_knownbad(machine) > 0)
+ string.cat("One or more ROMs/CHDs for this " GAMENOUN " have not been correctly dumped.\n");
+
+ /* add one line per warning flag */
+ if (input_machine_has_keyboard(machine))
+ string.cat("The keyboard emulation may not be 100% accurate.\n");
+ if (machine.system().flags & GAME_IMPERFECT_COLORS)
+ string.cat("The colors aren't 100% accurate.\n");
+ if (machine.system().flags & GAME_WRONG_COLORS)
+ string.cat("The colors are completely wrong.\n");
+ if (machine.system().flags & GAME_IMPERFECT_GRAPHICS)
+ string.cat("The video emulation isn't 100% accurate.\n");
+ if (machine.system().flags & GAME_IMPERFECT_SOUND)
+ string.cat("The sound emulation isn't 100% accurate.\n");
+ if (machine.system().flags & GAME_NO_SOUND)
+ string.cat("The game lacks sound.\n");
+ if (machine.system().flags & GAME_NO_COCKTAIL)
+ string.cat("Screen flipping in cocktail mode is not supported.\n");
+
+ /* check if external artwork is present before displaying this warning? */
+ if (machine.system().flags & GAME_REQUIRES_ARTWORK)
+ string.cat("The game requires external artwork files\n");
+
+ /* if there's a NOT WORKING, UNEMULATED PROTECTION or GAME MECHANICAL warning, make it stronger */
+ if (machine.system().flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_MECHANICAL))
+ {
+ /* add the strings for these warnings */
+ if (machine.system().flags & GAME_UNEMULATED_PROTECTION)
+ string.cat("The game has protection which isn't fully emulated.\n");
+ if (machine.system().flags & GAME_NOT_WORKING)
+ string.cat("\nTHIS " CAPGAMENOUN " DOESN'T WORK. The emulation for this game is not yet complete. "
+ "There is nothing you can do to fix this problem except wait for the developers to improve the emulation.\n");
+ if (machine.system().flags & GAME_MECHANICAL)
+ string.cat("\nCertain elements of this " GAMENOUN " cannot be emulated as it requires actual physical interaction or consists of mechanical devices. "
+ "It is not possible to fully play this " GAMENOUN ".\n");
+
+ /* find the parent of this driver */
+ driver_enumerator drivlist(machine.options());
+ int maindrv = drivlist.find(machine.system());
+ int clone_of = drivlist.non_bios_clone(maindrv);
+ if (clone_of != -1)
+ maindrv = clone_of;
+
+ /* scan the driver list for any working clones and add them */
+ bool foundworking = false;
+ while (drivlist.next())
+ if (drivlist.current() == maindrv || drivlist.clone() == maindrv)
+ if ((drivlist.driver().flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_MECHANICAL)) == 0)
+ {
+ /* this one works, add a header and display the name of the clone */
+ if (!foundworking)
+ string.cat("\n\nThere are working clones of this game: ");
+ else
+ string.cat(", ");
+ string.cat(drivlist.driver().name);
+ foundworking = true;
+ }
+
+ if (foundworking)
+ string.cat("\n");
+ }
+ }
+
+ /* add the 'press OK' string */
+ string.cat("\n\nType OK or move the joystick left then right to continue");
+ return string;
+}
+
+
+/*-------------------------------------------------
+ game_info_astring - populate an allocated
+ string with the game info text
+-------------------------------------------------*/
+
+astring &game_info_astring(running_machine &machine, astring &string)
+{
+ int scrcount = machine.devicelist().count(SCREEN);
+ int found_sound = FALSE;
+
+ /* print description, manufacturer, and CPU: */
+ string.printf("%s\n%s %s\n\nCPU:\n", machine.system().description, machine.system().year, machine.system().manufacturer);
+
+ /* loop over all CPUs */
+ device_execute_interface *exec = NULL;
+ for (bool gotone = machine.devicelist().first(exec); gotone; gotone = exec->next(exec))
+ {
+ /* get cpu specific clock that takes internal multiplier/dividers into account */
+ int clock = exec->device().clock();
+
+ /* count how many identical CPUs we have */
+ int count = 1;
+ device_execute_interface *scan = NULL;
+ for (bool gotanother = exec->next(scan); gotanother; gotanother = scan->next(scan))
+ {
+ if (exec->device().type() != scan->device().type() || exec->device().clock() != scan->device().clock())
+ break;
+ count++;
+ exec = scan;
+ }
+
+ /* if more than one, prepend a #x in front of the CPU name */
+ if (count > 1)
+ string.catprintf("%d" UTF8_MULTIPLY, count);
+ string.cat(exec->device().name());
+
+ /* display clock in kHz or MHz */
+ if (clock >= 1000000)
+ string.catprintf(" %d.%06d" UTF8_NBSP "MHz\n", clock / 1000000, clock % 1000000);
+ else
+ string.catprintf(" %d.%03d" UTF8_NBSP "kHz\n", clock / 1000, clock % 1000);
+ }
+
+ /* loop over all sound chips */
+ device_sound_interface *sound = NULL;
+ for (bool gotone = machine.devicelist().first(sound); gotone; gotone = sound->next(sound))
+ {
+ /* append the Sound: string */
+ if (!found_sound)
+ string.cat("\nSound:\n");
+ found_sound = TRUE;
+
+ /* count how many identical sound chips we have */
+ int count = 1;
+ device_sound_interface *scan = NULL;
+ for (bool gotanother = sound->next(scan); gotanother; gotanother = scan->next(scan))
+ {
+ if (sound->device().type() != scan->device().type() || sound->device().clock() != scan->device().clock())
+ break;
+ count++;
+ sound = scan;
+ }
+
+ /* if more than one, prepend a #x in front of the CPU name */
+ if (count > 1)
+ string.catprintf("%d" UTF8_MULTIPLY, count);
+ string.cat(sound->device().name());
+
+ /* display clock in kHz or MHz */
+ int clock = sound->device().clock();
+ if (clock >= 1000000)
+ string.catprintf(" %d.%06d" UTF8_NBSP "MHz\n", clock / 1000000, clock % 1000000);
+ else if (clock != 0)
+ string.catprintf(" %d.%03d" UTF8_NBSP "kHz\n", clock / 1000, clock % 1000);
+ else
+ string.cat("\n");
+ }
+
+ /* display screen information */
+ string.cat("\nVideo:\n");
+ if (scrcount == 0)
+ string.cat("None\n");
+ else
+ {
+ for (screen_device *screen = machine.first_screen(); screen != NULL; screen = screen->next_screen())
+ {
+ if (scrcount > 1)
+ {
+ string.cat(slider_get_screen_desc(*screen));
+ string.cat(": ");
+ }
+
+ if (screen->screen_type() == SCREEN_TYPE_VECTOR)
+ string.cat("Vector\n");
+ else
+ {
+ const rectangle &visarea = screen->visible_area();
+
+ string.catprintf("%d " UTF8_MULTIPLY " %d (%s) %f" UTF8_NBSP "Hz\n",
+ visarea.max_x - visarea.min_x + 1,
+ visarea.max_y - visarea.min_y + 1,
+ (machine.system().flags & ORIENTATION_SWAP_XY) ? "V" : "H",
+ ATTOSECONDS_TO_HZ(screen->frame_period().attoseconds));
+ }
+ }
+ }
+
+ return string;
+}
+
+
+
+/***************************************************************************
+ UI HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ handler_messagebox - displays the current
+ messagebox_text string but handles no input
+-------------------------------------------------*/
+
+static UINT32 handler_messagebox(running_machine &machine, render_container *container, UINT32 state)
+{
+ ui_draw_text_box(container, messagebox_text, JUSTIFY_LEFT, 0.5f, 0.5f, messagebox_backcolor);
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ handler_messagebox_ok - displays the current
+ messagebox_text string and waits for an OK
+-------------------------------------------------*/
+
+static UINT32 handler_messagebox_ok(running_machine &machine, render_container *container, UINT32 state)
+{
+ /* draw a standard message window */
+ ui_draw_text_box(container, messagebox_text, JUSTIFY_LEFT, 0.5f, 0.5f, messagebox_backcolor);
+
+ /* an 'O' or left joystick kicks us to the next state */
+ if (state == 0 && (machine.input().code_pressed_once(KEYCODE_O) || ui_input_pressed(machine, IPT_UI_LEFT)))
+ state++;
+
+ /* a 'K' or right joystick exits the state */
+ else if (state == 1 && (machine.input().code_pressed_once(KEYCODE_K) || ui_input_pressed(machine, IPT_UI_RIGHT)))
+ state = UI_HANDLER_CANCEL;
+
+ /* if the user cancels, exit out completely */
+ else if (ui_input_pressed(machine, IPT_UI_CANCEL))
+ {
+ machine.schedule_exit();
+ state = UI_HANDLER_CANCEL;
+ }
+
+ return state;
+}
+
+
+/*-------------------------------------------------
+ handler_messagebox_anykey - displays the
+ current messagebox_text string and waits for
+ any keypress
+-------------------------------------------------*/
+
+static UINT32 handler_messagebox_anykey(running_machine &machine, render_container *container, UINT32 state)
+{
+ /* draw a standard message window */
+ ui_draw_text_box(container, messagebox_text, JUSTIFY_LEFT, 0.5f, 0.5f, messagebox_backcolor);
+
+ /* if the user cancels, exit out completely */
+ if (ui_input_pressed(machine, IPT_UI_CANCEL))
+ {
+ machine.schedule_exit();
+ state = UI_HANDLER_CANCEL;
+ }
+
+ /* if any key is pressed, just exit */
+ else if (machine.input().poll_switches() != INPUT_CODE_INVALID)
+ state = UI_HANDLER_CANCEL;
+
+ return state;
+}
+
+/*-------------------------------------------------
+ process_natural_keyboard - processes any
+ natural keyboard input
+-------------------------------------------------*/
+
+static void process_natural_keyboard(running_machine &machine)
+{
+ ui_event event;
+ int i, pressed;
+ input_item_id itemid;
+ input_code code;
+ UINT8 *key_down_ptr;
+ UINT8 key_down_mask;
+
+ /* loop while we have interesting events */
+ while (ui_input_pop_event(machine, &event))
+ {
+ /* if this was a UI_EVENT_CHAR event, post it */
+ if (event.event_type == UI_EVENT_CHAR)
+ inputx_postc(machine, event.ch);
+ }
+
+ /* process natural keyboard keys that don't get UI_EVENT_CHARs */
+ for (i = 0; i < ARRAY_LENGTH(non_char_keys); i++)
+ {
+ /* identify this keycode */
+ itemid = non_char_keys[i];
+ code = machine.input().code_from_itemid(itemid);
+
+ /* ...and determine if it is pressed */
+ pressed = machine.input().code_pressed(code);
+
+ /* figure out whey we are in the key_down map */
+ key_down_ptr = &non_char_keys_down[i / 8];
+ key_down_mask = 1 << (i % 8);
+
+ if (pressed && !(*key_down_ptr & key_down_mask))
+ {
+ /* this key is now down */
+ *key_down_ptr |= key_down_mask;
+
+ /* post the key */
+ inputx_postc(machine, UCHAR_MAMEKEY_BEGIN + code.item_id());
+ }
+ else if (!pressed && (*key_down_ptr & key_down_mask))
+ {
+ /* this key is now up */
+ *key_down_ptr &= ~key_down_mask;
+ }
+ }
+}
+
+/*-------------------------------------------------
+ ui_paste - does a paste from the keyboard
+-------------------------------------------------*/
+
+void ui_paste(running_machine &machine)
+{
+ /* retrieve the clipboard text */
+ char *text = osd_get_clipboard_text();
+
+ /* was a result returned? */
+ if (text != NULL)
+ {
+ /* post the text */
+ inputx_post_utf8(machine, text);
+
+ /* free the string */
+ osd_free(text);
+ }
+}
+
+/*-------------------------------------------------
+ ui_image_handler_ingame - execute display
+ callback function for each image device
+-------------------------------------------------*/
+
+void ui_image_handler_ingame(running_machine &machine)
+{
+ device_image_interface *image = NULL;
+
+ /* run display routine for devices */
+ if (machine.phase() == MACHINE_PHASE_RUNNING)
+ {
+ for (bool gotone = machine.devicelist().first(image); gotone; gotone = image->next(image))
+ {
+ image->call_display();
+ }
+ }
+
+}
+
+/*-------------------------------------------------
+ handler_ingame - in-game handler takes care
+ of the standard keypresses
+-------------------------------------------------*/
+
+static UINT32 handler_ingame(running_machine &machine, render_container *container, UINT32 state)
+{
+ bool is_paused = machine.paused();
+
+ /* first draw the FPS counter */
+ if (showfps || osd_ticks() < showfps_end)
+ {
+ astring tempstring;
+ ui_draw_text_full(container, machine.video().speed_text(tempstring), 0.0f, 0.0f, 1.0f,
+ JUSTIFY_RIGHT, WRAP_WORD, DRAW_OPAQUE, ARGB_WHITE, ARGB_BLACK, NULL, NULL);
+ }
+ else
+ showfps_end = 0;
+
+ /* draw the profiler if visible */
+ if (show_profiler)
+ {
+ astring profilertext;
+ g_profiler.text(machine, profilertext);
+ ui_draw_text_full(container, profilertext, 0.0f, 0.0f, 1.0f, JUSTIFY_LEFT, WRAP_WORD, DRAW_OPAQUE, ARGB_WHITE, ARGB_BLACK, NULL, NULL);
+ }
+
+ /* if we're single-stepping, pause now */
+ if (single_step)
+ {
+ machine.pause();
+ single_step = FALSE;
+ }
+
+ /* determine if we should disable the rest of the UI */
+ int ui_disabled = (input_machine_has_keyboard(machine) && !machine.ui_active());
+
+ /* is ScrLk UI toggling applicable here? */
+ if (input_machine_has_keyboard(machine))
+ {
+ /* are we toggling the UI with ScrLk? */
+ if (ui_input_pressed(machine, IPT_UI_TOGGLE_UI))
+ {
+ /* toggle the UI */
+ machine.set_ui_active(!machine.ui_active());
+
+ /* display a popup indicating the new status */
+ if (machine.ui_active())
+ {
+ ui_popup_time(2, "%s\n%s\n%s\n%s\n%s\n%s\n",
+ "Keyboard Emulation Status",
+ "-------------------------",
+ "Mode: PARTIAL Emulation",
+ "UI: Enabled",
+ "-------------------------",
+ "**Use ScrLock to toggle**");
+ }
+ else
+ {
+ ui_popup_time(2, "%s\n%s\n%s\n%s\n%s\n%s\n",
+ "Keyboard Emulation Status",
+ "-------------------------",
+ "Mode: FULL Emulation",
+ "UI: Disabled",
+ "-------------------------",
+ "**Use ScrLock to toggle**");
+ }
+ }
+ }
+
+ /* is the natural keyboard enabled? */
+ if (ui_get_use_natural_keyboard(machine) && (machine.phase() == MACHINE_PHASE_RUNNING))
+ process_natural_keyboard(machine);
+
+ if (!ui_disabled)
+ {
+ /* paste command */
+ if (ui_input_pressed(machine, IPT_UI_PASTE))
+ ui_paste(machine);
+ }
+
+ ui_image_handler_ingame(machine);
+
+ if (ui_disabled) return ui_disabled;
+
+ if (ui_input_pressed(machine, IPT_UI_CANCEL))
+ {
+ if (!machine.options().confirm_quit())
+ machine.schedule_exit();
+ else
+ return ui_set_handler(handler_confirm_quit, 0);
+ }
+
+ /* turn on menus if requested */
+ if (ui_input_pressed(machine, IPT_UI_CONFIGURE))
+ return ui_set_handler(ui_menu_ui_handler, 0);
+
+ /* if the on-screen display isn't up and the user has toggled it, turn it on */
+ if ((machine.debug_flags & DEBUG_FLAG_ENABLED) == 0 && ui_input_pressed(machine, IPT_UI_ON_SCREEN_DISPLAY))
+ return ui_set_handler(ui_slider_ui_handler, 1);
+
+ /* handle a reset request */
+ if (ui_input_pressed(machine, IPT_UI_RESET_MACHINE))
+ machine.schedule_hard_reset();
+ if (ui_input_pressed(machine, IPT_UI_SOFT_RESET))
+ machine.schedule_soft_reset();
+
+ /* handle a request to display graphics/palette */
+ if (ui_input_pressed(machine, IPT_UI_SHOW_GFX))
+ {
+ if (!is_paused)
+ machine.pause();
+ return ui_set_handler(ui_gfx_ui_handler, is_paused);
+ }
+
+ /* handle a save state request */
+ if (ui_input_pressed(machine, IPT_UI_SAVE_STATE))
+ {
+ machine.pause();
+ return ui_set_handler(handler_load_save, LOADSAVE_SAVE);
+ }
+
+ /* handle a load state request */
+ if (ui_input_pressed(machine, IPT_UI_LOAD_STATE))
+ {
+ machine.pause();
+ return ui_set_handler(handler_load_save, LOADSAVE_LOAD);
+ }
+
+ /* handle a save snapshot request */
+ if (ui_input_pressed(machine, IPT_UI_SNAPSHOT))
+ machine.video().save_active_screen_snapshots();
+
+ /* toggle pause */
+ if (ui_input_pressed(machine, IPT_UI_PAUSE))
+ {
+ /* with a shift key, it is single step */
+ if (is_paused && (machine.input().code_pressed(KEYCODE_LSHIFT) || machine.input().code_pressed(KEYCODE_RSHIFT)))
+ {
+ single_step = TRUE;
+ machine.resume();
+ }
+ else if (machine.paused())
+ machine.resume();
+ else
+ machine.pause();
+ }
+
+ /* handle a toggle cheats request */
+ if (ui_input_pressed(machine, IPT_UI_TOGGLE_CHEAT))
+ machine.cheat().set_enable(!machine.cheat().enabled());
+
+ /* toggle movie recording */
+ if (ui_input_pressed(machine, IPT_UI_RECORD_MOVIE))
+ {
+ if (!machine.video().is_recording())
+ {
+ machine.video().begin_recording(NULL, video_manager::MF_MNG);
+ popmessage("REC START");
+ }
+ else
+ {
+ machine.video().end_recording();
+ popmessage("REC STOP");
+ }
+ }
+
+ /* toggle profiler display */
+ if (ui_input_pressed(machine, IPT_UI_SHOW_PROFILER))
+ ui_set_show_profiler(!ui_get_show_profiler());
+
+ /* toggle FPS display */
+ if (ui_input_pressed(machine, IPT_UI_SHOW_FPS))
+ ui_set_show_fps(!ui_get_show_fps());
+
+ /* increment frameskip? */
+ if (ui_input_pressed(machine, IPT_UI_FRAMESKIP_INC))
+ {
+ /* get the current value and increment it */
+ int newframeskip = machine.video().frameskip() + 1;
+ if (newframeskip > MAX_FRAMESKIP)
+ newframeskip = -1;
+ machine.video().set_frameskip(newframeskip);
+
+ /* display the FPS counter for 2 seconds */
+ ui_show_fps_temp(2.0);
+ }
+
+ /* decrement frameskip? */
+ if (ui_input_pressed(machine, IPT_UI_FRAMESKIP_DEC))
+ {
+ /* get the current value and decrement it */
+ int newframeskip = machine.video().frameskip() - 1;
+ if (newframeskip < -1)
+ newframeskip = MAX_FRAMESKIP;
+ machine.video().set_frameskip(newframeskip);
+
+ /* display the FPS counter for 2 seconds */
+ ui_show_fps_temp(2.0);
+ }
+
+ /* toggle throttle? */
+ if (ui_input_pressed(machine, IPT_UI_THROTTLE))
+ machine.video().set_throttled(!machine.video().throttled());
+
+ /* check for fast forward */
+ if (input_type_pressed(machine, IPT_UI_FAST_FORWARD, 0))
+ {
+ machine.video().set_fastforward(true);
+ ui_show_fps_temp(0.5);
+ }
+ else
+ machine.video().set_fastforward(false);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ handler_load_save - leads the user through
+ specifying a game to save or load
+-------------------------------------------------*/
+
+static UINT32 handler_load_save(running_machine &machine, render_container *container, UINT32 state)
+{
+ char filename[20];
+ input_code code;
+ char file = 0;
+
+ /* if we're not in the middle of anything, skip */
+ if (state == LOADSAVE_NONE)
+ return 0;
+
+ /* okay, we're waiting for a key to select a slot; display a message */
+ if (state == LOADSAVE_SAVE)
+ ui_draw_message_window(container, "Select position to save to");
+ else
+ ui_draw_message_window(container, "Select position to load from");
+
+ /* check for cancel key */
+ if (ui_input_pressed(machine, IPT_UI_CANCEL))
+ {
+ /* display a popup indicating things were cancelled */
+ if (state == LOADSAVE_SAVE)
+ popmessage("Save cancelled");
+ else
+ popmessage("Load cancelled");
+
+ /* reset the state */
+ machine.resume();
+ return UI_HANDLER_CANCEL;
+ }
+
+ /* check for A-Z or 0-9 */
+ for (input_item_id id = ITEM_ID_A; id <= ITEM_ID_Z; id++)
+ if (machine.input().code_pressed_once(input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, id)))
+ file = id - ITEM_ID_A + 'a';
+ if (file == 0)
+ for (input_item_id id = ITEM_ID_0; id <= ITEM_ID_9; id++)
+ if (machine.input().code_pressed_once(input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, id)))
+ file = id - ITEM_ID_0 + '0';
+ if (file == 0)
+ for (input_item_id id = ITEM_ID_0_PAD; id <= ITEM_ID_9_PAD; id++)
+ if (machine.input().code_pressed_once(input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, id)))
+ file = id - ITEM_ID_0_PAD + '0';
+ if (file == 0)
+ return state;
+
+ /* display a popup indicating that the save will proceed */
+ sprintf(filename, "%c", file);
+ if (state == LOADSAVE_SAVE)
+ {
+ popmessage("Save to position %c", file);
+ machine.schedule_save(filename);
+ }
+ else
+ {
+ popmessage("Load from position %c", file);
+ machine.schedule_load(filename);
+ }
+
+ /* remove the pause and reset the state */
+ machine.resume();
+ return UI_HANDLER_CANCEL;
+}
+
+
+/*-------------------------------------------------
+ handler_confirm_quit - leads the user through
+ confirming quit emulation
+ -------------------------------------------------*/
+
+static UINT32 handler_confirm_quit(running_machine &machine, render_container *container, UINT32 state)
+{
+ astring quit_message("Are you sure you want to quit?\n\n");
+ quit_message.cat("Press ''UI Select'' (default: Enter) to quit,\n");
+ quit_message.cat("Press ''UI Cancel'' (default: Esc) to return to emulation.");
+
+ ui_draw_text_box(container, quit_message, JUSTIFY_CENTER, 0.5f, 0.5f, UI_RED_COLOR);
+ machine.pause();
+
+ /* if the user press ENTER, quit the game */
+ if (ui_input_pressed(machine, IPT_UI_SELECT))
+ machine.schedule_exit();
+
+ /* if the user press ESC, just continue */
+ else if (ui_input_pressed(machine, IPT_UI_CANCEL))
+ {
+ machine.resume();
+ state = UI_HANDLER_CANCEL;
+ }
+
+ return state;
+}
+
+
+/***************************************************************************
+ SLIDER CONTROLS
+***************************************************************************/
+
+/*-------------------------------------------------
+ ui_get_slider_list - get the list of sliders
+-------------------------------------------------*/
+
+const slider_state *ui_get_slider_list(void)
+{
+ return slider_list;
+}
+
+
+/*-------------------------------------------------
+ slider_alloc - allocate a new slider entry
+-------------------------------------------------*/
+
+static slider_state *slider_alloc(running_machine &machine, const char *title, INT32 minval, INT32 defval, INT32 maxval, INT32 incval, slider_update update, void *arg)
+{
+ int size = sizeof(slider_state) + strlen(title);
+ slider_state *state = (slider_state *)auto_alloc_array_clear(machine, UINT8, size);
+
+ state->minval = minval;
+ state->defval = defval;
+ state->maxval = maxval;
+ state->incval = incval;
+ state->update = update;
+ state->arg = arg;
+ strcpy(state->description, title);
+
+ return state;
+}
+
+
+/*-------------------------------------------------
+ slider_init - initialize the list of slider
+ controls
+-------------------------------------------------*/
+
+static slider_state *slider_init(running_machine &machine)
+{
+ input_field_config *field;
+ input_port_config *port;
+ device_t *device;
+ slider_state *listhead = NULL;
+ slider_state **tailptr = &listhead;
+ astring string;
+ int item;
+
+ /* add overall volume */
+ *tailptr = slider_alloc(machine, "Master Volume", -32, 0, 0, 1, slider_volume, NULL);
+ tailptr = &(*tailptr)->next;
+
+ /* add per-channel volume */
+ speaker_input info;
+ for (item = 0; machine.sound().indexed_speaker_input(item, info); item++)
+ {
+ INT32 maxval = 2000;
+ INT32 defval = info.stream->initial_input_gain(info.inputnum) * 1000.0f + 0.5f;
+
+ if (defval > 1000)
+ maxval = 2 * defval;
+
+ info.stream->input_name(info.inputnum, string);
+ string.cat(" Volume");
+ *tailptr = slider_alloc(machine, string, 0, defval, maxval, 20, slider_mixervol, (void *)(FPTR)item);
+ tailptr = &(*tailptr)->next;
+ }
+
+ /* add analog adjusters */
+ for (port = machine.m_portlist.first(); port != NULL; port = port->next())
+ for (field = port->fieldlist().first(); field != NULL; field = field->next())
+ if (field->type == IPT_ADJUSTER)
+ {
+ void *param = (void *)field;
+ *tailptr = slider_alloc(machine, field->name, 0, field->defvalue, 100, 1, slider_adjuster, param);
+ tailptr = &(*tailptr)->next;
+ }
+
+ /* add CPU overclocking (cheat only) */
+ if (machine.options().cheat())
+ {
+ device_execute_interface *exec = NULL;
+ for (bool gotone = machine.devicelist().first(exec); gotone; gotone = exec->next(exec))
+ {
+ void *param = (void *)&exec->device();
+ string.printf("Overclock CPU %s", exec->device().tag());
+ *tailptr = slider_alloc(machine, string, 10, 1000, 2000, 1, slider_overclock, param);
+ tailptr = &(*tailptr)->next;
+ }
+ }
+
+ /* add screen parameters */
+ for (screen_device *screen = machine.first_screen(); screen != NULL; screen = screen->next_screen())
+ {
+ int defxscale = floor(screen->xscale() * 1000.0f + 0.5f);
+ int defyscale = floor(screen->yscale() * 1000.0f + 0.5f);
+ int defxoffset = floor(screen->xoffset() * 1000.0f + 0.5f);
+ int defyoffset = floor(screen->yoffset() * 1000.0f + 0.5f);
+ void *param = (void *)screen;
+
+ /* add refresh rate tweaker */
+ if (machine.options().cheat())
+ {
+ string.printf("%s Refresh Rate", slider_get_screen_desc(*screen));
+ *tailptr = slider_alloc(machine, string, -10000, 0, 10000, 1000, slider_refresh, param);
+ tailptr = &(*tailptr)->next;
+ }
+
+ /* add standard brightness/contrast/gamma controls per-screen */
+ string.printf("%s Brightness", slider_get_screen_desc(*screen));
+ *tailptr = slider_alloc(machine, string, 100, 1000, 2000, 10, slider_brightness, param);
+ tailptr = &(*tailptr)->next;
+ string.printf("%s Contrast", slider_get_screen_desc(*screen));
+ *tailptr = slider_alloc(machine, string, 100, 1000, 2000, 50, slider_contrast, param);
+ tailptr = &(*tailptr)->next;
+ string.printf("%s Gamma", slider_get_screen_desc(*screen));
+ *tailptr = slider_alloc(machine, string, 100, 1000, 3000, 50, slider_gamma, param);
+ tailptr = &(*tailptr)->next;
+
+ /* add scale and offset controls per-screen */
+ string.printf("%s Horiz Stretch", slider_get_screen_desc(*screen));
+ *tailptr = slider_alloc(machine, string, 500, defxscale, 1500, 2, slider_xscale, param);
+ tailptr = &(*tailptr)->next;
+ string.printf("%s Horiz Position", slider_get_screen_desc(*screen));
+ *tailptr = slider_alloc(machine, string, -500, defxoffset, 500, 2, slider_xoffset, param);
+ tailptr = &(*tailptr)->next;
+ string.printf("%s Vert Stretch", slider_get_screen_desc(*screen));
+ *tailptr = slider_alloc(machine, string, 500, defyscale, 1500, 2, slider_yscale, param);
+ tailptr = &(*tailptr)->next;
+ string.printf("%s Vert Position", slider_get_screen_desc(*screen));
+ *tailptr = slider_alloc(machine, string, -500, defyoffset, 500, 2, slider_yoffset, param);
+ tailptr = &(*tailptr)->next;
+ }
+
+ for (device = machine.devicelist().first(); device != NULL; device = device->next())
+ if (device_is_laserdisc(device))
+ {
+ const laserdisc_config *config = (const laserdisc_config *)downcast<const legacy_device_base *>(device)->inline_config();
+ if (config->overupdate != NULL)
+ {
+ int defxscale = floor(config->overscalex * 1000.0f + 0.5f);
+ int defyscale = floor(config->overscaley * 1000.0f + 0.5f);
+ int defxoffset = floor(config->overposx * 1000.0f + 0.5f);
+ int defyoffset = floor(config->overposy * 1000.0f + 0.5f);
+ void *param = (void *)device;
+
+ /* add scale and offset controls per-overlay */
+ string.printf("%s Horiz Stretch", slider_get_laserdisc_desc(device));
+ *tailptr = slider_alloc(machine, string, 500, (defxscale == 0) ? 1000 : defxscale, 1500, 2, slider_overxscale, param);
+ tailptr = &(*tailptr)->next;
+ string.printf("%s Horiz Position", slider_get_laserdisc_desc(device));
+ *tailptr = slider_alloc(machine, string, -500, defxoffset, 500, 2, slider_overxoffset, param);
+ tailptr = &(*tailptr)->next;
+ string.printf("%s Vert Stretch", slider_get_laserdisc_desc(device));
+ *tailptr = slider_alloc(machine, string, 500, (defyscale == 0) ? 1000 : defyscale, 1500, 2, slider_overyscale, param);
+ tailptr = &(*tailptr)->next;
+ string.printf("%s Vert Position", slider_get_laserdisc_desc(device));
+ *tailptr = slider_alloc(machine, string, -500, defyoffset, 500, 2, slider_overyoffset, param);
+ tailptr = &(*tailptr)->next;
+ }
+ }
+
+ for (screen_device *screen = machine.first_screen(); screen != NULL; screen = screen->next_screen())
+ if (screen->screen_type() == SCREEN_TYPE_VECTOR)
+ {
+ /* add flicker control */
+ *tailptr = slider_alloc(machine, "Vector Flicker", 0, 0, 1000, 10, slider_flicker, NULL);
+ tailptr = &(*tailptr)->next;
+ *tailptr = slider_alloc(machine, "Beam Width", 10, 100, 1000, 10, slider_beam, NULL);
+ tailptr = &(*tailptr)->next;
+ break;
+ }
+
+#ifdef MAME_DEBUG
+ /* add crosshair adjusters */
+ for (port = machine.m_portlist.first(); port != NULL; port = port->next())
+ for (field = port->fieldlist().first(); field != NULL; field = field->next())
+ if (field->crossaxis != CROSSHAIR_AXIS_NONE && field->player == 0)
+ {
+ void *param = (void *)field;
+ string.printf("Crosshair Scale %s", (field->crossaxis == CROSSHAIR_AXIS_X) ? "X" : "Y");
+ *tailptr = slider_alloc(machine, string, -3000, 1000, 3000, 100, slider_crossscale, param);
+ tailptr = &(*tailptr)->next;
+ string.printf("Crosshair Offset %s", (field->crossaxis == CROSSHAIR_AXIS_X) ? "X" : "Y");
+ *tailptr = slider_alloc(machine, string, -3000, 0, 3000, 100, slider_crossoffset, param);
+ tailptr = &(*tailptr)->next;
+ }
+#endif
+
+ return listhead;
+}
+
+
+/*-------------------------------------------------
+ slider_volume - global volume slider callback
+-------------------------------------------------*/
+
+static INT32 slider_volume(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ if (newval != SLIDER_NOCHANGE)
+ machine.sound().set_attenuation(newval);
+ if (string != NULL)
+ string->printf("%3ddB", machine.sound().attenuation());
+ return machine.sound().attenuation();
+}
+
+
+/*-------------------------------------------------
+ slider_mixervol - single channel volume
+ slider callback
+-------------------------------------------------*/
+
+static INT32 slider_mixervol(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ speaker_input info;
+ if (!machine.sound().indexed_speaker_input((FPTR)arg, info))
+ return 0;
+ if (newval != SLIDER_NOCHANGE)
+ {
+ INT32 curval = floor(info.stream->input_gain(info.inputnum) * 1000.0f + 0.5f);
+ if (newval > curval && (newval - curval) <= 4) newval += 4; // round up on increment
+ info.stream->set_input_gain(info.inputnum, (float)newval * 0.001f);
+ }
+ if (string != NULL)
+ string->printf("%4.2f", info.stream->input_gain(info.inputnum));
+ return floor(info.stream->input_gain(info.inputnum) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_adjuster - analog adjuster slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_adjuster(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ const input_field_config *field = (const input_field_config *)arg;
+ input_field_user_settings settings;
+
+ input_field_get_user_settings(field, &settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.value = newval;
+ input_field_set_user_settings(field, &settings);
+ }
+ if (string != NULL)
+ string->printf("%d%%", settings.value);
+ return settings.value;
+}
+
+
+/*-------------------------------------------------
+ slider_overclock - CPU overclocker slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_overclock(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ device_t *cpu = (device_t *)arg;
+ if (newval != SLIDER_NOCHANGE)
+ cpu->set_clock_scale((float)newval * 0.001f);
+ if (string != NULL)
+ string->printf("%3.0f%%", floor(cpu->clock_scale() * 100.0f + 0.5f));
+ return floor(cpu->clock_scale() * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_refresh - refresh rate slider callback
+-------------------------------------------------*/
+
+static INT32 slider_refresh(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ screen_device *screen = reinterpret_cast<screen_device *>(arg);
+ double defrefresh = ATTOSECONDS_TO_HZ(screen->refresh_attoseconds());
+ double refresh;
+
+ if (newval != SLIDER_NOCHANGE)
+ {
+ int width = screen->width();
+ int height = screen->height();
+ const rectangle &visarea = screen->visible_area();
+ screen->configure(width, height, visarea, HZ_TO_ATTOSECONDS(defrefresh + (double)newval * 0.001));
+ }
+ if (string != NULL)
+ string->printf("%.3ffps", ATTOSECONDS_TO_HZ(machine.primary_screen->frame_period().attoseconds));
+ refresh = ATTOSECONDS_TO_HZ(machine.primary_screen->frame_period().attoseconds);
+ return floor((refresh - defrefresh) * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_brightness - screen brightness slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_brightness(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ screen_device *screen = reinterpret_cast<screen_device *>(arg);
+ render_container::user_settings settings;
+
+ screen->container().get_user_settings(settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.m_brightness = (float)newval * 0.001f;
+ screen->container().set_user_settings(settings);
+ }
+ if (string != NULL)
+ string->printf("%.3f", settings.m_brightness);
+ return floor(settings.m_brightness * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_contrast - screen contrast slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_contrast(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ screen_device *screen = reinterpret_cast<screen_device *>(arg);
+ render_container::user_settings settings;
+
+ screen->container().get_user_settings(settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.m_contrast = (float)newval * 0.001f;
+ screen->container().set_user_settings(settings);
+ }
+ if (string != NULL)
+ string->printf("%.3f", settings.m_contrast);
+ return floor(settings.m_contrast * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_gamma - screen gamma slider callback
+-------------------------------------------------*/
+
+static INT32 slider_gamma(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ screen_device *screen = reinterpret_cast<screen_device *>(arg);
+ render_container::user_settings settings;
+
+ screen->container().get_user_settings(settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.m_gamma = (float)newval * 0.001f;
+ screen->container().set_user_settings(settings);
+ }
+ if (string != NULL)
+ string->printf("%.3f", settings.m_gamma);
+ return floor(settings.m_gamma * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_xscale - screen horizontal scale slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_xscale(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ screen_device *screen = reinterpret_cast<screen_device *>(arg);
+ render_container::user_settings settings;
+
+ screen->container().get_user_settings(settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.m_xscale = (float)newval * 0.001f;
+ screen->container().set_user_settings(settings);
+ }
+ if (string != NULL)
+ string->printf("%.3f", settings.m_xscale);
+ return floor(settings.m_xscale * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_yscale - screen vertical scale slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_yscale(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ screen_device *screen = reinterpret_cast<screen_device *>(arg);
+ render_container::user_settings settings;
+
+ screen->container().get_user_settings(settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.m_yscale = (float)newval * 0.001f;
+ screen->container().set_user_settings(settings);
+ }
+ if (string != NULL)
+ string->printf("%.3f", settings.m_yscale);
+ return floor(settings.m_yscale * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_xoffset - screen horizontal position
+ slider callback
+-------------------------------------------------*/
+
+static INT32 slider_xoffset(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ screen_device *screen = reinterpret_cast<screen_device *>(arg);
+ render_container::user_settings settings;
+
+ screen->container().get_user_settings(settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.m_xoffset = (float)newval * 0.001f;
+ screen->container().set_user_settings(settings);
+ }
+ if (string != NULL)
+ string->printf("%.3f", settings.m_xoffset);
+ return floor(settings.m_xoffset * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_yoffset - screen vertical position
+ slider callback
+-------------------------------------------------*/
+
+static INT32 slider_yoffset(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ screen_device *screen = reinterpret_cast<screen_device *>(arg);
+ render_container::user_settings settings;
+
+ screen->container().get_user_settings(settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.m_yoffset = (float)newval * 0.001f;
+ screen->container().set_user_settings(settings);
+ }
+ if (string != NULL)
+ string->printf("%.3f", settings.m_yoffset);
+ return floor(settings.m_yoffset * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_overxscale - screen horizontal scale slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_overxscale(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ device_t *laserdisc = (device_t *)arg;
+ laserdisc_config settings;
+
+ laserdisc_get_config(laserdisc, &settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.overscalex = (float)newval * 0.001f;
+ laserdisc_set_config(laserdisc, &settings);
+ }
+ if (string != NULL)
+ string->printf("%.3f", settings.overscalex);
+ return floor(settings.overscalex * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_overyscale - screen vertical scale slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_overyscale(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ device_t *laserdisc = (device_t *)arg;
+ laserdisc_config settings;
+
+ laserdisc_get_config(laserdisc, &settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.overscaley = (float)newval * 0.001f;
+ laserdisc_set_config(laserdisc, &settings);
+ }
+ if (string != NULL)
+ string->printf("%.3f", settings.overscaley);
+ return floor(settings.overscaley * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_overxoffset - screen horizontal position
+ slider callback
+-------------------------------------------------*/
+
+static INT32 slider_overxoffset(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ device_t *laserdisc = (device_t *)arg;
+ laserdisc_config settings;
+
+ laserdisc_get_config(laserdisc, &settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.overposx = (float)newval * 0.001f;
+ laserdisc_set_config(laserdisc, &settings);
+ }
+ if (string != NULL)
+ string->printf("%.3f", settings.overposx);
+ return floor(settings.overposx * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_overyoffset - screen vertical position
+ slider callback
+-------------------------------------------------*/
+
+static INT32 slider_overyoffset(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ device_t *laserdisc = (device_t *)arg;
+ laserdisc_config settings;
+
+ laserdisc_get_config(laserdisc, &settings);
+ if (newval != SLIDER_NOCHANGE)
+ {
+ settings.overposy = (float)newval * 0.001f;
+ laserdisc_set_config(laserdisc, &settings);
+ }
+ if (string != NULL)
+ string->printf("%.3f", settings.overposy);
+ return floor(settings.overposy * 1000.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_flicker - vector flicker slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_flicker(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ if (newval != SLIDER_NOCHANGE)
+ vector_set_flicker((float)newval * 0.1f);
+ if (string != NULL)
+ string->printf("%1.2f", vector_get_flicker());
+ return floor(vector_get_flicker() * 10.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_beam - vector beam width slider
+ callback
+-------------------------------------------------*/
+
+static INT32 slider_beam(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ if (newval != SLIDER_NOCHANGE)
+ vector_set_beam((float)newval * 0.01f);
+ if (string != NULL)
+ string->printf("%1.2f", vector_get_beam());
+ return floor(vector_get_beam() * 100.0f + 0.5f);
+}
+
+
+/*-------------------------------------------------
+ slider_get_screen_desc - returns the
+ description for a given screen
+-------------------------------------------------*/
+
+static char *slider_get_screen_desc(screen_device &screen)
+{
+ int scrcount = screen.machine().devicelist().count(SCREEN);
+ static char descbuf[256];
+
+ if (scrcount > 1)
+ sprintf(descbuf, "Screen '%s'", screen.tag());
+ else
+ strcpy(descbuf, "Screen");
+
+ return descbuf;
+}
+
+/*-------------------------------------------------
+ slider_get_laserdisc_desc - returns the
+ description for a given laseridsc
+-------------------------------------------------*/
+static char *slider_get_laserdisc_desc(device_t *laserdisc)
+{
+ static char descbuf[256];
+ for (device_t *device = laserdisc->machine().devicelist().first(); device != NULL; device = device->next())
+ if (device_is_laserdisc(device) && device != laserdisc)
+ {
+ sprintf(descbuf, "Laserdisc '%s'", laserdisc->tag());
+ return descbuf;
+ }
+
+ strcpy(descbuf, "Laserdisc");
+ return descbuf;
+}
+
+/*-------------------------------------------------
+ slider_crossscale - crosshair scale slider
+ callback
+-------------------------------------------------*/
+
+#ifdef MAME_DEBUG
+static INT32 slider_crossscale(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ input_field_config *field = (input_field_config *)arg;
+
+ if (newval != SLIDER_NOCHANGE)
+ field->crossscale = (float)newval * 0.001f;
+ if (string != NULL)
+ string->printf("%s %s %1.3f", "Crosshair Scale", (field->crossaxis == CROSSHAIR_AXIS_X) ? "X" : "Y", (float)newval * 0.001f);
+ return floor(field->crossscale * 1000.0f + 0.5f);
+}
+#endif
+
+
+/*-------------------------------------------------
+ slider_crossoffset - crosshair scale slider
+ callback
+-------------------------------------------------*/
+
+#ifdef MAME_DEBUG
+static INT32 slider_crossoffset(running_machine &machine, void *arg, astring *string, INT32 newval)
+{
+ input_field_config *field = (input_field_config *)arg;
+
+ if (newval != SLIDER_NOCHANGE)
+ field->crossoffset = (float)newval * 0.001f;
+ if (string != NULL)
+ string->printf("%s %s %1.3f", "Crosshair Offset", (field->crossaxis == CROSSHAIR_AXIS_X) ? "X" : "Y", (float)newval * 0.001f);
+ return field->crossoffset;
+}
+#endif
+
+
+/*-------------------------------------------------
+ ui_get_use_natural_keyboard - returns
+ whether the natural keyboard is active
+-------------------------------------------------*/
+
+int ui_get_use_natural_keyboard(running_machine &machine)
+{
+ return ui_use_natural_keyboard;
+}
+
+
+
+/*-------------------------------------------------
+ ui_set_use_natural_keyboard - specifies
+ whether the natural keyboard is active
+-------------------------------------------------*/
+
+void ui_set_use_natural_keyboard(running_machine &machine, int use_natural_keyboard)
+{
+ ui_use_natural_keyboard = use_natural_keyboard;
+ astring error;
+ machine.options().set_value(OPTION_NATURAL_KEYBOARD, use_natural_keyboard, OPTION_PRIORITY_CMDLINE, error);
+ assert(!error);
+}
+