diff options
Diffstat (limited to 'trunk/src/emu/ui.c')
-rw-r--r-- | trunk/src/emu/ui.c | 2252 |
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); +} + |