summaryrefslogblamecommitdiffstatshomepage
path: root/src/frontend/mame/ui/miscmenu.cpp
blob: df5754a380e73bf3fdceb0ce51454ed5e457fd72 (plain) (tree)
1
2
3
4
5
6
7
8
                       
                                                                                   

                                                                      
                   


                                               


                                                                      





                        
                     
 
                    
                 
 
                   
                     
                       
                      
                     
                   
                    
                    
 

                 

                    
                  
                   
                 
 
 
              
 




                                                                            
                                            


                                                   
                                                                                                                  
 
                                         

 
                                    
 
                                                    
                                                                           
         


                                                                                                             
                 

                                                                       
                         






                                                                                                                         
                                                                                                                                                          
                         
                 
         
 
                                               
                                              

 
                                           



                                                   
                                   

                                                   
                                                 
 

                                
 




                                                                       
 

                                                      
 





















                                                                                                                                                                          
 


                      
 





                                                                                                     
                 





                                                                                                                      
         


                                                

 

 
                                                                                                                    
 
                                          

 
                                             







                                                      
                                     
 
                                                       
                                                                                                       
         
                                                   
                                            
                                                     
                 

                                              

                                                           
                         
                 
 
                                                                                                                                    
         

                                               


                                                   
                                    

                                                   
                                                  
 
                                
         



                                                                         
                                                                                                       
                                                                                                  
                                                           





                                                    
                                                     



                                                
                                              
                 




                                                           
                 






                                                                
         

 





                                                   
                                                                                                                    
 
                                              

 
                                     


 
                                       
 

                                                    

 
                                                                                                  
 


                                                               
                                                     
 





                                                                                                                                                                                                   
 



                                                                                                                
 


















                                                                                                                     
         

                                       
 
                                 
 

 
                                              




                                                                                  
         
                               



                            
                                                
         


 




                                                   
                                            
 
                        
                              
         
                                                                                                 

                                     
 
                                   
                 













                                                                                          

                 




                                          
 

                                            
                 
                                          
                         












                                                                                                             


                         

                                                    
                 
                                           
                         



                                                                       
                                                                                         

                                                                                                         
                                                                                                                                   



















                                                                                                                                       



                            
                                                                               
         


                                                 







                                                   
                                                                                                        
 
                                             
                                                              

 
                               
 











                                                                                                 
                                                                                    







                                                                                        
                                                                                    







                                                                              
                                                                     






                                                                          
         








                                                                                            

                                                                                                


                                               






                                                                                                                                    


                                                                                
                                               
                                                       
                                                        
                                                              
 



                                                
                 
                                        
                         


                                                                                        
 
                                                                  
 







                                                                  




                                                                                                                              

















                                                                                                                       

                                                                   

                                                                     

                                                                
                                                                                      
                                         
                                                                                                                    


                                                             
                                         


                                                                                                                                   

                                         
















                                                                              





                                                                                                                                  















                                                                             





                                                                                                             
                         
                              

                 

 
                                 


 



                                                   

                                                                                                                       
 
                                                        

 
                           



                                                   
                          

                                                   
                                         

                           
                              
         
                                               
                 

                       
                                                        
                         

                                                                                          
                                                                    

                                                                  
                                                                                                                    
                                                                                  
                                                 

                                                                           
                                                 
                                         


                                                                                                                                     
                                                                  
                                 
                                                                                    
                                                     
                                                                      
 






                                                                                                                          
                                                                                                                                              



                                                                                 
                                                                                           

                                                                
                                                                                      
                                                                                       
                                                                                                                 

                                 

                              
                                                        
                         

                                                                                          
                                                                    

                                                                  
                                                                                                                    
                                                                                  
                                                 

                                                                           
                                                 
                                         


                                                                                                                                     
                                                                  










                                                                                          
                                                                                                                                                      
                                                                
                                                     
                                                                                                                 

                                 


                              
                 
         

                     





                                                   
                            

                            


                                                                                                                  
                                               





                                                   


                                               
                                           
                                                           
                              
                                       
                     
                      
                                                                                                       
                                         
 
                             
                                 
                                                   
                                                                       
                     
                                                                                         

 
                                                 
 


                                              
                                                                                                        
                    
                                                                                                           



                                                                              


                                                   
                                   
                                                   
 
                                                    

                           
                              
         
                                                
                 
                                                       
                         
                                  
                                 
                                                                                       
                                                                                                                          

                                                                                                         
                                         
                                                                                            
                                                                     
                                                                                                            

                                         








                                                                        
                                   
                                                                
                                                                                                                                      
                                      



                                                                                                                                        
                                      
                                                                
                                                                                                                                         


                                      
                         
                 
                                                                                 
                 
                                                                                
                                                                                                         
                                                                

                 


                                                 





                                                   
                                       
 
                            
                                                                        

                            
                                                                                                
                                                                                                   
         
            
                                                                                            
 
                                               


                                                                                                    
                                               
 
                             
                                                                      
            
                                                                           
 
                                               
                                                                           
 




                                                   
                                         
 
                               


                                            
                                          
                                                                                        



                                                 
 
                                   
                                                                                                        
         


                                                                              
 
                                             

                                                                               
 




                                                                                
                 


                                                                     
         
 




                                                   
                                                                                                 
                              
 
                                  

 
                                                 
 
                                                                                                                          
                                           




                                                                              
                                   
                                                                                   


                                                   
                           

                                                   
                                                    
 



                                                                                                   
         


                                                                                      
                 



                                                                                             

                 

                     





                                                   
                                       
 
                                                                                        
 
                         
                                                                     
         
                                          

                                      

                                                                                                             
                 
         
                  
                                                                          
                                               
 
 
                 
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods, Maurizio Petrarota
/*********************************************************************

    ui/miscmenu.cpp

    Internal MAME menus for the user interface.

*********************************************************************/

