diff options
Diffstat (limited to 'src/emu/ui.c')
-rw-r--r-- | src/emu/ui.c | 1961 |
1 files changed, 1961 insertions, 0 deletions
diff --git a/src/emu/ui.c b/src/emu/ui.c new file mode 100644 index 00000000000..4267422f0f7 --- /dev/null +++ b/src/emu/ui.c @@ -0,0 +1,1961 @@ +/********************************************************************* + + ui.c + + Functions used to handle MAME's user interface. + + Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +*********************************************************************/ + +#include "driver.h" +#include "osdepend.h" +#include "video/vector.h" +#include "profiler.h" +#include "cheat.h" +#include "render.h" +#include "rendfont.h" +#include "ui.h" +#include "uimenu.h" +#include "uigfx.h" +#include "uitext.h" + +#ifdef MESS +#include "mess.h" +#include "uimess.h" +#include "inputx.h" +#endif + +#include <ctype.h> +#include <stdarg.h> +#include <math.h> + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +enum +{ + INPUT_TYPE_DIGITAL = 0, + INPUT_TYPE_ANALOG = 1, + INPUT_TYPE_ANALOG_DEC = 2, + INPUT_TYPE_ANALOG_INC = 3 +}; + +enum +{ + ANALOG_ITEM_KEYSPEED = 0, + ANALOG_ITEM_CENTERSPEED, + ANALOG_ITEM_REVERSE, + ANALOG_ITEM_SENSITIVITY, + ANALOG_ITEM_COUNT +}; + +enum +{ + LOADSAVE_NONE, + LOADSAVE_LOAD, + LOADSAVE_SAVE +}; + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _slider_state slider_state; +struct _slider_state +{ + INT32 minval; /* minimum value */ + INT32 defval; /* default value */ + INT32 maxval; /* maximum value */ + INT32 incval; /* increment value */ + INT32 (*update)(INT32 newval, char *buffer, int arg); /* callback */ + int arg; /* argument */ +}; + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +/* font for rendering */ +static render_font *ui_font; + +/* current UI handler */ +static UINT32 (*ui_handler_callback)(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 char messagebox_text[4096]; +static rgb_t messagebox_backcolor; + +/* slider info */ +static slider_state slider_list[100]; +static int slider_count; +static int slider_current; + +static int display_rescale_message; +static int allow_rescale; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static void ui_exit(running_machine *machine); +static int rescale_notifier(running_machine *machine, int width, int height); + +/* text generators */ +static int sprintf_disclaimer(char *buffer); +static int sprintf_warnings(char *buffer); + +/* UI handlers */ +static UINT32 handler_messagebox(UINT32 state); +static UINT32 handler_messagebox_ok(UINT32 state); +static UINT32 handler_messagebox_anykey(UINT32 state); +static UINT32 handler_ingame(UINT32 state); +static UINT32 handler_slider(UINT32 state); +static UINT32 handler_load_save(UINT32 state); + +/* slider controls */ +static void slider_init(void); +static void slider_display(const char *text, int minval, int maxval, int defval, int curval); +static void slider_draw_bar(float leftx, float topy, float width, float height, float percentage, float default_percentage); +static INT32 slider_volume(INT32 newval, char *buffer, int arg); +static INT32 slider_mixervol(INT32 newval, char *buffer, int arg); +static INT32 slider_adjuster(INT32 newval, char *buffer, int arg); +static INT32 slider_overclock(INT32 newval, char *buffer, int arg); +static INT32 slider_refresh(INT32 newval, char *buffer, int arg); +static INT32 slider_brightness(INT32 newval, char *buffer, int arg); +static INT32 slider_contrast(INT32 newval, char *buffer, int arg); +static INT32 slider_gamma(INT32 newval, char *buffer, int arg); +static INT32 slider_xscale(INT32 newval, char *buffer, int arg); +static INT32 slider_yscale(INT32 newval, char *buffer, int arg); +static INT32 slider_xoffset(INT32 newval, char *buffer, int arg); +static INT32 slider_yoffset(INT32 newval, char *buffer, int arg); +static INT32 slider_flicker(INT32 newval, char *buffer, int arg); +static INT32 slider_beam(INT32 newval, char *buffer, int arg); +#ifdef MAME_DEBUG +static INT32 slider_crossscale(INT32 newval, char *buffer, int arg); +static INT32 slider_crossoffset(INT32 newval, char *buffer, int arg); +#endif + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + ui_set_handler - set a callback/parameter + pair for the current UI handler +-------------------------------------------------*/ + +INLINE UINT32 ui_set_handler(UINT32 (*callback)(UINT32), UINT32 param) +{ + ui_handler_callback = callback; + ui_handler_param = param; + return param; +} + + +/*------------------------------------------------- + slider_config - configure a slider entry +-------------------------------------------------*/ + +INLINE void slider_config(slider_state *state, INT32 minval, INT32 defval, INT32 maxval, INT32 incval, INT32 (*update)(INT32, char *, int), int arg) +{ + state->minval = minval; + state->defval = defval; + state->maxval = maxval; + state->incval = incval; + state->update = update; + state->arg = arg; +} + + +/*------------------------------------------------- + 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 */ + add_exit_callback(machine, ui_exit); + + /* load the localization file */ + /* fix me -- need to find a real way to do this */ + uistring_init(NULL); + + /* allocate the font */ + ui_font = render_font_alloc("ui.bdf"); + + /* initialize the other UI bits */ + ui_menu_init(machine); + ui_gfx_init(machine); + + /* reset globals */ + single_step = FALSE; + ui_set_handler(handler_messagebox, 0); + + /* request callbacks when the renderer does resizing */ + render_set_rescale_notify(machine, rescale_notifier); + allow_rescale = 0; + display_rescale_message = FALSE; + return 0; +} + + +/*------------------------------------------------- + ui_exit - clean up ourselves on exit +-------------------------------------------------*/ + +static void ui_exit(running_machine *machine) +{ + /* free the font */ + if (ui_font != NULL) + render_font_free(ui_font); + ui_font = NULL; +} + + +/*------------------------------------------------- + rescale_notifier - notifier to trigger a + rescale message during long operations +-------------------------------------------------*/ + +static int rescale_notifier(running_machine *machine, int width, int height) +{ + /* always allow "small" rescaling */ + if (width < 500 || height < 500) + return TRUE; + + /* if we've currently disallowed rescaling, turn on a message next frame */ + if (allow_rescale == 0) + display_rescale_message = TRUE; + + /* only allow rescaling once we're sure the message is visible */ + return (allow_rescale == 1); +} + + +/*------------------------------------------------- + ui_display_startup_screens - display the + various startup screens +-------------------------------------------------*/ + +int ui_display_startup_screens(int first_time, int show_disclaimer) +{ +#ifdef MESS + const int maxstate = 4; +#else + const int maxstate = 3; +#endif + int str = options_get_int(mame_options(), OPTION_SECONDS_TO_RUN); + int show_gameinfo = !options_get_bool(mame_options(), OPTION_SKIP_GAMEINFO); + int show_warnings = TRUE; + int state; + + /* disable everything if we are using -str */ + if (!first_time || (str > 0 && str < 60*5) || Machine->gamedrv == &driver_empty) + show_gameinfo = show_warnings = show_disclaimer = FALSE; + + /* initialize the on-screen display system */ + slider_init(); + + /* loop over states */ + ui_set_handler(handler_ingame, 0); + for (state = 0; state < maxstate && !mame_is_scheduled_event_pending(Machine) && !ui_menu_is_force_game_select(); state++) + { + /* default to standard colors */ + messagebox_backcolor = UI_FILLCOLOR; + + /* pick the next state */ + switch (state) + { + case 0: + if (show_disclaimer && sprintf_disclaimer(messagebox_text)) + ui_set_handler(handler_messagebox_ok, 0); + break; + + case 1: + if (show_warnings && sprintf_warnings(messagebox_text)) + { + ui_set_handler(handler_messagebox_ok, 0); + if (Machine->gamedrv->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION)) + messagebox_backcolor = UI_REDCOLOR; + } + break; + + case 2: + if (show_gameinfo && sprintf_game_info(messagebox_text)) + ui_set_handler(handler_messagebox_anykey, 0); + break; +#ifdef MESS + case 3: + break; +#endif + } + + /* clear the input memory */ + input_code_poll_switches(TRUE); + while (input_code_poll_switches(FALSE) != INPUT_CODE_INVALID) ; + + /* loop while we have a handler */ + while (ui_handler_callback != handler_ingame && !mame_is_scheduled_event_pending(Machine) && !ui_menu_is_force_game_select()) + video_frame_update(); + + /* clear the handler and force an update */ + ui_set_handler(handler_ingame, 0); + 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(const char *text, int force) +{ + static osd_ticks_t lastupdatetime = 0; + osd_ticks_t curtime = osd_ticks(); + + /* copy in the new text */ + strncpy(messagebox_text, text, sizeof(messagebox_text)); + messagebox_backcolor = UI_FILLCOLOR; + + /* don't update more than 4 times/second */ + if (force || (curtime - lastupdatetime) > osd_ticks_per_second() / 4) + { + lastupdatetime = curtime; + video_frame_update(); + } +} + + +/*------------------------------------------------- + ui_update_and_render - update the UI and + render it; called by video.c +-------------------------------------------------*/ + +void ui_update_and_render(void) +{ + /* always start clean */ + render_container_empty(render_container_get_ui()); + + /* if we're paused, dim the whole screen */ + if (mame_get_phase(Machine) >= MAME_PHASE_RESET && (single_step || mame_is_paused(Machine))) + { + int alpha = (1.0f - options_get_float(mame_options(), OPTION_PAUSE_BRIGHTNESS)) * 255.0f; + if (ui_menu_is_force_game_select()) + alpha = 255; + if (alpha > 255) + alpha = 255; + if (alpha >= 0) + render_ui_add_rect(0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(alpha,0x00,0x00,0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + } + + /* call the current UI handler */ + assert(ui_handler_callback != NULL); + ui_handler_param = (*ui_handler_callback)(ui_handler_param); + + /* cancel takes us back to the ingame handler */ + if (ui_handler_param == UI_HANDLER_CANCEL) + ui_set_handler(handler_ingame, 0); + + /* add a message if we are rescaling */ + if (display_rescale_message) + { + display_rescale_message = FALSE; + if (allow_rescale == 0) + allow_rescale = 2; + ui_draw_text_box("Updating Artwork...", JUSTIFY_CENTER, 0.5f, 0.5f, messagebox_backcolor); + } + + /* decrement the frame counter if it is non-zero */ + else if (allow_rescale != 0) + allow_rescale--; + +#ifdef MESS + /* let MESS display its stuff */ + mess_ui_update(); +#endif +} + + +/*------------------------------------------------- + ui_get_font - return the UI font +-------------------------------------------------*/ + +render_font *ui_get_font(void) +{ + return ui_font; +} + + +/*------------------------------------------------- + ui_get_line_height - return the current height + of a line +-------------------------------------------------*/ + +float ui_get_line_height(void) +{ + INT32 raw_font_pixel_height = render_font_get_pixel_height(ui_font); + INT32 target_pixel_width, target_pixel_height; + float one_to_one_line_height; + float target_aspect; + float scale_factor; + + /* get info about the UI target */ + render_target_get_bounds(render_get_ui_target(), &target_pixel_width, &target_pixel_height, &target_aspect); + + /* 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(unicode_char ch) +{ + return render_font_get_char_width(ui_font, ui_get_line_height(), render_get_ui_aspect(), ch); +} + + +/*------------------------------------------------- + ui_get_string_width - return the width of a + character string +-------------------------------------------------*/ + +float ui_get_string_width(const char *s) +{ + return render_font_get_utf8string_width(ui_font, ui_get_line_height(), render_get_ui_aspect(), s); +} + + +/*------------------------------------------------- + ui_draw_outlined_box - add primitives to draw + an outlined box with the given background + color +-------------------------------------------------*/ + +void ui_draw_outlined_box(float x0, float y0, float x1, float y1, rgb_t backcolor) +{ + float hw = UI_LINE_WIDTH * 0.5f; + render_ui_add_rect(x0, y0, x1, y1, backcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + render_ui_add_line(x0 + hw, y0 + hw, x1 - hw, y0 + hw, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + render_ui_add_line(x1 - hw, y0 + hw, x1 - hw, y1 - hw, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + render_ui_add_line(x1 - hw, y1 - hw, x0 + hw, y1 - hw, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + render_ui_add_line(x0 + hw, y1 - hw, x0 + hw, y0 + hw, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); +} + + +/*------------------------------------------------- + ui_draw_text - simple text renderer +-------------------------------------------------*/ + +void ui_draw_text(const char *buf, float x, float y) +{ + ui_draw_text_full(buf, x, y, 1.0f - x, JUSTIFY_LEFT, WRAP_WORD, DRAW_OPAQUE, ARGB_WHITE, ARGB_BLACK, NULL, NULL); +} + + +/*------------------------------------------------- + ui_draw_text_full - full featured text + renderer with word wrapping, justification, + and full size computation +-------------------------------------------------*/ + +void ui_draw_text_full(const char *origs, float x, float y, float wrapwidth, int justify, int wrap, int draw, rgb_t fgcolor, rgb_t bgcolor, float *totalwidth, float *totalheight) +{ + float lineheight = ui_get_line_height(); + const char *ends = origs + strlen(origs); + 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(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(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('.'); + + /* 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(schar); + } + } + } + + /* align according to the justfication */ + if (line_justify == JUSTIFY_CENTER) + curx += (wrapwidth - curwidth) * 0.5f; + else if (line_justify == JUSTIFY_RIGHT) + curx += wrapwidth - curwidth; + + /* track the maximum width of any given line */ + if (curwidth > maxwidth) + maxwidth = curwidth; + + /* if opaque, add a black box */ + if (draw == DRAW_OPAQUE) + render_ui_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) + { + render_ui_add_char(curx, cury, lineheight, render_get_ui_aspect(), fgcolor, ui_font, linechar); + curx += ui_get_char_width(linechar); + } + linestart += linecharcount; + } + + /* append ellipses if needed */ + if (wrap == WRAP_TRUNCATE && *s != 0 && draw != DRAW_NONE) + { + render_ui_add_char(curx, cury, lineheight, render_get_ui_aspect(), fgcolor, ui_font, '.'); + curx += ui_get_char_width('.'); + render_ui_add_char(curx, cury, lineheight, render_get_ui_aspect(), fgcolor, ui_font, '.'); + curx += ui_get_char_width('.'); + render_ui_add_char(curx, cury, lineheight, render_get_ui_aspect(), fgcolor, ui_font, '.'); + curx += ui_get_char_width('.'); + } + + /* 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(const char *text, int justify, float xpos, float ypos, rgb_t backcolor) +{ + float target_width, target_height; + float target_x, target_y; + + /* compute the multi-line target width/height */ + ui_draw_text_full(text, 0, 0, 1.0f - 2.0f * UI_BOX_LR_BORDER, + justify, WRAP_WORD, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &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) / ui_get_line_height()) * ui_get_line_height(); + + /* 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; + + /* add a box around that */ + ui_draw_outlined_box(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(text, target_x, target_y, target_width, + justify, WRAP_WORD, DRAW_NORMAL, ARGB_WHITE, ARGB_BLACK, NULL, NULL); +} + + +/*------------------------------------------------- + ui_popup - popup a message for a standard + amount of time +-------------------------------------------------*/ + +void CLIB_DECL ui_popup(const char *text, ...) +{ + int seconds; + va_list arg; + + /* extract the text */ + va_start(arg,text); + vsprintf(messagebox_text, text, arg); + messagebox_backcolor = UI_FILLCOLOR; + va_end(arg); + + /* set a timer */ + seconds = (int)strlen(messagebox_text) / 40 + 2; + popup_text_end = osd_ticks() + osd_ticks_per_second() * seconds; +} + + +/*------------------------------------------------- + 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); + vsprintf(messagebox_text, text, arg); + messagebox_backcolor = UI_FILLCOLOR; + 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) +{ + if (show) + { + show_profiler = TRUE; + profiler_start(); + } + else + { + show_profiler = FALSE; + profiler_stop(); + } +} + + +/*------------------------------------------------- + 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); +} + + +/*------------------------------------------------- + ui_is_slider_active - return TRUE if the slider + UI handler is active +-------------------------------------------------*/ + +int ui_is_slider_active(void) +{ + return (ui_handler_callback == handler_slider); +} + + + +/*************************************************************************** + TEXT GENERATORS +***************************************************************************/ + +/*------------------------------------------------- + sprintf_disclaimer - print the disclaimer + text to the given buffer +-------------------------------------------------*/ + +static int sprintf_disclaimer(char *buffer) +{ + char *bufptr = buffer; + bufptr += sprintf(bufptr, "%s\n\n", ui_getstring(UI_copyright1)); + bufptr += sprintf(bufptr, ui_getstring(UI_copyright2), Machine->gamedrv->description); + bufptr += sprintf(bufptr, "\n\n%s", ui_getstring(UI_copyright3)); + return bufptr - buffer; +} + + +/*------------------------------------------------- + sprintf_warnings - print the warning flags + text to the given buffer +-------------------------------------------------*/ + +static int sprintf_warnings(char *buffer) +{ +#define WARNING_FLAGS ( GAME_NOT_WORKING | \ + GAME_UNEMULATED_PROTECTION | \ + GAME_WRONG_COLORS | \ + GAME_IMPERFECT_COLORS | \ + GAME_NO_SOUND | \ + GAME_IMPERFECT_SOUND | \ + GAME_IMPERFECT_GRAPHICS | \ + GAME_NO_COCKTAIL) + char *bufptr = buffer; + int i; + + /* if no warnings, nothing to return */ + if (rom_load_warnings() == 0 && !(Machine->gamedrv->flags & WARNING_FLAGS)) + return 0; + + /* add a warning if any ROMs were loaded with warnings */ + if (rom_load_warnings() > 0) + { + bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_incorrectroms)); + if (Machine->gamedrv->flags & WARNING_FLAGS) + *bufptr++ = '\n'; + } + + /* if we have at least one warning flag, print the general header */ + if (Machine->gamedrv->flags & WARNING_FLAGS) + { + bufptr += sprintf(bufptr, "%s\n\n", ui_getstring(UI_knownproblems)); + + /* add one line per warning flag */ +#ifdef MESS + if (Machine->gamedrv->flags & GAME_COMPUTER) + bufptr += sprintf(bufptr, "%s\n\n%s\n", ui_getstring(UI_comp1), ui_getstring(UI_comp2)); +#endif + if (Machine->gamedrv->flags & GAME_IMPERFECT_COLORS) + bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_imperfectcolors)); + if (Machine->gamedrv->flags & GAME_WRONG_COLORS) + bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_wrongcolors)); + if (Machine->gamedrv->flags & GAME_IMPERFECT_GRAPHICS) + bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_imperfectgraphics)); + if (Machine->gamedrv->flags & GAME_IMPERFECT_SOUND) + bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_imperfectsound)); + if (Machine->gamedrv->flags & GAME_NO_SOUND) + bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_nosound)); + if (Machine->gamedrv->flags & GAME_NO_COCKTAIL) + bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_nococktail)); + + /* if there's a NOT WORKING or UNEMULATED PROTECTION warning, make it stronger */ + if (Machine->gamedrv->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION)) + { + const game_driver *maindrv; + const game_driver *clone_of; + int foundworking; + + /* add the strings for these warnings */ + if (Machine->gamedrv->flags & GAME_NOT_WORKING) + bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_brokengame)); + if (Machine->gamedrv->flags & GAME_UNEMULATED_PROTECTION) + bufptr += sprintf(bufptr, "%s\n", ui_getstring(UI_brokenprotection)); + + /* find the parent of this driver */ + clone_of = driver_get_clone(Machine->gamedrv); + if (clone_of != NULL && !(clone_of->flags & GAME_IS_BIOS_ROOT)) + maindrv = clone_of; + else + maindrv = Machine->gamedrv; + + /* scan the driver list for any working clones and add them */ + foundworking = 0; + for (i = 0; drivers[i] != NULL; i++) + if (drivers[i] == maindrv || driver_get_clone(drivers[i]) == maindrv) + if ((drivers[i]->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION)) == 0) + { + /* this one works, add a header and display the name of the clone */ + if (foundworking == 0) + bufptr += sprintf(bufptr, "\n\n%s\n\n", ui_getstring(UI_workingclones)); + bufptr += sprintf(bufptr, "%s\n", drivers[i]->name); + foundworking = 1; + } + } + } + + /* add the 'press OK' string */ + bufptr += sprintf(bufptr, "\n\n%s", ui_getstring(UI_typeok)); + return bufptr - buffer; +} + + +/*------------------------------------------------- + sprintf_game_info - print the game info text + to the given buffer +-------------------------------------------------*/ + +int sprintf_game_info(char *buffer) +{ + char *bufptr = buffer; + int cpunum, sndnum; + int count; + + /* print description, manufacturer, and CPU: */ + bufptr += sprintf(bufptr, "%s\n%s %s\n\n%s:\n", Machine->gamedrv->description, Machine->gamedrv->year, Machine->gamedrv->manufacturer, ui_getstring(UI_cpu)); + + /* loop over all CPUs */ + for (cpunum = 0; cpunum < MAX_CPU && Machine->drv->cpu[cpunum].type != CPU_DUMMY; cpunum += count) + { + cpu_type type = Machine->drv->cpu[cpunum].type; + int clock = Machine->drv->cpu[cpunum].clock; + + /* count how many identical CPUs we have */ + for (count = 1; cpunum + count < MAX_CPU; count++) + if (Machine->drv->cpu[cpunum + count].type != type || + Machine->drv->cpu[cpunum + count].clock != clock) + break; + + /* if more than one, prepend a #x in front of the CPU name */ + if (count > 1) + bufptr += sprintf(bufptr, "%d" UTF8_MULTIPLY, count); + bufptr += sprintf(bufptr, "%s", cputype_name(type)); + + /* display clock in kHz or MHz */ + if (clock >= 1000000) + bufptr += sprintf(bufptr, " %d.%06d" UTF8_NBSP "MHz\n", clock / 1000000, clock % 1000000); + else + bufptr += sprintf(bufptr, " %d.%03d" UTF8_NBSP "kHz\n", clock / 1000, clock % 1000); + } + + /* append the Sound: string */ + bufptr += sprintf(bufptr, "\n%s:\n", ui_getstring(UI_sound)); + + /* loop over all sound chips */ + for (sndnum = 0; sndnum < MAX_SOUND && Machine->drv->sound[sndnum].type != SOUND_DUMMY; sndnum += count) + { + sound_type type = Machine->drv->sound[sndnum].type; + int clock = sndnum_clock(sndnum); + + /* count how many identical sound chips we have */ + for (count = 1; sndnum + count < MAX_SOUND; count++) + if (Machine->drv->sound[sndnum + count].type != type || + sndnum_clock(sndnum + count) != clock) + break; + + /* if more than one, prepend a #x in front of the CPU name */ + if (count > 1) + bufptr += sprintf(bufptr, "%d" UTF8_MULTIPLY, count); + bufptr += sprintf(bufptr, "%s", sndnum_name(sndnum)); + + /* display clock in kHz or MHz */ + if (clock >= 1000000) + bufptr += sprintf(bufptr, " %d.%06d" UTF8_NBSP "MHz\n", clock / 1000000, clock % 1000000); + else if (clock != 0) + bufptr += sprintf(bufptr, " %d.%03d" UTF8_NBSP "kHz\n", clock / 1000, clock % 1000); + else + *bufptr++ = '\n'; + } + + /* display vector information for vector games */ + if (Machine->drv->video_attributes & VIDEO_TYPE_VECTOR) + bufptr += sprintf(bufptr, "\n%s\n", ui_getstring(UI_vectorgame)); + + /* display screen resolution and refresh rate info for raster games */ + else + bufptr += sprintf(bufptr,"\n%s:\n%d " UTF8_MULTIPLY " %d (%s) %f" UTF8_NBSP "Hz\n", + ui_getstring(UI_screenres), + Machine->screen[0].visarea.max_x - Machine->screen[0].visarea.min_x + 1, + Machine->screen[0].visarea.max_y - Machine->screen[0].visarea.min_y + 1, + (Machine->gamedrv->flags & ORIENTATION_SWAP_XY) ? "V" : "H", + ATTOSECONDS_TO_HZ(Machine->screen[0].refresh)); + return bufptr - buffer; +} + + + +/*************************************************************************** + UI HANDLERS +***************************************************************************/ + +/*------------------------------------------------- + handler_messagebox - displays the current + messagebox_text string but handles no input +-------------------------------------------------*/ + +static UINT32 handler_messagebox(UINT32 state) +{ + ui_draw_text_box(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(UINT32 state) +{ + /* draw a standard message window */ + ui_draw_text_box(messagebox_text, JUSTIFY_LEFT, 0.5f, 0.5f, messagebox_backcolor); + + /* an 'O' or left joystick kicks us to the next state */ + if (state == 0 && (input_code_pressed_once(KEYCODE_O) || input_ui_pressed(IPT_UI_LEFT))) + state++; + + /* a 'K' or right joystick exits the state */ + else if (state == 1 && (input_code_pressed_once(KEYCODE_K) || input_ui_pressed(IPT_UI_RIGHT))) + state = UI_HANDLER_CANCEL; + + /* if the user cancels, exit out completely */ + else if (input_ui_pressed(IPT_UI_CANCEL)) + { + mame_schedule_exit(Machine); + 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(UINT32 state) +{ + /* draw a standard message window */ + ui_draw_text_box(messagebox_text, JUSTIFY_LEFT, 0.5f, 0.5f, messagebox_backcolor); + + /* if the user cancels, exit out completely */ + if (input_ui_pressed(IPT_UI_CANCEL)) + { + mame_schedule_exit(Machine); + state = UI_HANDLER_CANCEL; + } + + /* if any key is pressed, just exit */ + else if (input_code_poll_switches(FALSE) != INPUT_CODE_INVALID) + state = UI_HANDLER_CANCEL; + + return state; +} + + +/*------------------------------------------------- + handler_ingame - in-game handler takes care + of the standard keypresses +-------------------------------------------------*/ + +static UINT32 handler_ingame(UINT32 state) +{ + int is_paused = mame_is_paused(Machine); + + /* first draw the FPS counter */ + if (showfps || osd_ticks() < showfps_end) + { + ui_draw_text_full(video_get_speed_text(), 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) + ui_draw_text_full(profiler_get_text(), 0.0f, 0.0f, 1.0f, JUSTIFY_LEFT, WRAP_WORD, DRAW_OPAQUE, ARGB_WHITE, ARGB_BLACK, NULL, NULL); + + /* let the cheat engine display its stuff */ + if (options_get_bool(mame_options(), OPTION_CHEAT)) + cheat_display_watches(); + + /* display any popup messages */ + if (osd_ticks() < popup_text_end) + ui_draw_text_box(messagebox_text, JUSTIFY_CENTER, 0.5f, 0.9f, messagebox_backcolor); + else + popup_text_end = 0; + + /* if we're single-stepping, pause now */ + if (single_step) + { + mame_pause(Machine, TRUE); + single_step = FALSE; + } + +#ifdef MESS + if (mess_disable_builtin_ui()) + return 0; +#endif + + /* if the user pressed ESC, stop the emulation */ + if (input_ui_pressed(IPT_UI_CANCEL)) + mame_schedule_exit(Machine); + + /* turn on menus if requested */ + if (input_ui_pressed(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 */ +#ifdef MAME_DEBUG + if (!Machine->debug_mode) +#endif + if (input_ui_pressed(IPT_UI_ON_SCREEN_DISPLAY)) + return ui_set_handler(handler_slider, 0); + + /* handle a reset request */ + if (input_ui_pressed(IPT_UI_RESET_MACHINE)) + mame_schedule_hard_reset(Machine); + if (input_ui_pressed(IPT_UI_SOFT_RESET)) + mame_schedule_soft_reset(Machine); + + /* handle a request to display graphics/palette */ + if (input_ui_pressed(IPT_UI_SHOW_GFX)) + { + if (!is_paused) + mame_pause(Machine, TRUE); + return ui_set_handler(ui_gfx_ui_handler, is_paused); + } + + /* handle a save state request */ + if (input_ui_pressed(IPT_UI_SAVE_STATE)) + { + mame_pause(Machine, TRUE); + return ui_set_handler(handler_load_save, LOADSAVE_SAVE); + } + + /* handle a load state request */ + if (input_ui_pressed(IPT_UI_LOAD_STATE)) + { + mame_pause(Machine, TRUE); + return ui_set_handler(handler_load_save, LOADSAVE_LOAD); + } + + /* handle a save snapshot request */ + if (input_ui_pressed(IPT_UI_SNAPSHOT)) + video_save_active_screen_snapshots(Machine); + + /* toggle pause */ + if (input_ui_pressed(IPT_UI_PAUSE)) + { + /* with a shift key, it is single step */ + if (is_paused && (input_code_pressed(KEYCODE_LSHIFT) || input_code_pressed(KEYCODE_RSHIFT))) + { + single_step = TRUE; + mame_pause(Machine, FALSE); + } + else + mame_pause(Machine, !mame_is_paused(Machine)); + } + + /* toggle movie recording */ + if (input_ui_pressed(IPT_UI_RECORD_MOVIE)) + { + if (!video_is_movie_active(Machine, 0)) + { + video_movie_begin_recording(Machine, 0, NULL); + popmessage("REC START"); + } + else + { + video_movie_end_recording(Machine, 0); + popmessage("REC STOP"); + } + } + + /* toggle profiler display */ + if (input_ui_pressed(IPT_UI_SHOW_PROFILER)) + ui_set_show_profiler(!ui_get_show_profiler()); + + /* toggle FPS display */ + if (input_ui_pressed(IPT_UI_SHOW_FPS)) + ui_set_show_fps(!ui_get_show_fps()); + + /* toggle crosshair display */ + if (input_ui_pressed(IPT_UI_TOGGLE_CROSSHAIR)) + video_crosshair_toggle(); + + /* increment frameskip? */ + if (input_ui_pressed(IPT_UI_FRAMESKIP_INC)) + { + /* get the current value and increment it */ + int newframeskip = video_get_frameskip() + 1; + if (newframeskip > MAX_FRAMESKIP) + newframeskip = -1; + video_set_frameskip(newframeskip); + + /* display the FPS counter for 2 seconds */ + ui_show_fps_temp(2.0); + } + + /* decrement frameskip? */ + if (input_ui_pressed(IPT_UI_FRAMESKIP_DEC)) + { + /* get the current value and decrement it */ + int newframeskip = video_get_frameskip() - 1; + if (newframeskip < -1) + newframeskip = MAX_FRAMESKIP; + video_set_frameskip(newframeskip); + + /* display the FPS counter for 2 seconds */ + ui_show_fps_temp(2.0); + } + + /* toggle throttle? */ + if (input_ui_pressed(IPT_UI_THROTTLE)) + video_set_throttle(!video_get_throttle()); + + /* check for fast forward */ + if (input_port_type_pressed(IPT_UI_FAST_FORWARD, 0)) + { + video_set_fastforward(TRUE); + ui_show_fps_temp(0.5); + } + else + video_set_fastforward(FALSE); + + return 0; +} + + +/*------------------------------------------------- + handler_slider - displays the current slider + and calls the slider handler +-------------------------------------------------*/ + +static UINT32 handler_slider(UINT32 state) +{ + slider_state *cur = &slider_list[slider_current]; + INT32 increment = 0, newval; + char textbuf[256]; + + /* left/right control the increment */ + if (input_ui_pressed_repeat(IPT_UI_LEFT,6)) + increment = -cur->incval; + if (input_ui_pressed_repeat(IPT_UI_RIGHT,6)) + increment = cur->incval; + + /* alt goes to 1, shift goes 10x smaller, control goes 10x larger */ + if (increment != 0) + { + if (input_code_pressed(KEYCODE_LALT) || input_code_pressed(KEYCODE_RALT)) + increment = (increment < 0) ? -1 : 1; + if (input_code_pressed(KEYCODE_LSHIFT) || input_code_pressed(KEYCODE_RSHIFT)) + increment = (increment < -10 || increment > 10) ? (increment / 10) : ((increment < 0) ? -1 : 1); + if (input_code_pressed(KEYCODE_LCONTROL) || input_code_pressed(KEYCODE_RCONTROL)) + increment *= 10; + } + + /* determine the new value */ + newval = (*cur->update)(0, NULL, cur->arg) + increment; + + /* select resets to the default value */ + if (input_ui_pressed(IPT_UI_SELECT)) + newval = cur->defval; + + /* clamp within bounds */ + if (newval < cur->minval) + newval = cur->minval; + if (newval > cur->maxval) + newval = cur->maxval; + + /* update the new data and get the text */ + (*cur->update)(newval, textbuf, cur->arg); + + /* display the UI */ + slider_display(textbuf, cur->minval, cur->maxval, cur->defval, newval); + + /* up/down select which slider to control */ + if (input_ui_pressed_repeat(IPT_UI_DOWN,6)) + slider_current = (slider_current + 1) % slider_count; + if (input_ui_pressed_repeat(IPT_UI_UP,6)) + slider_current = (slider_current + slider_count - 1) % slider_count; + + /* the slider toggle or ESC will cancel out of our display */ + if (input_ui_pressed(IPT_UI_ON_SCREEN_DISPLAY) || input_ui_pressed(IPT_UI_CANCEL)) + return UI_HANDLER_CANCEL; + + /* the menu key will take us directly to the menu */ + if (input_ui_pressed(IPT_UI_CONFIGURE)) + return ui_set_handler(ui_menu_ui_handler, 0); + + return 0; +} + + +/*------------------------------------------------- + handler_load_save - leads the user through + specifying a game to save or load +-------------------------------------------------*/ + +static UINT32 handler_load_save(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("Select position to save to"); + else + ui_draw_message_window("Select position to load from"); + + /* check for cancel key */ + if (input_ui_pressed(IPT_UI_CANCEL)) + { + /* display a popup indicating things were cancelled */ + if (state == LOADSAVE_SAVE) + popmessage("Save cancelled"); + else + popmessage("Load cancelled"); + + /* reset the state */ + mame_pause(Machine, FALSE); + return UI_HANDLER_CANCEL; + } + + /* check for A-Z or 0-9 */ + for (code = KEYCODE_A; code <= (input_code)KEYCODE_Z; code++) + if (input_code_pressed_once(code)) + file = code - KEYCODE_A + 'a'; + if (file == 0) + for (code = KEYCODE_0; code <= (input_code)KEYCODE_9; code++) + if (input_code_pressed_once(code)) + file = code - KEYCODE_0 + '0'; + if (file == 0) + for (code = KEYCODE_0_PAD; code <= (input_code)KEYCODE_9_PAD; code++) + if (input_code_pressed_once(code)) + file = code - KEYCODE_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); + mame_schedule_save(Machine, filename); + } + else + { + popmessage("Load from position %c", file); + mame_schedule_load(Machine, filename); + } + + /* remove the pause and reset the state */ + mame_pause(Machine, FALSE); + return UI_HANDLER_CANCEL; +} + + + +/*************************************************************************** + SLIDER CONTROLS +***************************************************************************/ + +/*------------------------------------------------- + slider_init - initialize the list of slider + controls +-------------------------------------------------*/ + +static void slider_init(void) +{ + int numitems, item; + input_port_entry *in; + + slider_count = 0; + + /* add overall volume */ + slider_config(&slider_list[slider_count++], -32, 0, 0, 1, slider_volume, 0); + + /* add per-channel volume */ + numitems = sound_get_user_gain_count(); + for (item = 0; item < numitems; item++) + slider_config(&slider_list[slider_count++], 0, sound_get_default_gain(item) * 1000.0f + 0.5f, 2000, 20, slider_mixervol, item); + + /* add analog adjusters */ + for (in = Machine->input_ports; in && in->type != IPT_END; in++) + if ((in->type & 0xff) == IPT_ADJUSTER) + slider_config(&slider_list[slider_count++], 0, in->default_value >> 8, 100, 1, slider_adjuster, in - Machine->input_ports); + + if (options_get_bool(mame_options(), OPTION_CHEAT)) + { + /* add CPU overclocking */ + numitems = cpu_gettotalcpu(); + for (item = 0; item < numitems; item++) + slider_config(&slider_list[slider_count++], 10, 1000, 2000, 1, slider_overclock, item); + + /* add refresh rate tweaker */ + slider_config(&slider_list[slider_count++], -10000, 0, 10000, 1000, slider_refresh, 0); + } + + for (item = 0; item < MAX_SCREENS; item++) + if (Machine->drv->screen[item].tag != NULL) + { + int defxscale = floor(Machine->drv->screen[item].xscale * 1000.0f + 0.5f); + int defyscale = floor(Machine->drv->screen[item].yscale * 1000.0f + 0.5f); + int defxoffset = floor(Machine->drv->screen[item].xoffset * 1000.0f + 0.5f); + int defyoffset = floor(Machine->drv->screen[item].yoffset * 1000.0f + 0.5f); + + /* add standard brightness/contrast/gamma controls per-screen */ + slider_config(&slider_list[slider_count++], 100, 1000, 2000, 10, slider_brightness, item); + slider_config(&slider_list[slider_count++], 100, 1000, 2000, 50, slider_contrast, item); + slider_config(&slider_list[slider_count++], 100, 1000, 3000, 50, slider_gamma, item); + + /* add scale and offset controls per-screen */ + slider_config(&slider_list[slider_count++], 500, (defxscale == 0) ? 1000 : defxscale, 1500, 2, slider_xscale, item); + slider_config(&slider_list[slider_count++], -500, defxoffset, 500, 2, slider_xoffset, item); + slider_config(&slider_list[slider_count++], 500, (defyscale == 0) ? 1000 : defyscale, 1500, 2, slider_yscale, item); + slider_config(&slider_list[slider_count++], -500, defyoffset, 500, 2, slider_yoffset, item); + } + + if (Machine->drv->video_attributes & VIDEO_TYPE_VECTOR) + { + /* add flicker control */ + slider_config(&slider_list[slider_count++], 0, 0, 1000, 10, slider_flicker, 0); + slider_config(&slider_list[slider_count++], 10, 100, 1000, 10, slider_beam, 0); + } + +#ifdef MAME_DEBUG + /* add crosshair adjusters */ + for (in = Machine->input_ports; in && in->type != IPT_END; in++) + if (in->analog.crossaxis != CROSSHAIR_AXIS_NONE && in->player == 0) + { + slider_config(&slider_list[slider_count++], -3000, 1000, 3000, 100, slider_crossscale, in->analog.crossaxis); + slider_config(&slider_list[slider_count++], -3000, 0, 3000, 100, slider_crossoffset, in->analog.crossaxis); + } +#endif +} + + +/*------------------------------------------------- + slider_display - display a slider box with + text +-------------------------------------------------*/ + +static void slider_display(const char *text, int minval, int maxval, int defval, int curval) +{ + float percentage = (float)(curval - minval) / (float)(maxval - minval); + float default_percentage = (float)(defval - minval) / (float)(maxval - minval); + float space_width = ui_get_char_width(' '); + float line_height = ui_get_line_height(); + float ui_width, ui_height; + float text_height; + + /* leave a spaces' worth of room along the left/right sides, and a lines' worth on the top/bottom */ + ui_width = 1.0f - 2.0f * space_width; + ui_height = 1.0f - 2.0f * line_height; + + /* determine the text height */ + ui_draw_text_full(text, 0, 0, ui_width - 2 * UI_BOX_LR_BORDER, + JUSTIFY_CENTER, WRAP_WORD, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, NULL, &text_height); + + /* add a box around the whole area */ + ui_draw_outlined_box(space_width, + line_height + ui_height - text_height - line_height - 2 * UI_BOX_TB_BORDER, + space_width + ui_width, + line_height + ui_height, UI_FILLCOLOR); + + /* draw the thermometer */ + slider_draw_bar(2.0f * space_width, line_height + ui_height - UI_BOX_TB_BORDER - text_height - line_height * 0.75f, + ui_width - 2.0f * space_width, line_height * 0.75f, percentage, default_percentage); + + /* draw the actual text */ + ui_draw_text_full(text, space_width + UI_BOX_LR_BORDER, line_height + ui_height - UI_BOX_TB_BORDER - text_height, ui_width - 2.0f * UI_BOX_LR_BORDER, + JUSTIFY_CENTER, WRAP_WORD, DRAW_NORMAL, ARGB_WHITE, ARGB_BLACK, NULL, &text_height); +} + + +/*------------------------------------------------- + slider_draw_bar - draw a slider thermometer +-------------------------------------------------*/ + +static void slider_draw_bar(float leftx, float topy, float width, float height, float percentage, float default_percentage) +{ + float current_x, default_x; + float bar_top, bar_bottom; + + /* compute positions */ + bar_top = topy + 0.125f * height; + bar_bottom = topy + 0.875f * height; + default_x = leftx + width * default_percentage; + current_x = leftx + width * percentage; + + /* fill in the percentage */ + render_ui_add_rect(leftx, bar_top, current_x, bar_bottom, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + + /* draw the top and bottom lines */ + render_ui_add_line(leftx, bar_top, leftx + width, bar_top, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + render_ui_add_line(leftx, bar_bottom, leftx + width, bar_bottom, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + + /* draw default marker */ + render_ui_add_line(default_x, topy, default_x, bar_top, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + render_ui_add_line(default_x, bar_bottom, default_x, topy + height, UI_LINE_WIDTH, ARGB_WHITE, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); +} + + +/*------------------------------------------------- + slider_volume - global volume slider callback +-------------------------------------------------*/ + +static INT32 slider_volume(INT32 newval, char *buffer, int arg) +{ + if (buffer != NULL) + { + sound_set_attenuation(newval); + sprintf(buffer, "%s %3ddB", ui_getstring(UI_volume), sound_get_attenuation()); + } + return sound_get_attenuation(); +} + + +/*------------------------------------------------- + slider_mixervol - single channel volume + slider callback +-------------------------------------------------*/ + +static INT32 slider_mixervol(INT32 newval, char *buffer, int arg) +{ + if (buffer != NULL) + { + sound_set_user_gain(arg, (float)newval * 0.001f); + sprintf(buffer, "%s %s %4.2f", sound_get_user_gain_name(arg), ui_getstring(UI_volume), sound_get_user_gain(arg)); + } + return floor(sound_get_user_gain(arg) * 1000.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_adjuster - analog adjuster slider + callback +-------------------------------------------------*/ + +static INT32 slider_adjuster(INT32 newval, char *buffer, int arg) +{ + input_port_entry *in = &Machine->input_ports[arg]; + if (buffer != NULL) + { + in->default_value = (in->default_value & ~0xff) | (newval & 0xff); + sprintf(buffer, "%s %d%%", in->name, in->default_value & 0xff); + } + return in->default_value & 0xff; +} + + +/*------------------------------------------------- + slider_overclock - CPU overclocker slider + callback +-------------------------------------------------*/ + +static INT32 slider_overclock(INT32 newval, char *buffer, int arg) +{ + if (buffer != NULL) + { + cpunum_set_clockscale(arg, (float)newval * 0.001f); + sprintf(buffer, "%s %s%d %3.0f%%", ui_getstring(UI_overclock), ui_getstring(UI_cpu), arg, floor(cpunum_get_clockscale(arg) * 100.0f + 0.5f)); + } + return floor(cpunum_get_clockscale(arg) * 1000.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_refresh - refresh rate slider callback +-------------------------------------------------*/ + +static INT32 slider_refresh(INT32 newval, char *buffer, int arg) +{ + double defrefresh = ATTOSECONDS_TO_HZ(Machine->drv->screen[arg].defstate.refresh); + double refresh; + + if (buffer != NULL) + { + screen_state *state = &Machine->screen[arg]; + video_screen_configure(arg, state->width, state->height, &state->visarea, HZ_TO_ATTOSECONDS(defrefresh + (double)newval * 0.001)); + sprintf(buffer, "Screen %d %s %.3f", arg, ui_getstring(UI_refresh_rate), ATTOSECONDS_TO_HZ(Machine->screen[arg].refresh)); + } + refresh = ATTOSECONDS_TO_HZ(Machine->screen[arg].refresh); + return floor((refresh - defrefresh) * 1000.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_brightness - screen brightness slider + callback +-------------------------------------------------*/ + +static INT32 slider_brightness(INT32 newval, char *buffer, int arg) +{ + render_container *container = render_container_get_screen(arg); + if (buffer != NULL) + { + render_container_set_brightness(container, (float)newval * 0.001f); + sprintf(buffer, "Screen %d %s %.3f", arg, ui_getstring(UI_brightness), render_container_get_brightness(container)); + } + return floor(render_container_get_brightness(container) * 1000.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_contrast - screen contrast slider + callback +-------------------------------------------------*/ + +static INT32 slider_contrast(INT32 newval, char *buffer, int arg) +{ + render_container *container = render_container_get_screen(arg); + if (buffer != NULL) + { + render_container_set_contrast(container, (float)newval * 0.001f); + sprintf(buffer, "Screen %d %s %.3f", arg, ui_getstring(UI_contrast), render_container_get_contrast(container)); + } + return floor(render_container_get_contrast(container) * 1000.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_gamma - screen gamma slider callback +-------------------------------------------------*/ + +static INT32 slider_gamma(INT32 newval, char *buffer, int arg) +{ + render_container *container = render_container_get_screen(arg); + if (buffer != NULL) + { + render_container_set_gamma(container, (float)newval * 0.001f); + sprintf(buffer, "Screen %d %s %.3f", arg, ui_getstring(UI_gamma), render_container_get_gamma(container)); + } + return floor(render_container_get_gamma(container) * 1000.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_xscale - screen horizontal scale slider + callback +-------------------------------------------------*/ + +static INT32 slider_xscale(INT32 newval, char *buffer, int arg) +{ + render_container *container = render_container_get_screen(arg); + if (buffer != NULL) + { + render_container_set_xscale(container, (float)newval * 0.001f); + sprintf(buffer, "Screen %d %s %.3f", arg, "Horiz stretch", render_container_get_xscale(container)); + } + return floor(render_container_get_xscale(container) * 1000.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_yscale - screen vertical scale slider + callback +-------------------------------------------------*/ + +static INT32 slider_yscale(INT32 newval, char *buffer, int arg) +{ + render_container *container = render_container_get_screen(arg); + if (buffer != NULL) + { + render_container_set_yscale(container, (float)newval * 0.001f); + sprintf(buffer, "Screen %d %s %.3f", arg, "Vert stretch", render_container_get_yscale(container)); + } + return floor(render_container_get_yscale(container) * 1000.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_xoffset - screen horizontal position + slider callback +-------------------------------------------------*/ + +static INT32 slider_xoffset(INT32 newval, char *buffer, int arg) +{ + render_container *container = render_container_get_screen(arg); + if (buffer != NULL) + { + render_container_set_xoffset(container, (float)newval * 0.001f); + sprintf(buffer, "Screen %d %s %.3f", arg, "Horiz position", render_container_get_xoffset(container)); + } + return floor(render_container_get_xoffset(container) * 1000.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_yoffset - screen vertical position + slider callback +-------------------------------------------------*/ + +static INT32 slider_yoffset(INT32 newval, char *buffer, int arg) +{ + render_container *container = render_container_get_screen(arg); + if (buffer != NULL) + { + render_container_set_yoffset(container, (float)newval * 0.001f); + sprintf(buffer, "Screen %d %s %.3f", arg, "Vert position", render_container_get_yoffset(container)); + } + return floor(render_container_get_yoffset(container) * 1000.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_flicker - vector flicker slider + callback +-------------------------------------------------*/ + +static INT32 slider_flicker(INT32 newval, char *buffer, int arg) +{ + if (buffer != NULL) + { + vector_set_flicker((float)newval * 0.1f); + sprintf(buffer, "%s %1.2f", ui_getstring(UI_vectorflicker), vector_get_flicker()); + } + return floor(vector_get_flicker() * 10.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_beam - vector beam width slider + callback +-------------------------------------------------*/ + +static INT32 slider_beam(INT32 newval, char *buffer, int arg) +{ + if (buffer != NULL) + { + vector_set_beam((float)newval * 0.01f); + sprintf(buffer, "%s %1.2f", "Beam Width", vector_get_beam()); + } + return floor(vector_get_beam() * 100.0f + 0.5f); +} + + +/*------------------------------------------------- + slider_crossscale - crosshair scale slider + callback +-------------------------------------------------*/ + +#ifdef MAME_DEBUG +static INT32 slider_crossscale(INT32 newval, char *buffer, int arg) +{ + input_port_entry *in; + + if (buffer != NULL) + { + for (in = Machine->input_ports; in && in->type != IPT_END; in++) + if (in->analog.crossaxis == arg) + { + in->analog.crossscale = (float)newval * 0.001f; + break; + } + sprintf(buffer, "%s %s %1.3f", "Crosshair Scale", (in->analog.crossaxis == CROSSHAIR_AXIS_X) ? "X" : "Y", (float)newval * 0.001f); + } + for (in = Machine->input_ports; in && in->type != IPT_END; in++) + if (in->analog.crossaxis == arg) + return floor(in->analog.crossscale * 1000.0f + 0.5f); + return 0; +} +#endif + + +/*------------------------------------------------- + slider_crossoffset - crosshair scale slider + callback +-------------------------------------------------*/ + +#ifdef MAME_DEBUG +static INT32 slider_crossoffset(INT32 newval, char *buffer, int arg) +{ + input_port_entry *in; + + if (buffer != NULL) + { + for (in = Machine->input_ports; in && in->type != IPT_END; in++) + if (in->analog.crossaxis == arg) + { + in->analog.crossoffset = (float)newval * 0.001f; + break; + } + sprintf(buffer, "%s %s %1.3f", "Crosshair Offset", (in->analog.crossaxis == CROSSHAIR_AXIS_X) ? "X" : "Y", (float)newval * 0.001f); + } + for (in = Machine->input_ports; in && in->type != IPT_END; in++) + if (in->analog.crossaxis == arg) + return floor(in->analog.crossoffset * 1000.0f + 0.5f); + return 0; +} +#endif |