// license:BSD-3-Clause // copyright-holders:Nathan Woods /********************************************************************* ui/filemngr.cpp MESS's clunky built-in file manager TODO - Restrict directory listing by file extension *********************************************************************/ #include "emu.h" #include "ui/ui.h" #include "ui/menu.h" #include "ui/filemngr.h" #include "ui/filesel.h" #include "ui/miscmenu.h" #include "ui/imgcntrl.h" #include "ui/floppycntrl.h" #include "softlist.h" namespace ui { /*************************************************************************** FILE MANAGER ***************************************************************************/ //------------------------------------------------- // ctor //------------------------------------------------- menu_file_manager::menu_file_manager(mame_ui_manager &mui, render_container *container, const char *warnings) : menu(mui, container), selected_device(nullptr) { // This warning string is used when accessing from the force_file_manager call, i.e. // when the file manager is loaded top front in the case of mandatory image devices if (warnings) m_warnings.assign(warnings); else m_warnings.clear(); m_curr_selected = FALSE; } //------------------------------------------------- // dtor //------------------------------------------------- menu_file_manager::~menu_file_manager() { } //------------------------------------------------- // custom_render - perform our special rendering //------------------------------------------------- void menu_file_manager::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2) { const char *path; // access the path path = selected_device ? selected_device->filename() : nullptr; extra_text_render(top, bottom, origx1, origy1, origx2, origy2, nullptr, path); } void menu_file_manager::fill_image_line(device_image_interface *img, std::string &instance, std::string &filename) { // get the image type/id instance = string_format("%s (%s)", img->instance_name(), img->brief_instance_name()); // get the base name if (img->basename() != nullptr) { filename.assign(img->basename()); // if the image has been loaded through softlist, also show the loaded part if (img->part_entry() != nullptr) { const software_part *tmp = img->part_entry(); if (tmp->name() != nullptr) { filename.append(" ("); filename.append(tmp->name()); // also check if this part has a specific part_id (e.g. "Map Disc", "Bonus Disc", etc.), and in case display it if (img->get_feature("part_id") != nullptr) { filename.append(": "); filename.append(img->get_feature("part_id")); } filename.append(")"); } } } else filename.assign("---"); } //------------------------------------------------- // populate //------------------------------------------------- void menu_file_manager::populate() { std::string tmp_inst, tmp_name; bool first_entry = true; if (!m_warnings.empty()) { item_append(m_warnings.c_str(), nullptr, FLAG_DISABLE, nullptr); item_append("", nullptr, FLAG_DISABLE, nullptr); } // cycle through all devices for this system std::unordered_set devtags; for (device_t &dev : device_iterator(machine().root_device())) { bool tag_appended = false; if (!devtags.insert(dev.tag()).second) continue; // check whether it owns an image interface image_interface_iterator subiter(dev); if (subiter.first() != nullptr) { // if so, cycle through all its image interfaces for (device_image_interface &scan : subiter) { if (!scan.user_loadable()) continue; // if it is a children device, and not something further down the device tree, we want it in the menu! if (strcmp(scan.device().owner()->tag(), dev.tag()) == 0) if (devtags.insert(scan.device().tag()).second) { // check whether we already had some devices with the same owner: if not, output the owner tag! if (!tag_appended) { if (first_entry) first_entry = false; else item_append(menu_item_type::SEPARATOR); item_append(string_format("[root%s]", dev.tag()).c_str(), nullptr, 0, nullptr); tag_appended = true; } // finally, append the image interface to the menu fill_image_line(&scan, tmp_inst, tmp_name); item_append(tmp_inst.c_str(), tmp_name.c_str(), 0, (void *)&scan); } } } } item_append(menu_item_type::SEPARATOR); item_append("Reset", nullptr, 0, (void *)1); custombottom = ui().get_line_height() + 3.0f * UI_BOX_TB_BORDER; } //------------------------------------------------- // handle //------------------------------------------------- void menu_file_manager::handle() { // process the menu const event *event = process(0); if (event != nullptr && event->itemref != nullptr && event->iptkey == IPT_UI_SELECT) { if ((FPTR)event->itemref == 1) { if (m_curr_selected) machine().schedule_hard_reset(); } else { selected_device = (device_image_interface *) event->itemref; if (selected_device != nullptr) { m_curr_selected = TRUE; floppy_image_device *floppy_device = dynamic_cast(selected_device); if (floppy_device != nullptr) { menu::stack_push(ui(), container, floppy_device); } else { menu::stack_push(ui(), container, selected_device); } // reset the existing menu reset(reset_options::REMEMBER_POSITION); } } } } // force file manager menu void menu_file_manager::force_file_manager(mame_ui_manager &mui, render_container *container, const char *warnings) { // reset the menu stack menu::stack_reset(mui.machine()); // add the quit entry followed by the game select entry menu::stack_push_special_main(mui, container); menu::stack_push(mui, container, warnings); // force the menus on mui.show_menu(); // make sure MAME is paused mui.machine().pause(); } } // namespace ui