summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/ui/swlist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/ui/swlist.cpp')
-rw-r--r--src/emu/ui/swlist.cpp455
1 files changed, 455 insertions, 0 deletions
diff --git a/src/emu/ui/swlist.cpp b/src/emu/ui/swlist.cpp
new file mode 100644
index 00000000000..d60e24f44a1
--- /dev/null
+++ b/src/emu/ui/swlist.cpp
@@ -0,0 +1,455 @@
+// license:BSD-3-Clause
+// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods
+/*********************************************************************
+
+ ui/swlist.c
+
+ Internal MAME user interface for software list.
+
+ *********************************************************************/
+
+#include "emu.h"
+#include "ui/ui.h"
+#include "ui/menu.h"
+#include "ui/swlist.h"
+#include "softlist.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* time (in seconds) to display errors */
+#define ERROR_MESSAGE_TIME 5
+
+
+/***************************************************************************
+ SOFTWARE PARTS
+***************************************************************************/
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+ui_menu_software_parts::ui_menu_software_parts(running_machine &machine, render_container *container, const software_info *info, const char *interface, const software_part **part, bool other_opt, int *result)
+ : ui_menu(machine, container)
+{
+ m_info = info;
+ m_interface = interface;
+ m_selected_part = part;
+ m_other_opt = other_opt;
+ m_result = result;
+}
+
+
+//-------------------------------------------------
+// dtor
+//-------------------------------------------------
+
+ui_menu_software_parts::~ui_menu_software_parts()
+{
+}
+
+
+//-------------------------------------------------
+// populate
+//-------------------------------------------------
+
+void ui_menu_software_parts::populate()
+{
+ if (m_other_opt)
+ {
+ software_part_menu_entry *entry1 = (software_part_menu_entry *) m_pool_alloc(sizeof(*entry1));
+ entry1->type = T_EMPTY;
+ entry1->part = 0;
+ item_append("[empty slot]", 0, 0, entry1);
+
+ software_part_menu_entry *entry2 = (software_part_menu_entry *) m_pool_alloc(sizeof(*entry2));
+ entry2->type = T_FMGR;
+ entry2->part = 0;
+ item_append("[file manager]", 0, 0, entry2);
+
+
+ software_part_menu_entry *entry3 = (software_part_menu_entry *) m_pool_alloc(sizeof(*entry3));
+ entry3->type = T_SWLIST;
+ entry3->part = 0;
+ item_append("[software list]", 0, 0, entry3);
+ }
+
+ for (const software_part *swpart = m_info->first_part(); swpart != NULL; swpart = swpart->next())
+ {
+ if (swpart->matches_interface(m_interface))
+ {
+ software_part_menu_entry *entry = (software_part_menu_entry *) m_pool_alloc(sizeof(*entry));
+ // check if the available parts have specific part_id to be displayed (e.g. "Map Disc", "Bonus Disc", etc.)
+ // if not, we simply display "part_name"; if yes we display "part_name (part_id)"
+ std::string menu_part_name(swpart->name());
+ if (swpart->feature("part_id") != NULL)
+ menu_part_name.append(" (").append(swpart->feature("part_id")).append(")");
+ entry->type = T_ENTRY;
+ entry->part = swpart;
+ item_append(m_info->shortname(), menu_part_name.c_str(), 0, entry);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// handle
+//-------------------------------------------------
+
+void ui_menu_software_parts::handle()
+{
+ // process the menu
+ const ui_menu_event *event = process(0);
+
+ if (event != NULL && event->iptkey == IPT_UI_SELECT && event->itemref != NULL)
+ {
+ software_part_menu_entry *entry = (software_part_menu_entry *) event->itemref;
+ *m_result = entry->type;
+ *m_selected_part = entry->part;
+ ui_menu::stack_pop(machine());
+ }
+}
+
+
+/***************************************************************************
+ SOFTWARE LIST
+***************************************************************************/
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+ui_menu_software_list::ui_menu_software_list(running_machine &machine, render_container *container, software_list_device *swlist, const char *interface, std::string &result)
+ : ui_menu(machine, container), m_result(result)
+{
+ m_swlist = swlist;
+ m_interface = interface;
+ m_entrylist = NULL;
+ m_ordered_by_shortname = true;
+}
+
+
+//-------------------------------------------------
+// dtor
+//-------------------------------------------------
+
+ui_menu_software_list::~ui_menu_software_list()
+{
+}
+
+
+//-------------------------------------------------
+// compare_entries
+//-------------------------------------------------
+
+int ui_menu_software_list::compare_entries(const entry_info *e1, const entry_info *e2, bool shortname)
+{
+ int result;
+ const char *e1_basename;
+ const char *e2_basename;
+
+ if (shortname)
+ {
+ e1_basename = (e1->short_name != NULL) ? e1->short_name : "";
+ e2_basename = (e2->short_name != NULL) ? e2->short_name : "";
+ }
+ else
+ {
+ e1_basename = (e1->long_name != NULL) ? e1->long_name : "";
+ e2_basename = (e2->long_name != NULL) ? e2->long_name : "";
+ }
+
+ result = core_stricmp(e1_basename, e2_basename);
+ if (result == 0)
+ {
+ result = strcmp(e1_basename, e2_basename);
+ if (result == 0)
+ {
+ if (e1 < e2)
+ result = -1;
+ else if (e1 > e2)
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+
+//-------------------------------------------------
+// append_software_entry - populate a specific list
+//-------------------------------------------------
+
+ui_menu_software_list::entry_info *ui_menu_software_list::append_software_entry(const software_info *swinfo)
+{
+ entry_info *entry = NULL;
+ entry_info **entryptr;
+ bool entry_updated = FALSE;
+
+ // check if at least one of the parts has the correct interface and add a menu entry only in this case
+ for (const software_part *swpart = swinfo->first_part(); swpart != NULL; swpart = swpart->next())
+ {
+ if (swpart->matches_interface(m_interface) && swpart->is_compatible(*m_swlist))
+ {
+ entry_updated = TRUE;
+ // allocate a new entry
+ entry = (entry_info *) m_pool_alloc(sizeof(*entry));
+ memset(entry, 0, sizeof(*entry));
+
+ entry->short_name = pool_strdup(swinfo->shortname());
+ entry->long_name = pool_strdup(swinfo->longname());
+ break;
+ }
+ }
+
+ // skip this if no new entry has been allocated (e.g. if the software has no matching interface for this image device)
+ if (entry_updated)
+ {
+ // find the end of the list
+ entryptr = &m_entrylist;
+ while ((*entryptr != NULL) && (compare_entries(entry, *entryptr, m_ordered_by_shortname) >= 0))
+ entryptr = &(*entryptr)->next;
+
+ // insert the entry
+ entry->next = *entryptr;
+ *entryptr = entry;
+ }
+
+ return entry;
+}
+
+
+//-------------------------------------------------
+// populate
+//-------------------------------------------------
+
+void ui_menu_software_list::populate()
+{
+ // build up the list of entries for the menu
+ for (const software_info *swinfo = m_swlist->first_software_info(); swinfo != NULL; swinfo = swinfo->next())
+ append_software_entry(swinfo);
+
+ // add an entry to change ordering
+ item_append("Switch Item Ordering", NULL, 0, (void *)1);
+
+ // append all of the menu entries
+ for (entry_info *entry = m_entrylist; entry != NULL; entry = entry->next)
+ item_append(entry->short_name, entry->long_name, 0, entry);
+}
+
+
+//-------------------------------------------------
+// handle
+//-------------------------------------------------
+
+void ui_menu_software_list::handle()
+{
+ const entry_info *entry;
+ const entry_info *selected_entry = NULL;
+ int bestmatch = 0;
+
+ // process the menu
+ const ui_menu_event *event = process(0);
+
+ if (event != NULL && event->itemref != NULL)
+ {
+ if ((FPTR)event->itemref == 1 && event->iptkey == IPT_UI_SELECT)
+ {
+ m_ordered_by_shortname = !m_ordered_by_shortname;
+ m_entrylist = NULL;
+
+ // reset the char buffer if we change ordering criterion
+ memset(m_filename_buffer, '\0', ARRAY_LENGTH(m_filename_buffer));
+
+ // reload the menu with the new order
+ reset(UI_MENU_RESET_REMEMBER_REF);
+ machine().popmessage("Switched Order: entries now ordered by %s", m_ordered_by_shortname ? "shortname" : "description");
+ }
+ // handle selections
+ else if (event->iptkey == IPT_UI_SELECT)
+ {
+ entry_info *entry = (entry_info *) event->itemref;
+ m_result = entry->short_name;
+ ui_menu::stack_pop(machine());
+ }
+ else if (event->iptkey == IPT_SPECIAL)
+ {
+ int buflen = strlen(m_filename_buffer);
+ bool update_selected = false;
+
+ // if it's a backspace and we can handle it, do so
+ if ((event->unichar == 8 || event->unichar == 0x7f) && buflen > 0)
+ {
+ *(char *)utf8_previous_char(&m_filename_buffer[buflen]) = 0;
+ update_selected = true;
+
+ if (ARRAY_LENGTH(m_filename_buffer) > 0)
+ machine().ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename_buffer);
+ }
+ // if it's any other key and we're not maxed out, update
+ else if (event->unichar >= ' ' && event->unichar < 0x7f)
+ {
+ buflen += utf8_from_uchar(&m_filename_buffer[buflen], ARRAY_LENGTH(m_filename_buffer) - buflen, event->unichar);
+ m_filename_buffer[buflen] = 0;
+ update_selected = true;
+
+ if (ARRAY_LENGTH(m_filename_buffer) > 0)
+ machine().ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename_buffer);
+ }
+
+ if (update_selected)
+ {
+ const entry_info *cur_selected;
+
+ // if the current selection is a software entry, start search from here
+ if ((FPTR)event->itemref != 1)
+ cur_selected= (const entry_info *)get_selection();
+ // else (if we are on the 'Switch Order' entry) start from the beginning
+ else
+ cur_selected = m_entrylist;
+
+ // check for entries which matches our filename_buffer:
+ // from current entry to the end
+ for (entry = cur_selected; entry != NULL; entry = entry->next)
+ {
+ const char *compare_name = m_ordered_by_shortname ? entry->short_name : entry->long_name;
+
+ if (compare_name != NULL && m_filename_buffer != NULL)
+ {
+ int match = 0;
+ for (int i = 0; i < ARRAY_LENGTH(m_filename_buffer); i++)
+ {
+ if (core_strnicmp(compare_name, m_filename_buffer, i) == 0)
+ match = i;
+ }
+
+ if (match > bestmatch)
+ {
+ bestmatch = match;
+ selected_entry = entry;
+ }
+ }
+ }
+ // and from the first entry to current one
+ for (entry = m_entrylist; entry != cur_selected; entry = entry->next)
+ {
+ const char *compare_name = m_ordered_by_shortname ? entry->short_name : entry->long_name;
+
+ if (compare_name != NULL && m_filename_buffer != NULL)
+ {
+ int match = 0;
+ for (int i = 0; i < ARRAY_LENGTH(m_filename_buffer); i++)
+ {
+ if (core_strnicmp(compare_name, m_filename_buffer, i) == 0)
+ match = i;
+ }
+
+ if (match > bestmatch)
+ {
+ bestmatch = match;
+ selected_entry = entry;
+ }
+ }
+ }
+
+ if (selected_entry != NULL && selected_entry != cur_selected)
+ set_selection((void *) selected_entry);
+ }
+ }
+ else if (event->iptkey == IPT_UI_CANCEL)
+ {
+ // reset the char buffer also in this case
+ if (m_filename_buffer[0] != '\0')
+ memset(m_filename_buffer, '\0', ARRAY_LENGTH(m_filename_buffer));
+ m_result = m_filename_buffer;
+ ui_menu::stack_pop(machine());
+ }
+ }
+}
+
+
+/***************************************************************************
+ SOFTWARE MENU - list of available software lists - i.e. cartridges,
+ floppies
+***************************************************************************/
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+ui_menu_software::ui_menu_software(running_machine &machine, render_container *container, const char *interface, software_list_device **result)
+ : ui_menu(machine, container)
+{
+ m_interface = interface;
+ m_result = result;
+}
+
+
+//-------------------------------------------------
+// dtor
+//-------------------------------------------------
+
+ui_menu_software::~ui_menu_software()
+{
+}
+
+
+//-------------------------------------------------
+// populate
+//-------------------------------------------------
+
+void ui_menu_software::populate()
+{
+ bool have_compatible = false;
+
+ // Add original software lists for this system
+ software_list_device_iterator iter(machine().config().root_device());
+ for (software_list_device *swlistdev = iter.first(); swlistdev != NULL; swlistdev = iter.next())
+ if (swlistdev->list_type() == SOFTWARE_LIST_ORIGINAL_SYSTEM)
+ if (swlistdev->first_software_info() != NULL && m_interface != NULL)
+ {
+ bool found = false;
+ for (const software_info *swinfo = swlistdev->first_software_info(); swinfo != NULL; swinfo = swinfo->next())
+ if (swinfo->first_part()->matches_interface(m_interface))
+ found = true;
+ if (found)
+ item_append(swlistdev->description(), NULL, 0, (void *)swlistdev);
+ }
+
+ // add compatible software lists for this system
+ for (software_list_device *swlistdev = iter.first(); swlistdev != NULL; swlistdev = iter.next())
+ if (swlistdev->list_type() == SOFTWARE_LIST_COMPATIBLE_SYSTEM)
+ if (swlistdev->first_software_info() != NULL && m_interface != NULL)
+ {
+ bool found = false;
+ for (const software_info *swinfo = swlistdev->first_software_info(); swinfo != NULL; swinfo = swinfo->next())
+ if (swinfo->first_part()->matches_interface(m_interface))
+ found = true;
+ if (found)
+ {
+ if (!have_compatible)
+ item_append("[compatible lists]", NULL, MENU_FLAG_DISABLE, NULL);
+ item_append(swlistdev->description(), NULL, 0, (void *)swlistdev);
+ }
+ have_compatible = true;
+ }
+}
+
+
+//-------------------------------------------------
+// handle
+//-------------------------------------------------
+
+void ui_menu_software::handle()
+{
+ // process the menu
+ const ui_menu_event *event = process(0);
+
+ if (event != NULL && event->iptkey == IPT_UI_SELECT) {
+ // ui_menu::stack_push(auto_alloc_clear(machine(), ui_menu_software_list(machine(), container, (software_list_config *)event->itemref, image)));
+ *m_result = (software_list_device *)event->itemref;
+ ui_menu::stack_pop(machine());
+ }
+}