Previous 15994 Revisions Next

r11097 Wednesday 6th April, 2011 at 19:34:08 UTC by Fabio Priuli
softlist: moved software list handling (in the Internal UI) to a separate source. [Fabio Priuli]
[src/emu]emu.mak softlist.c softlist.h uiimage.c uiswlist.c* uiswlist.h*

src/emu/uiimage.c
r11096r11097
2121#include "image.h"
2222#include "ui.h"
2323#include "uimenu.h"
24#include "uiswlist.h"
2425#include "zippath.h"
2526#include "unicode.h"
2627#include "imagedev/cassette.h"
src/emu/uiswlist.c
r0r11097
1/*********************************************************************
2
3    uiswlist.c
4
5    Internal MAME user interface for software list.
6 
7    Copyright Nicola Salmoria and the MAME Team.
8    Visit http://mamedev.org for licensing and usage restrictions.
9
10 *********************************************************************/
11
12#include "emu.h"
13#include "ui.h"
14#include "uimenu.h"
15#include "softlist.h"
16
17
18/***************************************************************************
19    CONSTANTS
20***************************************************************************/
21
22/* time (in seconds) to display errors */
23#define ERROR_MESSAGE_TIME      5
24
25
26/***************************************************************************
27    TYPE DEFINITIONS
28***************************************************************************/
29
30/* state of a software entry */
31typedef struct _software_entry_state software_entry_state;
32struct _software_entry_state
33{
34   software_entry_state *next;
35   
36   const char *short_name;
37   const char *long_name;
38   const char *interface;
39   char *list_name;
40   device_image_interface* image;
41};
42
43/* state of the software menu */
44typedef struct _software_menu_state software_menu_state;
45struct _software_menu_state
46{
47   char *list_name;   /* currently selected list */
48   device_image_interface* image;
49   software_entry_state *entrylist;
50   char filename_buffer[1024];
51};
52
53/* state of a software part */
54typedef struct _software_part_state software_part_state;
55struct _software_part_state
56{
57   const char *part_name;
58   const char *interface;
59};
60
61
62static void ui_mess_menu_populate_software_parts(running_machine &machine, ui_menu *menu, const char *swlist, const char *swinfo, const char *interface)
63{
64   software_list *list = software_list_open(machine.options(), swlist, FALSE, NULL);
65   
66   if (list)
67   {
68      software_info *info = software_list_find(list, swinfo, NULL);
69     
70      if (info)
71      {
72         for (software_part *swpart = software_find_part(info, NULL, NULL); swpart != NULL; swpart = software_part_next(swpart))
73         {
74            if (strcmp(interface, swpart->interface_) == 0)
75            {
76               software_part_state *entry = (software_part_state *) ui_menu_pool_alloc(menu, sizeof(*entry));
77               // check if the available parts have specific part_id to be displayed (e.g. "Map Disc", "Bonus Disc", etc.)
78               // if not, we simply display "part_name"; if yes we display "part_name (part_id)"
79               astring menu_part_name(swpart->name);
80               if (software_part_get_feature(swpart, "part_id") != NULL)
81               {
82                  menu_part_name.cat(" (");
83                  menu_part_name.cat(software_part_get_feature(swpart, "part_id"));
84                  menu_part_name.cat(")");
85               }
86               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!
87               entry->interface = ui_menu_pool_strdup(menu, swpart->interface_);
88               ui_menu_item_append(menu, info->shortname, menu_part_name.cstr(), 0, entry);
89            }
90         }
91      }
92     
93      software_list_close(list);
94   }
95}
96
97void ui_mess_menu_software_parts(running_machine &machine, ui_menu *menu, void *parameter, void *state)
98{
99   const ui_menu_event *event;
100   software_entry_state *sw_state = (software_entry_state *)state;
101   const char *swlist = sw_state->list_name;
102   const char *swinfo = sw_state->short_name;
103   const char *interface = sw_state->interface;
104   
105   // generate list of available parts
106   if (!ui_menu_populated(menu))
107   {
108      if (sw_state->list_name)
109      {
110         ui_mess_menu_populate_software_parts(machine, menu, swlist, swinfo, interface);
111      }
112   }
113   
114   /* process the menu */
115   event = ui_menu_process(machine, menu, 0);
116   
117   if (event != NULL && event->iptkey == IPT_UI_SELECT && event->itemref != NULL)
118   {
119      software_part_state *entry = (software_part_state *) event->itemref;
120     
121      // build the name for the part to be loaded
122      astring temp_name(sw_state->short_name);
123      temp_name.cat(":");
124      temp_name.cat(entry->part_name);
125      //printf("%s\n", temp_name.cstr());
126     
127      sw_state->image->load(temp_name.cstr());
128   }
129}
130
131static int compare_software_entries(const software_entry_state *e1, const software_entry_state *e2)
132{
133   int result;
134   const char *e1_basename = (e1->short_name != NULL) ? e1->short_name : "";
135   const char *e2_basename = (e2->short_name != NULL) ? e2->short_name : "";
136   
137   result = mame_stricmp(e1_basename, e2_basename);
138   if (result == 0)
139   {
140      result = strcmp(e1_basename, e2_basename);
141      if (result == 0)
142      {
143         if (e1 < e2)
144            result = -1;
145         else if (e1 > e2)
146            result = 1;
147      }
148   }
149   
150   return result;
151}
152
153/* populate a specific list */
154
155static software_entry_state *append_software_entry(ui_menu *menu, software_menu_state *menustate,
156                                       software_info *swinfo, char *list_name, device_image_interface* image)
157{
158   software_entry_state *entry = NULL;
159   software_entry_state **entryptr;
160   const char *interface = image->image_config().image_interface();
161   
162   // check if at least one of the parts has the correct interface and add a menu entry only in this case
163   for (software_part *swpart = software_find_part(swinfo, NULL, NULL); swpart != NULL; swpart = software_part_next(swpart))
164   {
165      if (strcmp(interface, swpart->interface_) == 0)
166      {
167         // allocate a new entry
168         entry = (software_entry_state *) ui_menu_pool_alloc(menu, sizeof(*entry));
169         memset(entry, 0, sizeof(*entry));
170         
171         entry->short_name = ui_menu_pool_strdup(menu, swinfo->shortname);
172         entry->long_name = ui_menu_pool_strdup(menu, swinfo->longname);
173         entry->list_name = list_name;
174         entry->image = image;
175         entry->interface = ui_menu_pool_strdup(menu, swpart->interface_);
176         break;
177      }
178   }
179   
180   // find the end of the list
181   entryptr = &menustate->entrylist;
182   while ((*entryptr != NULL) && (compare_software_entries(entry, *entryptr) >= 0))
183      entryptr = &(*entryptr)->next;
184   
185   // insert the entry
186   entry->next = *entryptr;
187   *entryptr = entry;
188   
189   return entry;
190}
191
192
193static void ui_mess_menu_populate_software_entries(running_machine &machine, ui_menu *menu, software_menu_state *menustate)
194{
195   software_list *list = software_list_open(machine.options(), menustate->list_name, FALSE, NULL);
196   
197   // build up the list of entries for the menu
198   if (list)
199   {
200      for (software_info *swinfo = software_list_find(list, "*", NULL); swinfo != NULL; swinfo = software_list_find(list, "*", swinfo))
201         append_software_entry(menu, menustate, swinfo, menustate->list_name, menustate->image);
202     
203      software_list_close(list);
204   }
205   
206   // append all of the menu entries
207   for (software_entry_state *entry = menustate->entrylist; entry != NULL; entry = entry->next)
208      ui_menu_item_append(menu, entry->short_name, entry->long_name, 0, entry);
209}
210
211bool swinfo_has_multiple_parts(software_info *swinfo, const char *interface)
212{
213   int count = 0;
214   
215   for (software_part *swpart = software_find_part(swinfo, NULL, NULL); swpart != NULL; swpart = software_part_next(swpart))
216   {
217      if (strcmp(interface, swpart->interface_) == 0)
218         count++;
219   }
220   return (count > 1) ? TRUE : FALSE;
221}
222
223void ui_mess_menu_software_list(running_machine &machine, ui_menu *menu, void *parameter, void *state)
224{
225   const ui_menu_event *event;
226   software_menu_state *sw_state = (software_menu_state *)state;
227   const software_entry_state *entry;
228   const software_entry_state *selected_entry = NULL;
229   int bestmatch = 0;
230   
231   if (!ui_menu_populated(menu))
232   {
233      if (sw_state->list_name)
234      {
235         ui_mess_menu_populate_software_entries(machine, menu, sw_state);
236      }
237   }
238   
239   /* process the menu */
240   event = ui_menu_process(machine, menu, 0);
241   
242   if (event != NULL && event->itemref != NULL)
243   {
244      /* handle selections */
245      if (event->iptkey == IPT_UI_SELECT)
246      {
247         device_image_interface *image = sw_state->image;
248         software_entry_state *entry = (software_entry_state *) event->itemref;
249         software_list *tmp_list = software_list_open(machine.options(), sw_state->list_name, FALSE, NULL);
250         software_info *tmp_info = software_list_find(tmp_list, entry->short_name, NULL);
251         
252         // if the selected software has multiple parts that can be loaded, open the submenu
253         if (swinfo_has_multiple_parts(tmp_info, image->image_config().image_interface()))
254         {
255            ui_menu *child_menu = ui_menu_alloc(machine, &machine.render().ui_container(), ui_mess_menu_software_parts, entry);
256            software_entry_state *child_menustate = (software_entry_state *)ui_menu_alloc_state(child_menu, sizeof(*child_menustate), NULL);
257            child_menustate->short_name = entry->short_name;
258            child_menustate->interface = image->image_config().image_interface();
259            child_menustate->list_name = sw_state->list_name;
260            child_menustate->image = image;
261            ui_menu_stack_push(child_menu);
262         }
263         else
264         {
265            // otherwise, load the file
266            if (image != NULL)
267               image->load(entry->short_name);
268            else
269               popmessage("No matching device found for interface '%s'!", entry->interface);
270         }
271         software_list_close(tmp_list);
272         
273         // reset the char buffer when pressing IPT_UI_SELECT
274         if (sw_state->filename_buffer[0] != '\0')
275            memset(sw_state->filename_buffer, '\0', ARRAY_LENGTH(sw_state->filename_buffer));
276      }
277      else if (event->iptkey == IPT_SPECIAL)
278      {
279         int buflen = strlen(sw_state->filename_buffer);
280         bool update_selected = FALSE;
281         
282         /* if it's a backspace and we can handle it, do so */
283         if ((event->unichar == 8 || event->unichar == 0x7f) && buflen > 0)
284         {
285            *(char *)utf8_previous_char(&sw_state->filename_buffer[buflen]) = 0;
286            update_selected = TRUE;
287           
288            if (ARRAY_LENGTH(sw_state->filename_buffer) > 0)
289               ui_popup_time(ERROR_MESSAGE_TIME, "%s", sw_state->filename_buffer);
290         }
291         /* if it's any other key and we're not maxed out, update */
292         else if (event->unichar >= ' ' && event->unichar < 0x7f)
293         {
294            buflen += utf8_from_uchar(&sw_state->filename_buffer[buflen], ARRAY_LENGTH(sw_state->filename_buffer) - buflen, event->unichar);
295            sw_state->filename_buffer[buflen] = 0;
296            update_selected = TRUE;
297           
298            if (ARRAY_LENGTH(sw_state->filename_buffer) > 0)
299               ui_popup_time(ERROR_MESSAGE_TIME, "%s", sw_state->filename_buffer);
300         }
301         
302         if (update_selected)
303         {
304            const software_entry_state *cur_selected = (const software_entry_state *)ui_menu_get_selection(menu);
305           
306            // check for entries which matches our filename_buffer:
307            // from current entry to the end
308            for (entry = cur_selected; entry != NULL; entry = entry->next)
309            {
310               if (entry->short_name != NULL && sw_state->filename_buffer != NULL)
311               {
312                  int match = 0;
313                  for (int i = 0; i < ARRAY_LENGTH(sw_state->filename_buffer); i++)
314                  {
315                     if (mame_strnicmp(entry->short_name, sw_state->filename_buffer, i) == 0)
316                        match = i;
317                  }
318                 
319                  if (match > bestmatch)
320                  {
321                     bestmatch = match;
322                     selected_entry = entry;
323                  }
324               }
325            }
326            // and from the first entry to current one
327            for (entry = sw_state->entrylist; entry != cur_selected; entry = entry->next)
328            {
329               if (entry->short_name != NULL && sw_state->filename_buffer != NULL)
330               {
331                  int match = 0;
332                  for (int i = 0; i < ARRAY_LENGTH(sw_state->filename_buffer); i++)
333                  {
334                     if (mame_strnicmp(entry->short_name, sw_state->filename_buffer, i) == 0)
335                        match = i;
336                  }
337                 
338                  if (match > bestmatch)
339                  {
340                     bestmatch = match;
341                     selected_entry = entry;
342                  }
343               }
344            }
345           
346            if (selected_entry != NULL && selected_entry != cur_selected)
347               ui_menu_set_selection(menu, (void *) selected_entry);
348         }
349      }
350      else if (event->iptkey == IPT_UI_CANCEL)
351      {
352         // reset the char buffer also in this case
353         if (sw_state->filename_buffer[0] != '\0')
354            memset(sw_state->filename_buffer, '\0', ARRAY_LENGTH(sw_state->filename_buffer));
355      }
356   }
357}
358
359/* list of available software lists - i.e. cartridges, floppies */
360static void ui_mess_menu_populate_software_list(running_machine &machine, ui_menu *menu, device_image_interface* image)
361{
362   bool haveCompatible = FALSE;
363   const char *interface = image->image_config().image_interface();
364   
365   // Add original software lists for this system
366   for (const device_config *dev = machine.config().m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext())
367   {
368      software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config();
369     
370      for (int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++)
371      {
372         if (swlist->list_name[i] && (swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM))
373         {
374            software_list *list = software_list_open(machine.options(), swlist->list_name[i], FALSE, NULL);
375           
376            if (list)
377            {
378               bool found = FALSE;
379               for (software_info *swinfo = software_list_find(list, "*", NULL); swinfo != NULL; swinfo = software_list_find(list, "*", swinfo))
380               {
381                  software_part *part = software_find_part(swinfo, NULL, NULL);
382                  if (strcmp(interface,part->interface_)==0) {
383                     found = TRUE;
384                  }
385               }
386               if (found) {
387                  ui_menu_item_append(menu, list->description, NULL, 0, swlist->list_name[i]);
388               }
389               
390               software_list_close(list);
391            }
392         }
393      }
394   }
395   
396   // Add compatible software lists for this system
397   for (const device_config *dev = machine.config().m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext())
398   {
399      software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config();
400     
401      for (int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++)
402      {
403         if (swlist->list_name[i] && (swlist->list_type == SOFTWARE_LIST_COMPATIBLE_SYSTEM))
404         {
405            software_list *list = software_list_open(machine.options(), swlist->list_name[i], FALSE, NULL);
406           
407            if (list)
408            {
409               bool found = FALSE;
410               for (software_info *swinfo = software_list_find(list, "*", NULL); swinfo != NULL; swinfo = software_list_find(list, "*", swinfo))
411               {
412                  software_part *part = software_find_part(swinfo, NULL, NULL);
413                  if (strcmp(interface,part->interface_)==0) {
414                     found = TRUE;
415                  }
416               }
417               if (found) {
418                  if (!haveCompatible) {
419                     ui_menu_item_append(menu, "[compatible lists]", NULL, 0, NULL);
420                  }
421                  ui_menu_item_append(menu, list->description, NULL, 0, swlist->list_name[i]);
422               }
423               
424               haveCompatible = TRUE;
425               software_list_close(list);
426            }
427         }
428      }
429   }
430   
431}
432
433void ui_image_menu_software(running_machine &machine, ui_menu *menu, void *parameter, void *state)
434{
435   const ui_menu_event *event;
436   device_image_interface* image = (device_image_interface*)parameter;
437   if (!ui_menu_populated(menu))
438      ui_mess_menu_populate_software_list(machine, menu, image);
439   
440   /* process the menu */
441   event = ui_menu_process(machine, menu, 0);
442   
443   if (event != NULL && event->iptkey == IPT_UI_SELECT)
444   {
445      ui_menu *child_menu = ui_menu_alloc(machine, &machine.render().ui_container(), ui_mess_menu_software_list, NULL);
446      software_menu_state *child_menustate = (software_menu_state *)ui_menu_alloc_state(child_menu, sizeof(*child_menustate), NULL);
447      child_menustate->list_name = (char *)event->itemref;
448      child_menustate->image = image;
449      child_menustate->entrylist = NULL;
450      ui_menu_stack_push(child_menu);
451   }
452}
src/emu/uiswlist.h
r0r11097
1/***************************************************************************
2
3    uiswlist.h
4
5    Internal MAME user interface for software list.
6
7    Copyright Nicola Salmoria and the MAME Team.
8    Visit http://mamedev.org for licensing and usage restrictions.
9
10***************************************************************************/
11
12#ifndef __UISWLIST_H__
13#define __UISWLIST_H__
14
15
16/***************************************************************************
17    FUNCTION PROTOTYPES
18***************************************************************************/
19
20void ui_image_menu_software(running_machine &machine, ui_menu *menu, void *parameter, void *state);
21
22#endif   /* __UISWLIST_H__ */
src/emu/softlist.c
r11096r11097
99
1010#include "emu.h"
1111#include "pool.h"
12#include "expat.h"
1312#include "emuopts.h"
1413#include "hash.h"
1514#include "softlist.h"
16#include "ui.h"
1715
1816#include <ctype.h>
1917
20enum softlist_parse_position
21{
22   POS_ROOT,
23   POS_MAIN,
24   POS_SOFT,
25   POS_PART,
26   POS_DATA
27};
28
29
30typedef struct _parse_state
31{
32   XML_Parser   parser;
33   int         done;
34
35   void (*error_proc)(const char *message);
36   void *param;
37
38   enum softlist_parse_position pos;
39   char **text_dest;
40} parse_state;
41
42
43struct _software_list
44{
45   emu_file   *file;
46   object_pool   *pool;
47   parse_state   state;
48   const char *description;
49   struct software_info   *software_info_list;
50   struct software_info   *current_software_info;
51   software_info   *softinfo;
52   const char *look_for;
53   int part_entries;
54   int current_part_entry;
55   int rom_entries;
56   int current_rom_entry;
57   void (*error_proc)(const char *message);
58   int list_entries;
59};
60
61
6218typedef tagmap_t<software_info *> softlist_map;
6319
6420/***************************************************************************
r11096r11097
18421798}
18431799
18441800
1845/***************************************************************************
1846    MENU SUPPORT
1847***************************************************************************/
1848
1849/* state of a software entry */
1850typedef struct _software_entry_state software_entry_state;
1851struct _software_entry_state
1852{
1853   software_entry_state *next;
1854   
1855   const char *short_name;
1856   const char *long_name;
1857   const char *interface;
1858   char *list_name;
1859   device_image_interface* image;
1860};
1861
1862/* state of the software menu */
1863typedef struct _software_menu_state software_menu_state;
1864struct _software_menu_state
1865{
1866   char *list_name;   /* currently selected list */
1867   device_image_interface* image;
1868   software_entry_state *entrylist;
1869   char filename_buffer[1024];
1870};
1871
1872/* state of a software part */
1873typedef struct _software_part_state software_part_state;
1874struct _software_part_state
1875{
1876   const char *part_name;
1877   const char *interface;
1878};
1879
1880
1881static void ui_mess_menu_populate_software_parts(running_machine &machine, ui_menu *menu, const char *swlist, const char *swinfo, const char *interface)
1882{
1883   software_list *list = software_list_open(machine.options(), swlist, FALSE, NULL);
1884
1885   if (list)
1886   {
1887      software_info *info = software_list_find(list, swinfo, NULL);
1888
1889      if (info)
1890      {
1891         for (software_part *swpart = software_find_part(info, NULL, NULL); swpart != NULL; swpart = software_part_next(swpart))
1892         {
1893            if (strcmp(interface, swpart->interface_) == 0)
1894            {
1895               software_part_state *entry = (software_part_state *) ui_menu_pool_alloc(menu, sizeof(*entry));
1896               // check if the available parts have specific part_id to be displayed (e.g. "Map Disc", "Bonus Disc", etc.)
1897               // if not, we simply display "part_name"; if yes we display "part_name (part_id)"
1898               astring menu_part_name(swpart->name);
1899               if (software_part_get_feature(swpart, "part_id") != NULL)
1900               {
1901                  menu_part_name.cat(" (");
1902                  menu_part_name.cat(software_part_get_feature(swpart, "part_id"));
1903                  menu_part_name.cat(")");
1904               }
1905               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!
1906               entry->interface = ui_menu_pool_strdup(menu, swpart->interface_);
1907               ui_menu_item_append(menu, info->shortname, menu_part_name.cstr(), 0, entry);
1908            }
1909         }
1910      }
1911
1912      software_list_close(list);
1913   }
1914}
1915
1916void ui_mess_menu_software_parts(running_machine &machine, ui_menu *menu, void *parameter, void *state)
1917{
1918   const ui_menu_event *event;
1919   software_entry_state *sw_state = (software_entry_state *)state;
1920   const char *swlist = sw_state->list_name;
1921   const char *swinfo = sw_state->short_name;
1922   const char *interface = sw_state->interface;
1923
1924   // generate list of available parts
1925   if (!ui_menu_populated(menu))
1926   {
1927      if (sw_state->list_name)
1928      {
1929         ui_mess_menu_populate_software_parts(machine, menu, swlist, swinfo, interface);
1930      }
1931   }
1932
1933   /* process the menu */
1934   event = ui_menu_process(machine, menu, 0);
1935
1936   if (event != NULL && event->iptkey == IPT_UI_SELECT && event->itemref != NULL)
1937   {
1938      software_part_state *entry = (software_part_state *) event->itemref;
1939
1940      // build the name for the part to be loaded
1941      astring temp_name(sw_state->short_name);
1942      temp_name.cat(":");
1943      temp_name.cat(entry->part_name);
1944      //printf("%s\n", temp_name.cstr());
1945
1946      sw_state->image->load(temp_name.cstr());
1947   }
1948}
1949
1950static int compare_software_entries(const software_entry_state *e1, const software_entry_state *e2)
1951{
1952   int result;
1953   const char *e1_basename = (e1->short_name != NULL) ? e1->short_name : "";
1954   const char *e2_basename = (e2->short_name != NULL) ? e2->short_name : "";
1955   
1956   result = mame_stricmp(e1_basename, e2_basename);
1957   if (result == 0)
1958   {
1959      result = strcmp(e1_basename, e2_basename);
1960      if (result == 0)
1961      {
1962         if (e1 < e2)
1963            result = -1;
1964         else if (e1 > e2)
1965            result = 1;
1966      }
1967   }
1968   
1969   return result;
1970}
1971
1972/* populate a specific list */
1973
1974static software_entry_state *append_software_entry(ui_menu *menu, software_menu_state *menustate,
1975                                          software_info *swinfo, char *list_name, device_image_interface* image)
1976{
1977   software_entry_state *entry = NULL;
1978   software_entry_state **entryptr;
1979   const char *interface = image->image_config().image_interface();
1980   
1981   // check if at least one of the parts has the correct interface and add a menu entry only in this case
1982   for (software_part *swpart = software_find_part(swinfo, NULL, NULL); swpart != NULL; swpart = software_part_next(swpart))
1983   {
1984      if (strcmp(interface, swpart->interface_) == 0)
1985      {
1986         // allocate a new entry
1987         entry = (software_entry_state *) ui_menu_pool_alloc(menu, sizeof(*entry));
1988         memset(entry, 0, sizeof(*entry));
1989
1990         entry->short_name = ui_menu_pool_strdup(menu, swinfo->shortname);
1991         entry->long_name = ui_menu_pool_strdup(menu, swinfo->longname);
1992         entry->list_name = list_name;
1993         entry->image = image;
1994         entry->interface = ui_menu_pool_strdup(menu, swpart->interface_);
1995         break;
1996      }
1997   }
1998
1999   // find the end of the list
2000   entryptr = &menustate->entrylist;
2001   while ((*entryptr != NULL) && (compare_software_entries(entry, *entryptr) >= 0))
2002      entryptr = &(*entryptr)->next;
2003   
2004   // insert the entry
2005   entry->next = *entryptr;
2006   *entryptr = entry;
2007
2008   return entry;
2009}
2010
2011
2012static void ui_mess_menu_populate_software_entries(running_machine &machine, ui_menu *menu, software_menu_state *menustate)
2013{
2014   software_list *list = software_list_open(machine.options(), menustate->list_name, FALSE, NULL);
2015
2016   // build up the list of entries for the menu
2017   if (list)
2018   {
2019      for (software_info *swinfo = software_list_find(list, "*", NULL); swinfo != NULL; swinfo = software_list_find(list, "*", swinfo))
2020         append_software_entry(menu, menustate, swinfo, menustate->list_name, menustate->image);
2021
2022      software_list_close(list);
2023   }
2024
2025   // append all of the menu entries
2026   for (software_entry_state *entry = menustate->entrylist; entry != NULL; entry = entry->next)
2027      ui_menu_item_append(menu, entry->short_name, entry->long_name, 0, entry);
2028}
2029
2030bool swinfo_has_multiple_parts(software_info *swinfo, const char *interface)
2031{
2032   int count = 0;
2033
2034   for (software_part *swpart = software_find_part(swinfo, NULL, NULL); swpart != NULL; swpart = software_part_next(swpart))
2035   {
2036      if (strcmp(interface, swpart->interface_) == 0)
2037         count++;
2038   }
2039   return (count > 1) ? TRUE : FALSE;
2040}
2041
2042void ui_mess_menu_software_list(running_machine &machine, ui_menu *menu, void *parameter, void *state)
2043{
2044   const ui_menu_event *event;
2045   software_menu_state *sw_state = (software_menu_state *)state;
2046   const software_entry_state *entry;
2047   const software_entry_state *selected_entry = NULL;
2048   int bestmatch = 0;
2049   
2050   if (!ui_menu_populated(menu))
2051   {
2052      if (sw_state->list_name)
2053      {
2054         ui_mess_menu_populate_software_entries(machine, menu, sw_state);
2055      }
2056   }
2057
2058   /* process the menu */
2059   event = ui_menu_process(machine, menu, 0);
2060
2061   if (event != NULL && event->itemref != NULL)
2062   {
2063      /* handle selections */
2064      if (event->iptkey == IPT_UI_SELECT)
2065      {
2066         device_image_interface *image = sw_state->image;
2067         software_entry_state *entry = (software_entry_state *) event->itemref;
2068         software_list *tmp_list = software_list_open(machine.options(), sw_state->list_name, FALSE, NULL);
2069         software_info *tmp_info = software_list_find(tmp_list, entry->short_name, NULL);
2070         
2071         // if the selected software has multiple parts that can be loaded, open the submenu
2072         if (swinfo_has_multiple_parts(tmp_info, image->image_config().image_interface()))
2073         {
2074            ui_menu *child_menu = ui_menu_alloc(machine, &machine.render().ui_container(), ui_mess_menu_software_parts, entry);
2075            software_entry_state *child_menustate = (software_entry_state *)ui_menu_alloc_state(child_menu, sizeof(*child_menustate), NULL);
2076            child_menustate->short_name = entry->short_name;
2077            child_menustate->interface = image->image_config().image_interface();
2078            child_menustate->list_name = sw_state->list_name;
2079            child_menustate->image = image;
2080            ui_menu_stack_push(child_menu);
2081         }
2082         else
2083         {
2084            // otherwise, load the file
2085            if (image != NULL)
2086               image->load(entry->short_name);
2087            else
2088               popmessage("No matching device found for interface '%s'!", entry->interface);
2089         }
2090         software_list_close(tmp_list);
2091         
2092         // reset the char buffer when pressing IPT_UI_SELECT
2093         if (sw_state->filename_buffer[0] != '\0')
2094            memset(sw_state->filename_buffer, '\0', ARRAY_LENGTH(sw_state->filename_buffer));
2095      }
2096      else if (event->iptkey == IPT_SPECIAL)
2097      {
2098         int buflen = strlen(sw_state->filename_buffer);
2099         bool update_selected = FALSE;
2100         
2101         /* if it's a backspace and we can handle it, do so */
2102         if ((event->unichar == 8 || event->unichar == 0x7f) && buflen > 0)
2103         {
2104            *(char *)utf8_previous_char(&sw_state->filename_buffer[buflen]) = 0;
2105            update_selected = TRUE;
2106           
2107            if (ARRAY_LENGTH(sw_state->filename_buffer) > 0)
2108               ui_popup_time(5, "%s", sw_state->filename_buffer);
2109         }
2110         /* if it's any other key and we're not maxed out, update */
2111         else if (event->unichar >= ' ' && event->unichar < 0x7f)
2112         {
2113            buflen += utf8_from_uchar(&sw_state->filename_buffer[buflen], ARRAY_LENGTH(sw_state->filename_buffer) - buflen, event->unichar);
2114            sw_state->filename_buffer[buflen] = 0;
2115            update_selected = TRUE;
2116           
2117            if (ARRAY_LENGTH(sw_state->filename_buffer) > 0)
2118               ui_popup_time(5, "%s", sw_state->filename_buffer);
2119         }
2120         
2121         if (update_selected)
2122         {
2123            const software_entry_state *cur_selected = (const software_entry_state *)ui_menu_get_selection(menu);
2124           
2125            // check for entries which matches our filename_buffer:
2126            // from current entry to the end
2127            for (entry = cur_selected; entry != NULL; entry = entry->next)
2128            {
2129               if (entry->short_name != NULL && sw_state->filename_buffer != NULL)
2130               {
2131                  int match = 0;
2132                  for (int i = 0; i < ARRAY_LENGTH(sw_state->filename_buffer); i++)
2133                  {
2134                     if (mame_strnicmp(entry->short_name, sw_state->filename_buffer, i) == 0)
2135                        match = i;
2136                  }
2137                 
2138                  if (match > bestmatch)
2139                  {
2140                     bestmatch = match;
2141                     selected_entry = entry;
2142                  }
2143               }
2144            }
2145            // and from the first entry to current one
2146            for (entry = sw_state->entrylist; entry != cur_selected; entry = entry->next)
2147            {
2148               if (entry->short_name != NULL && sw_state->filename_buffer != NULL)
2149               {
2150                  int match = 0;
2151                  for (int i = 0; i < ARRAY_LENGTH(sw_state->filename_buffer); i++)
2152                  {
2153                     if (mame_strnicmp(entry->short_name, sw_state->filename_buffer, i) == 0)
2154                        match = i;
2155                  }
2156                 
2157                  if (match > bestmatch)
2158                  {
2159                     bestmatch = match;
2160                     selected_entry = entry;
2161                  }
2162               }
2163            }
2164           
2165            if (selected_entry != NULL && selected_entry != cur_selected)
2166               ui_menu_set_selection(menu, (void *) selected_entry);
2167         }
2168      }
2169      else if (event->iptkey == IPT_UI_CANCEL)
2170      {
2171         // reset the char buffer also in this case
2172         if (sw_state->filename_buffer[0] != '\0')
2173            memset(sw_state->filename_buffer, '\0', ARRAY_LENGTH(sw_state->filename_buffer));
2174      }
2175   }
2176}
2177
2178/* list of available software lists - i.e. cartridges, floppies */
2179static void ui_mess_menu_populate_software_list(running_machine &machine, ui_menu *menu, device_image_interface* image)
2180{
2181   bool haveCompatible = FALSE;
2182   const char *interface = image->image_config().image_interface();
2183
2184   // Add original software lists for this system
2185   for (const device_config *dev = machine.config().m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext())
2186   {
2187      software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config();
2188
2189      for (int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++)
2190      {
2191         if (swlist->list_name[i] && (swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM))
2192         {
2193            software_list *list = software_list_open(machine.options(), swlist->list_name[i], FALSE, NULL);
2194
2195            if (list)
2196            {
2197               bool found = FALSE;
2198               for (software_info *swinfo = software_list_find(list, "*", NULL); swinfo != NULL; swinfo = software_list_find(list, "*", swinfo))
2199               {
2200                  software_part *part = software_find_part(swinfo, NULL, NULL);
2201                  if (strcmp(interface,part->interface_)==0) {
2202                     found = TRUE;
2203                  }
2204               }
2205               if (found) {
2206                  ui_menu_item_append(menu, list->description, NULL, 0, swlist->list_name[i]);
2207               }
2208
2209               software_list_close(list);
2210            }
2211         }
2212      }
2213   }
2214
2215   // Add compatible software lists for this system
2216   for (const device_config *dev = machine.config().m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext())
2217   {
2218      software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config();
2219
2220      for (int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++)
2221      {
2222         if (swlist->list_name[i] && (swlist->list_type == SOFTWARE_LIST_COMPATIBLE_SYSTEM))
2223         {
2224            software_list *list = software_list_open(machine.options(), swlist->list_name[i], FALSE, NULL);
2225
2226            if (list)
2227            {
2228               bool found = FALSE;
2229               for (software_info *swinfo = software_list_find(list, "*", NULL); swinfo != NULL; swinfo = software_list_find(list, "*", swinfo))
2230               {
2231                  software_part *part = software_find_part(swinfo, NULL, NULL);
2232                  if (strcmp(interface,part->interface_)==0) {
2233                     found = TRUE;
2234                  }
2235               }
2236               if (found) {
2237                  if (!haveCompatible) {
2238                     ui_menu_item_append(menu, "[compatible lists]", NULL, 0, NULL);
2239                  }
2240                  ui_menu_item_append(menu, list->description, NULL, 0, swlist->list_name[i]);
2241               }
2242
2243               haveCompatible = TRUE;
2244               software_list_close(list);
2245            }
2246         }
2247      }
2248   }
2249
2250}
2251
2252void ui_image_menu_software(running_machine &machine, ui_menu *menu, void *parameter, void *state)
2253{
2254   const ui_menu_event *event;
2255   device_image_interface* image = (device_image_interface*)parameter;
2256   if (!ui_menu_populated(menu))
2257      ui_mess_menu_populate_software_list(machine, menu, image);
2258
2259   /* process the menu */
2260   event = ui_menu_process(machine, menu, 0);
2261
2262   if (event != NULL && event->iptkey == IPT_UI_SELECT)
2263   {
2264      ui_menu *child_menu = ui_menu_alloc(machine, &machine.render().ui_container(), ui_mess_menu_software_list, NULL);
2265      software_menu_state *child_menustate = (software_menu_state *)ui_menu_alloc_state(child_menu, sizeof(*child_menustate), NULL);
2266      child_menustate->list_name = (char *)event->itemref;
2267      child_menustate->image = image;
2268      child_menustate->entrylist = NULL;
2269      ui_menu_stack_push(child_menu);
2270   }
2271}
2272
22731801DEFINE_LEGACY_DEVICE(SOFTWARE_LIST, software_list);
src/emu/softlist.h
r11096r11097
1010#define __SOFTLIST_H_
1111
1212#include "uimenu.h"
13#include "expat.h"
1314
1415
1516/*********************************************************************
r11096r11097
5253};
5354
5455
56enum softlist_parse_position
57{
58   POS_ROOT,
59   POS_MAIN,
60   POS_SOFT,
61   POS_PART,
62   POS_DATA
63};
64
65
66typedef struct _parse_state parse_state;
67struct _parse_state
68{
69   XML_Parser   parser;
70   int         done;
71   
72   void (*error_proc)(const char *message);
73   void *param;
74   
75   enum softlist_parse_position pos;
76   char **text_dest;
77};
78
79
5580typedef struct _software_list software_list;
81struct _software_list
82{
83   emu_file   *file;
84   object_pool   *pool;
85   parse_state   state;
86   const char *description;
87   struct software_info   *software_info_list;
88   struct software_info   *current_software_info;
89   software_info   *softinfo;
90   const char *look_for;
91   int part_entries;
92   int current_part_entry;
93   int rom_entries;
94   int current_rom_entry;
95   void (*error_proc)(const char *message);
96   int list_entries;
97};
5698
5799/* Handling a software list */
58100software_list *software_list_open(emu_options &options, const char *listname, int is_preload, void (*error_proc)(const char *message));
r11096r11097
71113
72114bool load_software_part(device_image_interface *image, const char *path, software_info **sw_info, software_part **sw_part, char **full_sw_name);
73115
74void ui_image_menu_software(running_machine &machine, ui_menu *menu, void *parameter, void *state);
75116
76
77117/*********************************************************************
78118
79119    Driver software list configuration
src/emu/emu.mak
r11096r11097
101101   $(EMUOBJ)/uigfx.o \
102102   $(EMUOBJ)/uiimage.o \
103103   $(EMUOBJ)/uiinput.o \
104   $(EMUOBJ)/uiswlist.o \
104105   $(EMUOBJ)/uimenu.o \
105106   $(EMUOBJ)/validity.o \
106107   $(EMUOBJ)/video.o \

Previous 15994 Revisions Next


© 1998-2018 The MESS Team