diff options
Diffstat (limited to 'docs/release/src/osd/winui/newui.cpp')
-rw-r--r-- | docs/release/src/osd/winui/newui.cpp | 3364 |
1 files changed, 3364 insertions, 0 deletions
diff --git a/docs/release/src/osd/winui/newui.cpp b/docs/release/src/osd/winui/newui.cpp new file mode 100644 index 00000000000..5ee6d76e5dd --- /dev/null +++ b/docs/release/src/osd/winui/newui.cpp @@ -0,0 +1,3364 @@ +// For licensing and usage information, read docs/winui_license.txt +//************************************************************************************************ +// MASTER +// +// newui.c - This is the NEWUI Windows dropdown menu system +// +// known bugs: +// - Unable to modify keyboard or joystick. Last known to be working in 0.158 . +// Need to use the default UI. +// +// +//************************************************************************************************ + +// Set minimum windows version to XP +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x501 + + +// standard windows headers +#include "newui.h" + +#include <shellapi.h> + + +enum _win_file_dialog_type +{ + WIN_FILE_DIALOG_OPEN = 1, + WIN_FILE_DIALOG_SAVE +}; +typedef enum _win_file_dialog_type win_file_dialog_type; + +typedef struct _win_open_file_name win_open_file_name; +struct _win_open_file_name +{ + win_file_dialog_type type; // type of file dialog + HWND owner; // owner of the dialog + HINSTANCE instance; // instance + const char * filter; // pipe char ("|") delimited strings + DWORD filter_index; // index into filter + char filename[MAX_PATH]; // filename buffer + const char * initial_directory; // initial directory for dialog + DWORD flags; // standard flags + LPARAM custom_data; // custom data for dialog hook + LPOFNHOOKPROC hook; // custom dialog hook + LPCTSTR template_name; // custom dialog template +}; + + +typedef struct _dialog_box dialog_box; + +struct dialog_layout +{ + short label_width; + short combo_width; +}; + +typedef void (*dialog_itemstoreval)(void *param, int val); +typedef void (*dialog_itemchangedproc)(dialog_box *dialog, HWND dlgitem, void *changed_param); +typedef void (*dialog_notification)(dialog_box *dialog, HWND dlgwnd, NMHDR *notification, void *param); + +#ifdef UNICODE +#define win_dialog_tcsdup win_dialog_wcsdup +#else +#define win_dialog_tcsdup win_dialog_strdup +#endif + +#define SEQWM_SETFOCUS (WM_APP + 0) +#define SEQWM_KILLFOCUS (WM_APP + 1) + +enum +{ + TRIGGER_INITDIALOG = 1, + TRIGGER_APPLY = 2, + TRIGGER_CHANGED = 4 +}; + +typedef LRESULT (*trigger_function)(dialog_box *dialog, HWND dlgwnd, UINT message, WPARAM wparam, LPARAM lparam); + +struct dialog_info_trigger +{ + struct dialog_info_trigger *next; + WORD dialog_item; + WORD trigger_flags; + UINT message; + WPARAM wparam; + LPARAM lparam; + void (*storeval)(void *param, int val); + void *storeval_param; + trigger_function trigger_proc; +}; + +struct dialog_object_pool +{ + HGDIOBJ objects[16]; +}; + +struct _dialog_box +{ + HGLOBAL handle; + size_t handle_size; + struct dialog_info_trigger *trigger_first; + struct dialog_info_trigger *trigger_last; + WORD item_count; + WORD size_x, size_y; + WORD pos_x, pos_y; + WORD cursize_x, cursize_y; + WORD home_y; + DWORD style; + int combo_string_count; + int combo_default_value; + //object_pool *mempool; + struct dialog_object_pool *objpool; + const struct dialog_layout *layout; + + // singular notification callback; hack + UINT notify_code; + dialog_notification notify_callback; + void *notify_param; +}; + +enum _seqselect_state +{ + SEQSELECT_STATE_NOT_POLLING, + SEQSELECT_STATE_POLLING, + SEQSELECT_STATE_POLLING_COMPLETE +}; +typedef enum _seqselect_state seqselect_state; + +// this is the structure that gets associated with each input_seq edit box +typedef struct _seqselect_info seqselect_info; +struct _seqselect_info +{ + WNDPROC oldwndproc; + ioport_field *field; // pointer to the field + ioport_field::user_settings settings; // the new settings + input_seq *code; // the input_seq within settings + WORD pos; + BOOL is_analog; + seqselect_state poll_state; +}; + + + +//============================================================ +// PARAMETERS +//============================================================ + +#define DIM_VERTICAL_SPACING 3 +#define DIM_HORIZONTAL_SPACING 5 +#define DIM_NORMAL_ROW_HEIGHT 10 +#define DIM_COMBO_ROW_HEIGHT 12 +#define DIM_SLIDER_ROW_HEIGHT 18 +#define DIM_BUTTON_ROW_HEIGHT 12 +#define DIM_EDIT_WIDTH 120 +#define DIM_BUTTON_WIDTH 50 +#define DIM_ADJUSTER_SCR_WIDTH 12 +#define DIM_ADJUSTER_HEIGHT 12 +#define DIM_SCROLLBAR_WIDTH 10 +#define DIM_BOX_VERTSKEW -3 + +#define DLGITEM_BUTTON ((const WCHAR *) dlgitem_button) +#define DLGITEM_EDIT ((const WCHAR *) dlgitem_edit) +#define DLGITEM_STATIC ((const WCHAR *) dlgitem_static) +#define DLGITEM_LISTBOX ((const WCHAR *) dlgitem_listbox) +#define DLGITEM_SCROLLBAR ((const WCHAR *) dlgitem_scrollbar) +#define DLGITEM_COMBOBOX ((const WCHAR *) dlgitem_combobox) + +#define DLGTEXT_OK "OK" +#define DLGTEXT_APPLY "Apply" +#define DLGTEXT_CANCEL "Cancel" + +#define FONT_SIZE 8 +#define FONT_FACE L"Arial" + +#define SCROLL_DELTA_LINE 10 +#define SCROLL_DELTA_PAGE 100 + +#define LOG_WINMSGS 0 +#define DIALOG_STYLE WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION | DS_SETFONT +#define MAX_DIALOG_HEIGHT 200 + + + +//============================================================ +// LOCAL VARIABLES +//============================================================ + +static running_machine *Machine; // HACK - please fix + +static double pixels_to_xdlgunits; +static double pixels_to_ydlgunits; + +static const struct dialog_layout default_layout = { 80, 140 }; +static const WORD dlgitem_button[] = { 0xFFFF, 0x0080 }; +static const WORD dlgitem_edit[] = { 0xFFFF, 0x0081 }; +static const WORD dlgitem_static[] = { 0xFFFF, 0x0082 }; +static const WORD dlgitem_listbox[] = { 0xFFFF, 0x0083 }; +static const WORD dlgitem_scrollbar[] = { 0xFFFF, 0x0084 }; +static const WORD dlgitem_combobox[] = { 0xFFFF, 0x0085 }; +static int joystick_menu_setup = 0; +static char state_filename[MAX_PATH]; +static void add_filter_entry(std::string &dest, const char *description, const char *extensions); +static const char* software_dir; + + +//============================================================ +// PROTOTYPES +//============================================================ + +static void dialog_prime(dialog_box *di); +static int dialog_write_item(dialog_box *di, DWORD style, short x, short y, short width, short height, const char *str, const WCHAR *class_name, WORD *id); + + + +//============================================================ +// PARAMETERS +//============================================================ + +#define ID_FRAMESKIP_0 10000 +#define ID_DEVICE_0 11000 +#define ID_JOYSTICK_0 12000 +#define ID_VIDEO_VIEW_0 14000 +#define MAX_JOYSTICKS (8) + +enum +{ + DEVOPTION_OPEN, + DEVOPTION_CREATE, + DEVOPTION_CLOSE, + DEVOPTION_CASSETTE_PLAYRECORD, + DEVOPTION_CASSETTE_STOPPAUSE, + DEVOPTION_CASSETTE_PLAY, + DEVOPTION_CASSETTE_RECORD, + DEVOPTION_CASSETTE_REWIND, + DEVOPTION_CASSETTE_FASTFORWARD, + DEVOPTION_MAX +}; + + +//======================================================================== +// LOCAL STRING FUNCTIONS (these require free after being called) +//======================================================================== + +static WCHAR *ui_wstring_from_utf8(const char *utf8string) +{ + int char_count; + WCHAR *result; + + // convert MAME string (UTF-8) to UTF-16 + char_count = MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, nullptr, 0); + result = (WCHAR *)malloc(char_count * sizeof(*result)); + if (result != nullptr) + MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, result, char_count); + + return result; +} + +static char *ui_utf8_from_wstring(const WCHAR *wstring) +{ + int char_count; + char *result; + + // convert UTF-16 to MAME string (UTF-8) + char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, nullptr, 0, nullptr, nullptr); + result = (char *)malloc(char_count * sizeof(*result)); + if (result != nullptr) + WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, nullptr, nullptr); + return result; +} + + + +//============================================================ +// win_get_file_name_dialog - sanitize all of the ugliness +// in invoking GetOpenFileName() and GetSaveFileName() +// called from win_file_dialog, state_dialog +//============================================================ + +static BOOL win_get_file_name_dialog(win_open_file_name *ofn) +{ + BOOL result = FALSE; + BOOL dialog_result; + OPENFILENAME os_ofn; + LPTSTR t_filter = NULL; + LPTSTR t_file = NULL; + DWORD t_file_size = 0; + LPTSTR t_initial_directory = NULL; + LPTSTR buffer; + char *utf8_file; + int i; + + // do we have to translate the filter? + if (ofn->filter) + { + buffer = ui_wstring_from_utf8(ofn->filter); + if (!buffer) + goto done; + + // convert a pipe-char delimited string into a NUL delimited string + t_filter = (LPTSTR) alloca((_tcslen(buffer) + 2) * sizeof(*t_filter)); + for (i = 0; buffer[i] != '\0'; i++) + t_filter[i] = (buffer[i] != '|') ? buffer[i] : '\0'; + t_filter[i++] = '\0'; + t_filter[i++] = '\0'; + free(buffer); + } + + // do we need to translate the file parameter? + if (ofn->filename) + { + buffer = ui_wstring_from_utf8(ofn->filename); + if (!buffer) + goto done; + + t_file_size = ((_tcslen(buffer) + 1) > MAX_PATH) ? (_tcslen(buffer) + 1) : MAX_PATH; + t_file = (LPTSTR) alloca(t_file_size * sizeof(*t_file)); + _tcscpy(t_file, buffer); + free(buffer); + } + + // do we need to translate the initial directory? + if (ofn->initial_directory) + { + t_initial_directory = ui_wstring_from_utf8(ofn->initial_directory); + if (t_initial_directory == NULL) + goto done; + } + + // translate our custom structure to a native Win32 structure + memset(&os_ofn, 0, sizeof(os_ofn)); + os_ofn.lStructSize = sizeof(OPENFILENAME); + os_ofn.hwndOwner = ofn->owner; + os_ofn.hInstance = ofn->instance; + os_ofn.lpstrFilter = t_filter; + os_ofn.nFilterIndex = ofn->filter_index; + os_ofn.lpstrFile = t_file; + os_ofn.nMaxFile = t_file_size; + os_ofn.lpstrInitialDir = t_initial_directory; + os_ofn.Flags = ofn->flags; + os_ofn.lCustData = ofn->custom_data; + os_ofn.lpfnHook = ofn->hook; + os_ofn.lpTemplateName = ofn->template_name; + + // invoke the correct Win32 call + switch(ofn->type) + { + case WIN_FILE_DIALOG_OPEN: + dialog_result = GetOpenFileName(&os_ofn); + break; + + case WIN_FILE_DIALOG_SAVE: + dialog_result = GetSaveFileName(&os_ofn); + break; + + default: + // should not reach here + dialog_result = FALSE; + break; + } + + // copy data out + ofn->filter_index = os_ofn.nFilterIndex; + ofn->flags = os_ofn.Flags; + + // copy file back out into passed structure + if (t_file) + { + utf8_file = ui_utf8_from_wstring(t_file); + if (!utf8_file) + goto done; + + snprintf(ofn->filename, ARRAY_LENGTH(ofn->filename), "%s", utf8_file); + free(utf8_file); + } + + // we've completed the process + result = dialog_result; + +done: + if (t_initial_directory) + free(t_initial_directory); + return result; +} + + + +//============================================================ +// win_scroll_window +// called from dialog_proc +//============================================================ + +static void win_scroll_window(HWND window, WPARAM wparam, int scroll_bar, int scroll_delta_line) +{ + SCROLLINFO si; + int scroll_pos; + + // retrieve vital info about the scroll bar + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + GetScrollInfo(window, scroll_bar, &si); + + scroll_pos = si.nPos; + + // change scroll_pos in accordance with this message + switch(LOWORD(wparam)) + { + case SB_BOTTOM: + scroll_pos = si.nMax; + break; + case SB_LINEDOWN: + scroll_pos += scroll_delta_line; + break; + case SB_LINEUP: + scroll_pos -= scroll_delta_line; + break; + case SB_PAGEDOWN: + scroll_pos += scroll_delta_line; + break; + case SB_PAGEUP: + scroll_pos -= scroll_delta_line; + break; + case SB_THUMBPOSITION: + case SB_THUMBTRACK: + scroll_pos = HIWORD(wparam); + break; + case SB_TOP: + scroll_pos = si.nMin; + break; + } + + // max out the scroll bar value + if (scroll_pos < si.nMin) + scroll_pos = si.nMin; + else if (scroll_pos > (si.nMax - si.nPage)) + scroll_pos = (si.nMax - si.nPage); + + // if the value changed, set the scroll position + if (scroll_pos != si.nPos) + { + SetScrollPos(window, scroll_bar, scroll_pos, TRUE); + ScrollWindowEx(window, 0, si.nPos - scroll_pos, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE); + } +} + + + +//============================================================ +// win_append_menu_utf8 +// create a menu item +//============================================================ + +static BOOL win_append_menu_utf8(HMENU menu, UINT flags, UINT_PTR id, const char *item) +{ + BOOL result; + const TCHAR *t_item = (const TCHAR*)item; + TCHAR *t_str = NULL; + + // only convert string when it's not a bitmap + if (!(flags & MF_BITMAP) && item) + { + t_str = ui_wstring_from_utf8(item); + t_item = t_str; + } + + result = AppendMenu(menu, flags, id, t_item); + + if (t_str) + free(t_str); + + return result; +} + + + +//============================================================ +// call_windowproc +// called from adjuster_sb_wndproc, seqselect_wndproc +//============================================================ + +static LRESULT call_windowproc(WNDPROC wndproc, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + LRESULT rc; + if (IsWindowUnicode(hwnd)) + rc = CallWindowProcW(wndproc, hwnd, msg, wparam, lparam); + else + rc = CallWindowProcA(wndproc, hwnd, msg, wparam, lparam); + return rc; +} + + + +//========================================================================== +// dialog_write +// called from dialog_write_string, win_dialog_init, dialog_write_item +//========================================================================== + +static int dialog_write(struct _dialog_box *di, const void *ptr, size_t sz, int align) +{ + HGLOBAL newhandle; + size_t base; + UINT8 *mem; + UINT8 *mem2; + + if (!di->handle) + { + newhandle = GlobalAlloc(GMEM_ZEROINIT, sz); + base = 0; + } + else + { + base = di->handle_size; + base += align - 1; + base -= base % align; + newhandle = GlobalReAlloc(di->handle, base + sz, GMEM_ZEROINIT); + if (!newhandle) + { + newhandle = GlobalAlloc(GMEM_ZEROINIT, base + sz); + if (newhandle) + { + mem = (UINT8*)GlobalLock(di->handle); + mem2 = (UINT8*)GlobalLock(newhandle); + memcpy(mem2, mem, base); + GlobalUnlock(di->handle); + GlobalUnlock(newhandle); + GlobalFree(di->handle); + } + } + } + if (!newhandle) + return 1; + + mem = (UINT8*)GlobalLock(newhandle); + memcpy(mem + base, ptr, sz); + GlobalUnlock(newhandle); + di->handle = newhandle; + di->handle_size = base + sz; + return 0; +} + + + +//============================================================ +// dialog_write_string +// called from win_dialog_init, dialog_write_item +//============================================================ + +static int dialog_write_string(dialog_box *di, const WCHAR *str) +{ + if (!str) + str = L""; + return dialog_write(di, str, (wcslen(str) + 1) * sizeof(WCHAR), 2); +} + + + + +//============================================================ +// win_dialog_exit +// called from win_dialog_init, calc_dlgunits_multiple, change_device, and all customise_input functions +//============================================================ + +static void win_dialog_exit(dialog_box *dialog) +{ + int i; + struct dialog_object_pool *objpool; + + if (!dialog) + printf("No dialog passed to win_dialog_exit\n"); + assert(dialog); + + objpool = dialog->objpool; + if (objpool) + { + for (i = 0; i < ARRAY_LENGTH(objpool->objects); i++) + DeleteObject(objpool->objects[i]); + } + + if (dialog->handle) + GlobalFree(dialog->handle); + + free(dialog); +} + + + +//=========================================================================== +// win_dialog_init +// called from calc_dlgunits_multiple, and all customise_input functions +//=========================================================================== + +dialog_box *win_dialog_init(const char *title, const struct dialog_layout *layout) +{ + struct _dialog_box *di; + DLGTEMPLATE dlg_template; + WORD w[2]; + WCHAR *w_title; + int rc; + + // use default layout if not specified + if (!layout) + layout = &default_layout; + + // create the dialog structure + di = (_dialog_box *)malloc(sizeof(struct _dialog_box)); + if (!di) + goto error; + memset(di, 0, sizeof(*di)); + + di->layout = layout; + + memset(&dlg_template, 0, sizeof(dlg_template)); + dlg_template.style = di->style = DIALOG_STYLE; + dlg_template.x = 10; + dlg_template.y = 10; + if (dialog_write(di, &dlg_template, sizeof(dlg_template), 4)) + goto error; + + w[0] = 0; + w[1] = 0; + if (dialog_write(di, w, sizeof(w), 2)) + goto error; + + w_title = ui_wstring_from_utf8(title); + rc = dialog_write_string(di, w_title); + free(w_title); + if (rc) + goto error; + + // set the font, if necessary + if (di->style & DS_SETFONT) + { + w[0] = FONT_SIZE; + if (dialog_write(di, w, sizeof(w[0]), 2)) + goto error; + if (dialog_write_string(di, FONT_FACE)) + goto error; + } + + return di; + +error: + if (di) + win_dialog_exit(di); + return NULL; +} + + +//============================================================ +// compute_dlgunits_multiple +// called from dialog_scrollbar_init +//============================================================ + +static void calc_dlgunits_multiple(void) +{ + dialog_box *dialog = NULL; + short offset_x = 2048; + short offset_y = 2048; + const char *wnd_title = "Foo"; + WORD id; + HWND dlg_window = NULL; + HWND child_window; + RECT r; + + if ((pixels_to_xdlgunits == 0) || (pixels_to_ydlgunits == 0)) + { + // create a bogus dialog + dialog = win_dialog_init(NULL, NULL); + if (!dialog) + goto done; + + if (dialog_write_item(dialog, WS_CHILD | WS_VISIBLE | SS_LEFT, 0, 0, offset_x, offset_y, wnd_title, DLGITEM_STATIC, &id)) + goto done; + + dialog_prime(dialog); + dlg_window = CreateDialogIndirectParam(NULL, (const DLGTEMPLATE*)dialog->handle, NULL, NULL, 0); + child_window = GetDlgItem(dlg_window, id); + + GetWindowRect(child_window, &r); + pixels_to_xdlgunits = (double)(r.right - r.left) / offset_x; + pixels_to_ydlgunits = (double)(r.bottom - r.top) / offset_y; + +done: + if (dialog) + win_dialog_exit(dialog); + if (dlg_window) + DestroyWindow(dlg_window); + } +} + + + +//============================================================ +// dialog_trigger +// called from dialog_proc, file_dialog_hook +//============================================================ + +static void dialog_trigger(HWND dlgwnd, WORD trigger_flags) +{ + LRESULT result; + HWND dialog_item; + struct _dialog_box *di; + struct dialog_info_trigger *trigger; + LONG_PTR l; + + l = GetWindowLongPtr(dlgwnd, GWLP_USERDATA); + di = (struct _dialog_box *) l; + if (!di) + printf("Unexpected result of di in dialog_trigger\n"); + assert(di); + for (trigger = di->trigger_first; trigger; trigger = trigger->next) + { + if (trigger->trigger_flags & trigger_flags) + { + if (trigger->dialog_item) + dialog_item = GetDlgItem(dlgwnd, trigger->dialog_item); + else + dialog_item = dlgwnd; + if (!dialog_item) + printf("Unexpected result of dialog_item in dialog_trigger\n"); + assert(dialog_item); + result = 0; + + if (trigger->message) + result = SendMessage(dialog_item, trigger->message, trigger->wparam, trigger->lparam); + if (trigger->trigger_proc) + result = trigger->trigger_proc(di, dialog_item, trigger->message, trigger->wparam, trigger->lparam); + + if (trigger->storeval) + trigger->storeval(trigger->storeval_param, result); + } + } +} + +//============================================================ +// dialog_proc +// called from win_dialog_runmodal +//============================================================ + +static INT_PTR CALLBACK dialog_proc(HWND dlgwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + INT_PTR handled = TRUE; + std::string buf; + WORD command; + + switch(msg) + { + case WM_INITDIALOG: + SetWindowLongPtr(dlgwnd, GWLP_USERDATA, (LONG_PTR) lparam); + dialog_trigger(dlgwnd, TRIGGER_INITDIALOG); + break; + + case WM_COMMAND: + command = LOWORD(wparam); + + buf = win_get_window_text_utf8((HWND) lparam); + if (!strcmp(buf.c_str(), DLGTEXT_OK)) + command = IDOK; + else if (!strcmp(buf.c_str(), DLGTEXT_CANCEL)) + command = IDCANCEL; + else + command = 0; + + switch(command) + { + case IDOK: + dialog_trigger(dlgwnd, TRIGGER_APPLY); + // fall through + + case IDCANCEL: + EndDialog(dlgwnd, 0); + break; + + default: + handled = FALSE; + break; + } + break; + + case WM_SYSCOMMAND: + if (wparam == SC_CLOSE) + EndDialog(dlgwnd, 0); + else + handled = FALSE; + + break; + + case WM_VSCROLL: + if (lparam) + // this scroll message came from an actual scroll bar window; + // pass it on + SendMessage((HWND) lparam, msg, wparam, lparam); + else + // scroll the dialog + win_scroll_window(dlgwnd, wparam, SB_VERT, SCROLL_DELTA_LINE); + + break; + + default: + handled = FALSE; + break; + } + return handled; +} + + + +//========================================================================================================================================================================================= +// dialog_write_item +// called from calc_dlgunits_multiple, win_dialog_add_active_combobox, win_dialog_add_adjuster, dialog_add_single_seqselect, win_dialog_add_portselect, win_dialog_add_standard_buttons +//========================================================================================================================================================================================= + +static int dialog_write_item(dialog_box *di, DWORD style, short x, short y, short width, short height, const char *str, const WCHAR *class_name, WORD *id) +{ + DLGITEMTEMPLATE item_template; + UINT class_name_length; + WORD w; + WCHAR *w_str; + int rc; + + memset(&item_template, 0, sizeof(item_template)); + item_template.style = style; + item_template.x = x; + item_template.y = y; + item_template.cx = width; + item_template.cy = height; + item_template.id = di->item_count + 1; + + if (dialog_write(di, &item_template, sizeof(item_template), 4)) + return 1; + + if (*class_name == 0xffff) + class_name_length = 4; + else + class_name_length = (wcslen(class_name) + 1) * sizeof(WCHAR); + if (dialog_write(di, class_name, class_name_length, 2)) + return 1; + + w_str = str ? ui_wstring_from_utf8(str) : NULL; + rc = dialog_write_string(di, w_str); + if (w_str) + free(w_str); + if (rc) + return 1; + + w = 0; + if (dialog_write(di, &w, sizeof(w), 2)) + return 1; + + di->item_count++; + + if (id) + *id = di->item_count; + return 0; +} + + + +//========================================================================================================================================================== +// dialog_add_trigger +// called from dialog_add_scrollbar, win_dialog_add_active_combobox, win_dialog_add_combobox_item, win_dialog_add_adjuster, dialog_add_single_seqselect +//========================================================================================================================================================== + +static int dialog_add_trigger(struct _dialog_box *di, WORD dialog_item, WORD trigger_flags, UINT message, trigger_function trigger_proc, + WPARAM wparam, LPARAM lparam, void (*storeval)(void *param, int val), void *storeval_param) +{ + if (!di) + printf("Unexpected result of di in dialog_add_trigger\n"); + assert(di); + if (!trigger_flags) + printf("Unexpected result of trigger_flags in dialog_add_trigger\n"); + assert(trigger_flags); + + dialog_info_trigger *trigger = new(dialog_info_trigger); + + trigger->next = NULL; + trigger->trigger_flags = trigger_flags; + trigger->dialog_item = dialog_item; + trigger->message = message; + trigger->trigger_proc = trigger_proc; + trigger->wparam = wparam; + trigger->lparam = lparam; + trigger->storeval = storeval; + trigger->storeval_param = storeval_param; + + if (di->trigger_last) + di->trigger_last->next = trigger; + else + di->trigger_first = trigger; + di->trigger_last = trigger; + return 0; +} + + + +//============================================================ +// dialog_scrollbar_init +// called from dialog_add_scrollbar +//============================================================ + +static LRESULT dialog_scrollbar_init(dialog_box *dialog, HWND dlgwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + SCROLLINFO si; + + calc_dlgunits_multiple(); + + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.nMin = pixels_to_ydlgunits * 0; + si.nMax = pixels_to_ydlgunits * dialog->size_y; + si.nPage = pixels_to_ydlgunits * MAX_DIALOG_HEIGHT; + si.fMask = SIF_PAGE | SIF_RANGE; + + SetScrollInfo(dlgwnd, SB_VERT, &si, TRUE); + return 0; +} + + + +//============================================================ +// dialog_add_scrollbar +// called from dialog_prime +//============================================================ + +static int dialog_add_scrollbar(dialog_box *dialog) +{ + if (dialog_add_trigger(dialog, 0, TRIGGER_INITDIALOG, 0, dialog_scrollbar_init, 0, 0, NULL, NULL)) + return 1; + + dialog->style |= WS_VSCROLL; + return 0; +} + + + +//============================================================================== +// dialog_prime +// called from calc_dlgunits_multiple, win_dialog_runmodal, win_file_dialog +//============================================================================== + +static void dialog_prime(dialog_box *di) +{ + DLGTEMPLATE *dlg_template; + + if (di->size_y > MAX_DIALOG_HEIGHT) + { + di->size_x += DIM_SCROLLBAR_WIDTH; + dialog_add_scrollbar(di); + } + + dlg_template = (DLGTEMPLATE *) GlobalLock(di->handle); + dlg_template->cdit = di->item_count; + dlg_template->cx = di->size_x; + dlg_template->cy = (di->size_y > MAX_DIALOG_HEIGHT) ? MAX_DIALOG_HEIGHT : di->size_y; + dlg_template->style = di->style; + GlobalUnlock(di->handle); +} + + + +//============================================================ +// dialog_get_combo_value +// called from win_dialog_add_active_combobox +//============================================================ + +static LRESULT dialog_get_combo_value(dialog_box *dialog, HWND dialog_item, UINT message, WPARAM wparam, LPARAM lparam) +{ + int idx; + idx = SendMessage(dialog_item, CB_GETCURSEL, 0, 0); + if (idx == CB_ERR) + return 0; + return SendMessage(dialog_item, CB_GETITEMDATA, idx, 0); +} + + + +//============================================================ +// dialog_get_adjuster_value +// called from win_dialog_add_adjuster +//============================================================ + +static LRESULT dialog_get_adjuster_value(dialog_box *dialog, HWND dialog_item, UINT message, WPARAM wparam, LPARAM lparam) +{ + TCHAR buf[32]; + GetWindowText(dialog_item, buf, ARRAY_LENGTH(buf)); + return _ttoi(buf); +} + + + +//==================================================================================================== +// dialog_new_control +// called from win_dialog_add_active_combobox, win_dialog_add_adjuster, win_dialog_add_portselect +//==================================================================================================== + +static void dialog_new_control(struct _dialog_box *di, short *x, short *y) +{ + *x = di->pos_x + DIM_HORIZONTAL_SPACING; + *y = di->pos_y + DIM_VERTICAL_SPACING; +} + + + +//==================================================================================================== +// dialog_finish_control +// called from win_dialog_add_active_combobox, win_dialog_add_adjuster, win_dialog_add_portselect +//==================================================================================================== + +static void dialog_finish_control(struct _dialog_box *di, short x, short y) +{ + di->pos_y = y; + + // update dialog size + if (x > di->size_x) + di->size_x = x; + if (y > di->size_y) + di->size_y = y; + if (x > di->cursize_x) + di->cursize_x = x; + if (y > di->cursize_y) + di->cursize_y = y; +} + + + +//============================================================ +// dialog_combo_changed +// called from win_dialog_add_active_combobox +//============================================================ + +static LRESULT dialog_combo_changed(dialog_box *dialog, HWND dlgitem, UINT message, WPARAM wparam, LPARAM lparam) +{ + dialog_itemchangedproc changed = (dialog_itemchangedproc) wparam; + changed(dialog, dlgitem, (void *) lparam); + return 0; +} + + + +//============================================================ +// win_dialog_wcsdup +// called from win_dialog_add_adjuster (via define) +//============================================================ + +static WCHAR *win_dialog_wcsdup(dialog_box *dialog, const WCHAR *s) +{ + WCHAR *result = global_alloc_array(WCHAR, wcslen(s) + 1); + if (result) + wcscpy(result, s); + return result; +} + + + +//============================================================ +// win_dialog_add_active_combobox +// called from win_dialog_add_combobox +//============================================================ + +static int win_dialog_add_active_combobox(dialog_box *dialog, const char *item_label, int default_value, + dialog_itemstoreval storeval, void *storeval_param, dialog_itemchangedproc changed, void *changed_param) +{ + int rc = 1; + short x; + short y; + + dialog_new_control(dialog, &x, &y); + + if (dialog_write_item(dialog, WS_CHILD | WS_VISIBLE | SS_LEFT, + x, y, dialog->layout->label_width, DIM_COMBO_ROW_HEIGHT, item_label, DLGITEM_STATIC, NULL)) + goto done; + + y += DIM_BOX_VERTSKEW; + + x += dialog->layout->label_width + DIM_HORIZONTAL_SPACING; + if (dialog_write_item(dialog, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | CBS_DROPDOWNLIST, + x, y, dialog->layout->combo_width, DIM_COMBO_ROW_HEIGHT * 8, NULL, DLGITEM_COMBOBOX, NULL)) + goto done; + dialog->combo_string_count = 0; + dialog->combo_default_value = default_value; + + // add the trigger invoked when the apply button is pressed + if (dialog_add_trigger(dialog, dialog->item_count, TRIGGER_APPLY, 0, dialog_get_combo_value, 0, 0, storeval, storeval_param)) + goto done; + + // if appropriate, add the optional changed trigger + if (changed) + { + if (dialog_add_trigger(dialog, dialog->item_count, TRIGGER_INITDIALOG | TRIGGER_CHANGED, 0, dialog_combo_changed, (WPARAM) changed, (LPARAM) changed_param, NULL, NULL)) + goto done; + } + + x += dialog->layout->combo_width + DIM_HORIZONTAL_SPACING; + y += DIM_COMBO_ROW_HEIGHT + DIM_VERTICAL_SPACING * 2; + + dialog_finish_control(dialog, x, y); + rc = 0; + +done: + return rc; +} + + + +//============================================================ +// win_dialog_add_combobox +// called from customise_switches, customise_analogcontrols +//============================================================ + +static int win_dialog_add_combobox(dialog_box *dialog, const char *item_label, int default_value, void (*storeval)(void *param, int val), void *storeval_param) +{ + return win_dialog_add_active_combobox(dialog, item_label, default_value, storeval, storeval_param, NULL, NULL); +} + + + +//============================================================ +// win_dialog_add_combobox_item +// called from customise_switches, customise_analogcontrols +//============================================================ + +static int win_dialog_add_combobox_item(dialog_box *dialog, const char *item_label, int item_data) +{ + // create our own copy of the string + size_t newsize = strlen(item_label) + 1; + wchar_t * t_item_label = new wchar_t[newsize]; + //size_t convertedChars = 0; + //mbstowcs_s(&convertedChars, t_item_label, newsize, item_label, _TRUNCATE); + mbstowcs(t_item_label, item_label, newsize); + + if (dialog_add_trigger(dialog, dialog->item_count, TRIGGER_INITDIALOG, CB_ADDSTRING, NULL, 0, (LPARAM) t_item_label, NULL, NULL)) + return 1; + dialog->combo_string_count++; + if (dialog_add_trigger(dialog, dialog->item_count, TRIGGER_INITDIALOG, CB_SETITEMDATA, NULL, dialog->combo_string_count-1, (LPARAM) item_data, NULL, NULL)) + return 1; + if (item_data == dialog->combo_default_value) + { + if (dialog_add_trigger(dialog, dialog->item_count, TRIGGER_INITDIALOG, CB_SETCURSEL, NULL, dialog->combo_string_count-1, 0, NULL, NULL)) + return 1; + } + return 0; +} + + + +//============================================================ +// adjuster_sb_wndproc +// called from adjuster_sb_setup +//============================================================ + +struct adjuster_sb_stuff +{ + WNDPROC oldwndproc; + int min_value; + int max_value; +}; + +static INT_PTR CALLBACK adjuster_sb_wndproc(HWND sbwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + INT_PTR result; + struct adjuster_sb_stuff *stuff; + std::string buf; + CHAR BUF[64]; + HWND dlgwnd, editwnd; + int value, id; + LONG_PTR l; + + l = GetWindowLongPtr(sbwnd, GWLP_USERDATA); + stuff = (struct adjuster_sb_stuff *) l; + + if (msg == WM_VSCROLL) + { + id = GetWindowLong(sbwnd, GWL_ID); + dlgwnd = GetParent(sbwnd); + editwnd = GetDlgItem(dlgwnd, id - 1); + buf = win_get_window_text_utf8(editwnd); + value = atoi(buf.c_str()); + + switch(wparam) + { + case SB_LINEDOWN: + case SB_PAGEDOWN: + value--; + break; + + case SB_LINEUP: + case SB_PAGEUP: + value++; + break; + } + + if (value < stuff->min_value) + value = stuff->min_value; + else if (value > stuff->max_value) + value = stuff->max_value; + _snprintf(BUF, 64, "%d", value); + win_set_window_text_utf8(editwnd, BUF); + result = 0; + } + else + result = call_windowproc(stuff->oldwndproc, sbwnd, msg, wparam, lparam); + + return result; +} + + + +//============================================================ +// adjuster_sb_setup +// called from win_dialog_add_adjuster +//============================================================ + +static LRESULT adjuster_sb_setup(dialog_box *dialog, HWND sbwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + struct adjuster_sb_stuff *stuff; + LONG_PTR l; + + stuff = global_alloc(adjuster_sb_stuff); + if (!stuff) + return 1; + stuff->min_value = (WORD) (lparam >> 0); + stuff->max_value = (WORD) (lparam >> 16); + + l = (LONG_PTR) stuff; + SetWindowLongPtr(sbwnd, GWLP_USERDATA, l); + l = (LONG_PTR) adjuster_sb_wndproc; + l = SetWindowLongPtr(sbwnd, GWLP_WNDPROC, l); + stuff->oldwndproc = (WNDPROC) l; + return 0; +} + + + +//============================================================ +// win_dialog_add_adjuster +// called from customise_analogcontrols +//============================================================ + +static int win_dialog_add_adjuster(dialog_box *dialog, const char *item_label, int default_value, + int min_value, int max_value, BOOL is_percentage, dialog_itemstoreval storeval, void *storeval_param) +{ + short x; + short y; + TCHAR buf[32]; + TCHAR *s; + + dialog_new_control(dialog, &x, &y); + + if (dialog_write_item(dialog, WS_CHILD | WS_VISIBLE | SS_LEFT, x, y, dialog->layout->label_width, DIM_ADJUSTER_HEIGHT, item_label, DLGITEM_STATIC, NULL)) + goto error; + x += dialog->layout->label_width + DIM_HORIZONTAL_SPACING; + + y += DIM_BOX_VERTSKEW; + + if (dialog_write_item(dialog, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_NUMBER, + x, y, dialog->layout->combo_width - DIM_ADJUSTER_SCR_WIDTH, DIM_ADJUSTER_HEIGHT, NULL, DLGITEM_EDIT, NULL)) + goto error; + x += dialog->layout->combo_width - DIM_ADJUSTER_SCR_WIDTH; + + _sntprintf(buf, ARRAY_LENGTH(buf), is_percentage ? TEXT("%d%%") : TEXT("%d"), default_value); + s = win_dialog_tcsdup(dialog, buf); + + if (!s) + return 1; + if (dialog_add_trigger(dialog, dialog->item_count, TRIGGER_INITDIALOG, WM_SETTEXT, NULL, 0, (LPARAM) s, NULL, NULL)) + goto error; + + // add the trigger invoked when the apply button is pressed + if (dialog_add_trigger(dialog, dialog->item_count, TRIGGER_APPLY, 0, dialog_get_adjuster_value, 0, 0, storeval, storeval_param)) + goto error; + + if (dialog_write_item(dialog, WS_CHILD | WS_VISIBLE | WS_TABSTOP | SBS_VERT, x, y, DIM_ADJUSTER_SCR_WIDTH, DIM_ADJUSTER_HEIGHT, NULL, DLGITEM_SCROLLBAR, NULL)) + goto error; + x += DIM_ADJUSTER_SCR_WIDTH + DIM_HORIZONTAL_SPACING; + + if (dialog_add_trigger(dialog, dialog->item_count, TRIGGER_INITDIALOG, 0, adjuster_sb_setup, 0, MAKELONG(min_value, max_value), NULL, NULL)) + return 1; + + y += DIM_COMBO_ROW_HEIGHT + DIM_VERTICAL_SPACING * 2; + + dialog_finish_control(dialog, x, y); + return 0; + +error: + return 1; +} + + + + +//============================================================ +// get_seqselect_info +//============================================================ + +static seqselect_info *get_seqselect_info(HWND editwnd) +{ + LONG_PTR lp; + lp = GetWindowLongPtr(editwnd, GWLP_USERDATA); + return (seqselect_info *) lp; +} + + + +//============================================================================= +// seqselect_settext +// called from seqselect_start_read_from_main_thread, seqselect_setup +//============================================================================= +//#pragma GCC diagnostic push +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-value" +#endif + +static void seqselect_settext(HWND editwnd) +{ + seqselect_info *stuff; + std::string seqstring, buf; + + // the basics + stuff = get_seqselect_info(editwnd); + if (stuff == NULL) + return; // this should not happen - need to fix this + + // retrieve the seq name + seqstring = Machine->input().seq_name(*stuff->code); + + // change the text - avoid calls to SetWindowText() if we can + buf = win_get_window_text_utf8(editwnd); + if (buf != seqstring) + win_set_window_text_utf8(editwnd, seqstring.c_str()); + + // reset the selection + if (GetFocus() == editwnd) + { + DWORD start = 0, end = 0; + SendMessage(editwnd, EM_GETSEL, (WPARAM) (LPDWORD) &start, (LPARAM) (LPDWORD) &end); + if ((start != 0) || (end != buf.size())) + SendMessage(editwnd, EM_SETSEL, 0, -1); + } +} + +#ifdef __GNUC__ +#pragma GCC diagnostic error "-Wunused-value" +#endif + + +//============================================================ +// seqselect_start_read_from_main_thread +// called from seqselect_wndproc +//============================================================ + +static void seqselect_start_read_from_main_thread(void *param) +{ + seqselect_info *stuff; + + // get the basics + HWND editwnd = (HWND) param; + stuff = get_seqselect_info(editwnd); + + // are we currently polling? if so bail out + if (stuff->poll_state != SEQSELECT_STATE_NOT_POLLING) + return; + + // change the state + stuff->poll_state = SEQSELECT_STATE_POLLING; + + // the Win32 OSD code thinks that we are paused, we need to temporarily + // unpause ourselves or else we will block + int pause_count = 0; + while(Machine->paused() && !winwindow_ui_is_paused(*Machine)) + { + winwindow_ui_pause(*Machine, FALSE); + pause_count++; + } + + // start the polling + (*Machine).input().seq_poll_start(stuff->is_analog ? ITEM_CLASS_ABSOLUTE : ITEM_CLASS_SWITCH, NULL); + + while(stuff->poll_state == SEQSELECT_STATE_POLLING) + { + // poll + if (Machine->input().seq_poll()) + { + *stuff->code = Machine->input().seq_poll_final(); + seqselect_settext(editwnd); + } + } + + // we are no longer polling + stuff->poll_state = SEQSELECT_STATE_NOT_POLLING; + + // repause the OSD code + while(pause_count--) + winwindow_ui_pause(*Machine, TRUE); +} + + + +//============================================================ +// seqselect_stop_read_from_main_thread +// called from seqselect_wndproc +//============================================================ + +static void seqselect_stop_read_from_main_thread(void *param) +{ + HWND editwnd; + seqselect_info *stuff; + + // get the basics + editwnd = (HWND) param; + stuff = get_seqselect_info(editwnd); + + // stop the read + if (stuff->poll_state == SEQSELECT_STATE_POLLING) + stuff->poll_state = SEQSELECT_STATE_POLLING_COMPLETE; +} + + + +//============================================================ +// seqselect_wndproc +// called from seqselect_setup +//============================================================ + +static INT_PTR CALLBACK seqselect_wndproc(HWND editwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + seqselect_info *stuff; + INT_PTR result = 0; + BOOL call_baseclass = TRUE; + + stuff = get_seqselect_info(editwnd); + + switch(msg) + { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_CHAR: + case WM_KEYUP: + case WM_SYSKEYUP: + result = 1; + call_baseclass = FALSE; + break; + + case WM_SETFOCUS: + PostMessage(editwnd, SEQWM_SETFOCUS, 0, 0); + break; + + case WM_KILLFOCUS: + PostMessage(editwnd, SEQWM_KILLFOCUS, 0, 0); + break; + + case SEQWM_SETFOCUS: + // if we receive the focus, we should start a polling loop + seqselect_start_read_from_main_thread( (void *) editwnd); + break; + + case SEQWM_KILLFOCUS: + // when we abort the focus, end any current polling loop + seqselect_stop_read_from_main_thread( (void *) editwnd); + break; + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + SetFocus(editwnd); + SendMessage(editwnd, EM_SETSEL, 0, -1); + call_baseclass = FALSE; + result = 0; + break; + } + + if (call_baseclass) + result = call_windowproc(stuff->oldwndproc, editwnd, msg, wparam, lparam); + return result; +} + + + +//============================================================ +// seqselect_setup +// called from dialog_add_single_seqselect +//============================================================ + +static LRESULT seqselect_setup(dialog_box *dialog, HWND editwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + seqselect_info *stuff = (seqselect_info *) lparam; + LONG_PTR lp; + + lp = SetWindowLongPtr(editwnd, GWLP_WNDPROC, (LONG_PTR) seqselect_wndproc); + stuff->oldwndproc = (WNDPROC) lp; + SetWindowLongPtr(editwnd, GWLP_USERDATA, lparam); + seqselect_settext(editwnd); + return 0; +} + + + +//============================================================ +// seqselect_apply +// called from dialog_add_single_seqselect +//============================================================ + +static LRESULT seqselect_apply(dialog_box *dialog, HWND editwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + seqselect_info *stuff; + stuff = get_seqselect_info(editwnd); + + // store the settings + stuff->field->set_user_settings(stuff->settings); + + return 0; +} + +//============================================================ +// dialog_add_single_seqselect +// called from win_dialog_add_portselect +//============================================================ + +static int dialog_add_single_seqselect(struct _dialog_box *di, short x, short y, short cx, short cy, ioport_field *field, int is_analog, int seqtype) +{ + // write the dialog item + if (dialog_write_item(di, WS_CHILD | WS_VISIBLE | SS_ENDELLIPSIS | ES_CENTER | SS_SUNKEN, x, y, cx, cy, NULL, DLGITEM_EDIT, NULL)) + return 1; + + // allocate a seqselect_info + seqselect_info *stuff = new(seqselect_info); + //seqselect_info *stuff; + //stuff = global_alloc(seqselect_info); + if (!stuff) + return 1; + + // initialize the structure + memset(stuff, 0, sizeof(*stuff)); + field->get_user_settings(stuff->settings); + stuff->field = field; + stuff->pos = di->item_count; + stuff->is_analog = is_analog; + + // This next line is completely unsafe, but I do not know what to use ***************** + stuff->code = const_cast <input_seq*> (&field->seq( (input_seq_type) seqtype) ); + + if (dialog_add_trigger(di, di->item_count, TRIGGER_INITDIALOG, 0, seqselect_setup, di->item_count, (LPARAM) stuff, NULL, NULL)) + return 1; + if (dialog_add_trigger(di, di->item_count, TRIGGER_APPLY, 0, seqselect_apply, 0, 0, NULL, NULL)) + return 1; + return 0; +} + + + +//============================================================ +// win_dialog_add_seqselect +// called from customise_input, customise_miscinput +//============================================================ + +static int win_dialog_add_portselect(dialog_box *dialog, ioport_field *field) +{ + dialog_box *di = dialog; + short x; + short y; + const char *port_name; + const char *this_port_name; + char *s; + int seq; + int seq_count = 0; + const char *port_suffix[3]; + int seq_types[3]; + int is_analog[3]; + int len; + + port_name = field->name(); + if (!port_name) + printf("Blank port_name encountered in win_dialog_add_portselect\n"); + assert(port_name); + + if (field->type() > IPT_ANALOG_FIRST && field->type() < IPT_ANALOG_LAST) + { + seq_types[seq_count] = SEQ_TYPE_STANDARD; + port_suffix[seq_count] = " Analog"; + is_analog[seq_count] = TRUE; + seq_count++; + + seq_types[seq_count] = SEQ_TYPE_DECREMENT; + port_suffix[seq_count] = " Dec"; + is_analog[seq_count] = FALSE; + seq_count++; + + seq_types[seq_count] = SEQ_TYPE_INCREMENT; + port_suffix[seq_count] = " Inc"; + is_analog[seq_count] = FALSE; + seq_count++; + } + else + { + seq_types[seq_count] = SEQ_TYPE_STANDARD; + port_suffix[seq_count] = NULL; + is_analog[seq_count] = FALSE; + seq_count++; + } + + for (seq = 0; seq < seq_count; seq++) + { + // create our local name for this entry; also convert from + // MAME strings to wide strings + len = strlen(port_name); + s = (char *) alloca((len + (port_suffix[seq] ? strlen(port_suffix[seq]) : 0) + 1) * sizeof(*s)); + strcpy(s, port_name); + + if (port_suffix[seq]) + strcpy(s + len, port_suffix[seq]); + this_port_name = s; + + // no positions specified + dialog_new_control(di, &x, &y); + + if (dialog_write_item(di, WS_CHILD | WS_VISIBLE | SS_LEFT | SS_NOPREFIX, x, y, + dialog->layout->label_width, DIM_NORMAL_ROW_HEIGHT, this_port_name, DLGITEM_STATIC, NULL)) + return 1; + x += dialog->layout->label_width + DIM_HORIZONTAL_SPACING; + + if (dialog_add_single_seqselect(di, x, y, DIM_EDIT_WIDTH, DIM_NORMAL_ROW_HEIGHT, field, is_analog[seq], seq_types[seq])) + return 1; + y += DIM_VERTICAL_SPACING + DIM_NORMAL_ROW_HEIGHT; + x += DIM_EDIT_WIDTH + DIM_HORIZONTAL_SPACING; + + dialog_finish_control(di, x, y); + } + return 0; +} + + + +//============================================================ +// win_dialog_add_standard_buttons +//============================================================ + +static int win_dialog_add_standard_buttons(dialog_box *dialog) +{ + dialog_box *di = dialog; + short x; + short y; + + // Handle the case of an empty dialog box (size_x & size_y will be 0) + if (!di->size_x) + di->size_x = 3 * DIM_HORIZONTAL_SPACING + 2 * DIM_BUTTON_WIDTH; + if (!di->size_y) + di->size_y = DIM_VERTICAL_SPACING; + + // work out where cancel button goes + x = di->size_x - DIM_HORIZONTAL_SPACING - DIM_BUTTON_WIDTH; + y = di->size_y + DIM_VERTICAL_SPACING; + + // display cancel button + if (dialog_write_item(di, WS_CHILD | WS_VISIBLE | SS_LEFT, x, y, DIM_BUTTON_WIDTH, DIM_BUTTON_ROW_HEIGHT, DLGTEXT_CANCEL, DLGITEM_BUTTON, NULL)) + return 1; + + // work out where OK button goes + x -= DIM_HORIZONTAL_SPACING + DIM_BUTTON_WIDTH; + + // display OK button + if (dialog_write_item(di, WS_CHILD | WS_VISIBLE | SS_LEFT, x, y, DIM_BUTTON_WIDTH, DIM_BUTTON_ROW_HEIGHT, DLGTEXT_OK, DLGITEM_BUTTON, NULL)) + return 1; + + di->size_y += DIM_BUTTON_ROW_HEIGHT + DIM_VERTICAL_SPACING * 2; + + return 0; +} + + + +//============================================================ +// before_display_dialog +//============================================================ + +static void before_display_dialog(running_machine &machine) +{ + Machine = &machine; + winwindow_ui_pause(machine, TRUE); +} + + + +//============================================================ +// after_display_dialog +//============================================================ + +static void after_display_dialog(running_machine &machine) +{ + winwindow_ui_pause(machine, FALSE); +} + + + +//============================================================ +// win_dialog_runmodal +// called from the various customise_inputs functions +//============================================================ + +static void win_dialog_runmodal(running_machine &machine, HWND wnd, dialog_box *dialog) +{ + if (!dialog) + printf("Unexpected result in win_dialog_runmodal\n"); + assert(dialog); + + // finishing touches on the dialog + dialog_prime(dialog); + + // show the dialog + before_display_dialog(machine); + DialogBoxIndirectParamW(NULL, (const DLGTEMPLATE*)dialog->handle, wnd, (DLGPROC) dialog_proc, (LPARAM) dialog); + after_display_dialog(machine); +} + + + +//============================================================ +// win_file_dialog +// called from change_device +//============================================================ + +static BOOL win_file_dialog(running_machine &machine, HWND parent, win_file_dialog_type dlgtype, const char *filter, + const char *initial_dir, char *filename, size_t filename_len) +{ + win_open_file_name ofn; + BOOL result = FALSE; + + // set up the OPENFILENAME data structure + memset(&ofn, 0, sizeof(ofn)); + ofn.type = dlgtype; + ofn.owner = parent; + ofn.flags = OFN_EXPLORER | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; + ofn.filter = filter; + ofn.initial_directory = initial_dir; + + if (dlgtype == WIN_FILE_DIALOG_OPEN) + ofn.flags |= OFN_FILEMUSTEXIST; + + snprintf(ofn.filename, ARRAY_LENGTH(ofn.filename), "%s", filename); + + before_display_dialog(machine); + result = win_get_file_name_dialog(&ofn); + after_display_dialog(machine); + + snprintf(filename, filename_len, "%s", ofn.filename); + return result; +} + + + +//============================================================ +// customise_input +//============================================================ + +static void customise_input(running_machine &machine, HWND wnd, const char *title, int player, int inputclass) +{ + dialog_box *dlg; + int this_inputclass, this_player; + + /* create the dialog */ + dlg = win_dialog_init(title, NULL); + if (!dlg) + return; + + for (auto &port : machine.ioport().ports()) + { + for (ioport_field &field : port.second->fields()) + { + /* add if we match the group and we have a valid name */ + const char *name = field.name(); + this_inputclass = field.type_class(); + this_player = field.player(); + + if ((name) + && (field.enabled()) +//check me && ((field->type() == IPT_OTHER && field->name()) || (machine.ioport().type_group(field->type(), field->player()) != IPG_INVALID)) + && (this_player == player) + && (this_inputclass == inputclass)) + { + if (win_dialog_add_portselect(dlg, &field)) + goto done; + } + } + } + + /* ...and now add OK/Cancel */ + if (win_dialog_add_standard_buttons(dlg)) + goto done; + + /* ...and finally display the dialog */ + win_dialog_runmodal(machine, wnd, dlg); + +done: + if (dlg) + win_dialog_exit(dlg); +} + + + +//============================================================ +// customise_joystick +//============================================================ + +static void customise_joystick(running_machine &machine, HWND wnd, int joystick_num) +{ + customise_input(machine, wnd, "Joysticks/Controllers", joystick_num, INPUT_CLASS_CONTROLLER); +} + + + +//============================================================ +// customise_keyboard +//============================================================ + +static void customise_keyboard(running_machine &machine, HWND wnd) +{ + customise_input(machine, wnd, "Emulated Keyboard", 0, INPUT_CLASS_KEYBOARD); +} + + + +//=============================================================================================== +// check_for_miscinput +// (to decide if "Miscellaneous Inputs" menu item should show or not). +// We do this here because the core check has been broken for years (always returns false). +//=============================================================================================== + +static bool check_for_miscinput(running_machine &machine) +{ + int this_inputclass = 0; + + for (auto &port : machine.ioport().ports()) + { + for (ioport_field &field : port.second->fields()) + { + const char *name = field.name(); + this_inputclass = field.type_class(); + + /* add if we match the group and we have a valid name */ + if ((name) + && (field.enabled()) + && ((field.type() == IPT_OTHER && field.name()) || (machine.ioport().type_group(field.type(), field.player()) != IPG_INVALID)) + && (this_inputclass != INPUT_CLASS_CONTROLLER) + && (this_inputclass != INPUT_CLASS_KEYBOARD)) + { + return TRUE; + } + } + } + return FALSE; +} + + + +//============================================================ +// customise_miscinput +//============================================================ + +static void customise_miscinput(running_machine &machine, HWND wnd) +{ + dialog_box *dlg; + int this_inputclass; + const char *title = "Miscellaneous Inputs"; + + /* create the dialog */ + dlg = win_dialog_init(title, NULL); + if (!dlg) + return; + + for (auto &port : machine.ioport().ports()) + { + for (ioport_field &field : port.second->fields()) + { + const char *name = field.name(); + this_inputclass = field.type_class(); + + /* add if we match the group and we have a valid name */ + if ((name) + && (field.enabled()) + && ((field.type() == IPT_OTHER && field.name()) || (machine.ioport().type_group(field.type(), field.player()) != IPG_INVALID)) + && (this_inputclass != INPUT_CLASS_CONTROLLER) + && (this_inputclass != INPUT_CLASS_KEYBOARD)) + { + if (win_dialog_add_portselect(dlg, &field)) + goto done; + } + } + } + + /* ...and now add OK/Cancel */ + if (win_dialog_add_standard_buttons(dlg)) + goto done; + + /* ...and finally display the dialog */ + win_dialog_runmodal(machine, wnd, dlg); + +done: + if (dlg) + win_dialog_exit(dlg); +} + + + +//============================================================ +// storeval_inputport +// called from customise_switches +//============================================================ + +static void storeval_inputport(void *param, int val) +{ + ioport_field *field = (ioport_field *) param; + ioport_field::user_settings settings; + + field->get_user_settings(settings); + settings.value = (ioport_value) val; + field->set_user_settings(settings); +} + + + +//============================================================ +// customise_switches +//============================================================ + +static void customise_switches(running_machine &machine, HWND wnd, const char* title_string, UINT32 ipt_name) +{ + dialog_box *dlg; + ioport_field *afield; + ioport_setting *setting; + const char *switch_name = NULL; + ioport_field::user_settings settings; + + UINT32 type = 0; + + dlg = win_dialog_init(title_string, NULL); + if (!dlg) + return; + + for (auto &port : machine.ioport().ports()) + { + for (ioport_field &field : port.second->fields()) + { + type = field.type(); + + if (type == ipt_name) + { + switch_name = field.name(); + + field.get_user_settings(settings); + afield = &field; + if (win_dialog_add_combobox(dlg, switch_name, settings.value, storeval_inputport, (void *) afield)) + goto done; + + for (setting = field.settings().first(); setting; setting = setting->next()) + { + if (win_dialog_add_combobox_item(dlg, setting->name(), setting->value())) + goto done; + } + } + } + } + + if (win_dialog_add_standard_buttons(dlg)) + goto done; + + win_dialog_runmodal(machine, wnd, dlg); + +done: + if (dlg) + win_dialog_exit(dlg); +} + + + +//============================================================ +// customise_dipswitches +//============================================================ + +static void customise_dipswitches(running_machine &machine, HWND wnd) +{ + customise_switches(machine, wnd, "Dip Switches", IPT_DIPSWITCH); +} + + + +//============================================================ +// customise_configuration +//============================================================ + +static void customise_configuration(running_machine &machine, HWND wnd) +{ + customise_switches(machine, wnd, "Driver Configuration", IPT_CONFIG); +} + + + +//============================================================ +// customise_analogcontrols +//============================================================ + +enum +{ + ANALOG_ITEM_KEYSPEED, + ANALOG_ITEM_CENTERSPEED, + ANALOG_ITEM_REVERSE, + ANALOG_ITEM_SENSITIVITY +}; + + + +static void store_analogitem(void *param, int val, int selected_item) +{ + ioport_field *field = (ioport_field *) param; + ioport_field::user_settings settings; + + field->get_user_settings(settings); + + switch(selected_item) + { + case ANALOG_ITEM_KEYSPEED: + settings.delta = val; + break; + case ANALOG_ITEM_CENTERSPEED: + settings.centerdelta = val; + break; + case ANALOG_ITEM_REVERSE: + settings.reverse = val; + break; + case ANALOG_ITEM_SENSITIVITY: + settings.sensitivity = val; + break; + } + field->set_user_settings(settings); +} + + + +static void store_delta(void *param, int val) +{ + store_analogitem(param, val, ANALOG_ITEM_KEYSPEED); +} + + + +static void store_centerdelta(void *param, int val) +{ + store_analogitem(param, val, ANALOG_ITEM_CENTERSPEED); +} + + + +static void store_reverse(void *param, int val) +{ + store_analogitem(param, val, ANALOG_ITEM_REVERSE); +} + + + +static void store_sensitivity(void *param, int val) +{ + store_analogitem(param, val, ANALOG_ITEM_SENSITIVITY); +} + + + +static int port_type_is_analog(int type) +{ + return (type > IPT_ANALOG_FIRST && type < IPT_ANALOG_LAST); +} + + + +static void customise_analogcontrols(running_machine &machine, HWND wnd) +{ + dialog_box *dlg; + ioport_field::user_settings settings; + ioport_field *afield; + const char *name; + char buf[255]; + static const struct dialog_layout layout = { 120, 52 }; + + dlg = win_dialog_init("Analog Controls", &layout); + if (!dlg) + return; + + for (auto &port : machine.ioport().ports()) + { + for (ioport_field &field : port.second->fields()) + { + if (port_type_is_analog(field.type())) + { + field.get_user_settings(settings); + name = field.name(); + afield = &field; + + _snprintf(buf, ARRAY_LENGTH(buf), "%s %s", name, "Digital Speed"); + if (win_dialog_add_adjuster(dlg, buf, settings.delta, 1, 255, FALSE, store_delta, (void *) afield)) + goto done; + + _snprintf(buf, ARRAY_LENGTH(buf), "%s %s", name, "Autocenter Speed"); + if (win_dialog_add_adjuster(dlg, buf, settings.centerdelta, 0, 255, FALSE, store_centerdelta, (void *) afield)) + goto done; + + _snprintf(buf, ARRAY_LENGTH(buf), "%s %s", name, "Reverse"); + if (win_dialog_add_combobox(dlg, buf, settings.reverse ? 1 : 0, store_reverse, (void *) afield)) + goto done; + if (win_dialog_add_combobox_item(dlg, "Off", 0)) + goto done; + if (win_dialog_add_combobox_item(dlg, "On", 1)) + goto done; + + _snprintf(buf, ARRAY_LENGTH(buf), "%s %s", name, "Sensitivity"); + if (win_dialog_add_adjuster(dlg, buf, settings.sensitivity, 1, 255, TRUE, store_sensitivity, (void *) afield)) + goto done; + } + } + } + + if (win_dialog_add_standard_buttons(dlg)) + goto done; + + win_dialog_runmodal(machine, wnd, dlg); + +done: + if (dlg) + win_dialog_exit(dlg); +} + + +//============================================================ +// win_dirname +// called from state_dialog +//============================================================ + +static char *win_dirname(const char *filename) +{ + char *dirname; + char *c; + + // NULL begets NULL + if (!filename) + return NULL; + + // allocate space for it + dirname = (char*)malloc(strlen(filename) + 1); + if (!dirname) + return NULL; + + // copy in the name + strcpy(dirname, filename); + + // search backward for a slash or a colon + for (c = dirname + strlen(dirname) - 1; c >= dirname; c--) + if (*c == '\\' || *c == '/' || *c == ':') + { + // found it: NULL terminate and return + *(c + 1) = 0; + return dirname; + } + + // otherwise, return an empty string + dirname[0] = 0; + return dirname; +} + + +//============================================================ +// state_dialog +// called when loading or saving a state +//============================================================ + +static void state_dialog(HWND wnd, win_file_dialog_type dlgtype, DWORD fileproc_flags, bool is_load, running_machine &machine) +{ + win_open_file_name ofn; + char *dir = NULL; + int result = 0; + + if (state_filename[0]) + dir = win_dirname(state_filename); + + memset(&ofn, 0, sizeof(ofn)); + ofn.type = dlgtype; + ofn.owner = wnd; + ofn.flags = OFN_EXPLORER | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | fileproc_flags; + ofn.filter = "State Files (*.sta)|*.sta|All Files (*.*)|*.*"; + ofn.initial_directory = dir; + + if (!core_filename_ends_with(ofn.filename, "sta")) + snprintf(ofn.filename, ARRAY_LENGTH(ofn.filename), "%s.sta", state_filename); + else + snprintf(ofn.filename, ARRAY_LENGTH(ofn.filename), "%s", state_filename); + + result = win_get_file_name_dialog(&ofn); + + if (result) + { + // the core doesn't add the extension if it's an absolute path + if (osd_is_absolute_path(ofn.filename) && !core_filename_ends_with(ofn.filename, "sta")) + snprintf(state_filename, ARRAY_LENGTH(state_filename), "%s.sta", ofn.filename); + else + snprintf(state_filename, ARRAY_LENGTH(state_filename), "%s", ofn.filename); + + if (is_load) + machine.schedule_load(state_filename); + else + machine.schedule_save(state_filename); + } + + if (dir) + free(dir); +} + + + +static void state_load(HWND wnd, running_machine &machine) +{ + state_dialog(wnd, WIN_FILE_DIALOG_OPEN, OFN_FILEMUSTEXIST, TRUE, machine); +} + +static void state_save_as(HWND wnd, running_machine &machine) +{ + state_dialog(wnd, WIN_FILE_DIALOG_SAVE, OFN_OVERWRITEPROMPT, FALSE, machine); +} + +static void state_save(running_machine &machine) +{ + machine.schedule_save(state_filename); +} + + + +//============================================================ +// copy_extension_list +//============================================================ + +static void copy_extension_list(std::string &dest, const char *extensions) +{ + // our extension lists are comma delimited; Win32 expects to see lists + // delimited by semicolons + char const *s = extensions; + while (*s) + { + // append a semicolon if not at the beginning + if (s != extensions) + dest.push_back(';'); + + // append ".*" + dest.append("*."); + + // append the file extension + while (*s && (*s != ',')) + dest.push_back(*s++); + + // if we found a comma, advance + while(*s == ',') + s++; + } +} + + + +//============================================================ +// add_filter_entry +//============================================================ + +static void add_filter_entry(std::string &dest, const char *description, const char *extensions) +{ + // add the description + dest.append(description); + dest.append(" ("); + + // add the extensions to the description + copy_extension_list(dest, extensions); + + // add the trailing rparen and '|' character + dest.append(")|"); + + // now add the extension list itself + copy_extension_list(dest, extensions); + + // append a '|' + dest.append("|"); +} + + + +//============================================================ +// build_generic_filter +//============================================================ + +static void build_generic_filter(device_image_interface *img, bool is_save, std::string &filter) +{ + std::string file_extension = img->file_extensions(); + + if (!is_save) + file_extension.append(",zip,7z"); + + add_filter_entry(filter, "Common image types", file_extension.c_str()); + + filter.append("All files (*.*)|*.*|"); + + if (!is_save) + filter.append("Compressed Images (*.zip;*.7z)|*.zip;*.7z|"); +} + + + +//============================================================ +// change_device +// open a dialog box to open or create a software file +//============================================================ + +static void change_device(HWND wnd, device_image_interface *image, bool is_save) +{ + std::string filter; + char filename[MAX_PATH]; + const char *initial_dir; + BOOL result = 0; + int create_format = 0; + util::option_resolution *create_args = NULL; + + // get the file + if (image->exists()) + { + const char *imgname; + imgname = image->basename(); + snprintf(filename, ARRAY_LENGTH(filename), "%s", imgname); + } + else + filename[0] = '\0'; + + // get the working directory, but if it is ".", then use the one specified in swpath + char *working = 0; + std::string dst; + osd_get_full_path(dst,"."); // turn local directory into full path + initial_dir = image->working_directory().c_str(); // get working directory from diimage.cpp + // if . use swpath + if (strcmp(dst.c_str(), initial_dir) == 0) // same? + initial_dir = software_dir; + + // remove any trailing backslash + working = core_strdup(initial_dir); + int temp = strlen(working) - 1; + if (temp > 2) + if (working[temp] == '\\') + { + working[temp] = '\0'; + initial_dir = working; + } + +// NOTE: the working directory can come from the .cfg file. If it's wrong delete the cfg. +//printf("%s = %s = %s = %s\n",dst,working,initial_dir,software_dir); + + // build a normal filter + build_generic_filter(image, is_save, filter); + + // display the dialog + result = win_file_dialog(image->device().machine(), wnd, is_save ? WIN_FILE_DIALOG_SAVE : WIN_FILE_DIALOG_OPEN, filter.c_str(), initial_dir, filename, ARRAY_LENGTH(filename)); + if (result) + { + // mount the image + if (is_save) + (image_error_t)image->create(filename, image->device_get_indexed_creatable_format(create_format), create_args); + else + (image_error_t)image->load( filename); + + // no need to check the returnvalue and show a messagebox anymore. + // a UI message will now be generated by the image code + } +} + + + +//============================================================ +// pause +//============================================================ + +static void pause(running_machine &machine) +{ + if (!winwindow_ui_is_paused(machine)) + machine.pause(); + else + machine.resume(); +} + + + +//============================================================ +// get_menu_item_string +//============================================================ + +static BOOL get_menu_item_string(HMENU menu, UINT item, BOOL by_position, HMENU *sub_menu, LPTSTR buffer, size_t buffer_len) +{ + MENUITEMINFO mii; + + // clear out results + memset(buffer, '\0', sizeof(*buffer) * buffer_len); + if (sub_menu) + *sub_menu = NULL; + + // prepare MENUITEMINFO structure + memset(&mii, 0, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_TYPE | (sub_menu ? MIIM_SUBMENU : 0); + mii.dwTypeData = buffer; + mii.cch = buffer_len; + + // call GetMenuItemInfo() + if (!GetMenuItemInfo(menu, item, by_position, &mii)) + return FALSE; + + // return results + if (sub_menu) + *sub_menu = mii.hSubMenu; + if (mii.fType == MFT_SEPARATOR) + _sntprintf(buffer, buffer_len, TEXT("-")); + return TRUE; +} + + + +//============================================================ +// find_sub_menu +//============================================================ + +static HMENU find_sub_menu(HMENU menu, const char *menutext, bool create_sub_menu) +{ + TCHAR buf[128]; + HMENU sub_menu; + + while(*menutext) + { + TCHAR *t_menutext = ui_wstring_from_utf8(menutext); + + int i = -1; + do + { + if (!get_menu_item_string(menu, ++i, TRUE, &sub_menu, buf, ARRAY_LENGTH(buf))) + { + free(t_menutext); + return NULL; + } + } + while(_tcscmp(t_menutext, buf)); + + free(t_menutext); + + if (!sub_menu && create_sub_menu) + { + MENUITEMINFO mii; + memset(&mii, 0, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_SUBMENU; + mii.hSubMenu = CreateMenu(); + if (!SetMenuItemInfo(menu, i, TRUE, &mii)) + { + i = GetLastError(); + return NULL; + } + sub_menu = mii.hSubMenu; + } + menu = sub_menu; + if (!menu) + return NULL; + menutext += strlen(menutext) + 1; + } + return menu; +} + + + +//============================================================ +// set_command_state +//============================================================ + +static void set_command_state(HMENU menu_bar, UINT command, UINT state) +{ + BOOL result = 0; + + MENUITEMINFO mii; + + memset(&mii, 0, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STATE; + mii.fState = state; + result = SetMenuItemInfo(menu_bar, command, FALSE, &mii); + result++; +} + + + + +//============================================================ +// remove_menu_items +//============================================================ + +static void remove_menu_items(HMENU menu) +{ + while(RemoveMenu(menu, 0, MF_BYPOSITION)) + ; +} + + + +//============================================================ +// setup_joystick_menu +//============================================================ + +static void setup_joystick_menu(running_machine &machine, HMENU menu_bar) +{ + int joystick_count = 0; + HMENU joystick_menu; + int i = 0; + char buf[256]; + int child_count = 0; + + joystick_menu = find_sub_menu(menu_bar, "&Options\0&Joysticks\0", TRUE); + if (!joystick_menu) + return; + + // set up joystick menu + joystick_count = machine.ioport().count_players(); + if (joystick_count > 0) + { + for (i = 0; i < joystick_count; i++) + { + snprintf(buf, ARRAY_LENGTH(buf), "Joystick %i", i + 1); + win_append_menu_utf8(joystick_menu, MF_STRING, ID_JOYSTICK_0 + i, buf); + child_count++; + } + } + + // last but not least, enable the joystick menu (or not) + set_command_state(menu_bar, ID_OPTIONS_JOYSTICKS, child_count ? MFS_ENABLED : MFS_GRAYED); +} + + + +//============================================================ +// is_windowed +//============================================================ + +static int is_windowed(void) +{ + return video_config.windowed; +} + + + +//============================================================ +// frameskip_level_count +//============================================================ + +static int frameskip_level_count(running_machine &machine) +{ + static int count = -1; + + if (count < 0) + { + int frameskip_max = 10; + count = frameskip_max + 1; + } + return count; +} + + + +//============================================================ +// prepare_menus +//============================================================ + +static void prepare_menus(HWND wnd) +{ + int i = 0; + char buf[MAX_PATH]; + TCHAR t_buf[MAX_PATH]; + const char *s; + HMENU menu_bar; + HMENU video_menu; + HMENU device_menu; + HMENU sub_menu; + UINT_PTR new_item; + UINT flags_for_exists = 0; + UINT flags_for_writing = 0; + bool has_config = 0, has_dipswitch = 0, has_keyboard = 0, has_misc = 0, has_analog = 0; + int frameskip = 0; + int orientation = 0; + int speed = 0; + LONG_PTR ptr = GetWindowLongPtr(wnd, GWLP_USERDATA); + win_window_info *window = (win_window_info *)ptr; + const char *view_name; + int view_index = 0; + ioport_field::user_settings settings; + + menu_bar = GetMenu(wnd); + if (!menu_bar) + return; + + if (!joystick_menu_setup) + { + setup_joystick_menu(window->machine(), menu_bar); + joystick_menu_setup = 1; + } + + frameskip = window->machine().video().frameskip(); + + orientation = window->m_target->orientation(); + + speed = window->machine().video().throttled() ? window->machine().video().speed_factor() : 0; + + has_config = window->machine().ioport().type_class_present(INPUT_CLASS_CONFIG); + has_dipswitch = window->machine().ioport().type_class_present(INPUT_CLASS_DIPSWITCH); + has_keyboard = window->machine().ioport().type_class_present(INPUT_CLASS_KEYBOARD); + has_misc = check_for_miscinput(window->machine()); + + has_analog = 0; + for (auto &port : window->machine().ioport().ports()) + { + for (ioport_field &field : port.second->fields()) + { + if (port_type_is_analog(field.type())) + { + has_analog = 1; + break; + } + } + } + + if (window->machine().system().flags & MACHINE_SUPPORTS_SAVE) + { + set_command_state(menu_bar, ID_FILE_LOADSTATE_NEWUI, MFS_ENABLED); + set_command_state(menu_bar, ID_FILE_SAVESTATE_AS, MFS_ENABLED); + set_command_state(menu_bar, ID_FILE_SAVESTATE, state_filename[0] != '\0' ? MFS_ENABLED : MFS_GRAYED); + } + else + { + set_command_state(menu_bar, ID_FILE_LOADSTATE_NEWUI, MFS_GRAYED); + set_command_state(menu_bar, ID_FILE_SAVESTATE_AS, MFS_GRAYED); + set_command_state(menu_bar, ID_FILE_SAVESTATE, MFS_GRAYED); + } + + set_command_state(menu_bar, ID_EDIT_PASTE, window->machine().ioport().natkeyboard().can_post() ? MFS_ENABLED : MFS_GRAYED); + + set_command_state(menu_bar, ID_OPTIONS_PAUSE, winwindow_ui_is_paused(window->machine()) ? MFS_CHECKED : MFS_ENABLED); + set_command_state(menu_bar, ID_OPTIONS_CONFIGURATION, has_config ? MFS_ENABLED : MFS_GRAYED); + set_command_state(menu_bar, ID_OPTIONS_DIPSWITCHES, has_dipswitch ? MFS_ENABLED : MFS_GRAYED); + set_command_state(menu_bar, ID_OPTIONS_MISCINPUT, has_misc ? MFS_ENABLED : MFS_GRAYED); + set_command_state(menu_bar, ID_OPTIONS_ANALOGCONTROLS, has_analog ? MFS_ENABLED : MFS_GRAYED); + set_command_state(menu_bar, ID_FILE_FULLSCREEN, !is_windowed() ? MFS_CHECKED : MFS_ENABLED); + set_command_state(menu_bar, ID_OPTIONS_TOGGLEFPS, mame_machine_manager::instance()->ui().show_fps() ? MFS_CHECKED : MFS_ENABLED); + set_command_state(menu_bar, ID_FILE_UIACTIVE, has_keyboard ? (window->machine().ui_active() ? MFS_CHECKED : MFS_ENABLED): MFS_CHECKED | MFS_GRAYED); + + set_command_state(menu_bar, ID_KEYBOARD_EMULATED, has_keyboard ? (!window->machine().ioport().natkeyboard().in_use() ? MFS_CHECKED : MFS_ENABLED): MFS_GRAYED); + set_command_state(menu_bar, ID_KEYBOARD_NATURAL, (has_keyboard && window->machine().ioport().natkeyboard().can_post()) ? (window->machine().ioport().natkeyboard().in_use() ? MFS_CHECKED : MFS_ENABLED): MFS_GRAYED); + set_command_state(menu_bar, ID_KEYBOARD_CUSTOMIZE, has_keyboard ? MFS_ENABLED : MFS_GRAYED); + + set_command_state(menu_bar, ID_VIDEO_ROTATE_0, (orientation == ROT0) ? MFS_CHECKED : MFS_ENABLED); + set_command_state(menu_bar, ID_VIDEO_ROTATE_90, (orientation == ROT90) ? MFS_CHECKED : MFS_ENABLED); + set_command_state(menu_bar, ID_VIDEO_ROTATE_180, (orientation == ROT180) ? MFS_CHECKED : MFS_ENABLED); + set_command_state(menu_bar, ID_VIDEO_ROTATE_270, (orientation == ROT270) ? MFS_CHECKED : MFS_ENABLED); + + set_command_state(menu_bar, ID_THROTTLE_50, (speed == 500) ? MFS_CHECKED : MFS_ENABLED); + set_command_state(menu_bar, ID_THROTTLE_100, (speed == 1000) ? MFS_CHECKED : MFS_ENABLED); + set_command_state(menu_bar, ID_THROTTLE_200, (speed == 2000) ? MFS_CHECKED : MFS_ENABLED); + set_command_state(menu_bar, ID_THROTTLE_500, (speed == 5000) ? MFS_CHECKED : MFS_ENABLED); + set_command_state(menu_bar, ID_THROTTLE_1000, (speed == 10000) ? MFS_CHECKED : MFS_ENABLED); + set_command_state(menu_bar, ID_THROTTLE_UNTHROTTLED, (speed == 0) ? MFS_CHECKED : MFS_ENABLED); + + set_command_state(menu_bar, ID_FRAMESKIP_AUTO, (frameskip < 0) ? MFS_CHECKED : MFS_ENABLED); + for (i = 0; i < frameskip_level_count(window->machine()); i++) + set_command_state(menu_bar, ID_FRAMESKIP_0 + i, (frameskip == i) ? MFS_CHECKED : MFS_ENABLED); + + // set up screens in video menu + video_menu = find_sub_menu(menu_bar, "&Options\0&Video\0", FALSE); + do + { + get_menu_item_string(video_menu, 0, TRUE, NULL, t_buf, ARRAY_LENGTH(t_buf)); + if (_tcscmp(t_buf, TEXT("-"))) + RemoveMenu(video_menu, 0, MF_BYPOSITION); + } + while(_tcscmp(t_buf, TEXT("-"))); + i = 0; + view_index = window->m_target->view(); + while((view_name = window->m_target->view_name(i))) + { + TCHAR *t_view_name = ui_wstring_from_utf8(view_name); + InsertMenu(video_menu, i, MF_BYPOSITION | (i == view_index ? MF_CHECKED : 0), ID_VIDEO_VIEW_0 + i, t_view_name); + free(t_view_name); + i++; + } + + // set up device menu; first remove all existing menu items + device_menu = find_sub_menu(menu_bar, "&Media\0", FALSE); + remove_menu_items(device_menu); + + int cnt = 0; + // then set up the actual devices + for (device_image_interface &img : image_interface_iterator(window->machine().root_device())) + { + new_item = ID_DEVICE_0 + (cnt * DEVOPTION_MAX); + flags_for_exists = MF_STRING; + + if (!img.exists()) + flags_for_exists |= MF_GRAYED; + + flags_for_writing = flags_for_exists; + if (img.is_readonly()) + flags_for_writing |= MF_GRAYED; + + sub_menu = CreateMenu(); + win_append_menu_utf8(sub_menu, MF_STRING, new_item + DEVOPTION_OPEN, "Mount File..."); + + if (img.is_creatable()) + win_append_menu_utf8(sub_menu, MF_STRING, new_item + DEVOPTION_CREATE, "Create..."); + + win_append_menu_utf8(sub_menu, flags_for_exists, new_item + DEVOPTION_CLOSE, "Unmount"); + + if (img.device().type() == CASSETTE) + { + cassette_state state; + state = (cassette_state)(img.exists() ? (dynamic_cast<cassette_image_device*>(&img.device())->get_state() & CASSETTE_MASK_UISTATE) : CASSETTE_STOPPED); + win_append_menu_utf8(sub_menu, MF_SEPARATOR, 0, NULL); + win_append_menu_utf8(sub_menu, flags_for_exists | ((state == CASSETTE_STOPPED) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_STOPPAUSE, "Pause/Stop"); + win_append_menu_utf8(sub_menu, flags_for_exists | ((state == CASSETTE_PLAY) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_PLAY, "Play"); + win_append_menu_utf8(sub_menu, flags_for_writing | ((state == CASSETTE_RECORD) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_RECORD, "Record"); + win_append_menu_utf8(sub_menu, flags_for_exists, new_item + DEVOPTION_CASSETTE_REWIND, "Rewind"); + win_append_menu_utf8(sub_menu, flags_for_exists, new_item + DEVOPTION_CASSETTE_FASTFORWARD, "Fast Forward"); + } + s = img.exists() ? img.filename() : "[empty slot]"; + + snprintf(buf, ARRAY_LENGTH(buf), "%s: %s", img.device().name(), s); + win_append_menu_utf8(device_menu, MF_POPUP, (UINT_PTR)sub_menu, buf); + + cnt++; + } +} + + + +//============================================================ +// set_speed +//============================================================ + +static void set_speed(running_machine &machine, int speed) +{ + std::string error_string; + if (speed != 0) + { + machine.video().set_speed_factor(speed); + machine.options().emu_options::set_value(OPTION_SPEED, speed / 1000, OPTION_PRIORITY_CMDLINE, error_string); + } + + machine.video().set_throttled(speed != 0); + machine.options().emu_options::set_value(OPTION_THROTTLE, (speed != 0), OPTION_PRIORITY_CMDLINE, error_string); +} + + + +//============================================================ +// win_toggle_menubar +//============================================================ + +static void win_toggle_menubar(void) +{ + LONG width_diff = 0; + LONG height_diff = 0; + DWORD style = 0, exstyle = 0; + HWND hwnd = 0; + HMENU menu = 0; + + for (auto window : osd_common_t::s_window_list) + { + RECT before_rect = { 100, 100, 200, 200 }; + RECT after_rect = { 100, 100, 200, 200 }; + + hwnd = std::static_pointer_cast<win_window_info>(window)->platform_window(); + + // get current menu + menu = GetMenu(hwnd); + + // get before rect + style = GetWindowLong(hwnd, GWL_STYLE); + exstyle = GetWindowLong(hwnd, GWL_EXSTYLE); + AdjustWindowRectEx(&before_rect, style, menu ? TRUE : FALSE, exstyle); + + // toggle the menu + if (menu) + { + SetProp(hwnd, TEXT("menu"), (HANDLE) menu); + menu = NULL; + } + else + menu = (HMENU) GetProp(hwnd, TEXT("menu")); + + SetMenu(hwnd, menu); + + // get after rect, and width/height diff + AdjustWindowRectEx(&after_rect, style, menu ? TRUE : FALSE, exstyle); + width_diff = (after_rect.right - after_rect.left) - (before_rect.right - before_rect.left); + height_diff = (after_rect.bottom - after_rect.top) - (before_rect.bottom - before_rect.top); + + if (is_windowed()) + { + RECT window_rect; + GetWindowRect(hwnd, &window_rect); + SetWindowPos(hwnd, HWND_TOP, 0, 0, window_rect.right - window_rect.left + width_diff, window_rect.bottom - window_rect.top + height_diff, SWP_NOMOVE | SWP_NOZORDER); + } + + RedrawWindow(hwnd, NULL, NULL, 0); + } +} + + + +//============================================================ +// device_command +// This handles all options under the "Media" dropdown +//============================================================ + +static void device_command(HWND wnd, device_image_interface *img, int devoption) +{ + switch(devoption) + { + case DEVOPTION_OPEN: + change_device(wnd, img, FALSE); + break; + + case DEVOPTION_CREATE: + change_device(wnd, img, TRUE); + break; + + case DEVOPTION_CLOSE: + img->unload(); + break; + + default: + if (img->device().type() == CASSETTE) + { + cassette_image_device* cassette = dynamic_cast<cassette_image_device*>(&img->device()); + + switch(devoption) + { + case DEVOPTION_CASSETTE_STOPPAUSE: + cassette->change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE); + break; + + case DEVOPTION_CASSETTE_PLAY: + cassette->change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE); + break; + + case DEVOPTION_CASSETTE_RECORD: + cassette->change_state(CASSETTE_RECORD, CASSETTE_MASK_UISTATE); + break; + + case DEVOPTION_CASSETTE_REWIND: + cassette->seek(-60.0, SEEK_CUR); + break; + + case DEVOPTION_CASSETTE_FASTFORWARD: + cassette->seek(+60.0, SEEK_CUR); + break; + } + } + break; + } +} + + + +//============================================================ +// help_display +//============================================================ + +static void help_display(HWND wnd, const char *chapter) +{ + typedef HWND (WINAPI *htmlhelpproc)(HWND hwndCaller, LPCTSTR pszFile, UINT uCommand, DWORD_PTR dwData); + static htmlhelpproc htmlhelp; + static DWORD htmlhelp_cookie; + LPCSTR htmlhelp_funcname; + + if (htmlhelp == NULL) + { +#ifdef UNICODE + htmlhelp_funcname = "HtmlHelpW"; +#else + htmlhelp_funcname = "HtmlHelpA"; +#endif + htmlhelp = (htmlhelpproc) GetProcAddress(LoadLibrary(TEXT("hhctrl.ocx")), htmlhelp_funcname); + if (!htmlhelp) + return; + htmlhelp(NULL, NULL, 28 /*HH_INITIALIZE*/, (DWORD_PTR) &htmlhelp_cookie); + } + + // if full screen, turn it off + if (!is_windowed()) + winwindow_toggle_full_screen(); + + TCHAR *t_chapter = ui_wstring_from_utf8(chapter); +// htmlhelp(wnd, t_chapter, 0 /*HH_DISPLAY_TOPIC*/, 0); +// TCHAR *szSite = new TCHAR[100]; +// _tcscpy(szSite, TEXT("http://messui.the-chronicles.org/onlinehelp/")); +// _tcscat(szSite, t_chapter); +// _tcscat(szSite, TEXT(".html")); +// ShellExecute(wnd, TEXT("open"), TEXT("http://www.microsoft.com/directx"), TEXT(""), NULL, SW_SHOWNORMAL); + ShellExecute(wnd, TEXT("open"), t_chapter, TEXT(""), NULL, SW_SHOWNORMAL); + free(t_chapter); +// free(szSite); +} + + + +//============================================================ +// help_about_mess +//============================================================ + +static void help_about_mess(HWND wnd) +{ + //help_display(wnd, "mess.chm::/windows/main.htm"); //doesnt do anything + //help_display(wnd, "mess.chm"); + help_display(wnd, "http://mamedev.org/"); +} + + + +//============================================================ +// help_about_thissystem +//============================================================ + +static void help_about_thissystem(running_machine &machine, HWND wnd) +{ + char buf[100]; +// snprintf(buf, ARRAY_LENGTH(buf), "mess.chm::/sysinfo/%s.htm", machine.system().name); +// snprintf(buf, ARRAY_LENGTH(buf), "http://messui.the-chronicles.org/onlinehelp/%s.html", machine.system().name); + snprintf(buf, ARRAY_LENGTH(buf), "http://www.progettoemma.net/mess/system.php?machine=%s", machine.system().name); + help_display(wnd, buf); +} + + + +//============================================================ +// decode_deviceoption +//============================================================ + +static device_image_interface *decode_deviceoption(running_machine &machine, int command, int *devoption) +{ + command -= ID_DEVICE_0; + int absolute_index = command / DEVOPTION_MAX; + + if (devoption) + *devoption = command % DEVOPTION_MAX; + + image_interface_iterator iter(machine.root_device()); + return iter.byindex(absolute_index); +} + + + +//============================================================ +// set_window_orientation +//============================================================ + +static void set_window_orientation(win_window_info *window, int orientation) +{ + window->m_target->set_orientation(orientation); + if (window->m_target->is_ui_target()) + { + render_container::user_settings settings; + window->machine().render().ui_container().get_user_settings(settings); + settings.m_orientation = orientation; + window->machine().render().ui_container().set_user_settings(settings); + } + window->update(); +} + + + +//============================================================ +// pause_for_command +//============================================================ + +static int pause_for_command(UINT command) +{ + // we really should be more conservative and only pause for commands + // that do dialog stuff + return (command != ID_OPTIONS_PAUSE); +} + + + +//============================================================ +// invoke_command +//============================================================ + +static bool invoke_command(HWND wnd, UINT command) +{ + std::string error_string; + bool handled = TRUE; + int dev_command = 0; + device_image_interface *img; + LONG_PTR ptr = GetWindowLongPtr(wnd, GWLP_USERDATA); + win_window_info *window = (win_window_info *)ptr; + ioport_field::user_settings settings; + + // pause while invoking certain commands + if (pause_for_command(command)) + winwindow_ui_pause(window->machine(), TRUE); + + switch(command) + { + case ID_FILE_LOADSTATE_NEWUI: + state_load(wnd, window->machine()); + break; + + case ID_FILE_SAVESTATE: + state_save(window->machine()); + break; + + case ID_FILE_SAVESTATE_AS: + state_save_as(wnd, window->machine()); + break; + + case ID_FILE_SAVESCREENSHOT: + window->machine().video().save_active_screen_snapshots(); + break; + + case ID_FILE_UIACTIVE: + window->machine().set_ui_active(!window->machine().ui_active()); + break; + + case ID_FILE_EXIT_NEWUI: + window->machine().schedule_exit(); + break; + + case ID_EDIT_PASTE: + PostMessage(wnd, WM_PASTE, 0, 0); + break; + + case ID_KEYBOARD_NATURAL: + window->machine().ioport().natkeyboard().set_in_use(TRUE); + break; + + case ID_KEYBOARD_EMULATED: + window->machine().ioport().natkeyboard().set_in_use(FALSE); + break; + + case ID_KEYBOARD_CUSTOMIZE: + customise_keyboard(window->machine(), wnd); + break; + + case ID_VIDEO_ROTATE_0: + set_window_orientation(window, ROT0); + break; + + case ID_VIDEO_ROTATE_90: + set_window_orientation(window, ROT90); + break; + + case ID_VIDEO_ROTATE_180: + set_window_orientation(window, ROT180); + break; + + case ID_VIDEO_ROTATE_270: + set_window_orientation(window, ROT270); + break; + + case ID_OPTIONS_PAUSE: + pause(window->machine()); + break; + + case ID_OPTIONS_HARDRESET: + window->machine().schedule_hard_reset(); + break; + + case ID_OPTIONS_SOFTRESET: + window->machine().schedule_soft_reset(); + break; + + case ID_OPTIONS_CONFIGURATION: + customise_configuration(window->machine(), wnd); + break; + + case ID_OPTIONS_DIPSWITCHES: + customise_dipswitches(window->machine(), wnd); + break; + + case ID_OPTIONS_MISCINPUT: + customise_miscinput(window->machine(), wnd); + break; + + case ID_OPTIONS_ANALOGCONTROLS: + customise_analogcontrols(window->machine(), wnd); + break; + + case ID_FILE_OLDUI: + mame_machine_manager::instance()->ui().show_menu(); + break; + + case ID_FILE_FULLSCREEN: + winwindow_toggle_full_screen(); + break; + + case ID_OPTIONS_TOGGLEFPS: + mame_machine_manager::instance()->ui().set_show_fps(!mame_machine_manager::instance()->ui().show_fps()); + break; + + case ID_OPTIONS_USEMOUSE: + { + // FIXME +// extern int win_use_mouse; +// win_use_mouse = !win_use_mouse; + } + break; + + case ID_FILE_TOGGLEMENUBAR: + win_toggle_menubar(); + break; + + case ID_FRAMESKIP_AUTO: + window->machine().video().set_frameskip(-1); + window->machine().options().emu_options::set_value(OPTION_AUTOFRAMESKIP, 1, OPTION_PRIORITY_CMDLINE, error_string); + break; + + case ID_HELP_ABOUT_NEWUI: + help_about_mess(wnd); + break; + + case ID_HELP_ABOUTSYSTEM: + help_about_thissystem(window->machine(), wnd); + break; + + case ID_THROTTLE_50: + set_speed(window->machine(), 500); + break; + + case ID_THROTTLE_100: + set_speed(window->machine(), 1000); + break; + + case ID_THROTTLE_200: + set_speed(window->machine(), 2000); + break; + + case ID_THROTTLE_500: + set_speed(window->machine(), 5000); + break; + + case ID_THROTTLE_1000: + set_speed(window->machine(), 10000); + break; + + case ID_THROTTLE_UNTHROTTLED: + set_speed(window->machine(), 0); + break; + + default: + if ((command >= ID_FRAMESKIP_0) && (command < ID_FRAMESKIP_0 + frameskip_level_count(window->machine()))) + { + // change frameskip + window->machine().video().set_frameskip(command - ID_FRAMESKIP_0); + window->machine().options().emu_options::set_value(OPTION_AUTOFRAMESKIP, 0, OPTION_PRIORITY_CMDLINE, error_string); + window->machine().options().emu_options::set_value(OPTION_FRAMESKIP, (int)command - ID_FRAMESKIP_0, OPTION_PRIORITY_CMDLINE, error_string); + } + else + if ((command >= ID_DEVICE_0) && (command < ID_DEVICE_0 + (IO_COUNT*DEVOPTION_MAX))) + { + // change device + img = decode_deviceoption(window->machine(), command, &dev_command); + device_command(wnd, img, dev_command); + } + else + if ((command >= ID_JOYSTICK_0) && (command < ID_JOYSTICK_0 + MAX_JOYSTICKS)) + // customise joystick + customise_joystick(window->machine(), wnd, command - ID_JOYSTICK_0); + else + if ((command >= ID_VIDEO_VIEW_0) && (command < ID_VIDEO_VIEW_0 + 1000)) + { + // render views + window->m_target->set_view(command - ID_VIDEO_VIEW_0); + window->update(); // actually change window size + } + else + // bogus command + handled = FALSE; + + break; + } + + // resume emulation + if (pause_for_command(command)) + winwindow_ui_pause(window->machine(), FALSE); + + return handled; +} + + + +//============================================================ +// set_menu_text +//============================================================ + +static void set_menu_text(HMENU menu_bar, int command, const char *text) +{ + TCHAR *t_text; + MENUITEMINFO mii; + + // convert to TCHAR + t_text = ui_wstring_from_utf8(text); + + // invoke SetMenuItemInfo() + memset(&mii, 0, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_TYPE; + mii.dwTypeData = t_text; + SetMenuItemInfo(menu_bar, command, FALSE, &mii); + + // cleanup + free(t_text); +} + + + +//============================================================ +// win_setup_menus +//============================================================ + +static int win_setup_menus(running_machine &machine, HMODULE module, HMENU menu_bar) +{ + HMENU frameskip_menu; + char buf[256]; + int i = 0; + + // verify that our magic numbers work + assert((ID_DEVICE_0 + IO_COUNT * DEVOPTION_MAX) < ID_JOYSTICK_0); + + // initialize critical values + joystick_menu_setup = 0; + + // set up frameskip menu + frameskip_menu = find_sub_menu(menu_bar, "&Options\0&Frameskip\0", FALSE); + + if (!frameskip_menu) + return 1; + + for(i = 0; i < frameskip_level_count(machine); i++) + { + snprintf(buf, ARRAY_LENGTH(buf), "%i", i); + win_append_menu_utf8(frameskip_menu, MF_STRING, ID_FRAMESKIP_0 + i, buf); + } + + // set the help menu to refer to this machine + snprintf(buf, ARRAY_LENGTH(buf), "About %s (%s)...", machine.system().description, machine.system().name); + set_menu_text(menu_bar, ID_HELP_ABOUTSYSTEM, buf); + + // initialize state_filename for each driver, so we don't carry names in-between them + { + char *src; + char *dst; + + snprintf(state_filename, ARRAY_LENGTH(state_filename), "%s State", machine.system().description); + + src = state_filename; + dst = state_filename; + do + { + if ((*src == '\0') || isalnum(*src) || isspace(*src) || strchr("(),.", *src)) + *(dst++) = *src; + } + while(*(src++)); + } + + return 0; +} + + + +//============================================================ +// win_resource_module +//============================================================ + +static HMODULE win_resource_module(void) +{ + static HMODULE module; + if (module == NULL) + { + MEMORY_BASIC_INFORMATION info; + if ((VirtualQuery((const void*)win_resource_module, &info, sizeof(info))) == sizeof(info)) + module = (HMODULE)info.AllocationBase; + } + return module; +} + +///// Interface to the core ///// + +//============================================================ +// win_create_menu +//============================================================ + +int win_create_menu(running_machine &machine, HMENU *menus) +{ + // Get the path for loose software from <gamename>.ini + // if this is invalid, then windows chooses whatever directory it used last. + const char* t = machine.options().emu_options::sw_path(); + // This pulls out the first path from a multipath field + const char* t1 = strtok((char*)t, ";"); + if (t1) + software_dir = t1; // the first path of many + else + software_dir = t; // the only path + + // do not show in the mewui ui. + if (strcmp(machine.system().name, "___empty") == 0) + return 0; + + HMODULE module = win_resource_module(); + HMENU menu_bar = LoadMenu(module, MAKEINTRESOURCE(IDR_RUNTIME_MENU)); + + if (!menu_bar) + { + printf("No memory for the menu, running without it.\n"); + return 0; + } + + if (win_setup_menus(machine, module, menu_bar)) + { + printf("Unable to setup the menu, running without it.\n"); + if (menu_bar) + DestroyMenu(menu_bar); + return 0; // return 1 causes a crash + } + + *menus = menu_bar; + return 0; +} + + + +//============================================================ +// winwindow_video_window_proc_ui +//============================================================ + +LRESULT CALLBACK winwindow_video_window_proc_ui(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + switch(message) + { + case WM_INITMENU: + prepare_menus(wnd); + break; + + case WM_PASTE: + { + mame_machine_manager::instance()->ui().paste(); + } + break; + + case WM_COMMAND: + if (invoke_command(wnd, wparam)) + break; + /* fall through */ + + default: + return win_window_info::video_window_proc(wnd, message, wparam, lparam); + } + return 0; +} + |