#include "emu.h"
#include "ui/miscmenu.h"

#include "ui/inifile.h"
#include "ui/selector.h"
#include "ui/submenu.h"
#include "ui/ui.h"
#include "ui/utils.h"

#include "infoxml.h"
#include "mame.h"

#include "osdnet.h"
#include "mameopts.h"
#include "pluginopts.h"
#include "dinetwork.h"
#include "drivenum.h"
#include "fileio.h"
#include "romload.h"
#include "uiinput.h"

#include "path.h"

#include <algorithm>
#include <cstring>
#include <fstream>
#include <iterator>
#include <locale>


namespace ui {

/***************************************************************************
    MENU HANDLERS
***************************************************************************/

/*-------------------------------------------------
    menu_bios_selection - populates the main
    bios selection menu
-------------------------------------------------*/

menu_bios_selection::menu_bios_selection(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
	set_heading(_("BIOS Selection"));
}

void menu_bios_selection::populate()
{
	// cycle through all devices for this system
	for (device_t &device : device_enumerator(machine().root_device()))
	{
		device_t const *const parent(device.owner());
		device_slot_interface const *const slot(dynamic_cast<device_slot_interface const *>(parent));
		if (!parent || (slot && (slot->get_card_device() == &device)))
		{
			tiny_rom_entry const *rom(device.rom_region());
			if (rom && !ROMENTRY_ISEND(rom))
			{
				char const *val = nullptr;
				for ( ; !ROMENTRY_ISEND(rom) && !val; rom++)
				{
					if (ROMENTRY_ISSYSTEM_BIOS(rom) && ROM_GETBIOSFLAGS(rom) == device.system_bios())
						val = rom->hashdata;
				}
				if (val)
					item_append(!parent ? _("System") : (device.tag() + 1), val, FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, (void *)&device);
			}
		}
	}

	item_append(menu_item_type::SEPARATOR);
	item_append(_("Reset"), 0, (void *)1);
}

menu_bios_selection::~menu_bios_selection()
{
}

/*-------------------------------------------------
    menu_bios_selection - menu that
-------------------------------------------------*/

bool menu_bios_selection::handle(event const *ev)
{
	if (!ev || !ev->itemref)
		return false;

	if ((uintptr_t)ev->itemref == 1 && ev->iptkey == IPT_UI_SELECT)
	{
		machine().schedule_hard_reset();
		return false;
	}

	device_t *const dev = (device_t *)ev->itemref;
	int bios_val = 0;

	switch (ev->iptkey)
	{
	// reset to default
	case IPT_UI_CLEAR:
		bios_val = dev->default_bios();
		break;

	// previous/next BIOS setting
	case IPT_UI_SELECT:
	case IPT_UI_LEFT:
	case IPT_UI_RIGHT:
		{
			int const cnt = ([bioses = romload::entries(dev->rom_region()).get_system_bioses()] () { return std::distance(bioses.begin(), bioses.end()); })();
			bios_val = dev->system_bios() + ((ev->iptkey == IPT_UI_LEFT) ? -1 : +1);

			// wrap
			if (bios_val < 1)
				bios_val = cnt;
			if (bios_val > cnt)
				bios_val = 1;
		}
		break;

	default:
		break;
	}

	if (bios_val > 0)
	{
		dev->set_system_bios(bios_val);
		if (!strcmp(dev->tag(), ":"))
		{
			machine().options().set_value("bios", bios_val - 1, OPTION_PRIORITY_CMDLINE);
		}
		else
		{
			const char *slot_option_name = dev->owner()->tag() + 1;
			machine().options().slot_option(slot_option_name).set_bios(string_format("%d", bios_val - 1));
		}
		reset(reset_options::REMEMBER_REF);
	}

	// triggers an item reset for any change
	return false;
}



menu_network_devices::menu_network_devices(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
	set_heading(_("Network Devices"));
}

menu_network_devices::~menu_network_devices()
{
}

/*-------------------------------------------------
    menu_network_devices_populate - populates the main
    network device menu
-------------------------------------------------*/

void menu_network_devices::populate()
{
	/* cycle through all devices for this system */
	for (device_network_interface &network : network_interface_enumerator(machine().root_device()))
	{
		int curr = network.get_interface();
		const char *title = nullptr;
		for (auto &entry : get_netdev_list())
		{
			if (entry->id == curr)
			{
				title = entry->description;
				break;
			}
		}

		item_append(network.device().tag(), title ? title : "------", FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, (void *)&network);
	}

	item_append(menu_item_type::SEPARATOR);
}

/*-------------------------------------------------
    menu_network_devices - menu that
-------------------------------------------------*/

bool menu_network_devices::handle(event const *ev)
{
	if (!ev || !ev->itemref)
	{
		return false;
	}
	else if (ev->iptkey == IPT_UI_LEFT || ev->iptkey == IPT_UI_RIGHT)
	{
		// FIXME: this conflates presumably arbitrary interface ID numbers with 0-based indices
		device_network_interface *const network = (device_network_interface *)ev->itemref;
		auto const &interfaces = get_netdev_list();
		int curr = network->get_interface();
		if (ev->iptkey == IPT_UI_LEFT)
			curr--;
		else
			curr++;
		if (curr == -2)
			curr = interfaces.size() - 1;
		network->set_interface(curr);

		curr = network->get_interface();
		const char *title = nullptr;
		for (auto &entry : interfaces)
		{
			if (entry->id == curr)
			{
				title = entry->description;
				break;
			}
		}

		ev->item->set_subtext(title ? title : "------");
		return true;
	}
	else
	{
		return false;
	}
}


/*-------------------------------------------------
    menu_bookkeeping - handle the bookkeeping
    information menu
-------------------------------------------------*/

menu_bookkeeping::menu_bookkeeping(mame_ui_manager &mui, render_container &container) : menu_textbox(mui, container)
{
	set_process_flags(PROCESS_CUSTOM_NAV);
}

menu_bookkeeping::~menu_bookkeeping()
{
}

void menu_bookkeeping::menu_activated()
{
	// stuff can change while the menu is hidden
	reset_layout();
}

void menu_bookkeeping::populate_text(std::optional<text_layout> &layout, float &width, int &lines)
{
	if (!layout || (layout->width() != width))
	{
		rgb_t const color = ui().colors().text_color();
		layout.emplace(create_layout(width));

		// show total time first
		prevtime = machine().time();
		if (prevtime.seconds() >= (60 * 60))
			layout->add_text(util::string_format(_("Uptime: %1$d:%2$02d:%3$02d\n\n"), prevtime.seconds() / (60 * 60), (prevtime.seconds() / 60) % 60, prevtime.seconds() % 60), color);
		else
			layout->add_text(util::string_format(_("Uptime: %1$d:%2$02d\n\n"), (prevtime.seconds() / 60) % 60, prevtime.seconds() % 60), color);

		// show tickets at the top
		int const tickets = machine().bookkeeping().get_dispensed_tickets();
		if (tickets > 0)
			layout->add_text(util::string_format(_("Tickets dispensed: %1$d\n\n"), tickets), color);

		// loop over coin counters
		for (int ctrnum = 0; ctrnum < bookkeeping_manager::COIN_COUNTERS; ctrnum++)
		{
			int const count = machine().bookkeeping().coin_counter_get_count(ctrnum);
			bool const locked = machine().bookkeeping().coin_lockout_get_state(ctrnum);

			// display the coin counter number
			// display how many coins
			// display whether or not we are locked out
			layout->add_text(
					util::string_format(
						(count == 0) ? _("Coin %1$c: NA%3$s\n") : _("Coin %1$c: %2$d%3$s\n"),
						ctrnum + 'A',
						count,
						locked ? _(" (locked)") : ""),
					color);
		}

		lines = layout->lines();
	}
	width = layout->actual_width();
}

void menu_bookkeeping::populate()
{
}

bool menu_bookkeeping::handle(event const *ev)
{
	// if the time has rolled over another second, regenerate
	// TODO: what about other bookkeeping events happening with the menu open?
	attotime const curtime = machine().time();
	if (curtime.seconds() != prevtime.seconds())
	{
		reset_layout();
		return true;
	}
	else
	{
		return menu_textbox::handle(ev);
	}
}


/*-------------------------------------------------
    menu_crosshair - handle the crosshair settings
    menu
-------------------------------------------------*/

bool menu_crosshair::handle(event const *ev)
{
	// handle events
	if (ev && ev->itemref)
	{
		crosshair_item_data &data(*reinterpret_cast<crosshair_item_data *>(ev->itemref));
		bool changed(false);
		int newval(data.cur);

		switch (ev->iptkey)
		{
		// if selected, reset to default value
		case IPT_UI_SELECT:
			newval = data.defvalue;
			break;

		// left decrements
		case IPT_UI_LEFT:
			newval -= machine().input().code_pressed(KEYCODE_LSHIFT) ? 10 : 1;
			break;

		// right increments
		case IPT_UI_RIGHT:
			newval += machine().input().code_pressed(KEYCODE_LSHIFT) ? 10 : 1;
			break;
		}

		// clamp to range
		if (newval < data.min)
			newval = data.min;
		if (newval > data.max)
			newval = data.max;

		// if things changed, update
		if (newval != data.cur)
		{
			switch (data.type)
			{
			// visibility state
			case CROSSHAIR_ITEM_VIS:
				data.crosshair->set_mode(newval);
				// set visibility as specified by mode - auto mode starts with visibility off
				data.crosshair->set_visible(newval == CROSSHAIR_VISIBILITY_ON);
				changed = true;
				break;

			// auto time
			case CROSSHAIR_ITEM_AUTO_TIME:
				machine().crosshair().set_auto_time(newval);
				changed = true;
				break;
			}
		}

		// crosshair graphic name
		if (data.type == CROSSHAIR_ITEM_PIC)
		{
			switch (ev->iptkey)
			{
			case IPT_UI_SELECT:
				{
					std::vector<std::string> sel;
					sel.reserve(m_pics.size() + 1);
					sel.push_back(_("menu-crosshair", "[built-in]"));
					std::copy(m_pics.begin(), m_pics.end(), std::back_inserter(sel));
					menu::stack_push<menu_selector>(
							ui(), container(), std::string(ev->item->text()), std::move(sel), data.cur,
							[this, &data] (int selection)
							{
								if (!selection)
									data.crosshair->set_default_bitmap();
								else
									data.crosshair->set_bitmap_name(m_pics[selection - 1].c_str());
								reset(reset_options::REMEMBER_REF);
							});
				}
				break;

			case IPT_UI_LEFT:
				data.crosshair->set_bitmap_name(data.last_name.c_str());
				changed = true;
				break;

			case IPT_UI_RIGHT:
				data.crosshair->set_bitmap_name(data.next_name.c_str());
				changed = true;
				break;
			}
		}

		if (changed)
			reset(reset_options::REMEMBER_REF); // rebuild the menu
	}

	// triggers an item reset for any changes
	return false;
}


/*-------------------------------------------------
    menu_crosshair_populate - populate the
    crosshair settings menu
-------------------------------------------------*/

menu_crosshair::menu_crosshair(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
	set_process_flags(PROCESS_LR_REPEAT);
	set_heading(_("menu-crosshair", "Crosshair Options"));
}

void menu_crosshair::populate()
{
	if (m_data.empty())
	{
		// loop over player and add the manual items
		for (int player = 0; player < MAX_PLAYERS; player++)
		{
			// get the user settings
			render_crosshair &crosshair(machine().crosshair().get_crosshair(player));

			// add menu items for usable crosshairs
			if (crosshair.is_used())
			{
				// CROSSHAIR_ITEM_VIS - allocate a data item and fill it
				crosshair_item_data &visdata(m_data.emplace_back());
				visdata.crosshair = &crosshair;
				visdata.type = CROSSHAIR_ITEM_VIS;
				visdata.player = player;
				visdata.min = CROSSHAIR_VISIBILITY_OFF;
				visdata.max = CROSSHAIR_VISIBILITY_AUTO;
				visdata.defvalue = CROSSHAIR_VISIBILITY_DEFAULT;

				// CROSSHAIR_ITEM_PIC - allocate a data item and fill it
				crosshair_item_data &picdata(m_data.emplace_back());
				picdata.crosshair = &crosshair;
				picdata.type = CROSSHAIR_ITEM_PIC;
				picdata.player = player;
				// other data item not used by this menu
			}
		}

		// CROSSHAIR_ITEM_AUTO_TIME - allocate a data item and fill it
		crosshair_item_data &timedata(m_data.emplace_back());
		timedata.type = CROSSHAIR_ITEM_AUTO_TIME;
		timedata.min = CROSSHAIR_VISIBILITY_AUTOTIME_MIN;
		timedata.max = CROSSHAIR_VISIBILITY_AUTOTIME_MAX;
		timedata.defvalue = CROSSHAIR_VISIBILITY_AUTOTIME_DEFAULT;
	}

	if (m_pics.empty())
	{
		// open a path to the crosshairs
		file_enumerator path(machine().options().crosshair_path());
		for (osd::directory::entry const *dir = path.next(); dir; dir = path.next())
		{
			// look for files ending in .png
			size_t const length(std::strlen(dir->name));
			if ((length > 4) && core_filename_ends_with(dir->name, ".png"))
				m_pics.emplace_back(dir->name, length - 4);
		}
		std::locale const lcl;
		std::collate<wchar_t> const &coll = std::use_facet<std::collate<wchar_t> >(lcl);
		std::stable_sort(
				m_pics.begin(),
				m_pics.end(),
				[&coll] (auto const &x, auto const &y)
				{
					std::wstring const wx = wstring_from_utf8(x);
					std::wstring const wy = wstring_from_utf8(y);
					return 0 > coll.compare(wx.data(), wx.data() + wx.size(), wy.data(), wy.data() + wy.size());
				}
		);
	}

	// Make sure to keep these matched to the CROSSHAIR_VISIBILITY_xxx types
	static char const *const vis_text[] = {
			N_p("menu-crosshair", "Never"),
			N_p("menu-crosshair", "Always"),
			N_p("menu-crosshair", "When moved") };

	bool use_auto = false;
	for (crosshair_item_data &data : m_data)
	{
		switch (data.type)
		{
		case CROSSHAIR_ITEM_VIS:
			{
				// track if we need the auto time menu
				if (data.crosshair->mode() == CROSSHAIR_VISIBILITY_AUTO)
					use_auto = true;

				data.cur = data.crosshair->mode();

				// put on arrows
				uint32_t flags(0U);
				if (data.cur > data.min)
					flags |= FLAG_LEFT_ARROW;
				if (data.cur < data.max)
					flags |= FLAG_RIGHT_ARROW;

				// add CROSSHAIR_ITEM_VIS menu */
				item_append(
						util::string_format(_("menu-crosshair", "P%1$d Visibility"), data.player + 1),
						_("menu-crosshair", vis_text[data.crosshair->mode()]),
						flags,
						&data);
			}
			break;

		case CROSSHAIR_ITEM_PIC:
			// search for crosshair graphics
			{
				// reset search flags
				bool const using_default(*data.crosshair->bitmap_name() == '\0');
				bool finished(false);
				bool found(false);
				data.cur = using_default ? 0U : 1U;
				data.last_name.clear();
				data.next_name.clear();

				// look for the current name, then remember the name before and find the next name
				for (auto it = m_pics.begin(); it != m_pics.end() && !finished; ++it)
				{
					// if we are using the default, then we just need to find the first in the list
					if (found || using_default)
					{
						// get the next name
						data.next_name = *it;
						finished = true;
					}
					else if (data.crosshair->bitmap_name() == *it)
					{
						// we found the current name so loop once more to find the next name
						found = true;
					}
					else
					{
						// remember last name - we will do it here in case files get added to the directory
						++data.cur;
						data.last_name = *it;
					}
				}

				// if name not found then next item is DEFAULT
				if (!found && !using_default)
				{
					data.cur = 0U;
					data.next_name.clear();
					finished = true;
				}

				// set up the selection flags
				uint32_t flags(0U);
				if (finished)
					flags |= FLAG_RIGHT_ARROW;
				if (found)
					flags |= FLAG_LEFT_ARROW;

				// add CROSSHAIR_ITEM_PIC menu
				item_append(
						util::string_format(_("menu-crosshair", "P%1$d Crosshair"), data.player + 1),
						using_default ? _("menu-crosshair", "[built-in]") : data.crosshair->bitmap_name(),
						flags,
						&data);
				item_append(menu_item_type::SEPARATOR);
			}
			break;

		case CROSSHAIR_ITEM_AUTO_TIME:
			if (use_auto)
			{
				data.cur = machine().crosshair().auto_time();

				// put on arrows in visible menu
				uint32_t flags(0U);
				if (data.cur > data.min)
					flags |= FLAG_LEFT_ARROW;
				if (data.cur < data.max)
					flags |= FLAG_RIGHT_ARROW;

				// add CROSSHAIR_ITEM_AUTO_TIME menu
				item_append(
						_("menu-crosshair", "Auto-Hide Delay"),
						util::string_format(_("menu-crosshair", "%1$d s"), data.cur),
						flags,
						&data);
				item_append(menu_item_type::SEPARATOR);
			}
			break;
		}
	}
}

menu_crosshair::~menu_crosshair()
{
}

//-------------------------------------------------
//  ctor / dtor
//-------------------------------------------------

menu_export::menu_export(mame_ui_manager &mui, render_container &container, std::vector<const game_driver *> &&drvlist)
	: menu(mui, container), m_list(std::move(drvlist))
{
	set_heading(_("Export Displayed List to File"));
}

menu_export::~menu_export()
{
}

//-------------------------------------------------
//  handle the export menu
//-------------------------------------------------

bool menu_export::handle(event const *ev)
{
	// process the menu
	if (ev && ev->itemref)
	{
		switch (uintptr_t(ev->itemref))
		{
		case 1:
		case 3:
			if (ev->iptkey == IPT_UI_SELECT)
			{
				std::string filename("exported");
				emu_file infile(ui().options().ui_path(), OPEN_FLAG_READ);
				if (!infile.open(filename + ".xml"))
					for (int seq = 0; ; ++seq)
					{
						const std::string seqtext = string_format("%s_%04d", filename, seq);
						if (infile.open(seqtext + ".xml"))
						{
							filename = seqtext;
							break;
						}
					}

				// attempt to open the output file
				emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
				if (!file.open(filename + ".xml"))
				{
					const std::string fullpath(file.fullpath());
					file.close();
					std::ofstream pfile(fullpath);

					// prepare a filter for the drivers we want to show
					std::unordered_set<const game_driver *> driver_list(m_list.begin(), m_list.end());
					auto filter = [&driver_list](const char *shortname, bool &)
					{
						auto iter = std::find_if(
							driver_list.begin(),
							driver_list.end(),
							[shortname] (const game_driver *driver) { return !strcmp(shortname, driver->name); });
						return iter != driver_list.end();
					};

					// do we want to show devices?
					bool include_devices = uintptr_t(ev->itemref) == 1;

					// and do the dirty work
					info_xml_creator creator(machine().options());
					creator.output(pfile, filter, include_devices);
					machine().popmessage(_("%s.xml saved in UI settings folder."), filename);
				}
			}
			break;
		case 2:
			if (ev->iptkey == IPT_UI_SELECT)
			{
				std::string filename("exported");
				emu_file infile(ui().options().ui_path(), OPEN_FLAG_READ);
				if (!infile.open(filename + ".txt"))
					for (int seq = 0; ; ++seq)
					{
						const std::string seqtext = string_format("%s_%04d", filename, seq);
						if (infile.open(seqtext + ".txt"))
						{
							filename = seqtext;
							break;
						}
					}

				// attempt to open the output file
				emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
				if (!file.open(filename + ".txt"))
				{
					// print the header
					std::ostringstream buffer;
					buffer << _("Name:             Description:\n");
					driver_enumerator drvlist(machine().options());
					drvlist.exclude_all();
					for (auto & elem : m_list)
						drvlist.include(driver_list::find(*elem));

					// iterate through drivers and output the info
					while (drvlist.next())
						util::stream_format(buffer, "%-18s\"%s\"\n", drvlist.driver().name, drvlist.driver().type.fullname());
					file.puts(buffer.str());
					file.close();
					machine().popmessage(_("%s.txt saved in UI settings folder."), filename);
				}
			}
			break;
		default:
			break;
		}
	}

	return false;
}

//-------------------------------------------------
//  populate
//-------------------------------------------------

void menu_export::populate()
{
	// add options items
	item_append(_("Export list in XML format (like -listxml)"), 0, (void *)(uintptr_t)1);
	item_append(_("Export list in XML format (like -listxml, but exclude devices)"), 0, (void *)(uintptr_t)3);
	item_append(_("Export list in TXT format (like -listfull)"), 0, (void *)(uintptr_t)2);
	item_append(menu_item_type::SEPARATOR);
}

//-------------------------------------------------
//  ctor / dtor
//-------------------------------------------------

menu_machine_configure::menu_machine_configure(
		mame_ui_manager &mui,
		render_container &container,
		ui_system_info const &info,
		std::function<void (bool, bool)> &&handler)
	: menu(mui, container)
	, m_handler(std::move(handler))
	, m_sys(info)
	, m_curbios(0)
	, m_was_favorite(mame_machine_manager::instance()->favorite().is_favorite_system(*info.driver))
	, m_want_favorite(m_was_favorite)
{
	// parse the INI file
	std::ostringstream error;
	osd_setup_osd_specific_emu_options(m_opts);
	mame_options::parse_standard_inis(m_opts, error, m_sys.driver);
	setup_bios();
	set_heading(util::string_format(_("System Settings:\n%1$s"), m_sys.description));
}

menu_machine_configure::~menu_machine_configure()
{
	if (m_was_favorite != m_want_favorite)
	{
		if (m_want_favorite)
			mame_machine_manager::instance()->favorite().add_favorite_system(*m_sys.driver);
		else
			mame_machine_manager::instance()->favorite().remove_favorite_system(*m_sys.driver);
	}

	if (m_handler)
		m_handler(m_want_favorite, m_was_favorite != m_want_favorite);
}

//-------------------------------------------------
//  handle the machine options menu
//-------------------------------------------------

bool menu_machine_configure::handle(event const *ev)
{
	// process the menu
	if (ev && ev->itemref)
	{
		if (ev->iptkey == IPT_UI_SELECT)
		{
			switch ((uintptr_t)ev->itemref)
			{
			case SAVE:
				{
					const std::string filename(m_sys.driver->name);
					emu_file file(machine().options().ini_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
					std::error_condition const filerr = file.open(filename + ".ini");
					if (!filerr)
					{
						std::string inistring = m_opts.output_ini();
						file.puts(inistring);
						ui().popup_time(2, "%s", _("\n    Settings saved    \n\n"));
					}
				}
				break;
			case ADDFAV:
				m_want_favorite = true;
				reset(reset_options::REMEMBER_POSITION);
				break;
			case DELFAV:
				m_want_favorite = false;
				reset(reset_options::REMEMBER_POSITION);
				break;
			case VIDEO:
				if (ev->iptkey == IPT_UI_SELECT)
					menu::stack_push<submenu>(ui(), container(), submenu::video_options(), m_sys.driver, &m_opts);
				break;
			case CONTROLLER:
				if (ev->iptkey == IPT_UI_SELECT)
					menu::stack_push<submenu>(ui(), container(), submenu::control_options(), m_sys.driver, &m_opts);
				break;
			case ADVANCED:
				if (ev->iptkey == IPT_UI_SELECT)
					menu::stack_push<submenu>(ui(), container(), submenu::advanced_options(), m_sys.driver, &m_opts);
				break;
			default:
				break;
			}
		}
		else if (ev->iptkey == IPT_UI_LEFT || ev->iptkey == IPT_UI_RIGHT)
		{
			(ev->iptkey == IPT_UI_LEFT) ? --m_curbios : ++m_curbios;
			m_opts.set_value(OPTION_BIOS, m_bios[m_curbios].second, OPTION_PRIORITY_CMDLINE);
			reset(reset_options::REMEMBER_POSITION);
		}
	}

	// triggers an item reset for any changes
	return false;
}

//-------------------------------------------------
//  populate
//-------------------------------------------------

void menu_machine_configure::populate()
{
	// add options items
	item_append(_("BIOS"), FLAG_DISABLE | FLAG_UI_HEADING, nullptr);
	if (!m_bios.empty())
	{
		uint32_t arrows = get_arrow_flags(std::size_t(0), m_bios.size() - 1, m_curbios);
		item_append(_("System"), m_bios[m_curbios].first, arrows, (void *)(uintptr_t)BIOS);
	}
	else
		item_append(_("[this system has no BIOS settings]"), FLAG_DISABLE, nullptr);

	item_append(menu_item_type::SEPARATOR);
	item_append(_(submenu::advanced_options()[0].description), 0, (void *)(uintptr_t)ADVANCED);
	item_append(_(submenu::video_options()[0].description), 0, (void *)(uintptr_t)VIDEO);
	item_append(_(submenu::control_options()[0].description), 0, (void *)(uintptr_t)CONTROLLER);
	item_append(menu_item_type::SEPARATOR);

	if (!m_want_favorite)
		item_append(_("Add To Favorites"), 0, (void *)ADDFAV);
	else
		item_append(_("Remove From Favorites"), 0, (void *)DELFAV);

	item_append(menu_item_type::SEPARATOR);
	item_append(_("Save System Settings"), 0, (void *)(uintptr_t)SAVE);
}

//-------------------------------------------------
//  perform our special rendering
//-------------------------------------------------

void menu_machine_configure::setup_bios()
{
	if (!m_sys.driver->rom)
		return;

	std::string specbios(m_opts.bios());
	char const *default_name(nullptr);
	for (tiny_rom_entry const *rom = m_sys.driver->rom; !ROMENTRY_ISEND(rom); ++rom)
	{
		if (ROMENTRY_ISDEFAULT_BIOS(rom))
			default_name = rom->name;
	}

	std::size_t bios_count = 0;
	for (romload::system_bios const &bios : romload::entries(m_sys.driver->rom).get_system_bioses())
	{
		std::string name(bios.get_description());
		u32 const bios_flags(bios.get_value());
		std::string const bios_number(std::to_string(bios_flags - 1));

		// check BIOS number and name
		if ((bios_number == specbios) || (specbios == bios.get_name()))
			m_curbios = bios_count;

		if (default_name && !std::strcmp(bios.get_name(), default_name))
		{
			name.append(_(" (default)"));
			if (specbios == "default")
				m_curbios = bios_count;
		}

		m_bios.emplace_back(std::move(name), bios_flags - 1);
		bios_count++;
	}
}

//-------------------------------------------------
//  ctor / dtor
//-------------------------------------------------

menu_plugins_configure::menu_plugins_configure(mame_ui_manager &mui, render_container &container)
	: menu(mui, container)
{
	set_heading(_("Plugins"));
}

menu_plugins_configure::~menu_plugins_configure()
{
	emu_file file_plugin(machine().options().ini_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
	if (file_plugin.open("plugin.ini"))
		// Can't throw in a destructor, so let's ignore silently for
		// now.  We shouldn't write files in a destructor in any case.
		//
		// throw emu_fatalerror("Unable to create file plugin.ini\n");
		return;
	// generate the updated INI
	file_plugin.puts(mame_machine_manager::instance()->plugins().output_ini());
}

//-------------------------------------------------
//  handle the plugins menu
//-------------------------------------------------

bool menu_plugins_configure::handle(event const *ev)
{
	if (!ev || !ev->itemref)
		return false;

	if (ev->iptkey == IPT_UI_LEFT || ev->iptkey == IPT_UI_RIGHT || ev->iptkey == IPT_UI_SELECT)
	{
		plugin_options &plugins = mame_machine_manager::instance()->plugins();
		plugin_options::plugin *p = plugins.find((const char*)ev->itemref);
		if (p)
		{
			p->m_start = !p->m_start;
			ev->item->set_subtext(p->m_start ? _("On") : _("Off"));
			ev->item->set_flags(p->m_start ? FLAG_LEFT_ARROW : FLAG_RIGHT_ARROW);
			return true;
		}
	}

	return false;
}

//-------------------------------------------------
//  populate
//-------------------------------------------------

void menu_plugins_configure::populate()
{
	plugin_options const &plugin_opts = mame_machine_manager::instance()->plugins();

	bool first(true);
	for (const plugin_options::plugin &p : plugin_opts.plugins())
	{
		if (p.m_type != "library")
		{
			first = false;
			bool const enabled = p.m_start;
			item_append_on_off(p.m_description, enabled, 0, (void *)(uintptr_t)p.m_name.c_str());
		}
	}
	if (first)
		item_append(_("No plugins found"), FLAG_DISABLE, nullptr);
	item_append(menu_item_type::SEPARATOR);
}

} // namespace ui