diff options
author | 2016-02-21 11:48:45 +0100 | |
---|---|---|
committer | 2016-02-21 11:48:45 +0100 | |
commit | cc24a339d8c0517259084b5c178d784626ba965c (patch) | |
tree | 9868e9687b5802ae0a3733712a3bbeb3bc75c953 /src/emu/ui/ui.cpp | |
parent | b5daabda5495dea5c50e17961ecfed2ea8619d76 (diff) |
Merge remote-tracking branch 'refs/remotes/mamedev/master'
Second attempt
Diffstat (limited to 'src/emu/ui/ui.cpp')
-rw-r--r-- | src/emu/ui/ui.cpp | 440 |
1 files changed, 372 insertions, 68 deletions
diff --git a/src/emu/ui/ui.cpp b/src/emu/ui/ui.cpp index 3f2d252c107..b002560382c 100644 --- a/src/emu/ui/ui.cpp +++ b/src/emu/ui/ui.cpp @@ -37,6 +37,8 @@ enum LOADSAVE_SAVE }; +#define MAX_SAVED_STATE_JOYSTICK 4 + /*************************************************************************** LOCAL VARIABLES @@ -86,6 +88,25 @@ static const input_item_id non_char_keys[] = ITEM_ID_CANCEL }; +static const char *s_color_list[] = { + OPTION_UI_BORDER_COLOR, + OPTION_UI_BACKGROUND_COLOR, + OPTION_UI_GFXVIEWER_BG_COLOR, + OPTION_UI_UNAVAILABLE_COLOR, + OPTION_UI_TEXT_COLOR, + OPTION_UI_TEXT_BG_COLOR, + OPTION_UI_SUBITEM_COLOR, + OPTION_UI_CLONE_COLOR, + OPTION_UI_SELECTED_COLOR, + OPTION_UI_SELECTED_BG_COLOR, + OPTION_UI_MOUSEOVER_COLOR, + OPTION_UI_MOUSEOVER_BG_COLOR, + OPTION_UI_MOUSEDOWN_COLOR, + OPTION_UI_MOUSEDOWN_BG_COLOR, + OPTION_UI_DIPSW_COLOR, + OPTION_UI_SLIDER_COLOR +}; + /*************************************************************************** GLOBAL VARIABLES ***************************************************************************/ @@ -139,6 +160,24 @@ static INT32 slider_crossoffset(running_machine &machine, void *arg, std::string ***************************************************************************/ //------------------------------------------------- +// load ui options +//------------------------------------------------- + +static void load_ui_options(running_machine &machine) +{ + // parse the file + std::string error; + // attempt to open the output file + emu_file file(machine.options().ini_path(), OPEN_FLAG_READ); + if (file.open("ui.ini") == FILERR_NONE) + { + bool result = machine.ui().options().parse_ini_file((core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_DRIVER_INI, error); + if (!result) + osd_printf_error("**Error to load ui.ini**"); + } +} + +//------------------------------------------------- // is_breakable_char - is a given unicode // character a possible line break? //------------------------------------------------- @@ -183,7 +222,8 @@ static inline int is_breakable_char(unicode_char ch) CORE IMPLEMENTATION ***************************************************************************/ -static const UINT32 mouse_bitmap[] = { +static const UINT32 mouse_bitmap[32*32] = +{ 0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff, 0x09a46f30,0x81ac7c43,0x24af8049,0x00ad7d45,0x00a8753a,0x00a46f30,0x009f6725,0x009b611c,0x00985b14,0x0095560d,0x00935308,0x00915004,0x00904e02,0x008f4e01,0x008f4d00,0x008f4d00,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff, 0x00a16a29,0xa2aa783d,0xffbb864a,0xc0b0824c,0x5aaf7f48,0x09ac7b42,0x00a9773c,0x00a67134,0x00a26b2b,0x009e6522,0x009a5e19,0x00965911,0x0094550b,0x00925207,0x00915004,0x008f4e01,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff,0x00ffffff, @@ -226,9 +266,14 @@ static const UINT32 mouse_bitmap[] = { ui_manager::ui_manager(running_machine &machine) : m_machine(machine) { +} + +void ui_manager::init() +{ + load_ui_options(machine()); // initialize the other UI bits - ui_menu::init(machine); - ui_gfx_init(machine); + ui_menu::init(machine()); + ui_gfx_init(machine()); // reset instance variables m_font = nullptr; @@ -236,26 +281,32 @@ ui_manager::ui_manager(running_machine &machine) m_handler_param = 0; m_single_step = false; m_showfps = false; - m_showfps_end = false; + m_showfps_end = 0; m_show_profiler = false; m_popup_text_end = 0; m_use_natural_keyboard = false; m_mouse_arrow_texture = nullptr; + m_show_timecode_counter = false; + m_show_timecode_total = false; + m_load_save_hold = false; + + get_font_rows(&machine()); + decode_ui_color(0, &machine()); // more initialization set_handler(handler_messagebox, 0); m_non_char_keys_down = std::make_unique<UINT8[]>((ARRAY_LENGTH(non_char_keys) + 7) / 8); - m_mouse_show = machine.system().flags & MACHINE_CLICKABLE_ARTWORK ? true : false; + m_mouse_show = machine().system().flags & MACHINE_CLICKABLE_ARTWORK ? true : false; // request a callback upon exiting - machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(ui_manager::exit), this)); + machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(ui_manager::exit), this)); // retrieve options - m_use_natural_keyboard = machine.options().natural_keyboard(); - bitmap_argb32 *ui_mouse_bitmap = auto_alloc(machine, bitmap_argb32(32, 32)); + m_use_natural_keyboard = machine().options().natural_keyboard(); + bitmap_argb32 *ui_mouse_bitmap = auto_alloc(machine(), bitmap_argb32(32, 32)); UINT32 *dst = &ui_mouse_bitmap->pix32(0); memcpy(dst,mouse_bitmap,32*32*sizeof(UINT32)); - m_mouse_arrow_texture = machine.render().texture_alloc(); + m_mouse_arrow_texture = machine().render().texture_alloc(); m_mouse_arrow_texture->set_bitmap(*ui_mouse_bitmap, ui_mouse_bitmap->cliprect(), TEXFORMAT_ARGB32); } @@ -312,7 +363,7 @@ void ui_manager::display_startup_screens(bool first_time, bool show_disclaimer) { const int maxstate = 4; int str = machine().options().seconds_to_run(); - bool show_gameinfo = !machine().options().skip_gameinfo(); + bool show_gameinfo = !machine().ui().options().skip_gameinfo(); bool show_warnings = true, show_mandatory_fileman = true; int state; @@ -447,7 +498,8 @@ void ui_manager::update_and_render(render_container *container) else m_popup_text_end = 0; - if (m_mouse_show || (is_menu_active() && machine().options().ui_mouse())) + // display the internal mouse cursor + if (m_mouse_show || (is_menu_active() && machine().ui().options().ui_mouse())) { INT32 mouse_target_x, mouse_target_y; bool mouse_button; @@ -456,8 +508,10 @@ void ui_manager::update_and_render(render_container *container) if (mouse_target != nullptr) { float mouse_y=-1,mouse_x=-1; - if (mouse_target->map_point_container(mouse_target_x, mouse_target_y, *container, mouse_x, mouse_y)) { - container->add_quad(mouse_x,mouse_y,mouse_x + 0.05f*container->manager().ui_aspect(container),mouse_y + 0.05f,UI_TEXT_COLOR,m_mouse_arrow_texture,PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + if (mouse_target->map_point_container(mouse_target_x, mouse_target_y, *container, mouse_x, mouse_y)) + { + const float cursor_size = 0.6 * machine().ui().get_line_height(); + container->add_quad(mouse_x, mouse_y, mouse_x + cursor_size*container->manager().ui_aspect(container), mouse_y + cursor_size, UI_TEXT_COLOR, m_mouse_arrow_texture, PRIMFLAG_ANTIALIAS(1) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); } } } @@ -476,7 +530,7 @@ render_font *ui_manager::get_font() { // allocate the font and messagebox string if (m_font == nullptr) - m_font = machine().render().font_alloc(machine().options().ui_font()); + m_font = machine().render().font_alloc(machine().ui().options().ui_font()); return m_font; } @@ -592,9 +646,9 @@ void ui_manager::draw_text(render_container *container, const char *buf, float x // and full size computation //------------------------------------------------- -void ui_manager::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) +void ui_manager::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, float text_size) { - float lineheight = get_line_height(); + float lineheight = get_line_height() * text_size; const char *ends = origs + strlen(origs); float wrapwidth = origwrapwidth; const char *s = origs; @@ -983,6 +1037,16 @@ bool ui_manager::is_menu_active(void) } +bool ui_manager::show_timecode_counter() +{ + return m_show_timecode_counter; +} +bool ui_manager::show_timecode_total() +{ + return m_show_timecode_total; +} + + /*************************************************************************** TEXT GENERATORS @@ -1032,11 +1096,7 @@ std::string &ui_manager::warnings_string(std::string &str) // add a warning if any ROMs were loaded with warnings if (machine().rom_load().warnings() > 0) { - str.append("One or more ROMs/CHDs for this "); - str.append(emulator_info::get_gamenoun()); - str.append(" are incorrect. The "); - str.append(emulator_info::get_gamenoun()); - str.append(" may not run correctly.\n"); + str.append("One or more ROMs/CHDs for this machine are incorrect. The machine may not run correctly.\n"); if (machine().system().flags & WARNING_FLAGS) str.append("\n"); } @@ -1049,15 +1109,11 @@ std::string &ui_manager::warnings_string(std::string &str) // if we have at least one warning flag, print the general header if ((machine().system().flags & WARNING_FLAGS) || machine().rom_load().knownbad() > 0) { - str.append("There are known problems with this "); - str.append(emulator_info::get_gamenoun()); - str.append("\n\n"); + str.append("There are known problems with this machine\n\n"); // add a warning if any ROMs are flagged BAD_DUMP/NO_DUMP if (machine().rom_load().knownbad() > 0) { - str.append("One or more ROMs/CHDs for this "); - str.append(emulator_info::get_gamenoun()); - str.append(" have not been correctly dumped.\n"); + str.append("One or more ROMs/CHDs for this machine have not been correctly dumped.\n"); } // add one line per warning flag if (machine().system().flags & MACHINE_IMPERFECT_KEYBOARD) @@ -1071,32 +1127,24 @@ std::string &ui_manager::warnings_string(std::string &str) if (machine().system().flags & MACHINE_IMPERFECT_SOUND) str.append("The sound emulation isn't 100% accurate.\n"); if (machine().system().flags & MACHINE_NO_SOUND) { - str.append("The "); - str.append(emulator_info::get_gamenoun()); - str.append(" lacks sound.\n"); + str.append("The machine lacks sound.\n"); } if (machine().system().flags & MACHINE_NO_COCKTAIL) str.append("Screen flipping in cocktail mode is not supported.\n"); // check if external artwork is present before displaying this warning? if (machine().system().flags & MACHINE_REQUIRES_ARTWORK) { - str.append("The "); - str.append(emulator_info::get_gamenoun()); - str.append(" requires external artwork files\n"); + str.append("The machine requires external artwork files\n"); } if (machine().system().flags & MACHINE_IS_INCOMPLETE ) { - str.append("This "); - str.append(emulator_info::get_gamenoun()); - str.append(" was never completed. It may exhibit strange behavior or missing elements that are not bugs in the emulation.\n"); + str.append("This machine was never completed. It may exhibit strange behavior or missing elements that are not bugs in the emulation.\n"); } if (machine().system().flags & MACHINE_NO_SOUND_HW ) { - str.append("This "); - str.append(emulator_info::get_gamenoun()); - str.append(" has no sound hardware, MAME will produce no sounds, this is expected behaviour.\n"); + str.append("This machine has no sound hardware, MAME will produce no sounds, this is expected behaviour.\n"); } // if there's a NOT WORKING, UNEMULATED PROTECTION or GAME MECHANICAL warning, make it stronger @@ -1104,25 +1152,15 @@ std::string &ui_manager::warnings_string(std::string &str) { // add the strings for these warnings if (machine().system().flags & MACHINE_UNEMULATED_PROTECTION) { - str.append("The "); - str.append(emulator_info::get_gamenoun()); - str.append(" has protection which isn't fully emulated.\n"); + str.append("The machine has protection which isn't fully emulated.\n"); } if (machine().system().flags & MACHINE_NOT_WORKING) { - str.append("\nTHIS "); - str.append(emulator_info::get_capgamenoun()); - str.append(" DOESN'T WORK. The emulation for this "); - str.append(emulator_info::get_gamenoun()); - str.append(" is not yet complete. " + str.append("\nTHIS MACHINE DOESN'T WORK. The emulation for this machine 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 & MACHINE_MECHANICAL) { - str.append("\nCertain elements of this "); - str.append(emulator_info::get_gamenoun()); - str.append(" cannot be emulated as it requires actual physical interaction or consists of mechanical devices. " - "It is not possible to fully play this "); - str.append(emulator_info::get_gamenoun()); - str.append(".\n"); + str.append("\nCertain elements of this machine cannot be emulated as it requires actual physical interaction or consists of mechanical devices. " + "It is not possible to fully play this machine.\n"); } // find the parent of this driver @@ -1140,9 +1178,7 @@ std::string &ui_manager::warnings_string(std::string &str) { // this one works, add a header and display the name of the clone if (!foundworking) { - str.append("\n\nThere are working clones of this "); - str.append(emulator_info::get_gamenoun()); - str.append(": "); + str.append("\n\nThere are working clones of this machine: "); } else str.append(", "); @@ -1503,11 +1539,24 @@ UINT32 ui_manager::handler_ingame(running_machine &machine, render_container *co // first draw the FPS counter if (machine.ui().show_fps_counter()) { - std::string tempstring; machine.ui().draw_text_full(container, machine.video().speed_text().c_str(), 0.0f, 0.0f, 1.0f, JUSTIFY_RIGHT, WRAP_WORD, DRAW_OPAQUE, ARGB_WHITE, ARGB_BLACK, nullptr, nullptr); } + // Show the duration of current part (intro or gameplay or extra) + if (machine.ui().show_timecode_counter()) { + std::string tempstring; + machine.ui().draw_text_full(container, machine.video().timecode_text(tempstring).c_str(), 0.0f, 0.0f, 1.0f, + JUSTIFY_RIGHT, WRAP_WORD, DRAW_OPAQUE, rgb_t(0xf0,0xf0,0x10,0x10), ARGB_BLACK, NULL, NULL); + } + // Show the total time elapsed for the video preview (all parts intro, gameplay, extras) + if (machine.ui().show_timecode_total()) { + std::string tempstring; + machine.ui().draw_text_full(container, machine.video().timecode_total_text(tempstring).c_str(), 0.0f, 0.0f, 1.0f, + JUSTIFY_LEFT, WRAP_WORD, DRAW_OPAQUE, rgb_t(0xf0,0x10,0xf0,0x10), ARGB_BLACK, NULL, NULL); + } + + // draw the profiler if visible if (machine.ui().show_profiler()) { @@ -1571,6 +1620,10 @@ UINT32 ui_manager::handler_ingame(running_machine &machine, render_container *co machine.ui().image_handler_ingame(); + // handle a save input timecode request + if (machine.ui_input().pressed(IPT_UI_TIMECODE)) + machine.video().save_input_timecode(); + if (ui_disabled) return ui_disabled; if (machine.ui_input().pressed(IPT_UI_CANCEL)) @@ -1625,6 +1678,7 @@ UINT32 ui_manager::handler_ingame(running_machine &machine, render_container *co if (machine.ui_input().pressed(IPT_UI_SAVE_STATE)) { machine.pause(); + machine.ui().m_load_save_hold = true; return machine.ui().set_handler(handler_load_save, LOADSAVE_SAVE); } @@ -1632,6 +1686,7 @@ UINT32 ui_manager::handler_ingame(running_machine &machine, render_container *co if (machine.ui_input().pressed(IPT_UI_LOAD_STATE)) { machine.pause(); + machine.ui().m_load_save_hold = true; return machine.ui().set_handler(handler_load_save, LOADSAVE_LOAD); } @@ -1643,15 +1698,21 @@ UINT32 ui_manager::handler_ingame(running_machine &machine, render_container *co if (machine.ui_input().pressed(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))) - { - machine.ui().set_single_step(true); - machine.resume(); - } - else +// if (is_paused && (machine.input().code_pressed(KEYCODE_LSHIFT) || machine.input().code_pressed(KEYCODE_RSHIFT))) +// { +// machine.ui().set_single_step(true); +// machine.resume(); +// } +// else machine.toggle_pause(); } + if (machine.ui_input().pressed(IPT_UI_PAUSE_SINGLE)) + { + machine.ui().set_single_step(true); + machine.resume(); + } + // handle a toggle cheats request if (machine.ui_input().pressed(IPT_UI_TOGGLE_CHEAT)) machine.cheat().set_enable(!machine.cheat().enabled()); @@ -1680,6 +1741,21 @@ UINT32 ui_manager::handler_ingame(running_machine &machine, render_container *co if (machine.ui_input().pressed(IPT_UI_THROTTLE)) machine.video().toggle_throttle(); + // toggle autofire + if (machine.ui_input().pressed(IPT_UI_TOGGLE_AUTOFIRE)) + { + if (!machine.options().cheat()) + { + machine.popmessage("Autofire can't be enabled"); + } + else + { + bool autofire_toggle = machine.ioport().get_autofire_toggle(); + machine.ioport().set_autofire_toggle(!autofire_toggle); + machine.popmessage("Autofire %s", autofire_toggle ? "Enabled" : "Disabled"); + } + } + // check for fast forward if (machine.ioport().type_pressed(IPT_UI_FAST_FORWARD)) { @@ -1713,6 +1789,23 @@ UINT32 ui_manager::handler_load_save(running_machine &machine, render_container else machine.ui().draw_message_window(container, "Select position to load from"); + // if load/save state sequence is still being pressed, do not read the filename yet + if (machine.ui().m_load_save_hold) { + bool seq_in_progress = false; + const input_seq &load_save_seq = state == LOADSAVE_SAVE ? + machine.ioport().type_seq(IPT_UI_SAVE_STATE) : + machine.ioport().type_seq(IPT_UI_LOAD_STATE); + + for (int i = 0; i < load_save_seq.length(); i++) + if (machine.input().code_pressed_once(load_save_seq[i])) + seq_in_progress = true; + + if (seq_in_progress) + return state; + else + machine.ui().m_load_save_hold = false; + } + // check for cancel key if (machine.ui_input().pressed(IPT_UI_CANCEL)) { @@ -1740,21 +1833,41 @@ UINT32 ui_manager::handler_load_save(running_machine &machine, render_container 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; + { + bool found = false; + + for (int joy_index = 0; joy_index <= MAX_SAVED_STATE_JOYSTICK; joy_index++) + for (input_item_id id = ITEM_ID_BUTTON1; id <= ITEM_ID_BUTTON32; ++id) + if (machine.input().code_pressed_once(input_code(DEVICE_CLASS_JOYSTICK, joy_index, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, id))) + { + snprintf(filename, sizeof(filename), "joy%i-%i", joy_index, id - ITEM_ID_BUTTON1 + 1); + found = true; + break; + } + + if (!found) + return state; + } + else + { + sprintf(filename, "%c", file); + } // display a popup indicating that the save will proceed - sprintf(filename, "%c", file); if (state == LOADSAVE_SAVE) { - machine.popmessage("Save to position %c", file); + machine.popmessage("Save to position %s", filename); machine.schedule_save(filename); } else { - machine.popmessage("Load from position %c", file); + machine.popmessage("Load from position %s", filename); machine.schedule_load(filename); } + // avoid handling the name of the save state slot as a seperate input + machine.ui_input().mark_all_as_pressed(); + // remove the pause and reset the state machine.resume(); return UI_HANDLER_CANCEL; @@ -1767,7 +1880,7 @@ UINT32 ui_manager::handler_load_save(running_machine &machine, render_container void ui_manager::request_quit() { - if (!machine().options().confirm_quit()) + if (!machine().ui().options().confirm_quit()) machine().schedule_exit(); else set_handler(handler_confirm_quit, 0); @@ -2490,3 +2603,194 @@ void ui_manager::set_use_natural_keyboard(bool use_natural_keyboard) machine().options().set_value(OPTION_NATURAL_KEYBOARD, use_natural_keyboard, OPTION_PRIORITY_CMDLINE, error); assert(error.empty()); } + +//------------------------------------------------- +// wrap_text +//------------------------------------------------- + +int ui_manager::wrap_text(render_container *container, const char *origs, float x, float y, float origwrapwidth, std::vector<int> &xstart, std::vector<int> &xend, float text_size) +{ + float lineheight = get_line_height() * text_size; + const char *ends = origs + strlen(origs); + float wrapwidth = origwrapwidth; + const char *s = origs; + const char *linestart; + float maxwidth = 0; + float aspect = machine().render().ui_aspect(container); + int count = 0; + + // loop over lines + while (*s != 0) + { + const char *lastbreak = nullptr; + unicode_char schar; + int scharcount; + float lastbreak_width = 0; + float curwidth = 0; + + // get the current character + scharcount = uchar_from_utf8(&schar, s, ends - s); + if (scharcount == -1) + break; + + // 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 = get_font()->char_width(lineheight, aspect, 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 hit a break, back up to there with the appropriate width + if (lastbreak != nullptr) + { + 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 -= get_font()->char_width(lineheight, aspect, schar); + } + } + + // track the maximum width of any given line + if (curwidth > maxwidth) + maxwidth = curwidth; + + xstart.push_back(linestart - origs); + xend.push_back(s - origs); + + // 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; + linestart += linecharcount; + } + + // advance by a row + count++; + + // 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; + } + } + return count; +} + +//------------------------------------------------- +// draw_textured_box - add primitives to +// draw an outlined box with the given +// textured background and line color +//------------------------------------------------- + +void ui_manager::draw_textured_box(render_container *container, float x0, float y0, float x1, float y1, rgb_t backcolor, rgb_t linecolor, render_texture *texture, UINT32 flags) +{ + container->add_quad(x0, y0, x1, y1, backcolor, texture, flags); + container->add_line(x0, y0, x1, y0, UI_LINE_WIDTH, linecolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + container->add_line(x1, y0, x1, y1, UI_LINE_WIDTH, linecolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + container->add_line(x1, y1, x0, y1, UI_LINE_WIDTH, linecolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + container->add_line(x0, y1, x0, y0, UI_LINE_WIDTH, linecolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); +} + +//------------------------------------------------- +// get_string_width_ex - return the width of a +// character string with given text size +//------------------------------------------------- + +float ui_manager::get_string_width_ex(const char *s, float text_size) +{ + return get_font()->utf8string_width(get_line_height() * text_size, machine().render().ui_aspect(), s); +} + +//------------------------------------------------- +// decode UI color options +//------------------------------------------------- + +rgb_t decode_ui_color(int id, running_machine *machine) +{ + static rgb_t color[ARRAY_LENGTH(s_color_list)]; + + if (machine != nullptr) { + ui_options option; + for (int x = 0; x < ARRAY_LENGTH(s_color_list); x++) { + const char *o_default = option.value(s_color_list[x]); + const char *s_option = machine->ui().options().value(s_color_list[x]); + int len = strlen(s_option); + if (len != 8) + color[x] = rgb_t((UINT32)strtoul(o_default, nullptr, 16)); + else + color[x] = rgb_t((UINT32)strtoul(s_option, nullptr, 16)); + } + } + return color[id]; +} + +//------------------------------------------------- +// get font rows from options +//------------------------------------------------- + +int get_font_rows(running_machine *machine) +{ + static int value; + + return ((machine != nullptr) ? value = machine->ui().options().font_rows() : value); +} |