summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/uiswlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/uiswlist.c')
-rw-r--r--trunk/src/emu/uiswlist.c491
1 files changed, 491 insertions, 0 deletions
diff --git a/trunk/src/emu/uiswlist.c b/trunk/src/emu/uiswlist.c
new file mode 100644
index 00000000000..9fffb999ded
--- /dev/null
+++ b/trunk/src/emu/uiswlist.c
@@ -0,0 +1,491 @@
+/*********************************************************************
+
+ uiswlist.c
+
+ Internal MAME user interface for software list.
+
+ Copyright Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ *********************************************************************/
+
+#include "emu.h"
+#include "ui.h"
+#include "uimenu.h"
+#include "softlist.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* time (in seconds) to display errors */
+#define ERROR_MESSAGE_TIME 5
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* state of a software entry */
+typedef struct _software_entry_state software_entry_state;
+struct _software_entry_state
+{
+ software_entry_state *next;
+
+ const char *short_name;
+ const char *long_name;
+ const char *interface;
+ char *list_name;
+ device_image_interface* image;
+};
+
+/* state of the software menu */
+typedef struct _software_menu_state software_menu_state;
+struct _software_menu_state
+{
+ char *list_name; /* currently selected list */
+ device_image_interface* image;
+ software_entry_state *entrylist;
+ char filename_buffer[1024];
+ int ordered_by_shortname;
+ int reorder;
+};
+
+/* state of a software part */
+typedef struct _software_part_state software_part_state;
+struct _software_part_state
+{
+ const char *part_name;
+ const char *interface;
+};
+
+
+static void ui_mess_menu_populate_software_parts(running_machine &machine, ui_menu *menu, const char *swlist, const char *swinfo, const char *interface)
+{
+ software_list *list = software_list_open(machine.options(), swlist, FALSE, NULL);
+
+ if (list)
+ {
+ software_info *info = software_list_find(list, swinfo, NULL);
+
+ if (info)
+ {
+ for (software_part *swpart = software_find_part(info, NULL, NULL); swpart != NULL; swpart = software_part_next(swpart))
+ {
+ if (strcmp(interface, swpart->interface_) == 0)
+ {
+ software_part_state *entry = (software_part_state *) ui_menu_pool_alloc(menu, 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)"
+ astring menu_part_name(swpart->name);
+ if (software_part_get_feature(swpart, "part_id") != NULL)
+ {
+ menu_part_name.cat(" (");
+ menu_part_name.cat(software_part_get_feature(swpart, "part_id"));
+ menu_part_name.cat(")");
+ }
+ entry->part_name = ui_menu_pool_strdup(menu, swpart->name); // part_name is later used to build up the filename to load, so we use swpart->name!
+ entry->interface = ui_menu_pool_strdup(menu, swpart->interface_);
+ ui_menu_item_append(menu, info->shortname, menu_part_name.cstr(), 0, entry);
+ }
+ }
+ }
+
+ software_list_close(list);
+ }
+}
+
+void ui_mess_menu_software_parts(running_machine &machine, ui_menu *menu, void *parameter, void *state)
+{
+ const ui_menu_event *event;
+ software_entry_state *sw_state = (software_entry_state *)state;
+ const char *swlist = sw_state->list_name;
+ const char *swinfo = sw_state->short_name;
+ const char *interface = sw_state->interface;
+
+ // generate list of available parts
+ if (!ui_menu_populated(menu))
+ {
+ if (sw_state->list_name)
+ {
+ ui_mess_menu_populate_software_parts(machine, menu, swlist, swinfo, interface);
+ }
+ }
+
+ /* process the menu */
+ event = ui_menu_process(machine, menu, 0);
+
+ if (event != NULL && event->iptkey == IPT_UI_SELECT && event->itemref != NULL)
+ {
+ software_part_state *entry = (software_part_state *) event->itemref;
+
+ // build the name for the part to be loaded
+ astring temp_name(sw_state->short_name);
+ temp_name.cat(":");
+ temp_name.cat(entry->part_name);
+ //printf("%s\n", temp_name.cstr());
+
+ sw_state->image->load(temp_name.cstr());
+ }
+}
+
+static int compare_software_entries(const software_entry_state *e1, const software_entry_state *e2, int 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 = mame_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;
+}
+
+/* populate a specific list */
+
+static software_entry_state *append_software_entry(ui_menu *menu, software_menu_state *menustate,
+ software_info *swinfo, char *list_name, device_image_interface* image)
+{
+ software_entry_state *entry = NULL;
+ software_entry_state **entryptr;
+ const char *interface = image->image_interface();
+
+ // check if at least one of the parts has the correct interface and add a menu entry only in this case
+ for (software_part *swpart = software_find_part(swinfo, NULL, NULL); swpart != NULL; swpart = software_part_next(swpart))
+ {
+ if (strcmp(interface, swpart->interface_) == 0)
+ {
+ // allocate a new entry
+ entry = (software_entry_state *) ui_menu_pool_alloc(menu, sizeof(*entry));
+ memset(entry, 0, sizeof(*entry));
+
+ entry->short_name = ui_menu_pool_strdup(menu, swinfo->shortname);
+ entry->long_name = ui_menu_pool_strdup(menu, swinfo->longname);
+ entry->list_name = list_name;
+ entry->image = image;
+ entry->interface = ui_menu_pool_strdup(menu, swpart->interface_);
+ break;
+ }
+ }
+
+ // find the end of the list
+ entryptr = &menustate->entrylist;
+ while ((*entryptr != NULL) && (compare_software_entries(entry, *entryptr, menustate->ordered_by_shortname) >= 0))
+ entryptr = &(*entryptr)->next;
+
+ // insert the entry
+ entry->next = *entryptr;
+ *entryptr = entry;
+
+ return entry;
+}
+
+
+static void ui_mess_menu_populate_software_entries(running_machine &machine, ui_menu *menu, software_menu_state *menustate)
+{
+ software_list *list = software_list_open(machine.options(), menustate->list_name, FALSE, NULL);
+
+ // build up the list of entries for the menu
+ if (list)
+ {
+ for (software_info *swinfo = software_list_find(list, "*", NULL); swinfo != NULL; swinfo = software_list_find(list, "*", swinfo))
+ append_software_entry(menu, menustate, swinfo, menustate->list_name, menustate->image);
+
+ software_list_close(list);
+ }
+
+ // add an entry to change ordering
+ ui_menu_item_append(menu, "Switch Item Ordering", NULL, 0, (void *)1);
+
+ // append all of the menu entries
+ for (software_entry_state *entry = menustate->entrylist; entry != NULL; entry = entry->next)
+ ui_menu_item_append(menu, entry->short_name, entry->long_name, 0, entry);
+}
+
+bool swinfo_has_multiple_parts(software_info *swinfo, const char *interface)
+{
+ int count = 0;
+
+ for (software_part *swpart = software_find_part(swinfo, NULL, NULL); swpart != NULL; swpart = software_part_next(swpart))
+ {
+ if (strcmp(interface, swpart->interface_) == 0)
+ count++;
+ }
+ return (count > 1) ? TRUE : FALSE;
+}
+
+void ui_mess_menu_software_list(running_machine &machine, ui_menu *menu, void *parameter, void *state)
+{
+ const ui_menu_event *event;
+ software_menu_state *sw_state = (software_menu_state *)state;
+ const software_entry_state *entry;
+ const software_entry_state *selected_entry = NULL;
+ int bestmatch = 0;
+
+ if (!ui_menu_populated(menu) || sw_state->reorder)
+ {
+ sw_state->reorder = 0;
+
+ if (sw_state->list_name)
+ {
+ ui_mess_menu_populate_software_entries(machine, menu, sw_state);
+ }
+ }
+
+ /* process the menu */
+ event = ui_menu_process(machine, menu, 0);
+
+ if (event != NULL && event->itemref != NULL)
+ {
+ if ((FPTR)event->itemref == 1 && event->iptkey == IPT_UI_SELECT)
+ {
+ sw_state->ordered_by_shortname ^= 1;
+ sw_state->reorder = 1;
+ sw_state->entrylist = NULL;
+ // reset the char buffer if we change ordering criterion
+ memset(sw_state->filename_buffer, '\0', ARRAY_LENGTH(sw_state->filename_buffer));
+
+ // reload the menu with the new order
+ ui_menu_reset(menu, UI_MENU_RESET_REMEMBER_REF);
+ popmessage("Switched Order: entries now ordered by %s", sw_state->ordered_by_shortname ? "shortname" : "description");
+ }
+ /* handle selections */
+ else if (event->iptkey == IPT_UI_SELECT)
+ {
+ device_image_interface *image = sw_state->image;
+ software_entry_state *entry = (software_entry_state *) event->itemref;
+ software_list *tmp_list = software_list_open(machine.options(), sw_state->list_name, FALSE, NULL);
+ software_info *tmp_info = software_list_find(tmp_list, entry->short_name, NULL);
+
+ // if the selected software has multiple parts that can be loaded, open the submenu
+ if (swinfo_has_multiple_parts(tmp_info, image->image_interface()))
+ {
+ ui_menu *child_menu = ui_menu_alloc(machine, &machine.render().ui_container(), ui_mess_menu_software_parts, entry);
+ software_entry_state *child_menustate = (software_entry_state *)ui_menu_alloc_state(child_menu, sizeof(*child_menustate), NULL);
+ child_menustate->short_name = entry->short_name;
+ child_menustate->interface = image->image_interface();
+ child_menustate->list_name = sw_state->list_name;
+ child_menustate->image = image;
+ ui_menu_stack_push(child_menu);
+ }
+ else
+ {
+ // otherwise, load the file
+ image->load(entry->short_name);
+ }
+ software_list_close(tmp_list);
+
+ // reset the char buffer when pressing IPT_UI_SELECT
+ if (sw_state->filename_buffer[0] != '\0')
+ memset(sw_state->filename_buffer, '\0', ARRAY_LENGTH(sw_state->filename_buffer));
+ }
+ else if (event->iptkey == IPT_SPECIAL)
+ {
+ int buflen = strlen(sw_state->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(&sw_state->filename_buffer[buflen]) = 0;
+ update_selected = TRUE;
+
+ if (ARRAY_LENGTH(sw_state->filename_buffer) > 0)
+ ui_popup_time(ERROR_MESSAGE_TIME, "%s", sw_state->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(&sw_state->filename_buffer[buflen], ARRAY_LENGTH(sw_state->filename_buffer) - buflen, event->unichar);
+ sw_state->filename_buffer[buflen] = 0;
+ update_selected = TRUE;
+
+ if (ARRAY_LENGTH(sw_state->filename_buffer) > 0)
+ ui_popup_time(ERROR_MESSAGE_TIME, "%s", sw_state->filename_buffer);
+ }
+
+ if (update_selected)
+ {
+ const software_entry_state *cur_selected;
+
+ // if the current selection is a software entry, start search from here
+ if ((FPTR)event->itemref != 1)
+ cur_selected= (const software_entry_state *)ui_menu_get_selection(menu);
+ // else (if we are on the 'Switch Order' entry) start from the beginning
+ else
+ cur_selected= sw_state->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 = sw_state->ordered_by_shortname ? entry->short_name : entry->long_name;
+
+ if (compare_name != NULL && sw_state->filename_buffer != NULL)
+ {
+ int match = 0;
+ for (int i = 0; i < ARRAY_LENGTH(sw_state->filename_buffer); i++)
+ {
+ if (mame_strnicmp(compare_name, sw_state->filename_buffer, i) == 0)
+ match = i;
+ }
+
+ if (match > bestmatch)
+ {
+ bestmatch = match;
+ selected_entry = entry;
+ }
+ }
+ }
+ // and from the first entry to current one
+ for (entry = sw_state->entrylist; entry != cur_selected; entry = entry->next)
+ {
+ const char *compare_name = sw_state->ordered_by_shortname ? entry->short_name : entry->long_name;
+
+ if (compare_name != NULL && sw_state->filename_buffer != NULL)
+ {
+ int match = 0;
+ for (int i = 0; i < ARRAY_LENGTH(sw_state->filename_buffer); i++)
+ {
+ if (mame_strnicmp(compare_name, sw_state->filename_buffer, i) == 0)
+ match = i;
+ }
+
+ if (match > bestmatch)
+ {
+ bestmatch = match;
+ selected_entry = entry;
+ }
+ }
+ }
+
+ if (selected_entry != NULL && selected_entry != cur_selected)
+ ui_menu_set_selection(menu, (void *) selected_entry);
+ }
+ }
+ else if (event->iptkey == IPT_UI_CANCEL)
+ {
+ // reset the char buffer also in this case
+ if (sw_state->filename_buffer[0] != '\0')
+ memset(sw_state->filename_buffer, '\0', ARRAY_LENGTH(sw_state->filename_buffer));
+ }
+ }
+}
+
+/* list of available software lists - i.e. cartridges, floppies */
+static void ui_mess_menu_populate_software_list(running_machine &machine, ui_menu *menu, device_image_interface* image)
+{
+ bool haveCompatible = FALSE;
+ const char *interface = image->image_interface();
+
+ // Add original software lists for this system
+ for (const device_t *dev = machine.config().devicelist().first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext())
+ {
+ software_list_config *swlist = (software_list_config *)downcast<const legacy_device_base *>(dev)->inline_config();
+
+ for (int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++)
+ {
+ if (swlist->list_name[i] && (swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM))
+ {
+ software_list *list = software_list_open(machine.options(), swlist->list_name[i], FALSE, NULL);
+
+ if (list)
+ {
+ bool found = FALSE;
+ for (software_info *swinfo = software_list_find(list, "*", NULL); swinfo != NULL; swinfo = software_list_find(list, "*", swinfo))
+ {
+ software_part *part = software_find_part(swinfo, NULL, NULL);
+ if (strcmp(interface,part->interface_)==0) {
+ found = TRUE;
+ }
+ }
+ if (found) {
+ ui_menu_item_append(menu, list->description, NULL, 0, swlist->list_name[i]);
+ }
+
+ software_list_close(list);
+ }
+ }
+ }
+ }
+
+ // Add compatible software lists for this system
+ for (const device_t *dev = machine.config().devicelist().first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext())
+ {
+ software_list_config *swlist = (software_list_config *)downcast<const legacy_device_base *>(dev)->inline_config();
+
+ for (int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++)
+ {
+ if (swlist->list_name[i] && (swlist->list_type == SOFTWARE_LIST_COMPATIBLE_SYSTEM))
+ {
+ software_list *list = software_list_open(machine.options(), swlist->list_name[i], FALSE, NULL);
+
+ if (list)
+ {
+ bool found = FALSE;
+ for (software_info *swinfo = software_list_find(list, "*", NULL); swinfo != NULL; swinfo = software_list_find(list, "*", swinfo))
+ {
+ software_part *part = software_find_part(swinfo, NULL, NULL);
+ if (strcmp(interface,part->interface_)==0) {
+ found = TRUE;
+ }
+ }
+ if (found) {
+ if (!haveCompatible) {
+ ui_menu_item_append(menu, "[compatible lists]", NULL, MENU_FLAG_DISABLE, NULL);
+ }
+ ui_menu_item_append(menu, list->description, NULL, 0, swlist->list_name[i]);
+ }
+
+ haveCompatible = TRUE;
+ software_list_close(list);
+ }
+ }
+ }
+ }
+
+}
+
+void ui_image_menu_software(running_machine &machine, ui_menu *menu, void *parameter, void *state)
+{
+ const ui_menu_event *event;
+ device_image_interface* image = (device_image_interface*)parameter;
+ if (!ui_menu_populated(menu))
+ ui_mess_menu_populate_software_list(machine, menu, image);
+
+ /* process the menu */
+ event = ui_menu_process(machine, menu, 0);
+
+ if (event != NULL && event->iptkey == IPT_UI_SELECT)
+ {
+ ui_menu *child_menu = ui_menu_alloc(machine, &machine.render().ui_container(), ui_mess_menu_software_list, NULL);
+ software_menu_state *child_menustate = (software_menu_state *)ui_menu_alloc_state(child_menu, sizeof(*child_menustate), NULL);
+ child_menustate->list_name = (char *)event->itemref;
+ child_menustate->image = image;
+ child_menustate->entrylist = NULL;
+ child_menustate->ordered_by_shortname = 1;
+ ui_menu_stack_push(child_menu);
+ }
+}