// license:BSD-3-Clause // copyright-holders:Nathan Woods /********************************************************************* ui/devopt.cpp Internal menu for the device configuration. *********************************************************************/ #include "emu.h" #include "ui/devopt.h" #include "ui/ui.h" #include "romload.h" #include "screen.h" namespace ui { /*------------------------------------------------- device_config - handle the game information menu -------------------------------------------------*/ menu_device_config::menu_device_config( mame_ui_manager &mui, render_container &container, device_slot_interface *slot, device_slot_interface::slot_option const *option) : menu_textbox(mui, container) , m_option(option) , m_mounted(machine().root_device().subdevice(slot->device().subtag(option->name())) != nullptr) { set_process_flags(PROCESS_CUSTOM_NAV); } menu_device_config::~menu_device_config() { } void menu_device_config::populate_text(std::optional &layout, float &width, int &lines) { if (!layout || (layout->width() != width)) { rgb_t const color = ui().colors().text_color(); layout.emplace(ui().create_layout(container(), width)); machine_config &mconfig(const_cast(machine().config())); machine_config::token const tok(mconfig.begin_configuration(mconfig.root_device())); device_t *const dev = mconfig.device_add(m_option->name(), m_option->devtype(), 0); for (device_t &d : device_enumerator(*dev)) if (!d.configured()) d.config_complete(); layout->add_text( util::string_format( m_mounted ? _("[This option is currently mounted in the running system]\n\nOption: %1$s\nDevice: %2$s\n\nThe selected option enables the following items:\n") : _("[This option is NOT currently mounted in the running system]\n\nOption: %1$s\nDevice: %2$s\n\nIf you select this option, the following items will be enabled:\n"), m_option->name(), dev->name()), color); // loop over all CPUs execute_interface_enumerator execiter(*dev); if (execiter.count() > 0) { layout->add_text(_("* CPU:\n"), color); std::unordered_set exectags; for (device_execute_interface &exec : execiter) { if (!exectags.insert(exec.device().tag()).second) continue; // get cpu specific clock that takes internal multiplier/dividers into account u32 clock = exec.device().clock(); // count how many identical CPUs we have int count = 1; const char *name = exec.device().name(); for (device_execute_interface &scan : execiter) { if (exec.device().type() == scan.device().type() && strcmp(name, scan.device().name()) == 0 && exec.device().clock() == scan.device().clock()) if (exectags.insert(scan.device().tag()).second) count++; } std::string hz(std::to_string(clock)); int d = (clock >= 1'000'000'000) ? 9 : (clock >= 1'000'000) ? 6 : (clock >= 1000) ? 3 : 0; if (d > 0) { size_t dpos = hz.length() - d; hz.insert(dpos, "."); size_t last = hz.find_last_not_of('0'); hz = hz.substr(0, last + (last != dpos ? 1 : 0)); } // if more than one, prepend a #x in front of the CPU name and display clock layout->add_text( util::string_format( (count > 1) ? ((clock != 0) ? " %1$d" UTF8_MULTIPLY "%2$s %3$s" UTF8_NBSP "%4$s\n" : " %1$d" UTF8_MULTIPLY "%2$s\n") : ((clock != 0) ? " %2$s %3$s" UTF8_NBSP "%4$s\n" : " %2$s\n"), count, name, hz, (d == 9) ? _("GHz") : (d == 6) ? _("MHz") : (d == 3) ? _("kHz") : _("Hz")), color); } } // display screen information screen_device_enumerator scriter(*dev); if (scriter.count() > 0) { layout->add_text(_("* Video:\n"), color); for (screen_device &screen : scriter) { if (screen.screen_type() == SCREEN_TYPE_VECTOR) { layout->add_text(util::string_format(_(" Screen '%1$s': Vector\n"), screen.tag()), color); } else { const u32 rate = u32(screen.frame_period().as_hz() * 1'000'000 + 0.5); const bool valid = rate >= 1'000'000; std::string hz(valid ? std::to_string(rate) : "?"); if (valid) { size_t dpos = hz.length() - 6; hz.insert(dpos, "."); size_t last = hz.find_last_not_of('0'); hz = hz.substr(0, last + (last != dpos ? 1 : 0)); } const rectangle &visarea = screen.visible_area(); layout->add_text( util::string_format( (screen.orientation() & ORIENTATION_SWAP_XY) ? _(" Screen '%1$s': %2$d \xC3\x97 %3$d (V) %4$s\xC2\xA0Hz\n") : _(" Screen '%1$s': %2$d \xC3\x97 %3$d (H) %4$s\xC2\xA0Hz\n"), screen.tag(), visarea.width(), visarea.height(), hz), color); } } } // loop over all sound chips sound_interface_enumerator snditer(*dev); if (snditer.count() > 0) { layout->add_text(_("* Sound:\n"), color); std::unordered_set soundtags; for (device_sound_interface &sound : snditer) { if (!sound.issound() || !soundtags.insert(sound.device().tag()).second) continue; // count how many identical sound chips we have int count = 1; for (device_sound_interface &scan : snditer) { if (sound.device().type() == scan.device().type() && sound.device().clock() == scan.device().clock()) if (soundtags.insert(scan.device().tag()).second) count++; } const u32 clock = sound.device().clock(); std::string hz(std::to_string(clock)); int d = (clock >= 1'000'000'000) ? 9 : (clock >= 1'000'000) ? 6 : (clock >= 1000) ? 3 : 0; if (d > 0) { size_t dpos = hz.length() - d; hz.insert(dpos, "."); size_t last = hz.find_last_not_of('0'); hz = hz.substr(0, last + (last != dpos ? 1 : 0)); } // if more than one, prepend a #x in front of the name and display clock layout->add_text( util::string_format( (count > 1) ? ((clock != 0) ? " %1$d" UTF8_MULTIPLY "%2$s %3$s" UTF8_NBSP "%4$s\n" : " %1$d" UTF8_MULTIPLY "%2$s\n") : ((clock != 0) ? " %2$s %3$s" UTF8_NBSP "%4$s\n" : " %2$s\n"), count, sound.device().name(), hz, (d == 9) ? _("GHz") : (d == 6) ? _("MHz") : (d == 3) ? _("kHz") : _("Hz")), color); } } // scan for BIOS settings int bios = 0; if (dev->rom_region()) { // first loop through roms in search of default bios (shortname) char const *bios_str(nullptr); for (const tiny_rom_entry *rom = dev->rom_region(); !ROMENTRY_ISEND(rom); ++rom) { if (ROMENTRY_ISDEFAULT_BIOS(rom)) bios_str = rom->name; } // then loop again to count bios options and to get the default bios complete name char const *bios_desc(nullptr); for (romload::system_bios const &rom : romload::entries(dev->rom_region()).get_system_bioses()) { bios++; if (bios_str && !std::strcmp(bios_str, rom.get_name())) bios_desc = rom.get_description(); } if (bios) { layout->add_text( util::string_format( _("* BIOS settings:\n %1$d options [default: %2$s]\n"), bios, bios_desc ? bios_desc : bios_str ? bios_str : ""), color); } } int input = 0, input_mj = 0, input_hana = 0, input_gamble = 0, input_analog = 0, input_adjust = 0; int input_keypad = 0, input_keyboard = 0, dips = 0, confs = 0; std::string errors; std::ostringstream dips_opt, confs_opt; ioport_list portlist; for (device_t &iptdev : device_enumerator(*dev)) portlist.append(iptdev, errors); // check if the device adds inputs to the system for (auto &port : portlist) for (ioport_field &field : port.second->fields()) { if (field.type() >= IPT_MAHJONG_FIRST && field.type() < IPT_MAHJONG_LAST) input_mj++; else if (field.type() >= IPT_HANAFUDA_FIRST && field.type() < IPT_HANAFUDA_LAST) input_hana++; else if (field.type() >= IPT_GAMBLING_FIRST && field.type() < IPT_GAMBLING_LAST) input_gamble++; else if (field.type() >= IPT_ANALOG_FIRST && field.type() < IPT_ANALOG_LAST) input_analog++; else if (field.type() == IPT_ADJUSTER) input_adjust++; else if (field.type() == IPT_KEYPAD) input_keypad++; else if (field.type() == IPT_KEYBOARD) input_keyboard++; else if (field.type() >= IPT_START1 && field.type() < IPT_UI_FIRST) input++; else if (field.type() == IPT_DIPSWITCH) { dips++; bool def(false); for (ioport_setting const &setting : field.settings()) { if (setting.value() == field.defvalue()) { def = true; util::stream_format(dips_opt, _(" %1$s [default: %2$s]\n"), field.specific_name(), setting.name()); break; } } if (!def) util::stream_format(dips_opt, _(" %1$s\n"), field.specific_name()); } else if (field.type() == IPT_CONFIG) { confs++; bool def(false); for (ioport_setting const &setting : field.settings()) { if (setting.value() == field.defvalue()) { def = true; util::stream_format(confs_opt, _(" %1$s [default: %2$s]\n"), field.specific_name(), setting.name()); break; } } if (!def) util::stream_format(confs_opt, _(" %1$s\n"), field.specific_name()); } } if (dips) { layout->add_text(_("* DIP switch settings:\n"), color); layout->add_text(std::move(dips_opt).str(), color); } if (confs) { layout->add_text(_("* Configuration settings:\n"), color); layout->add_text(std::move(confs_opt).str(), color); } if (input || input_mj || input_hana || input_gamble || input_analog || input_adjust || input_keypad || input_keyboard) layout->add_text(_("* Input device(s):\n"), color); if (input) layout->add_text(util::string_format(_(" User inputs [%1$d inputs]\n"), input), color); if (input_mj) layout->add_text(util::string_format(_(" Mahjong inputs [%1$d inputs]\n"), input_mj), color); if (input_hana) layout->add_text(util::string_format(_(" Hanafuda inputs [%1$d inputs]\n"), input_hana), color); if (input_gamble) layout->add_text(util::string_format(_(" Gambling inputs [%1$d inputs]\n"), input_gamble), color); if (input_analog) layout->add_text(util::string_format(_(" Analog inputs [%1$d inputs]\n"), input_analog), color); if (input_adjust) layout->add_text(util::string_format(_(" Adjuster inputs [%1$d inputs]\n"), input_adjust), color); if (input_keypad) layout->add_text(util::string_format(_(" Keypad inputs [%1$d inputs]\n"), input_keypad), color); if (input_keyboard) layout->add_text(util::string_format(_(" Keyboard inputs [%1$d inputs]\n"), input_keyboard), color); image_interface_enumerator imgiter(*dev); if (imgiter.count() > 0) { layout->add_text(_("* Media Options:\n"), color); for (const device_image_interface &imagedev : imgiter) { layout->add_text( util::string_format( _(" %1$s [tag: %2$s]\n"), imagedev.image_type_name(), imagedev.device().tag()), color); } } slot_interface_enumerator slotiter(*dev); if (slotiter.count() > 0) { layout->add_text(_("* Slot Options:\n"), color); for (const device_slot_interface &slot : slotiter) { layout->add_text( util::string_format( _(" %1$s [default: %2$s]\n"), slot.device().tag(), slot.default_option() ? slot.default_option() : "----"), color); } } if ((execiter.count() + scriter.count() + snditer.count() + imgiter.count() + slotiter.count() + bios + dips + confs + input + input_mj + input_hana + input_gamble + input_analog + input_adjust + input_keypad + input_keyboard) == 0) layout->add_text(_("[None]\n"), color); mconfig.device_remove(m_option->name()); lines = layout->lines(); } width = layout->actual_width(); } void menu_device_config::populate(float &customtop, float &custombottom) { } void menu_device_config::handle(event const *ev) { if (ev) handle_key(ev->iptkey); } } // namespace ui