summaryrefslogtreecommitdiffstats
path: root/docs/release/src/osd/winui/winui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'docs/release/src/osd/winui/winui.cpp')
-rw-r--r--docs/release/src/osd/winui/winui.cpp6685
1 files changed, 6685 insertions, 0 deletions
diff --git a/docs/release/src/osd/winui/winui.cpp b/docs/release/src/osd/winui/winui.cpp
new file mode 100644
index 00000000000..7d2ba6749ab
--- /dev/null
+++ b/docs/release/src/osd/winui/winui.cpp
@@ -0,0 +1,6685 @@
+// For licensing and usage information, read docs/winui_license.txt
+//****************************************************************************
+
+ /***************************************************************************
+
+ winui.cpp
+
+ Win32 GUI code.
+
+ Created 8/12/97 by Christopher Kirmse (ckirmse@ricochet.net)
+ Additional code November 1997 by Jeff Miller (miller@aa.net)
+ More July 1998 by Mike Haaland (mhaaland@hypertech.com)
+ Added Spitters/Property Sheets/Removed Tabs/Added Tree Control in
+ Nov/Dec 1998 - Mike Haaland
+
+***************************************************************************/
+
+// standard windows headers
+#define _WIN32_IE 0x0501
+#include <windows.h>
+#include <windowsx.h>
+#include <shellapi.h>
+#include <commctrl.h>
+#include <wingdi.h>
+
+// standard C headers
+#include <stdio.h>
+#include <ctype.h>
+#include <io.h>
+#include <fcntl.h>
+#include <dlgs.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <tchar.h>
+
+/* Uncomment to add Direct Draw support (has to be added back to the core too) */
+//#define UI_DIRECTDRAW
+
+// MAME/MAMEUI headers
+#include "emu.h"
+#include "mame.h"
+#include "mameopts.h"
+#include "language.h"
+#include "unzip.h"
+#include "winutf8.h"
+#include "strconv.h"
+#include "window.h"
+#include "../osdcore.h"
+#include "zippath.h"
+
+#include "resource.h"
+#include "resource.hm"
+
+#include "winui.h"
+#include "mui_util.h"
+#include "mui_audit.h"
+#include "directories.h"
+#include "mui_opts.h"
+#include "properties.h"
+#include "columnedit.h"
+#include "picker.h"
+#include "tabview.h"
+#include "bitmask.h"
+#include "treeview.h"
+#include "splitters.h"
+#include "dirwatch.h"
+#include "help.h"
+#include "history.h"
+#include "dialogs.h"
+#ifdef UI_DIRECTDRAW
+#include "directdraw.h"
+#endif
+#include "directinput.h"
+#include "dijoystick.h" /* For DIJoystick availability. */
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+#ifndef LVS_EX_LABELTIP
+#define LVS_EX_LABELTIP 0x00004000 // listview unfolds partly hidden labels if it does not have infotip text
+#endif // LVS_EX_LABELTIP
+
+// fix warning: cast does not match function type
+#if defined(__GNUC__) && defined(ListView_CreateDragImage)
+#undef ListView_CreateDragImage
+#endif
+
+#ifndef ListView_CreateDragImage
+#define ListView_CreateDragImage(hwnd, i, lpptUpLeft) \
+ (HIMAGELIST)(LRESULT)(int)SendMessage((hwnd), LVM_CREATEDRAGIMAGE, (WPARAM)(int)(i), (LPARAM)(LPPOINT)(lpptUpLeft))
+#endif // ListView_CreateDragImage
+
+#ifndef TreeView_EditLabel
+#define TreeView_EditLabel(w, i) \
+ SNDMSG(w,TVM_EDITLABEL,0,(LPARAM)(i))
+#endif // TreeView_EditLabel
+
+#ifndef HDF_SORTUP
+#define HDF_SORTUP 0x400
+#endif // HDF_SORTUP
+
+#ifndef HDF_SORTDOWN
+#define HDF_SORTDOWN 0x200
+#endif // HDF_SORTDOWN
+
+#ifndef LVM_SETBKIMAGEA
+#define LVM_SETBKIMAGEA (LVM_FIRST + 68)
+#endif // LVM_SETBKIMAGEA
+
+#ifndef LVM_SETBKIMAGEW
+#define LVM_SETBKIMAGEW (LVM_FIRST + 138)
+#endif // LVM_SETBKIMAGEW
+
+#ifndef LVM_GETBKIMAGEA
+#define LVM_GETBKIMAGEA (LVM_FIRST + 69)
+#endif // LVM_GETBKIMAGEA
+
+#ifndef LVM_GETBKIMAGEW
+#define LVM_GETBKIMAGEW (LVM_FIRST + 139)
+#endif // LVM_GETBKIMAGEW
+
+#ifndef LVBKIMAGE
+
+typedef struct tagLVBKIMAGEA
+{
+ ULONG ulFlags;
+ HBITMAP hbm;
+ LPSTR pszImage;
+ UINT cchImageMax;
+ int xOffsetPercent;
+ int yOffsetPercent;
+} LVBKIMAGEA, *LPLVBKIMAGEA;
+
+typedef struct tagLVBKIMAGEW
+{
+ ULONG ulFlags;
+ HBITMAP hbm;
+ LPWSTR pszImage;
+ UINT cchImageMax;
+ int xOffsetPercent;
+ int yOffsetPercent;
+} LVBKIMAGEW, *LPLVBKIMAGEW;
+
+#ifdef UNICODE
+#define LVBKIMAGE LVBKIMAGEW
+#define LPLVBKIMAGE LPLVBKIMAGEW
+#define LVM_SETBKIMAGE LVM_SETBKIMAGEW
+#define LVM_GETBKIMAGE LVM_GETBKIMAGEW
+#else
+#define LVBKIMAGE LVBKIMAGEA
+#define LPLVBKIMAGE LPLVBKIMAGEA
+#define LVM_SETBKIMAGE LVM_SETBKIMAGEA
+#define LVM_GETBKIMAGE LVM_GETBKIMAGEA
+#endif
+#endif
+
+#ifndef LVBKIF_SOURCE_NONE
+#define LVBKIF_SOURCE_NONE 0x00000000
+#endif // LVBKIF_SOURCE_NONE
+
+#ifndef LVBKIF_SOURCE_HBITMAP
+#define LVBKIF_SOURCE_HBITMAP 0x00000001
+#endif
+
+#ifndef LVBKIF_SOURCE_URL
+#define LVBKIF_SOURCE_URL 0x00000002
+#endif // LVBKIF_SOURCE_URL
+
+#ifndef LVBKIF_SOURCE_MASK
+#define LVBKIF_SOURCE_MASK 0x00000003
+#endif // LVBKIF_SOURCE_MASK
+
+#ifndef LVBKIF_STYLE_NORMAL
+#define LVBKIF_STYLE_NORMAL 0x00000000
+#endif // LVBKIF_STYLE_NORMAL
+
+#ifndef LVBKIF_STYLE_TILE
+#define LVBKIF_STYLE_TILE 0x00000010
+#endif // LVBKIF_STYLE_TILE
+
+#ifndef LVBKIF_STYLE_MASK
+#define LVBKIF_STYLE_MASK 0x00000010
+#endif // LVBKIF_STYLE_MASK
+
+#ifndef ListView_SetBkImage
+#define ListView_SetBkImage(hwnd, plvbki) \
+ (BOOL)SNDMSG((hwnd), LVM_SETBKIMAGE, 0, (LPARAM)(plvbki))
+#endif // ListView_SetBkImage
+
+#ifndef ListView_GetBkImage
+#define ListView_GetBkImage(hwnd, plvbki) \
+ (BOOL)SNDMSG((hwnd), LVM_GETBKIMAGE, 0, (LPARAM)(plvbki))
+#endif // ListView_GetBkImage
+
+#define MM_PLAY_GAME (WM_APP + 15000)
+
+#define JOYGUI_MS 100
+
+#define JOYGUI_TIMER 1
+#define SCREENSHOT_TIMER 2
+#define GAMEWND_TIMER 3
+
+/* Max size of a sub-menu */
+#define DBU_MIN_WIDTH 292
+#define DBU_MIN_HEIGHT 190
+
+static int MIN_WIDTH = DBU_MIN_WIDTH;
+static int MIN_HEIGHT = DBU_MIN_HEIGHT;
+
+/* Max number of bkground picture files */
+#define MAX_BGFILES 100
+
+#ifndef LVS_EX_LABELTIP
+#define LVS_EX_LABELTIP 0x00004000 // listview unfolds partly hidden labels if it does not have infotip text
+#endif
+
+#define NO_FOLDER -1
+#define STATESAVE_VERSION 1
+//I could not find a predefined value for this event and docs just say it has 1 for the parameter
+#define TOOLBAR_EDIT_ACCELERATOR_PRESSED 1
+#define SHOW_MISSING_ROMS_ICON
+
+/***************************************************************************
+ externally defined global variables
+ ***************************************************************************/
+extern const ICONDATA g_iconData[];
+extern const TCHAR g_szPlayGameString[];
+extern const char g_szGameCountString[];
+UINT8 playopts_apply = 0;
+
+typedef struct _play_options play_options;
+struct _play_options
+{
+ const char *record; // OPTION_RECORD
+ const char *playback; // OPTION_PLAYBACK
+ const char *state; // OPTION_STATE
+ const char *wavwrite; // OPTION_WAVWRITE
+ const char *mngwrite; // OPTION_MNGWRITE
+ const char *aviwrite; // OPTION_AVIWRITE
+};
+
+/***************************************************************************
+ function prototypes
+ ***************************************************************************/
+
+static BOOL Win32UI_init(HINSTANCE hInstance, LPWSTR lpCmdLine, int nCmdShow);
+static void Win32UI_exit(void);
+
+static BOOL PumpMessage(void);
+static BOOL OnIdle(HWND hWnd);
+static void OnSize(HWND hwnd, UINT state, int width, int height);
+static LRESULT CALLBACK MameWindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);
+
+static void SetView(int menu_id);
+static void ResetListView(void);
+static void UpdateGameList(BOOL bUpdateRomAudit, BOOL bUpdateSampleAudit);
+static void DestroyIcons(void);
+static void ReloadIcons(void);
+static void PollGUIJoystick(void);
+//static void PressKey(HWND hwnd,UINT vk);
+static BOOL MameCommand(HWND hwnd,int id, HWND hwndCtl, UINT codeNotify);
+static void KeyboardKeyDown(int syskey, int vk_code, int special);
+static void KeyboardKeyUp(int syskey, int vk_code, int special);
+static void KeyboardStateClear(void);
+
+static void UpdateStatusBar(void);
+//static BOOL PickerHitTest(HWND hWnd);
+static BOOL TreeViewNotify(NMHDR *nm);
+
+static void LoadBackgroundBitmap(void);
+static void PaintBackgroundImage(HWND hWnd, HRGN hRgn, int x, int y);
+
+static int GamePicker_Compare(HWND hwndPicker, int index1, int index2, int sort_subitem);
+
+static void DisableSelection(void);
+static void EnableSelection(int nGame);
+
+static HICON GetSelectedPickItemIcon(void);
+static void SetRandomPickItem(void);
+static void PickColor(COLORREF *cDefault);
+
+static LPTREEFOLDER GetSelectedFolder(void);
+static HICON GetSelectedFolderIcon(void);
+
+static LRESULT CALLBACK HistoryWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK PictureFrameWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK PictureWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+static void MamePlayRecordGame(void);
+static void MamePlayBackGame(void);
+static void MamePlayRecordWave(void);
+static void MamePlayRecordMNG(void);
+static void MamePlayRecordAVI(void);
+static void MameLoadState(void);
+static void MamePlayGameWithOptions(int nGame, const play_options *playopts);
+static BOOL GameCheck(void);
+static BOOL FolderCheck(void);
+
+static void ToggleScreenShot(void);
+static void AdjustMetrics(void);
+//static void EnablePlayOptions(int nIndex, windows_options *o);
+
+/* Icon routines */
+static DWORD GetShellLargeIconSize(void);
+static DWORD GetShellSmallIconSize(void);
+static void CreateIcons(void);
+static int GetIconForDriver(int nItem);
+static void AddDriverIcon(int nItem,int default_icon_index);
+
+// Context Menu handlers
+static void UpdateMenu(HMENU hMenu);
+static void InitTreeContextMenu(HMENU hTreeMenu);
+static void InitBodyContextMenu(HMENU hBodyContextMenu);
+static void ToggleShowFolder(int folder);
+static BOOL HandleTreeContextMenu( HWND hWnd, WPARAM wParam, LPARAM lParam);
+static BOOL HandleScreenShotContextMenu( HWND hWnd, WPARAM wParam, LPARAM lParam);
+static void GamePicker_OnHeaderContextMenu(POINT pt, int nColumn);
+static void GamePicker_OnBodyContextMenu(POINT pt);
+
+static void InitListView(void);
+/* Re/initialize the ListView header columns */
+static void ResetColumnDisplay(BOOL first_time);
+
+static void CopyToolTipText (LPTOOLTIPTEXT lpttt);
+
+static void ProgressBarShow(void);
+static void ProgressBarHide(void);
+static void ResizeProgressBar(void);
+static void ProgressBarStep(void);
+static void ProgressBarStepParam(int iGameIndex, int nGameCount);
+
+static HWND InitProgressBar(HWND hParent);
+static HWND InitToolbar(HWND hParent);
+static HWND InitStatusBar(HWND hParent);
+
+static LRESULT Statusbar_MenuSelect (HWND hwnd, WPARAM wParam, LPARAM lParam);
+
+static void UpdateHistory(void);
+
+
+static void RemoveCurrentGameCustomFolder(void);
+static void RemoveGameCustomFolder(int driver_index);
+
+static void BeginListViewDrag(NM_LISTVIEW *pnmv);
+static void MouseMoveListViewDrag(POINTS pt);
+static void ButtonUpListViewDrag(POINTS p);
+
+static void CalculateBestScreenShotRect(HWND hWnd, RECT *pRect, BOOL restrict_height);
+
+BOOL MouseHasBeenMoved(void);
+static void SwitchFullScreenMode(void);
+
+/***************************************************************************
+ External variables
+ ***************************************************************************/
+
+/***************************************************************************
+ Internal structures
+ ***************************************************************************/
+
+/*
+ * These next two structs represent how the icon information
+ * is stored in an ICO file.
+ */
+typedef struct
+{
+ BYTE bWidth; /* Width of the image */
+ BYTE bHeight; /* Height of the image (times 2) */
+ BYTE bColorCount; /* Number of colors in image (0 if >=8bpp) */
+ BYTE bReserved; /* Reserved */
+ WORD wPlanes; /* Color Planes */
+ WORD wBitCount; /* Bits per pixel */
+ DWORD dwBytesInRes; /* how many bytes in this resource? */
+ DWORD dwImageOffset; /* where in the file is this image */
+} ICONDIRENTRY, *LPICONDIRENTRY;
+
+typedef struct
+{
+ UINT Width, Height, Colors; /* Width, Height and bpp */
+ LPBYTE lpBits; /* ptr to DIB bits */
+ DWORD dwNumBytes; /* how many bytes? */
+ LPBITMAPINFO lpbi; /* ptr to header */
+ LPBYTE lpXOR; /* ptr to XOR image bits */
+ LPBYTE lpAND; /* ptr to AND image bits */
+} ICONIMAGE, *LPICONIMAGE;
+
+/* Which edges of a control are anchored to the corresponding side of the parent window */
+#define RA_LEFT 0x01
+#define RA_RIGHT 0x02
+#define RA_TOP 0x04
+#define RA_BOTTOM 0x08
+#define RA_ALL 0x0F
+
+#define RA_END 0
+#define RA_ID 1
+#define RA_HWND 2
+
+typedef struct
+{
+ int type; /* Either RA_ID or RA_HWND, to indicate which member of u is used; or RA_END
+ to signify last entry */
+ union /* Can identify a child window by control id or by handle */
+ {
+ int id; /* Window control id */
+ HWND hwnd; /* Window handle */
+ } u;
+ BOOL setfont; /* Do we set this item's font? */
+ int action; /* What to do when control is resized */
+ void *subwindow; /* Points to a Resize structure for this subwindow; NULL if none */
+} ResizeItem;
+
+typedef struct
+{
+ RECT rect; /* Client rect of window; must be initialized before first resize */
+ const ResizeItem* items; /* Array of subitems to be resized */
+} Resize;
+
+static void ResizeWindow(HWND hParent, Resize *r);
+static void SetAllWindowsFont(HWND hParent, const Resize *r, HFONT hFont, BOOL bRedraw);
+
+/* List view Icon defines */
+#define LG_ICONMAP_WIDTH GetSystemMetrics(SM_CXICON)
+#define LG_ICONMAP_HEIGHT GetSystemMetrics(SM_CYICON)
+#define ICONMAP_WIDTH GetSystemMetrics(SM_CXSMICON)
+#define ICONMAP_HEIGHT GetSystemMetrics(SM_CYSMICON)
+
+typedef struct tagPOPUPSTRING
+{
+ HMENU hMenu;
+ UINT uiString;
+} POPUPSTRING;
+
+#define MAX_MENUS 3
+
+#define SPLITTER_WIDTH 4
+#define MIN_VIEW_WIDTH 10
+
+// Struct needed for Game Window Communication
+
+typedef struct
+{
+ LPPROCESS_INFORMATION ProcessInfo;
+ HWND hwndFound;
+} FINDWINDOWHANDLE;
+
+/***************************************************************************
+ Internal variables
+ ***************************************************************************/
+
+static HWND hMain = NULL;
+static HACCEL hAccel = NULL;
+
+static HWND hwndList = NULL;
+static HWND hTreeView = NULL;
+static HWND hProgWnd = NULL;
+static HWND hTabCtrl = NULL;
+
+static HINSTANCE hInst = NULL;
+
+static HFONT hFont = NULL; /* Font for list view */
+
+static int optionfolder_count = 0;
+
+/* global data--know where to send messages */
+static BOOL in_emulation;
+
+/* idle work at startup */
+static BOOL idle_work;
+
+/* object pool in use */
+static object_pool *mameui_pool;
+
+static int game_index;
+static int progBarStep;
+
+static BOOL bDoGameCheck = false;
+
+/* Tree control variables */
+static BOOL bShowToolBar = 1;
+static BOOL bShowStatusBar = 1;
+static BOOL bShowTabCtrl = 1;
+static BOOL bProgressShown = false;
+static BOOL bListReady = false;
+
+#define WM_MAME32_FILECHANGED (WM_USER + 0)
+#define WM_MAME32_AUDITGAME (WM_USER + 1)
+
+static PDIRWATCHER s_pWatcher;
+
+/* use a joystick subsystem in the gui? */
+static const struct OSDJoystick* g_pJoyGUI = NULL;
+
+/* store current keyboard state (in bools) here */
+static bool keyboard_state[4096]; /* __code_max #defines the number of internal key_codes */
+
+/* search */
+static char g_SearchText[256];
+/* table copied from windows/inputs.c */
+// table entry indices
+#define MAME_KEY 0
+#define DI_KEY 1
+#define VIRTUAL_KEY 2
+#define ASCII_KEY 3
+
+// master keyboard translation table
+static const int win_key_trans_table[][4] =
+{
+ // MAME key dinput key virtual key ascii
+ { ITEM_ID_ESC, DIK_ESCAPE, VK_ESCAPE, 27 },
+ { ITEM_ID_1, DIK_1, '1', '1' },
+ { ITEM_ID_2, DIK_2, '2', '2' },
+ { ITEM_ID_3, DIK_3, '3', '3' },
+ { ITEM_ID_4, DIK_4, '4', '4' },
+ { ITEM_ID_5, DIK_5, '5', '5' },
+ { ITEM_ID_6, DIK_6, '6', '6' },
+ { ITEM_ID_7, DIK_7, '7', '7' },
+ { ITEM_ID_8, DIK_8, '8', '8' },
+ { ITEM_ID_9, DIK_9, '9', '9' },
+ { ITEM_ID_0, DIK_0, '0', '0' },
+ { ITEM_ID_BACKSPACE, DIK_BACK, VK_BACK, 8 },
+ { ITEM_ID_TAB, DIK_TAB, VK_TAB, 9 },
+ { ITEM_ID_Q, DIK_Q, 'Q', 'Q' },
+ { ITEM_ID_W, DIK_W, 'W', 'W' },
+ { ITEM_ID_E, DIK_E, 'E', 'E' },
+ { ITEM_ID_R, DIK_R, 'R', 'R' },
+ { ITEM_ID_T, DIK_T, 'T', 'T' },
+ { ITEM_ID_Y, DIK_Y, 'Y', 'Y' },
+ { ITEM_ID_U, DIK_U, 'U', 'U' },
+ { ITEM_ID_I, DIK_I, 'I', 'I' },
+ { ITEM_ID_O, DIK_O, 'O', 'O' },
+ { ITEM_ID_P, DIK_P, 'P', 'P' },
+ { ITEM_ID_OPENBRACE, DIK_LBRACKET, VK_OEM_4, '[' },
+ { ITEM_ID_CLOSEBRACE, DIK_RBRACKET, VK_OEM_6, ']' },
+ { ITEM_ID_ENTER, DIK_RETURN, VK_RETURN, 13 },
+ { ITEM_ID_LCONTROL, DIK_LCONTROL, VK_LCONTROL, 0 },
+ { ITEM_ID_A, DIK_A, 'A', 'A' },
+ { ITEM_ID_S, DIK_S, 'S', 'S' },
+ { ITEM_ID_D, DIK_D, 'D', 'D' },
+ { ITEM_ID_F, DIK_F, 'F', 'F' },
+ { ITEM_ID_G, DIK_G, 'G', 'G' },
+ { ITEM_ID_H, DIK_H, 'H', 'H' },
+ { ITEM_ID_J, DIK_J, 'J', 'J' },
+ { ITEM_ID_K, DIK_K, 'K', 'K' },
+ { ITEM_ID_L, DIK_L, 'L', 'L' },
+ { ITEM_ID_COLON, DIK_SEMICOLON, VK_OEM_1, ';' },
+ { ITEM_ID_QUOTE, DIK_APOSTROPHE, VK_OEM_7, '\'' },
+ { ITEM_ID_TILDE, DIK_GRAVE, VK_OEM_3, '`' },
+ { ITEM_ID_LSHIFT, DIK_LSHIFT, VK_LSHIFT, 0 },
+ { ITEM_ID_BACKSLASH, DIK_BACKSLASH, VK_OEM_5, '\\' },
+ { ITEM_ID_Z, DIK_Z, 'Z', 'Z' },
+ { ITEM_ID_X, DIK_X, 'X', 'X' },
+ { ITEM_ID_C, DIK_C, 'C', 'C' },
+ { ITEM_ID_V, DIK_V, 'V', 'V' },
+ { ITEM_ID_B, DIK_B, 'B', 'B' },
+ { ITEM_ID_N, DIK_N, 'N', 'N' },
+ { ITEM_ID_M, DIK_M, 'M', 'M' },
+ { ITEM_ID_SLASH, DIK_SLASH, VK_OEM_2, '/' },
+ { ITEM_ID_RSHIFT, DIK_RSHIFT, VK_RSHIFT, 0 },
+ { ITEM_ID_ASTERISK, DIK_MULTIPLY, VK_MULTIPLY, '*' },
+ { ITEM_ID_LALT, DIK_LMENU, VK_LMENU, 0 },
+ { ITEM_ID_SPACE, DIK_SPACE, VK_SPACE, ' ' },
+ { ITEM_ID_CAPSLOCK, DIK_CAPITAL, VK_CAPITAL, 0 },
+ { ITEM_ID_F1, DIK_F1, VK_F1, 0 },
+ { ITEM_ID_F2, DIK_F2, VK_F2, 0 },
+ { ITEM_ID_F3, DIK_F3, VK_F3, 0 },
+ { ITEM_ID_F4, DIK_F4, VK_F4, 0 },
+ { ITEM_ID_F5, DIK_F5, VK_F5, 0 },
+ { ITEM_ID_F6, DIK_F6, VK_F6, 0 },
+ { ITEM_ID_F7, DIK_F7, VK_F7, 0 },
+ { ITEM_ID_F8, DIK_F8, VK_F8, 0 },
+ { ITEM_ID_F9, DIK_F9, VK_F9, 0 },
+ { ITEM_ID_F10, DIK_F10, VK_F10, 0 },
+ { ITEM_ID_NUMLOCK, DIK_NUMLOCK, VK_NUMLOCK, 0 },
+ { ITEM_ID_SCRLOCK, DIK_SCROLL, VK_SCROLL, 0 },
+ { ITEM_ID_7_PAD, DIK_NUMPAD7, VK_NUMPAD7, 0 },
+ { ITEM_ID_8_PAD, DIK_NUMPAD8, VK_NUMPAD8, 0 },
+ { ITEM_ID_9_PAD, DIK_NUMPAD9, VK_NUMPAD9, 0 },
+ { ITEM_ID_MINUS_PAD, DIK_SUBTRACT, VK_SUBTRACT, 0 },
+ { ITEM_ID_4_PAD, DIK_NUMPAD4, VK_NUMPAD4, 0 },
+ { ITEM_ID_5_PAD, DIK_NUMPAD5, VK_NUMPAD5, 0 },
+ { ITEM_ID_6_PAD, DIK_NUMPAD6, VK_NUMPAD6, 0 },
+ { ITEM_ID_PLUS_PAD, DIK_ADD, VK_ADD, 0 },
+ { ITEM_ID_1_PAD, DIK_NUMPAD1, VK_NUMPAD1, 0 },
+ { ITEM_ID_2_PAD, DIK_NUMPAD2, VK_NUMPAD2, 0 },
+ { ITEM_ID_3_PAD, DIK_NUMPAD3, VK_NUMPAD3, 0 },
+ { ITEM_ID_0_PAD, DIK_NUMPAD0, VK_NUMPAD0, 0 },
+ { ITEM_ID_DEL_PAD, DIK_DECIMAL, VK_DECIMAL, 0 },
+ { ITEM_ID_F11, DIK_F11, VK_F11, 0 },
+ { ITEM_ID_F12, DIK_F12, VK_F12, 0 },
+ { ITEM_ID_F13, DIK_F13, VK_F13, 0 },
+ { ITEM_ID_F14, DIK_F14, VK_F14, 0 },
+ { ITEM_ID_F15, DIK_F15, VK_F15, 0 },
+ { ITEM_ID_ENTER_PAD, DIK_NUMPADENTER, VK_RETURN, 0 },
+ { ITEM_ID_RCONTROL, DIK_RCONTROL, VK_RCONTROL, 0 },
+ { ITEM_ID_SLASH_PAD, DIK_DIVIDE, VK_DIVIDE, 0 },
+ { ITEM_ID_PRTSCR, DIK_SYSRQ, 0, 0 },
+ { ITEM_ID_RALT, DIK_RMENU, VK_RMENU, 0 },
+ { ITEM_ID_HOME, DIK_HOME, VK_HOME, 0 },
+ { ITEM_ID_UP, DIK_UP, VK_UP, 0 },
+ { ITEM_ID_PGUP, DIK_PRIOR, VK_PRIOR, 0 },
+ { ITEM_ID_LEFT, DIK_LEFT, VK_LEFT, 0 },
+ { ITEM_ID_RIGHT, DIK_RIGHT, VK_RIGHT, 0 },
+ { ITEM_ID_END, DIK_END, VK_END, 0 },
+ { ITEM_ID_DOWN, DIK_DOWN, VK_DOWN, 0 },
+ { ITEM_ID_PGDN, DIK_NEXT, VK_NEXT, 0 },
+ { ITEM_ID_INSERT, DIK_INSERT, VK_INSERT, 0 },
+ { ITEM_ID_DEL, DIK_DELETE, VK_DELETE, 0 },
+ { ITEM_ID_LWIN, DIK_LWIN, VK_LWIN, 0 },
+ { ITEM_ID_RWIN, DIK_RWIN, VK_RWIN, 0 },
+ { ITEM_ID_MENU, DIK_APPS, VK_APPS, 0 },
+ { ITEM_ID_PAUSE, DIK_PAUSE, VK_PAUSE, 0 },
+ { ITEM_ID_CANCEL, 0, VK_CANCEL, 0 },
+};
+
+
+
+typedef struct
+{
+ char name[40]; // functionality name (optional)
+ input_seq is; // the input sequence (the keys pressed)
+ UINT func_id; // the identifier
+ input_seq* (*const getiniptr)(void);// pointer to function to get the value from .ini file
+} GUISequence;
+
+static const GUISequence GUISequenceControl[]=
+{
+ {"gui_key_up", input_seq(), ID_UI_UP, Get_ui_key_up },
+ {"gui_key_down", input_seq(), ID_UI_DOWN, Get_ui_key_down },
+ {"gui_key_left", input_seq(), ID_UI_LEFT, Get_ui_key_left },
+ {"gui_key_right", input_seq(), ID_UI_RIGHT, Get_ui_key_right },
+ {"gui_key_start", input_seq(), ID_UI_START, Get_ui_key_start },
+ {"gui_key_pgup", input_seq(), ID_UI_PGUP, Get_ui_key_pgup },
+ {"gui_key_pgdwn", input_seq(), ID_UI_PGDOWN, Get_ui_key_pgdwn },
+ {"gui_key_home", input_seq(), ID_UI_HOME, Get_ui_key_home },
+ {"gui_key_end", input_seq(), ID_UI_END, Get_ui_key_end },
+ {"gui_key_ss_change", input_seq(), IDC_SSFRAME, Get_ui_key_ss_change },
+ {"gui_key_history_up", input_seq(), ID_UI_HISTORY_UP, Get_ui_key_history_up },
+ {"gui_key_history_down", input_seq(), ID_UI_HISTORY_DOWN, Get_ui_key_history_down },
+
+ {"gui_key_context_filters", input_seq(), ID_CONTEXT_FILTERS, Get_ui_key_context_filters },
+ {"gui_key_select_random", input_seq(), ID_CONTEXT_SELECT_RANDOM, Get_ui_key_select_random },
+ {"gui_key_game_audit", input_seq(), ID_GAME_AUDIT, Get_ui_key_game_audit },
+ {"gui_key_game_properties", input_seq(), ID_GAME_PROPERTIES, Get_ui_key_game_properties },
+ {"gui_key_help_contents", input_seq(), ID_HELP_CONTENTS, Get_ui_key_help_contents },
+ {"gui_key_update_gamelist", input_seq(), ID_UPDATE_GAMELIST, Get_ui_key_update_gamelist },
+ {"gui_key_view_folders", input_seq(), ID_VIEW_FOLDERS, Get_ui_key_view_folders },
+ {"gui_key_view_fullscreen", input_seq(), ID_VIEW_FULLSCREEN, Get_ui_key_view_fullscreen },
+ {"gui_key_view_pagetab", input_seq(), ID_VIEW_PAGETAB, Get_ui_key_view_pagetab },
+ {"gui_key_view_picture_area", input_seq(), ID_VIEW_PICTURE_AREA, Get_ui_key_view_picture_area },
+ {"gui_key_view_status", input_seq(), ID_VIEW_STATUS, Get_ui_key_view_status },
+ {"gui_key_view_toolbars", input_seq(), ID_VIEW_TOOLBARS, Get_ui_key_view_toolbars },
+
+ {"gui_key_view_tab_cabinet", input_seq(), ID_VIEW_TAB_CABINET, Get_ui_key_view_tab_cabinet },
+ {"gui_key_view_tab_cpanel", input_seq(), ID_VIEW_TAB_CONTROL_PANEL, Get_ui_key_view_tab_cpanel },
+ {"gui_key_view_tab_flyer", input_seq(), ID_VIEW_TAB_FLYER, Get_ui_key_view_tab_flyer },
+ {"gui_key_view_tab_history", input_seq(), ID_VIEW_TAB_HISTORY, Get_ui_key_view_tab_history },
+ {"gui_key_view_tab_marquee", input_seq(), ID_VIEW_TAB_MARQUEE, Get_ui_key_view_tab_marquee },
+ {"gui_key_view_tab_screenshot", input_seq(), ID_VIEW_TAB_SCREENSHOT, Get_ui_key_view_tab_screenshot },
+ {"gui_key_view_tab_title", input_seq(), ID_VIEW_TAB_TITLE, Get_ui_key_view_tab_title },
+ {"gui_key_view_tab_pcb", input_seq(), ID_VIEW_TAB_PCB, Get_ui_key_view_tab_pcb },
+ {"gui_key_quit", input_seq(), ID_FILE_EXIT, Get_ui_key_quit },
+};
+
+
+#define NUM_GUI_SEQUENCES (sizeof(GUISequenceControl) / sizeof(GUISequenceControl[0]))
+
+
+static UINT lastColumnClick = 0;
+static WNDPROC g_lpHistoryWndProc = NULL;
+static WNDPROC g_lpPictureFrameWndProc = NULL;
+static WNDPROC g_lpPictureWndProc = NULL;
+
+static POPUPSTRING popstr[MAX_MENUS + 1];
+
+/* Tool and Status bar variables */
+static HWND hStatusBar = 0;
+static HWND s_hToolBar = 0;
+
+/* Column Order as Displayed */
+static BOOL oldControl = false;
+static BOOL xpControl = false;
+
+/* Used to recalculate the main window layout */
+static int bottomMargin;
+static int topMargin;
+static int have_history = false;
+
+static BOOL have_selection = false;
+
+static HBITMAP hMissing_bitmap = NULL;
+
+/* Icon variables */
+static HIMAGELIST hLarge = NULL;
+static HIMAGELIST hSmall = NULL;
+static HIMAGELIST hHeaderImages = NULL;
+static int *icon_index = NULL; /* for custom per-game icons */
+
+static const TBBUTTON tbb[] =
+{
+ {0, ID_VIEW_FOLDERS, TBSTATE_ENABLED, TBSTYLE_CHECK, {0, 0}, 0, 0},
+ {1, ID_VIEW_PICTURE_AREA,TBSTATE_ENABLED, TBSTYLE_CHECK, {0, 0}, 0, 1},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0},
+ {2, ID_VIEW_LARGE_ICON, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, {0, 0}, 0, 2},
+ {3, ID_VIEW_SMALL_ICON, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, {0, 0}, 0, 3},
+ {4, ID_VIEW_LIST_MENU, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, {0, 0}, 0, 4},
+ {5, ID_VIEW_DETAIL, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, {0, 0}, 0, 5},
+ {6, ID_VIEW_GROUPED, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, {0, 0}, 0, 6},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0},
+ {7, ID_HELP_ABOUT, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 7},
+ {8, ID_HELP_CONTENTS, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 8}
+};
+
+#define NUM_TOOLBUTTONS (sizeof(tbb) / sizeof(tbb[0]))
+
+#define NUM_TOOLTIPS 9
+
+static const TCHAR szTbStrings[NUM_TOOLTIPS + 1][30] =
+{
+ TEXT("Toggle Folder List"),
+ TEXT("Toggle Screen Shot"),
+ TEXT("Large Icons"),
+ TEXT("Small Icons"),
+ TEXT("List"),
+ TEXT("Details"),
+ TEXT("Grouped"),
+ TEXT("About"),
+ TEXT("Help")
+};
+
+static const int CommandToString[] =
+{
+ ID_VIEW_FOLDERS,
+ ID_VIEW_PICTURE_AREA,
+ ID_VIEW_LARGE_ICON,
+ ID_VIEW_SMALL_ICON,
+ ID_VIEW_LIST_MENU,
+ ID_VIEW_DETAIL,
+ ID_VIEW_GROUPED,
+ ID_HELP_ABOUT,
+ ID_HELP_CONTENTS,
+ -1
+};
+
+static const int s_nPickers[] =
+{
+ IDC_LIST
+};
+
+
+/* How to resize toolbar sub window */
+static ResizeItem toolbar_resize_items[] =
+{
+ { RA_ID, { ID_TOOLBAR_EDIT }, true, RA_LEFT | RA_TOP, NULL },
+ { RA_END, { 0 }, false, 0, NULL }
+};
+
+static Resize toolbar_resize = { {0, 0, 0, 0}, toolbar_resize_items };
+
+/* How to resize main window */
+static ResizeItem main_resize_items[] =
+{
+ { RA_HWND, { 0 }, false, RA_LEFT | RA_RIGHT | RA_TOP, &toolbar_resize },
+ { RA_HWND, { 0 }, false, RA_LEFT | RA_RIGHT | RA_BOTTOM, NULL },
+ { RA_ID, { IDC_DIVIDER }, false, RA_LEFT | RA_RIGHT | RA_TOP, NULL },
+ { RA_ID, { IDC_TREE }, true, RA_LEFT | RA_BOTTOM | RA_TOP, NULL },
+ { RA_ID, { IDC_LIST }, true, RA_ALL, NULL },
+ { RA_ID, { IDC_SPLITTER }, false, RA_LEFT | RA_BOTTOM | RA_TOP, NULL },
+ { RA_ID, { IDC_SPLITTER2 },false, RA_RIGHT | RA_BOTTOM | RA_TOP, NULL },
+ { RA_ID, { IDC_SSFRAME }, false, RA_RIGHT | RA_BOTTOM | RA_TOP, NULL },
+ { RA_ID, { IDC_SSPICTURE },false, RA_RIGHT | RA_BOTTOM | RA_TOP, NULL },
+ { RA_ID, { IDC_HISTORY }, true, RA_RIGHT | RA_BOTTOM | RA_TOP, NULL },
+ { RA_ID, { IDC_SSTAB }, false, RA_RIGHT | RA_TOP, NULL },
+ { RA_END, { 0 }, false, 0, NULL }
+};
+
+static Resize main_resize = { {0, 0, 0, 0}, main_resize_items };
+
+/* last directory for common file dialogs */
+TCHAR last_directory[MAX_PATH];
+
+/* system-wide window message sent out with an ATOM of the current game name
+ each time it changes */
+static UINT g_mame32_message = 0;
+
+static BOOL g_listview_dragging = false;
+static HIMAGELIST himl_drag;
+static int game_dragged; /* which game started the drag */
+static HTREEITEM prev_drag_drop_target; /* which tree view item we're currently highlighting */
+
+static BOOL g_in_treeview_edit = false;
+
+/***************************************************************************
+ Global variables
+ ***************************************************************************/
+
+/* Background Image handles also accessed from TreeView.c */
+static HPALETTE hPALbg = 0;
+static HBITMAP hBackground = 0;
+static MYBITMAPINFO bmDesc;
+
+/* List view Column text */
+extern const LPCTSTR column_names[COLUMN_MAX] =
+{
+ TEXT("Machine"),
+ TEXT("Source"),
+ TEXT("Directory"),
+ TEXT("Type"),
+ TEXT("Screen"),
+ TEXT("Manufacturer"),
+ TEXT("Year"),
+ TEXT("Played"),
+ TEXT("Play Time"),
+ TEXT("Clone Of"),
+ TEXT("Trackball"),
+ TEXT("Samples"),
+ TEXT("ROMs"),
+};
+
+/***************************************************************************
+ Message Macros
+ ***************************************************************************/
+
+#ifndef StatusBar_GetItemRect
+#define StatusBar_GetItemRect(hWnd, iPart, lpRect) \
+ SendMessage(hWnd, SB_GETRECT, (WPARAM) iPart, (LPARAM) (LPRECT) lpRect)
+#endif
+
+#ifndef ToolBar_CheckButton
+#define ToolBar_CheckButton(hWnd, idButton, fCheck) \
+ SendMessage(hWnd, TB_CHECKBUTTON, (WPARAM)idButton, (LPARAM)MAKELONG(fCheck, 0))
+#endif
+
+//============================================================
+// winui_output_error
+//============================================================
+
+
+class mameui_output_error : public osd_output
+{
+public:
+ virtual void output_callback(osd_output_channel channel, const char *msg, va_list args)
+ {
+ if (channel == OSD_OUTPUT_CHANNEL_VERBOSE)
+ {
+ FILE *pFile;
+ pFile = fopen("verbose.log", "a");
+ vfprintf(pFile, msg, args);fflush(pFile);
+ fclose (pFile);
+ return;
+ }
+
+ int s_action = 0;
+ char buffer[4096];
+ vsnprintf(buffer, ARRAY_LENGTH(buffer), msg, args);
+
+ if (channel == OSD_OUTPUT_CHANNEL_ERROR)
+ {
+ s_action = 0x80;
+ }
+ else
+ if (channel == OSD_OUTPUT_CHANNEL_WARNING)
+ {
+ if (strstr(buffer, "WRONG"))
+ {
+ s_action = 0x81;
+ }
+ }
+
+ if (s_action)
+ {
+ // if we are in fullscreen mode, go to windowed mode
+ if ((video_config.windowed == 0) && !osd_common_t::s_window_list.empty())
+ winwindow_toggle_full_screen();
+
+ win_message_box_utf8(!osd_common_t::s_window_list.empty() ?
+ std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window() :
+ hMain, buffer, MAMEUINAME, (BIT(s_action, 0) ? MB_ICONINFORMATION : MB_ICONERROR) | MB_OK);
+ }
+
+// else
+// chain_output(channel, msg, args); // goes down the black hole
+ // LOG all messages
+ FILE *pFile;
+ pFile = fopen("winui.log", "a");
+ vfprintf(pFile, msg, args);fflush(pFile);
+ fclose (pFile);
+/* List of output types:
+ case OSD_OUTPUT_CHANNEL_ERROR:
+ case OSD_OUTPUT_CHANNEL_WARNING:
+ vfprintf(stderr, msg, args); // send errors and warnings to standard error (=console)
+ break;
+ case OSD_OUTPUT_CHANNEL_INFO:
+ case OSD_OUTPUT_CHANNEL_LOG:
+ vfprintf(stdout, msg, args); // send info and logging to standard output (=console)
+ break;
+ case OSD_OUTPUT_CHANNEL_VERBOSE:
+ if (verbose()) vfprintf(stdout, msg, args); // send verbose (2nd half) to console if enabled (first half lost)
+ break;
+ case OSD_OUTPUT_CHANNEL_DEBUG: // only for debug builds
+ vfprintf(stdout, msg, args);
+*/
+ }
+};
+
+static std::wstring s2ws(const string& s)
+{
+ int slength = (int)s.length() + 1;
+ int len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
+ wchar_t* buf = new wchar_t[len];
+ MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
+ std::wstring r(buf);
+ delete[] buf;
+ return r;
+}
+
+
+/***************************************************************************
+ External functions
+ ***************************************************************************/
+static DWORD RunMAME(int nGameIndex, const play_options *playopts)
+{
+ time_t start, end;
+ double elapsedtime;
+ int i;
+ //mame_options mame_opts; //seems useless....
+ windows_options global_opts;
+ // set up MAME options
+ // mame_opts = mame_options_init(mame_win_options);
+
+ // Tell mame were to get the INIs
+ SetDirectories(global_opts);
+
+ // set some startup options
+ global_opts.set_value(OPTION_LANGUAGE, GetLanguageUI(), OPTION_PRIORITY_CMDLINE);
+ global_opts.set_value(OPTION_PLUGINS, GetEnablePlugins(), OPTION_PRIORITY_CMDLINE);
+ global_opts.set_value(OPTION_PLUGIN, GetPlugins(), OPTION_PRIORITY_CMDLINE);
+
+ // add image specific device options
+ //mame_opts.set_system_name(global_opts, driver_list::driver(nGameIndex).name);
+ global_opts.set_value(OPTION_SYSTEMNAME, driver_list::driver(nGameIndex).name, OPTION_PRIORITY_CMDLINE);
+
+ // set any specified play options
+ if (playopts_apply == 0x57)
+ {
+ if (playopts->record)
+ global_opts.set_value(OPTION_RECORD, playopts->record, OPTION_PRIORITY_CMDLINE);
+ if (playopts->playback)
+ global_opts.set_value(OPTION_PLAYBACK, playopts->playback, OPTION_PRIORITY_CMDLINE);
+ if (playopts->state)
+ global_opts.set_value(OPTION_STATE, playopts->state, OPTION_PRIORITY_CMDLINE);
+ if (playopts->wavwrite)
+ global_opts.set_value(OPTION_WAVWRITE, playopts->wavwrite, OPTION_PRIORITY_CMDLINE);
+ if (playopts->mngwrite)
+ global_opts.set_value(OPTION_MNGWRITE, playopts->mngwrite, OPTION_PRIORITY_CMDLINE);
+ if (playopts->aviwrite)
+ global_opts.set_value(OPTION_AVIWRITE, playopts->aviwrite, OPTION_PRIORITY_CMDLINE);
+ }
+
+ // Mame will parse all the needed .ini files.
+
+ // prepare MAME32 to run the game
+ ShowWindow(hMain, SW_HIDE);
+
+ for (i = 0; i < ARRAY_LENGTH(s_nPickers); i++)
+ Picker_ClearIdle(GetDlgItem(hMain, s_nPickers[i]));
+
+ // run the emulation
+ // Time the game run.
+ time(&start);
+ windows_osd_interface osd(global_opts);
+ // output errors to message boxes
+ mameui_output_error winerror;
+ osd_output::push(&winerror);
+ osd.register_options();
+ mame_machine_manager *manager = mame_machine_manager::instance(global_opts, osd);
+ load_translation(global_opts);
+ manager->start_http_server();
+ manager->start_luaengine();
+ manager->execute();
+ osd_output::pop(&winerror);
+ global_free(manager);
+ // Calc the duration
+ time(&end);
+ elapsedtime = end - start;
+ // Increment our playtime.
+ IncrementPlayTime(nGameIndex, elapsedtime);
+
+ // clear any specified play options
+ // do it this way to preserve slots and software entries
+ if (playopts_apply == 0x57)
+ {
+ windows_options o;
+ load_options(o, OPTIONS_GAME, nGameIndex, 0);
+ if (playopts->record)
+ o.set_value(OPTION_RECORD, "", OPTION_PRIORITY_CMDLINE);
+ if (playopts->playback)
+ o.set_value(OPTION_PLAYBACK, "", OPTION_PRIORITY_CMDLINE);
+ if (playopts->state)
+ o.set_value(OPTION_STATE, "", OPTION_PRIORITY_CMDLINE);
+ if (playopts->wavwrite)
+ o.set_value(OPTION_WAVWRITE, "", OPTION_PRIORITY_CMDLINE);
+ if (playopts->mngwrite)
+ o.set_value(OPTION_MNGWRITE, "", OPTION_PRIORITY_CMDLINE);
+ if (playopts->aviwrite)
+ o.set_value(OPTION_AVIWRITE, "", OPTION_PRIORITY_CMDLINE);
+ // apply the above to the ini file
+ save_options(o, OPTIONS_GAME, nGameIndex);
+ }
+ playopts_apply = 0;
+
+ // the emulation is complete; continue
+ for (i = 0; i < ARRAY_LENGTH(s_nPickers); i++)
+ Picker_ResetIdle(GetDlgItem(hMain, s_nPickers[i]));
+ ShowWindow(hMain, SW_SHOW);
+ SetForegroundWindow(hMain);
+
+ return (DWORD)0;
+}
+
+int MameUIMain(HINSTANCE hInstance, LPWSTR lpCmdLine, int nCmdShow)
+{
+ // delete old log file, ignore any error
+ unlink("verbose.log");
+ unlink("winui.log");
+
+ if (__argc != 1)
+ {
+ /* Rename main because gcc will use it instead of WinMain even with -mwindows */
+ extern int main_(int argc, char *argv[]);
+ exit(main_(__argc, __argv));
+ }
+
+ // printf's not allowed before here, else they get into mame queries
+
+ printf("HBMAMEUI starting\n");fflush(stdout);
+
+ if (!Win32UI_init(hInstance, lpCmdLine, nCmdShow))
+ return 1;
+
+ // pump message, but quit on WM_QUIT
+ while(PumpMessage())
+ ;
+
+ Win32UI_exit();
+ return 0;
+}
+
+
+HWND GetMainWindow(void)
+{
+ return hMain;
+}
+
+HWND GetTreeView(void)
+{
+ return hTreeView;
+}
+
+object_pool *GetMameUIMemoryPool(void)
+{
+ return mameui_pool;
+}
+
+void GetRealColumnOrder(int order[])
+{
+ int nColumnMax = Picker_GetNumColumns(hwndList);
+
+ /* Get the Column Order and save it */
+ if (!oldControl)
+ {
+ int tmpOrder[COLUMN_MAX];
+ BOOL res = ListView_GetColumnOrderArray(hwndList, nColumnMax, tmpOrder);
+ res++;
+
+ for (int i = 0; i < nColumnMax; i++)
+ order[i] = Picker_GetRealColumnFromViewColumn(hwndList, tmpOrder[i]);
+ }
+}
+
+/*
+ * PURPOSE: Format raw data read from an ICO file to an HICON
+ * PARAMS: PBYTE ptrBuffer - Raw data from an ICO file
+ * UINT nBufferSize - Size of buffer ptrBuffer
+ * RETURNS: HICON - handle to the icon, NULL for failure
+ * History: July '95 - Created
+ * March '00- Seriously butchered from MSDN for mine own
+ * purposes, sayeth H0ek.
+ */
+static HICON FormatICOInMemoryToHICON(PBYTE ptrBuffer, UINT nBufferSize)
+{
+ /* Is there a WORD? */
+ if (nBufferSize < sizeof(WORD))
+ return NULL;
+
+ /* Was it 'reserved' ? (ie 0) */
+ UINT nBufferIndex = 0;
+ if ((WORD)(ptrBuffer[nBufferIndex]) != 0)
+ return NULL;
+
+ nBufferIndex += sizeof(WORD);
+
+ /* Is there a WORD? */
+ if (nBufferSize - nBufferIndex < sizeof(WORD))
+ return NULL;
+
+ /* Was it type 1? */
+ if ((WORD)(ptrBuffer[nBufferIndex]) != 1)
+ return NULL;
+
+ nBufferIndex += sizeof(WORD);
+
+ /* Is there a WORD? */
+ if (nBufferSize - nBufferIndex < sizeof(WORD))
+ return NULL;
+
+ /* Then that's the number of images in the ICO file */
+ UINT nNumImages = (WORD)(ptrBuffer[nBufferIndex]);
+
+ /* Is there at least one icon in the file? */
+ if ( nNumImages < 1 )
+ return NULL;
+
+ nBufferIndex += sizeof(WORD);
+
+ /* Is there enough space for the icon directory entries? */
+ if ((nBufferIndex + nNumImages * sizeof(ICONDIRENTRY)) > nBufferSize)
+ return NULL;
+
+ /* Assign icon directory entries from buffer */
+ LPICONDIRENTRY lpIDE = (LPICONDIRENTRY)(&ptrBuffer[nBufferIndex]);
+ nBufferIndex += nNumImages * sizeof (ICONDIRENTRY);
+
+ ICONIMAGE IconImage;
+ IconImage.dwNumBytes = lpIDE->dwBytesInRes;
+
+ /* Seek to beginning of this image */
+ if ( lpIDE->dwImageOffset > nBufferSize )
+ return NULL;
+
+ nBufferIndex = lpIDE->dwImageOffset;
+
+ /* Read it in */
+ if ((nBufferIndex + lpIDE->dwBytesInRes) > nBufferSize)
+ return NULL;
+
+ IconImage.lpBits = &ptrBuffer[nBufferIndex];
+ nBufferIndex += lpIDE->dwBytesInRes;
+
+ /* It failed, odds are good we're on NT so try the non-Ex way */
+ HICON hIcon = NULL;
+ if (hIcon == NULL)
+ /* We would break on NT if we try with a 16bpp image */
+ if (((LPBITMAPINFO)IconImage.lpBits)->bmiHeader.biBitCount != 16)
+ hIcon = CreateIconFromResourceEx(IconImage.lpBits, IconImage.dwNumBytes, true, 0x00030000,0,0,LR_DEFAULTSIZE);
+
+ return hIcon;
+}
+
+HICON LoadIconFromFile(const char *iconname)
+{
+ HICON hIcon = 0;
+ struct stat file_stat;
+ char tmpStr[MAX_PATH];
+ char tmpIcoName[MAX_PATH];
+ PBYTE bufferPtr = 0;
+ util::archive_file::ptr zip;
+
+ const string t = GetIconsDir();
+ sprintf(tmpStr, "%s/%s.ico", t.c_str(), iconname);
+ if (stat(tmpStr, &file_stat) != 0 || (hIcon = win_extract_icon_utf8(hInst, tmpStr, 0)) == 0)
+ {
+ sprintf(tmpStr, "%s/icons.zip", t.c_str());
+ sprintf(tmpIcoName, "%s.ico", iconname);
+
+ if (util::archive_file::open_zip(tmpStr, zip) == util::archive_file::error::NONE)
+ {
+ if (zip->search(tmpIcoName, false) >= 0)
+ {
+ bufferPtr = (PBYTE)malloc(zip->current_uncompressed_length());
+ if (bufferPtr)
+ {
+ if (zip->decompress(bufferPtr, zip->current_uncompressed_length()) == util::archive_file::error::NONE)
+ hIcon = FormatICOInMemoryToHICON(bufferPtr, zip->current_uncompressed_length());
+
+ free(bufferPtr);
+ }
+ }
+ zip.reset();
+ }
+ else
+ {
+ sprintf(tmpStr, "%s/icons.7z", t.c_str());
+ sprintf(tmpIcoName, "%s.ico", iconname);
+
+ if (util::archive_file::open_7z(tmpStr, zip) == util::archive_file::error::NONE)
+ {
+ if (zip->search(tmpIcoName, false) >= 0)
+ {
+ bufferPtr = (PBYTE)malloc(zip->current_uncompressed_length());
+ if (bufferPtr)
+ {
+ if (zip->decompress(bufferPtr, zip->current_uncompressed_length()) == util::archive_file::error::NONE)
+ hIcon = FormatICOInMemoryToHICON(bufferPtr, zip->current_uncompressed_length());
+
+ free(bufferPtr);
+ }
+ }
+ zip.reset();
+ }
+ }
+ }
+ return hIcon;
+}
+
+
+/* Return the number of folders with options */
+void SetNumOptionFolders(int count)
+{
+ optionfolder_count = count;
+}
+
+/* search */
+const char * GetSearchText(void)
+{
+ return g_SearchText;
+}
+
+
+/* Sets the treeview and listviews sizes in accordance with their visibility and the splitters */
+static void ResizeTreeAndListViews(BOOL bResizeHidden)
+{
+ bool bShowPicture = BIT(GetWindowPanes(), 3);
+ int nLastWidth = 0;
+ int nLastWidth2 = 0;
+ int nLeftWindowWidth = 0;
+ RECT rect;
+ BOOL bVisible;
+ //int nLastOverlap = -1;
+
+ /* Size the List Control in the Picker */
+ GetClientRect(hMain, &rect);
+
+ if (bShowStatusBar)
+ rect.bottom -= bottomMargin;
+ if (bShowToolBar)
+ rect.top += topMargin;
+
+ /* Tree control */
+ ShowWindow(GetDlgItem(hMain, IDC_TREE), BIT(GetWindowPanes(), 0) ? SW_SHOW : SW_HIDE);
+
+ for (int i = 0; g_splitterInfo[i].nSplitterWindow; i++)
+ {
+ bVisible = GetWindowLong(GetDlgItem(hMain, g_splitterInfo[i].nLeftWindow), GWL_STYLE) & WS_VISIBLE ? true : false;
+ if (bResizeHidden || bVisible)
+ {
+ nLeftWindowWidth = nSplitterOffset[i] - SPLITTER_WIDTH/2 - nLastWidth;
+
+ /* special case for the rightmost pane when the screenshot is gone */
+ if (!bShowPicture && !g_splitterInfo[i+1].nSplitterWindow)
+ nLeftWindowWidth = rect.right - nLastWidth;
+
+ /* woah? are we overlapping ourselves? */
+ if (nLeftWindowWidth < MIN_VIEW_WIDTH)
+ {
+ //nLastOverlap = i;
+ nLastWidth = nLastWidth2;
+ nLeftWindowWidth = nSplitterOffset[i] - MIN_VIEW_WIDTH - (SPLITTER_WIDTH*3/2) - nLastWidth;
+ i--;
+ }
+
+ MoveWindow(GetDlgItem(hMain, g_splitterInfo[i].nLeftWindow), nLastWidth, rect.top + 2, nLeftWindowWidth, (rect.bottom - rect.top) - 4 , true);
+
+ MoveWindow(GetDlgItem(hMain, g_splitterInfo[i].nSplitterWindow), nSplitterOffset[i], rect.top + 2, SPLITTER_WIDTH, (rect.bottom - rect.top) - 4, true);
+ }
+
+ if (bVisible)
+ {
+ nLastWidth2 = nLastWidth;
+ nLastWidth += nLeftWindowWidth + SPLITTER_WIDTH;
+ }
+ }
+}
+
+/* Adjust the list view and screenshot button based on GetShowScreenShot() */
+void UpdateScreenShot(void)
+{
+ /* first time through can't do this stuff */
+ if (hwndList == NULL)
+ return;
+
+ RECT rect;
+ //int nWidth;
+ RECT fRect;
+ POINT p = {0, 0};
+
+ /* Size the List Control in the Picker */
+ GetClientRect(hMain, &rect);
+
+ if (bShowStatusBar)
+ rect.bottom -= bottomMargin;
+ if (bShowToolBar)
+ rect.top += topMargin;
+
+ BOOL bShowImage = BIT(GetWindowPanes(), 3); // ss
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_PICTURE_AREA, bShowImage ? MF_CHECKED : MF_UNCHECKED);
+ ToolBar_CheckButton(s_hToolBar, ID_VIEW_PICTURE_AREA, bShowImage ? MF_CHECKED : MF_UNCHECKED);
+
+ ResizeTreeAndListViews(false);
+
+ FreeScreenShot();
+
+ if (have_selection)
+ // load and set image, or empty it if we don't have one
+ LoadScreenShot(Picker_GetSelectedItem(hwndList), NULL, TabView_GetCurrentTab(hTabCtrl));
+
+ // figure out if we have a history or not, to place our other windows properly
+ UpdateHistory();
+
+ // setup the picture area
+
+ if (bShowImage)
+ {
+ DWORD dwStyle;
+ DWORD dwStyleEx;
+ BOOL showing_history;
+
+ ClientToScreen(hMain, &p);
+ GetWindowRect(GetDlgItem(hMain, IDC_SSFRAME), &fRect);
+ OffsetRect(&fRect, -p.x, -p.y);
+
+ // show history on this tab IF
+ // - we have history for the game
+ // - we're on the first tab
+ // - we DON'T have a separate history tab
+ showing_history = (have_history && (TabView_GetCurrentTab(hTabCtrl) == GetHistoryTab() || GetHistoryTab() == TAB_ALL ) && GetShowTab(TAB_HISTORY) == false);
+ CalculateBestScreenShotRect(GetDlgItem(hMain, IDC_SSFRAME), &rect,showing_history);
+
+ dwStyle = GetWindowLong(GetDlgItem(hMain, IDC_SSPICTURE), GWL_STYLE);
+ dwStyleEx = GetWindowLong(GetDlgItem(hMain, IDC_SSPICTURE), GWL_EXSTYLE);
+
+ AdjustWindowRectEx(&rect, dwStyle, false, dwStyleEx);
+ MoveWindow(GetDlgItem(hMain, IDC_SSPICTURE), fRect.left + rect.left, fRect.top + rect.top, rect.right - rect.left, rect.bottom - rect.top, true);
+
+ ShowWindow(GetDlgItem(hMain,IDC_SSPICTURE), (TabView_GetCurrentTab(hTabCtrl) != TAB_HISTORY) ? SW_SHOW : SW_HIDE);
+ ShowWindow(GetDlgItem(hMain,IDC_SSFRAME),SW_SHOW);
+ ShowWindow(GetDlgItem(hMain,IDC_SSTAB),bShowTabCtrl ? SW_SHOW : SW_HIDE);
+
+ InvalidateRect(GetDlgItem(hMain,IDC_SSPICTURE),NULL,false);
+ }
+ else
+ {
+ ShowWindow(GetDlgItem(hMain,IDC_SSPICTURE),SW_HIDE);
+ ShowWindow(GetDlgItem(hMain,IDC_SSFRAME),SW_HIDE);
+ ShowWindow(GetDlgItem(hMain,IDC_SSTAB),SW_HIDE);
+ }
+
+}
+
+void ResizePickerControls(HWND hWnd)
+{
+ RECT frameRect;
+ RECT rect, sRect;
+ static BOOL firstTime = true;
+ int doSSControls = true;
+
+ int nSplitterCount = GetSplitterCount();
+
+ /* Size the List Control in the Picker */
+ GetClientRect(hWnd, &rect);
+
+ /* Calc the display sizes based on g_splitterInfo */
+ if (firstTime)
+ {
+ RECT rWindow;
+
+ for (int i = 0; i < nSplitterCount; i++)
+ nSplitterOffset[i] = rect.right * g_splitterInfo[i].dPosition;
+
+ GetWindowRect(hStatusBar, &rWindow);
+ bottomMargin = rWindow.bottom - rWindow.top;
+ GetWindowRect(s_hToolBar, &rWindow);
+ topMargin = rWindow.bottom - rWindow.top;
+ /*buttonMargin = (sRect.bottom + 4); */
+
+ firstTime = false;
+ }
+ else
+ doSSControls = BIT(GetWindowPanes(), 3);
+
+ if (bShowStatusBar)
+ rect.bottom -= bottomMargin;
+
+ if (bShowToolBar)
+ rect.top += topMargin;
+
+ MoveWindow(GetDlgItem(hWnd, IDC_DIVIDER), rect.left, rect.top - 4, rect.right, 2, true);
+
+ ResizeTreeAndListViews(true);
+
+ int nListWidth = nSplitterOffset[nSplitterCount-1];
+ int nScreenShotWidth = (rect.right - nListWidth) - 4;
+
+ /* Screen shot Page tab control */
+ if (bShowTabCtrl)
+ {
+ MoveWindow(GetDlgItem(hWnd, IDC_SSTAB), nListWidth + 4, rect.top + 2, nScreenShotWidth - 2, rect.top + 20, doSSControls);
+ rect.top += 20;
+ }
+
+ /* resize the Screen shot frame */
+ MoveWindow(GetDlgItem(hWnd, IDC_SSFRAME), nListWidth + 4, rect.top + 2, nScreenShotWidth - 2, (rect.bottom - rect.top) - 4, doSSControls);
+
+ /* The screen shot controls */
+ GetClientRect(GetDlgItem(hWnd, IDC_SSFRAME), &frameRect);
+
+ /* Text control - game history */
+ sRect.left = nListWidth + 14;
+ sRect.right = sRect.left + (nScreenShotWidth - 22);
+
+ if (GetShowTab(TAB_HISTORY))
+ {
+ // We're using the new mode, with the history filling the entire tab (almost)
+ sRect.top = rect.top + 14;
+ sRect.bottom = (rect.bottom - rect.top) - 30;
+ }
+ else
+ {
+ // We're using the original mode, with the history beneath the SS picture
+ sRect.top = rect.top + 264;
+ sRect.bottom = (rect.bottom - rect.top) - 278;
+ }
+
+ MoveWindow(GetDlgItem(hWnd, IDC_HISTORY), sRect.left, sRect.top, sRect.right - sRect.left, sRect.bottom, doSSControls);
+
+ /* the other screen shot controls will be properly placed in UpdateScreenshot() */
+}
+
+
+char *ModifyThe(const char *str)
+{
+ static int bufno = 0;
+ static char buffer[4][255];
+
+ if (strncmp(str, "The ", 4) == 0)
+ {
+ char *s, *p;
+ char temp[255];
+
+ strcpy(temp, &str[4]);
+
+ bufno = (bufno + 1) % 4;
+
+ s = buffer[bufno];
+
+ /* Check for version notes in parens */
+ p = strchr(temp, '(');
+ if (p)
+ {
+ p[-1] = '\0';
+ }
+
+ strcpy(s, temp);
+ strcat(s, ", The");
+
+ if (p)
+ {
+ strcat(s, " ");
+ strcat(s, p);
+ }
+
+ return s;
+ }
+ return (char *)str;
+}
+
+HBITMAP GetBackgroundBitmap(void)
+{
+ return hBackground;
+}
+
+HPALETTE GetBackgroundPalette(void)
+{
+ return hPALbg;
+}
+
+MYBITMAPINFO *GetBackgroundInfo(void)
+{
+ return &bmDesc;
+}
+
+BOOL GetUseOldControl(void)
+{
+ return oldControl;
+}
+
+BOOL GetUseXPControl(void)
+{
+ return xpControl;
+}
+
+int GetMinimumScreenShotWindowWidth(void)
+{
+ BITMAP bmp;
+ GetObject(hMissing_bitmap,sizeof(BITMAP),&bmp);
+
+ return bmp.bmWidth + 6; // 6 is for a little breathing room
+}
+
+
+int GetParentIndex(const game_driver *driver)
+{
+ return GetGameNameIndex(driver->parent);
+}
+
+int GetParentRomSetIndex(const game_driver *driver)
+{
+ int nParentIndex = GetGameNameIndex(driver->parent);
+
+ if( nParentIndex >= 0)
+ if ((driver_list::driver(nParentIndex).flags & MACHINE_IS_BIOS_ROOT) == 0)
+ return nParentIndex;
+
+ return -1;
+}
+
+int GetGameNameIndex(const char *name)
+{
+ return driver_list::find(name);
+}
+
+/***************************************************************************
+ Internal functions
+ ***************************************************************************/
+
+
+static void SetMainTitle(void)
+{
+ char version[50];
+ char buffer[100];
+
+ sscanf(GetVersionString(),"%49s",version);
+ snprintf(buffer, ARRAY_LENGTH(buffer), "%s %s", MAMEUINAME, GetVersionString());
+ win_set_window_text_utf8(hMain,buffer);
+}
+
+static void memory_error(const char *message)
+{
+ win_message_box_utf8(hMain, message, emulator_info::get_appname(), MB_OK);
+ exit(-1);
+}
+
+static BOOL Win32UI_init(HINSTANCE hInstance, LPWSTR lpCmdLine, int nCmdShow)
+{
+ extern int mame_validitychecks(int game);
+ WNDCLASS wndclass;
+ RECT rect;
+ int i, nSplitterCount;
+ extern const FOLDERDATA g_folderData[];
+ extern const FILTER_ITEM g_filterList[];
+ LONG common_control_version = GetCommonControlVersion();
+ int validity_failed = 0;
+ LONG_PTR l;
+
+ if (!OptionsInit())
+ return false;
+
+ srand((unsigned)time(NULL));
+
+ // create the memory pool
+ mameui_pool = pool_alloc_lib(memory_error);
+
+ // custom per-game icons
+ icon_index = (int*)pool_malloc_lib(mameui_pool, sizeof(int) * driver_list::total());
+ memset(icon_index, '\0', sizeof(int) * driver_list::total());
+
+ // set up window class
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = MameWindowProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = DLGWINDOWEXTRA;
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAMEUI_ICON));
+ wndclass.hCursor = NULL;
+ wndclass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
+ wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_UI_MENU);
+ wndclass.lpszClassName = TEXT("MainClass");
+
+ RegisterClass(&wndclass);
+
+ InitCommonControls();
+
+ // Are we using an Old comctl32.dll?
+ dprintf("common controlversion %ld %ld\n",common_control_version >> 16, common_control_version & 0xffff);
+
+ oldControl = (common_control_version < PACKVERSION(4,71));
+ xpControl = (common_control_version >= PACKVERSION(6,0));
+ if (oldControl)
+ {
+ char buf[] = MAMEUINAME " has detected an old version of comctl32.dll.\n\n"
+ "Various features are not available without an updated DLL.\n\n";
+
+ win_message_box_utf8(0, buf, MAMEUINAME " Outdated comctl32.dll Error", MB_OK | MB_ICONWARNING);
+ return false;
+ }
+
+ g_mame32_message = RegisterWindowMessage(TEXT("MAME32"));
+
+ HelpInit();
+
+ hMain = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
+ if (hMain == NULL)
+ {
+ dprintf("error creating main dialog, aborting\n");
+ return false;
+ }
+
+ s_pWatcher = DirWatcher_Init(hMain, WM_MAME32_FILECHANGED);
+ if (s_pWatcher)
+ {
+ DirWatcher_Watch(s_pWatcher, 0, GetRomDirs(), true);
+ DirWatcher_Watch(s_pWatcher, 1, GetSampleDirs(), true);
+ }
+
+ SetMainTitle();
+ hTabCtrl = GetDlgItem(hMain, IDC_SSTAB);
+
+ {
+ struct TabViewOptions opts;
+
+ static const struct TabViewCallbacks s_tabviewCallbacks =
+ {
+ GetShowTabCtrl, // pfnGetShowTabCtrl
+ SetCurrentTab, // pfnSetCurrentTab
+ GetCurrentTab, // pfnGetCurrentTab
+ SetShowTab, // pfnSetShowTab
+ GetShowTab, // pfnGetShowTab
+
+ GetImageTabShortName, // pfnGetTabShortName
+ GetImageTabLongName, // pfnGetTabLongName
+ UpdateScreenShot // pfnOnSelectionChanged
+ };
+
+ memset(&opts, 0, sizeof(opts));
+ opts.pCallbacks = &s_tabviewCallbacks;
+ opts.nTabCount = MAX_TAB_TYPES;
+
+ if (!SetupTabView(hTabCtrl, &opts))
+ return false;
+ }
+
+ /* subclass history window */
+ l = GetWindowLongPtr(GetDlgItem(hMain, IDC_HISTORY), GWLP_WNDPROC);
+ g_lpHistoryWndProc = (WNDPROC)l;
+ SetWindowLongPtr(GetDlgItem(hMain, IDC_HISTORY), GWLP_WNDPROC, (LONG_PTR)HistoryWndProc);
+
+ /* subclass picture frame area */
+ l = GetWindowLongPtr(GetDlgItem(hMain, IDC_SSFRAME), GWLP_WNDPROC);
+ g_lpPictureFrameWndProc = (WNDPROC)l;
+ SetWindowLongPtr(GetDlgItem(hMain, IDC_SSFRAME), GWLP_WNDPROC, (LONG_PTR)PictureFrameWndProc);
+
+ /* subclass picture area */
+ l = GetWindowLongPtr(GetDlgItem(hMain, IDC_SSPICTURE), GWLP_WNDPROC);
+ g_lpPictureWndProc = (WNDPROC)l;
+ SetWindowLongPtr(GetDlgItem(hMain, IDC_SSPICTURE), GWLP_WNDPROC, (LONG_PTR)PictureWndProc);
+
+ /* Load the pic for the default screenshot. */
+ hMissing_bitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_ABOUT));
+
+ /* Stash hInstance for later use */
+ hInst = hInstance;
+
+ s_hToolBar = InitToolbar(hMain);
+ hStatusBar = InitStatusBar(hMain);
+ hProgWnd = InitProgressBar(hStatusBar);
+
+ main_resize_items[0].u.hwnd = s_hToolBar;
+ main_resize_items[1].u.hwnd = hStatusBar;
+
+ /* In order to handle 'Large Fonts' as the Windows
+ * default setting, we need to make the dialogs small
+ * enough to fit in our smallest window size with
+ * large fonts, then resize the picker, tab and button
+ * controls to fill the window, no matter which font
+ * is currently set. This will still look like bad
+ * if the user uses a bigger default font than 125%
+ * (Large Fonts) on the Windows display setting tab.
+ *
+ * NOTE: This has to do with Windows default font size
+ * settings, NOT our picker font size.
+ */
+
+ GetClientRect(hMain, &rect);
+
+ hTreeView = GetDlgItem(hMain, IDC_TREE);
+ hwndList = GetDlgItem(hMain, IDC_LIST);
+
+ if (!InitSplitters())
+ return false;
+
+ nSplitterCount = GetSplitterCount();
+ for (i = 0; i < nSplitterCount; i++)
+ {
+ HWND hWnd;
+ HWND hWndLeft;
+ HWND hWndRight;
+
+ hWnd = GetDlgItem(hMain, g_splitterInfo[i].nSplitterWindow);
+ hWndLeft = GetDlgItem(hMain, g_splitterInfo[i].nLeftWindow);
+ hWndRight = GetDlgItem(hMain, g_splitterInfo[i].nRightWindow);
+
+ AddSplitter(hWnd, hWndLeft, hWndRight, g_splitterInfo[i].pfnAdjust);
+ }
+
+ /* Initial adjustment of controls on the Picker window */
+ ResizePickerControls(hMain);
+
+ TabView_UpdateSelection(hTabCtrl);
+
+ bDoGameCheck = GetGameCheck();
+ idle_work = true;
+ game_index = 0;
+
+ BOOL bShowTree = BIT(GetWindowPanes(), 0);
+ bShowToolBar = GetShowToolBar();
+ bShowStatusBar = GetShowStatusBar();
+ bShowTabCtrl = GetShowTabCtrl();
+
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_FOLDERS, (bShowTree) ? MF_CHECKED : MF_UNCHECKED);
+ ToolBar_CheckButton(s_hToolBar, ID_VIEW_FOLDERS, (bShowTree) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_TOOLBARS, (bShowToolBar) ? MF_CHECKED : MF_UNCHECKED);
+ ShowWindow(s_hToolBar, (bShowToolBar) ? SW_SHOW : SW_HIDE);
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_STATUS, (bShowStatusBar) ? MF_CHECKED : MF_UNCHECKED);
+ ShowWindow(hStatusBar, (bShowStatusBar) ? SW_SHOW : SW_HIDE);
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_PAGETAB, (bShowTabCtrl) ? MF_CHECKED : MF_UNCHECKED);
+
+ if (oldControl)
+ {
+ EnableMenuItem(GetMenu(hMain), ID_CUSTOMIZE_FIELDS, MF_GRAYED);
+ EnableMenuItem(GetMenu(hMain), ID_GAME_PROPERTIES, MF_GRAYED);
+ EnableMenuItem(GetMenu(hMain), ID_OPTIONS_DEFAULTS, MF_GRAYED);
+ }
+
+#ifdef UI_DIRECTDRAW
+ /* Init DirectDraw */
+ if (!DirectDraw_Initialize())
+ {
+ DialogBox(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_DIRECTX), NULL, DirectXDialogProc);
+ return false;
+ }
+#endif
+
+ LoadBackgroundBitmap();
+
+ dprintf("about to init tree\n");
+ InitTree(g_folderData, g_filterList);
+ dprintf("did init tree\n");
+
+ /* Initialize listview columns */
+ InitListView();
+ SetFocus(hwndList);
+
+ /* Reset the font */
+ {
+ LOGFONT logfont;
+
+ GetListFont(&logfont);
+ if (hFont ) {
+ //Clenaup old Font, otherwise we have a GDI handle leak
+ DeleteFont(hFont);
+ }
+ hFont = CreateFontIndirect(&logfont);
+ if (hFont )
+ SetAllWindowsFont(hMain, &main_resize, hFont, false);
+ }
+
+ /* Init DirectInput */
+ if (!DirectInputInitialize())
+ {
+ DialogBox(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_DIRECTX), NULL, DirectXDialogProc);
+ return false;
+ }
+
+ AdjustMetrics();
+ UpdateScreenShot();
+
+ hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDA_TAB_KEYS));
+
+ /* clear keyboard state */
+ KeyboardStateClear();
+
+ if (GetJoyGUI() == true)
+ {
+ g_pJoyGUI = &DIJoystick;
+ if (g_pJoyGUI->init() != 0)
+ g_pJoyGUI = NULL;
+ else
+ SetTimer(hMain, JOYGUI_TIMER, JOYGUI_MS, NULL);
+ }
+ else
+ g_pJoyGUI = NULL;
+
+ if (GetHideMouseOnStartup())
+ {
+ /* For some reason the mouse is centered when a game is exited, which of
+ course causes a WM_MOUSEMOVE event that shows the mouse. So we center
+ it now, before the startup coords are initilized, and that way the mouse
+ will still be hidden when exiting from a game (i hope) :)
+ */
+ SetCursorPos(GetSystemMetrics(SM_CXSCREEN)/2,GetSystemMetrics(SM_CYSCREEN)/2);
+
+ // Then hide it
+ ShowCursor(false);
+ }
+
+ nCmdShow = GetWindowState();
+ if (nCmdShow == SW_HIDE || nCmdShow == SW_MINIMIZE || nCmdShow == SW_SHOWMINIMIZED)
+ {
+ nCmdShow = SW_RESTORE;
+ }
+
+ if (GetRunFullScreen())
+ {
+ LONG lMainStyle;
+
+ // Remove menu
+ SetMenu(hMain,NULL);
+
+ // Frameless dialog (fake fullscreen)
+ lMainStyle = GetWindowLong(hMain, GWL_STYLE);
+ lMainStyle = lMainStyle & (WS_BORDER ^ 0xffffffff);
+ SetWindowLong(hMain, GWL_STYLE, lMainStyle);
+
+ nCmdShow = SW_MAXIMIZE;
+ }
+
+ ShowWindow(hMain, nCmdShow);
+
+ switch (GetViewMode())
+ {
+ case VIEW_LARGE_ICONS :
+ SetView(ID_VIEW_LARGE_ICON);
+ break;
+ case VIEW_SMALL_ICONS :
+ SetView(ID_VIEW_SMALL_ICON);
+ break;
+ case VIEW_INLIST :
+ SetView(ID_VIEW_LIST_MENU);
+ break;
+ case VIEW_REPORT :
+ SetView(ID_VIEW_DETAIL);
+ break;
+ case VIEW_GROUPED :
+ default :
+ SetView(ID_VIEW_GROUPED);
+ break;
+ }
+
+ if (GetCycleScreenshot() > 0)
+ {
+ SetTimer(hMain, SCREENSHOT_TIMER, GetCycleScreenshot()*1000, NULL); //scale to Seconds
+ }
+
+ if (validity_failed)
+ {
+ win_message_box_utf8(hMain, MAMEUINAME " has failed its validity checks. The GUI will "
+ "still work, but emulations will fail to execute", MAMEUINAME, MB_OK | MB_ICONERROR);
+ }
+
+ return true;
+}
+
+
+static void Win32UI_exit()
+{
+ if (g_pJoyGUI)
+ g_pJoyGUI->exit();
+
+ /* Free GDI resources */
+ if (hMain) {
+ DeleteObject(hMain);
+ hMain = NULL;
+ }
+
+ if (hMissing_bitmap)
+ {
+ DeleteBitmap(hMissing_bitmap);
+ hMissing_bitmap = NULL;
+ }
+
+ if (hBackground)
+ {
+ DeleteBitmap(hBackground);
+ hBackground = NULL;
+ }
+
+ if (hPALbg)
+ {
+ DeletePalette(hPALbg);
+ hPALbg = NULL;
+ }
+
+ if (hFont)
+ {
+ DeleteFont(hFont);
+ hFont = NULL;
+ }
+
+ DestroyIcons();
+
+ DestroyAcceleratorTable(hAccel);
+
+ DirectInputClose();
+#ifdef UI_DIRECTDRAW
+ DirectDraw_Close();
+#endif
+
+ SetSavedFolderID(GetCurrentFolderID());
+ SaveGameListOptions();
+ //SaveDefaultOptions();
+ SaveOptions();
+
+ FreeFolders();
+
+ /* DestroyTree(hTreeView); */
+
+ FreeScreenShot();
+
+ HelpExit();
+
+ pool_free_lib(mameui_pool);
+ mameui_pool = NULL;
+}
+
+static LRESULT CALLBACK MameWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ MINMAXINFO *mminfo;
+ int i;
+ TCHAR szClass[128];
+ BOOL res;
+
+ switch (message)
+ {
+ case WM_CTLCOLORSTATIC:
+ if (hBackground && (HWND)lParam == GetDlgItem(hMain, IDC_HISTORY))
+ {
+ static HBRUSH hBrush=0;
+ HDC hDC=(HDC)wParam;
+ LOGBRUSH lb;
+
+ if (hBrush)
+ DeleteBrush(hBrush);
+ lb.lbStyle = BS_HOLLOW;
+ hBrush = CreateBrushIndirect(&lb);
+ SetBkMode(hDC, TRANSPARENT);
+ SetTextColor(hDC, GetListFontColor());
+ return (LRESULT) hBrush;
+ }
+ break;
+
+ case WM_INITDIALOG:
+ /* Initialize info for resizing subitems */
+ GetClientRect(hWnd, &main_resize.rect);
+ return true;
+
+ case WM_SETFOCUS:
+ SetFocus(hwndList);
+ break;
+
+ case WM_SETTINGCHANGE:
+ AdjustMetrics();
+ return 0;
+
+ case WM_SIZE:
+ OnSize(hWnd, wParam, LOWORD(lParam), HIWORD(wParam));
+ return true;
+
+ case WM_MENUSELECT:
+ return Statusbar_MenuSelect(hWnd, wParam, lParam);
+
+ case MM_PLAY_GAME:
+ MamePlayGame();
+ return true;
+
+ case WM_INITMENUPOPUP:
+ UpdateMenu(GetMenu(hWnd));
+ break;
+
+ case WM_CONTEXTMENU:
+ if (HandleTreeContextMenu(hWnd, wParam, lParam) || HandleScreenShotContextMenu(hWnd, wParam, lParam))
+ return false;
+ break;
+
+ case WM_COMMAND:
+ return MameCommand(hWnd,(int)(LOWORD(wParam)),(HWND)(lParam),(UINT)HIWORD(wParam));
+
+ case WM_GETMINMAXINFO:
+ /* Don't let the window get too small; it can break resizing */
+ mminfo = (MINMAXINFO *) lParam;
+ mminfo->ptMinTrackSize.x = MIN_WIDTH;
+ mminfo->ptMinTrackSize.y = MIN_HEIGHT;
+ return 0;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case JOYGUI_TIMER:
+ PollGUIJoystick();
+ break;
+ case SCREENSHOT_TIMER:
+ TabView_CalculateNextTab(hTabCtrl);
+ UpdateScreenShot();
+ TabView_UpdateSelection(hTabCtrl);
+ break;
+ default:
+ break;
+ }
+ return true;
+
+ case WM_CLOSE:
+ {
+ /* save current item */
+ RECT rect;
+ AREA area;
+ int nItem;
+ WINDOWPLACEMENT wndpl;
+ UINT state;
+
+ wndpl.length = sizeof(WINDOWPLACEMENT);
+ GetWindowPlacement(hMain, &wndpl);
+ state = wndpl.showCmd;
+
+ /* Restore the window before we attempt to save parameters,
+ * This fixed the lost window on startup problem, among other problems
+ */
+ if (state == SW_MINIMIZE || state == SW_SHOWMINIMIZED || state == SW_MAXIMIZE)
+ {
+ if( wndpl.flags & WPF_RESTORETOMAXIMIZED || state == SW_MAXIMIZE)
+ state = SW_MAXIMIZE;
+ else
+ state = SW_RESTORE;
+
+ ShowWindow(hWnd, SW_RESTORE);
+ }
+
+ /* Restore the window before we attempt to save parameters,
+ * This fixed the lost window on startup problem, among other problems
+ */
+ if (state == SW_MAXIMIZE)
+ ShowWindow(hWnd, SW_RESTORE);
+
+ for (i = 0; i < GetSplitterCount(); i++)
+ SetSplitterPos(i, nSplitterOffset[i]);
+ SetWindowState(state);
+
+ for (i = 0; i < sizeof(s_nPickers) / sizeof(s_nPickers[0]); i++)
+ Picker_SaveColumnWidths(GetDlgItem(hMain, s_nPickers[i]));
+
+ GetWindowRect(hWnd, &rect);
+ area.x = rect.left;
+ area.y = rect.top;
+ area.width = rect.right - rect.left;
+ area.height = rect.bottom - rect.top;
+ SetWindowArea(&area);
+
+ /* Save the users current game options and default game */
+ nItem = Picker_GetSelectedItem(hwndList);
+ if (nItem >= 0)
+ SetDefaultGame(nItem);
+
+ /* hide window to prevent orphan empty rectangles on the taskbar */
+ /* ShowWindow(hWnd,SW_HIDE); */
+ DestroyWindow( hWnd );
+
+ /* PostQuitMessage(0); */
+ break;
+ }
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+
+ case WM_LBUTTONDOWN:
+ OnLButtonDown(hWnd, (UINT)wParam, MAKEPOINTS(lParam));
+ break;
+
+ /*
+ Check to see if the mouse has been moved by the user since
+ startup. I'd like this checking to be done only in the
+ main WinProc (here), but somehow the WM_MOUSEDOWN messages
+ are eaten up before they reach MameWindowProc. That's why
+ there is one check for each of the subclassed windows too.
+
+ POSSIBLE BUGS:
+ I've included this check in the subclassed windows, but a
+ mose move in either the title bar, the menu, or the
+ toolbar will not generate a WM_MOUSEOVER message. At least
+ not one that I know how to pick up. A solution could maybe
+ be to subclass those too, but that's too much work :)
+ */
+
+ case WM_MOUSEMOVE:
+ {
+ if (MouseHasBeenMoved())
+ ShowCursor(true);
+
+ if (g_listview_dragging)
+ MouseMoveListViewDrag(MAKEPOINTS(lParam));
+ else
+ /* for splitters */
+ OnMouseMove(hWnd, (UINT)wParam, MAKEPOINTS(lParam));
+ break;
+ }
+
+ case WM_LBUTTONUP:
+ if (g_listview_dragging)
+ ButtonUpListViewDrag(MAKEPOINTS(lParam));
+ else
+ /* for splitters */
+ OnLButtonUp(hWnd, (UINT)wParam, MAKEPOINTS(lParam));
+ break;
+
+ case WM_NOTIFY:
+ /* Where is this message intended to go */
+ {
+ LPNMHDR lpNmHdr = (LPNMHDR)lParam;
+
+ /* Fetch tooltip text */
+ if (lpNmHdr->code == TTN_NEEDTEXT)
+ {
+ LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam;
+ CopyToolTipText(lpttt);
+ }
+
+ if (lpNmHdr->hwndFrom == hTreeView)
+ return TreeViewNotify(lpNmHdr);
+
+ GetClassName(lpNmHdr->hwndFrom, szClass, sizeof(szClass) / sizeof(szClass[0]));
+ if (!_tcscmp(szClass, TEXT("SysListView32")))
+ return Picker_HandleNotify(lpNmHdr);
+ if (!_tcscmp(szClass, TEXT("SysTabControl32")))
+ return TabView_HandleNotify(lpNmHdr);
+ }
+ break;
+
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT lpDis = (LPDRAWITEMSTRUCT)lParam;
+
+ GetClassName(lpDis->hwndItem, szClass, sizeof(szClass) / sizeof(szClass[0]));
+ if (!_tcscmp(szClass, TEXT("SysListView32")))
+ Picker_HandleDrawItem(GetDlgItem(hMain, lpDis->CtlID), lpDis);
+ }
+ break;
+
+ case WM_MEASUREITEM :
+ {
+ LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam;
+
+ // tell the list view that each row (item) should be just taller than our font
+
+ //DefWindowProc(hWnd, message, wParam, lParam);
+ //dprintf("default row height calculation gives %u\n",lpmis->itemHeight);
+
+ TEXTMETRIC tm;
+ HDC hDC = GetDC(NULL);
+ HFONT hFontOld = (HFONT)SelectObject(hDC,hFont);
+
+ GetTextMetrics(hDC,&tm);
+
+ lpmis->itemHeight = tm.tmHeight + tm.tmExternalLeading + 1;
+ if (lpmis->itemHeight < 17)
+ lpmis->itemHeight = 17;
+ //dprintf("we would do %u\n",tm.tmHeight + tm.tmExternalLeading + 1);
+ SelectObject(hDC,hFontOld);
+ ReleaseDC(NULL,hDC);
+
+ return true;
+ }
+
+ case WM_MAME32_FILECHANGED:
+ {
+ char szFileName[32];
+ char *s;
+ int nGameIndex;
+ int (*pfnGetAuditResults)(uint32_t driver_index) = NULL;
+ void (*pfnSetAuditResults)(uint32_t driver_index, int audit_results) = NULL;
+
+ switch(HIWORD(wParam))
+ {
+ case 0:
+ pfnGetAuditResults = GetRomAuditResults;
+ pfnSetAuditResults = SetRomAuditResults;
+ break;
+
+ case 1:
+ pfnGetAuditResults = GetSampleAuditResults;
+ pfnSetAuditResults = SetSampleAuditResults;
+ break;
+ }
+
+ if (pfnGetAuditResults && pfnSetAuditResults)
+ {
+ int nParentIndex = -1;
+
+ snprintf(szFileName, sizeof(szFileName), "%s", (LPCSTR) lParam);
+ s = strchr(szFileName, '.');
+ if (s)
+ *s = '\0';
+ s = strchr(szFileName, '\\');
+ if (s)
+ *s = '\0';
+
+ for (nGameIndex = 0; nGameIndex < driver_list::total(); nGameIndex++)
+ {
+ for (nParentIndex = nGameIndex; nGameIndex == -1; nParentIndex = GetParentIndex(&driver_list::driver(nParentIndex)))
+ {
+ if (!core_stricmp(driver_list::driver(nParentIndex).name, szFileName))
+ {
+ if (pfnGetAuditResults(nGameIndex) != UNKNOWN)
+ {
+ pfnSetAuditResults(nGameIndex, UNKNOWN);
+ PostMessage(hMain, WM_MAME32_AUDITGAME, wParam, nGameIndex);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case WM_MAME32_AUDITGAME:
+ {
+ LV_FINDINFO lvfi;
+ int nGameIndex;
+
+ nGameIndex = lParam;
+
+ switch(HIWORD(wParam))
+ {
+ case 0:
+ MameUIVerifyRomSet(nGameIndex, 0);
+ break;
+ case 1:
+ MameUIVerifySampleSet(nGameIndex);
+ break;
+ }
+
+ memset(&lvfi, 0, sizeof(lvfi));
+ lvfi.flags = LVFI_PARAM;
+ lvfi.lParam = nGameIndex;
+
+ i = ListView_FindItem(hwndList, -1, &lvfi);
+ if (i != -1)
+ {
+ res = ListView_RedrawItems(hwndList, i, i);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ res++;
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+static int HandleKeyboardGUIMessage(HWND hWnd, UINT message, UINT wParam, LONG lParam)
+{
+ switch (message)
+ {
+ case WM_CHAR: /* List-View controls use this message for searching the items "as user types" */
+ //MessageBox(NULL,"wm_char message arrived","TitleBox",MB_OK);
+ return true;
+
+ case WM_KEYDOWN:
+ KeyboardKeyDown(0, wParam, lParam);
+ return true;
+
+ case WM_KEYUP:
+ KeyboardKeyUp(0, wParam, lParam);
+ return true;
+
+ case WM_SYSKEYDOWN:
+ KeyboardKeyDown(1, wParam, lParam);
+ return true;
+
+ case WM_SYSKEYUP:
+ KeyboardKeyUp(1, wParam, lParam);
+ return true;
+ }
+
+ return false; /* message not processed */
+}
+
+static BOOL PumpMessage()
+{
+ MSG msg;
+
+ if (!GetMessage(&msg, NULL, 0, 0))
+ return false;
+
+ if (IsWindow(hMain))
+ {
+ BOOL absorbed_key = false;
+ if (GetKeyGUI())
+ absorbed_key = HandleKeyboardGUIMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ else
+ absorbed_key = TranslateAccelerator(hMain, hAccel, &msg);
+
+ if (!absorbed_key)
+ {
+ if (!IsDialogMessage(hMain, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+
+ return true;
+}
+
+static BOOL FolderCheck(void)
+{
+
+ const char *pDescription = NULL;
+ int nGameIndex = 0;
+ int i=0;
+ int iStep = 0;
+ LV_FINDINFO lvfi;
+ int nCount = ListView_GetItemCount(hwndList);
+ BOOL changed = false;
+ BOOL res;
+
+ MSG msg;
+ for(i=0; i<nCount;i++)
+ {
+ LV_ITEM lvi;
+
+ lvi.iItem = i;
+ lvi.iSubItem = 0;
+ lvi.mask = LVIF_PARAM;
+ res = ListView_GetItem(hwndList, &lvi);
+ nGameIndex = lvi.lParam;
+ SetRomAuditResults(nGameIndex, UNKNOWN);
+ SetSampleAuditResults(nGameIndex, UNKNOWN);
+ }
+ if( nCount > 0)
+ ProgressBarShow();
+ else
+ return false;
+ if( nCount < 100 )
+ iStep = 100 / nCount;
+ else
+ iStep = nCount/100;
+ UpdateListView();
+ UpdateWindow(hMain);
+ for(i=0; i<nCount;i++)
+ {
+ LV_ITEM lvi;
+
+ lvi.iItem = i;
+ lvi.iSubItem = 0;
+ lvi.mask = LVIF_PARAM;
+ res = ListView_GetItem(hwndList, &lvi);
+ nGameIndex = lvi.lParam;
+ if (GetRomAuditResults(nGameIndex) == UNKNOWN)
+ {
+ MameUIVerifyRomSet(nGameIndex, 0);
+ changed = true;
+ }
+
+ if (GetSampleAuditResults(nGameIndex) == UNKNOWN)
+ {
+ MameUIVerifySampleSet(nGameIndex);
+ changed = true;
+ }
+
+ lvfi.flags = LVFI_PARAM;
+ lvfi.lParam = nGameIndex;
+
+ i = ListView_FindItem(hwndList, -1, &lvfi);
+ if (changed && i != -1)
+ {
+ res = ListView_RedrawItems(hwndList, i, i);
+ while( PeekMessage( &msg, hwndList, 0, 0, PM_REMOVE ) != 0)
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ changed = false;
+ if ((i % iStep) == 0)
+ ProgressBarStepParam(i, nCount);
+ }
+ ProgressBarHide();
+ if (Picker_GetSelectedItem(hwndList) >= 0)
+ pDescription = ModifyThe(driver_list::driver(Picker_GetSelectedItem(hwndList)).type.fullname());
+ else
+ pDescription = "No Selection";
+ SetStatusBarText(0, pDescription);
+ UpdateStatusBar();
+ res++;
+ return true;
+}
+
+static BOOL GameCheck(void)
+{
+ LV_FINDINFO lvfi;
+ int i;
+ BOOL changed = false;
+ BOOL res;
+
+ if (game_index == 0)
+ ProgressBarShow();
+
+ if (game_index >= driver_list::total())
+ {
+ bDoGameCheck = false;
+ ProgressBarHide();
+ ResetWhichGamesInFolders();
+ return false;
+ }
+
+ if (GetRomAuditResults(game_index) == UNKNOWN)
+ {
+ MameUIVerifyRomSet(game_index, 0);
+ changed = true;
+ }
+
+ if (GetSampleAuditResults(game_index) == UNKNOWN)
+ {
+ MameUIVerifySampleSet(game_index);
+ changed = true;
+ }
+
+ lvfi.flags = LVFI_PARAM;
+ lvfi.lParam = game_index;
+
+ i = ListView_FindItem(hwndList, -1, &lvfi);
+ if (changed && i != -1)
+ res = ListView_RedrawItems(hwndList, i, i);
+ if ((game_index % progBarStep) == 0)
+ ProgressBarStep();
+ game_index++;
+ res++;
+ return changed;
+}
+
+static BOOL OnIdle(HWND hWnd)
+{
+ static int bFirstTime = true;
+ static int bResetList = true;
+
+ const char *pDescription;
+ int driver_index;
+
+ if (bFirstTime)
+ {
+ bResetList = false;
+ bFirstTime = false;
+ }
+ if (bDoGameCheck)
+ {
+ bResetList |= GameCheck();
+ return idle_work;
+ }
+ // NPW 17-Jun-2003 - Commenting this out because it is redundant
+ // and it causes the game to reset back to the original game after an F5
+ // refresh
+ //driver_index = GetGameNameIndex(GetDefaultGame());
+ //SetSelectedPickItem(driver_index);
+
+ // in case it's not found, get it back
+ driver_index = Picker_GetSelectedItem(hwndList);
+ if (driver_index >= 0)
+ pDescription = ModifyThe(driver_list::driver(driver_index).type.fullname());
+ else
+ pDescription = "No Selection";
+
+ SetStatusBarText(0, pDescription);
+ idle_work = false;
+ UpdateStatusBar();
+ bFirstTime = true;
+
+ if (!idle_work)
+ PostMessage(GetMainWindow(),WM_COMMAND, MAKEWPARAM(ID_VIEW_LINEUPICONS, true),(LPARAM)NULL);
+ return idle_work;
+}
+
+static void OnSize(HWND hWnd, UINT nState, int nWidth, int nHeight)
+{
+ static BOOL firstTime = true;
+
+ if (nState != SIZE_MAXIMIZED && nState != SIZE_RESTORED)
+ return;
+
+ ResizeWindow(hWnd, &main_resize);
+ ResizeProgressBar();
+ if (firstTime == false)
+ OnSizeSplitter(hMain);
+ //firstTime = false;
+ /* Update the splitters structures as appropriate */
+ RecalcSplitters();
+ if (firstTime == false)
+ ResizePickerControls(hMain);
+ firstTime = false;
+ UpdateScreenShot();
+}
+
+
+
+static HWND GetResizeItemWindow(HWND hParent, const ResizeItem *ri)
+{
+ HWND hControl;
+ if (ri->type == RA_ID)
+ hControl = GetDlgItem(hParent, ri->u.id);
+ else
+ hControl = ri->u.hwnd;
+ return hControl;
+}
+
+
+
+static void SetAllWindowsFont(HWND hParent, const Resize *r, HFONT hTheFont, BOOL bRedraw)
+{
+ int i;
+ HWND hControl;
+
+ for (i = 0; r->items[i].type != RA_END; i++)
+ {
+ hControl = GetResizeItemWindow(hParent, &r->items[i]);
+ if (r->items[i].setfont)
+ {
+ SetWindowFont(hControl, hTheFont, bRedraw);
+ }
+ /* Take care of subcontrols, if appropriate */
+ if (r->items[i].subwindow )
+ SetAllWindowsFont(hControl, (const Resize*)r->items[i].subwindow, hTheFont, bRedraw);
+
+ }
+}
+
+
+
+static void ResizeWindow(HWND hParent, Resize *r)
+{
+ int cmkindex = 0, dx, dy;
+ HWND hControl;
+ RECT parent_rect, rect;
+ const ResizeItem *ri;
+ POINT p = {0, 0};
+
+ if (hParent == NULL)
+ return;
+
+ /* Calculate change in width and height of parent window */
+ GetClientRect(hParent, &parent_rect);
+ dy = parent_rect.bottom - r->rect.bottom;
+ dx = parent_rect.right - r->rect.right;
+ ClientToScreen(hParent, &p);
+
+ while (r->items[cmkindex].type != RA_END)
+ {
+ int width, height;
+ ri = &r->items[cmkindex];
+ if (ri->type == RA_ID)
+ hControl = GetDlgItem(hParent, ri->u.id);
+ else
+ hControl = ri->u.hwnd;
+
+ if (hControl == NULL)
+ {
+ cmkindex++;
+ continue;
+ }
+
+ /* Get control's rectangle relative to parent */
+ GetWindowRect(hControl, &rect);
+ OffsetRect(&rect, -p.x, -p.y);
+ width = rect.right - rect.left;
+ height = rect.bottom - rect.top;
+
+ if (!(ri->action & RA_LEFT))
+ rect.left += dx;
+
+ if (!(ri->action & RA_TOP))
+ rect.top += dy;
+
+ if (ri->action & RA_RIGHT)
+ rect.right += dx;
+
+ if (ri->action & RA_BOTTOM)
+ rect.bottom += dy;
+ //Sanity Check the child rect
+ if (parent_rect.top > rect.top)
+ rect.top = parent_rect.top;
+ if (parent_rect.left > rect.left)
+ rect.left = parent_rect.left;
+ if (parent_rect.bottom < rect.bottom)
+ {
+ rect.bottom = parent_rect.bottom;
+ //ensure we have at least a minimal height
+ rect.top = rect.bottom - height;
+ if (rect.top < parent_rect.top)
+ rect.top = parent_rect.top;
+ }
+ if (parent_rect.right < rect.right)
+ {
+ rect.right = parent_rect.right;
+ //ensure we have at least a minimal width
+ rect.left = rect.right - width;
+ if (rect.left < parent_rect.left)
+ rect.left = parent_rect.left;
+ }
+ MoveWindow(hControl, rect.left, rect.top,
+ (rect.right - rect.left),
+ (rect.bottom - rect.top), true);
+
+ /* Take care of subcontrols, if appropriate */
+ if (ri->subwindow )
+ ResizeWindow(hControl, (Resize*)ri->subwindow);
+
+ cmkindex++;
+ }
+
+ /* Record parent window's new location */
+ memcpy(&r->rect, &parent_rect, sizeof(RECT));
+}
+
+static void ProgressBarShow()
+{
+ RECT rect;
+ int widths[2] = {150, -1};
+
+ if (driver_list::total() < 100)
+ progBarStep = 100 / driver_list::total();
+ else
+ progBarStep = (driver_list::total() / 100);
+
+ SendMessage(hStatusBar, SB_SETPARTS, (WPARAM)2, (LPARAM)(LPINT)widths);
+ SendMessage(hProgWnd, PBM_SETRANGE, 0, (LPARAM)MAKELONG(0, driver_list::total()));
+ SendMessage(hProgWnd, PBM_SETSTEP, (WPARAM)progBarStep, 0);
+ SendMessage(hProgWnd, PBM_SETPOS, 0, 0);
+
+ StatusBar_GetItemRect(hStatusBar, 1, &rect);
+
+ MoveWindow(hProgWnd, rect.left, rect.top,
+ rect.right - rect.left,
+ rect.bottom - rect.top, true);
+
+ bProgressShown = true;
+}
+
+static void ProgressBarHide()
+{
+ RECT rect;
+ int widths[4];
+ HDC hDC;
+ SIZE size;
+ int numParts = 4;
+
+ if (hProgWnd == NULL)
+ return;
+
+ hDC = GetDC(hProgWnd);
+
+ ShowWindow(hProgWnd, SW_HIDE);
+
+ GetTextExtentPoint32(hDC, TEXT("MMX"), 3, &size);
+ widths[3] = size.cx;
+ GetTextExtentPoint32(hDC, TEXT("MMMM games"), 10, &size);
+ widths[2] = size.cx;
+ //Just specify 24 instead of 30, gives us sufficient space to display the message, and saves some space
+ GetTextExtentPoint32(hDC, TEXT("Screen flip support is missing"), 24, &size);
+ widths[1] = size.cx;
+
+ ReleaseDC(hProgWnd, hDC);
+
+ widths[0] = -1;
+ SendMessage(hStatusBar, SB_SETPARTS, (WPARAM)1, (LPARAM)(LPINT)widths);
+ StatusBar_GetItemRect(hStatusBar, 0, &rect);
+
+ widths[0] = (rect.right - rect.left) - (widths[1] + widths[2] + widths[3]);
+ widths[1] += widths[0];
+ widths[2] += widths[1];
+ widths[3] = -1;
+
+ SendMessage(hStatusBar, SB_SETPARTS, (WPARAM)numParts, (LPARAM)(LPINT)widths);
+ UpdateStatusBar();
+
+ bProgressShown = false;
+}
+
+static void ResizeProgressBar()
+{
+ if (bProgressShown)
+ {
+ RECT rect;
+ int widths[2] = {150, -1};
+
+ SendMessage(hStatusBar, SB_SETPARTS, (WPARAM)2, (LPARAM)(LPINT)widths);
+ StatusBar_GetItemRect(hStatusBar, 1, &rect);
+ MoveWindow(hProgWnd, rect.left, rect.top,
+ rect.right - rect.left,
+ rect.bottom - rect.top, true);
+ }
+ else
+ {
+ ProgressBarHide();
+ }
+}
+
+static void ProgressBarStepParam(int iGameIndex, int nGameCount)
+{
+ SetStatusBarTextF(0, "Game search %d%% complete", ((iGameIndex + 1) * 100) / nGameCount);
+ if (iGameIndex == 0)
+ ShowWindow(hProgWnd, SW_SHOW);
+ SendMessage(hProgWnd, PBM_STEPIT, 0, 0);
+}
+
+static void ProgressBarStep()
+{
+ ProgressBarStepParam(game_index, driver_list::total());
+}
+
+static HWND InitProgressBar(HWND hParent)
+{
+ RECT rect;
+
+ StatusBar_GetItemRect(hStatusBar, 0, &rect);
+
+ rect.left += 150;
+
+ return CreateWindowEx(WS_EX_STATICEDGE, PROGRESS_CLASS, TEXT("Progress Bar"),
+ WS_CHILD | PBS_SMOOTH, rect.left, rect.top, rect.right - rect.left,
+ rect.bottom - rect.top, hParent, NULL, hInst, NULL);
+}
+
+static void CopyToolTipText(LPTOOLTIPTEXT lpttt)
+{
+ int i;
+ int iButton = lpttt->hdr.idFrom;
+ static TCHAR String[1024];
+ BOOL bConverted = false;
+ TCHAR* t_gameinfostatus;
+
+ /* Map command ID to string index */
+ for (i = 0; CommandToString[i] != -1; i++)
+ {
+ if (CommandToString[i] == iButton)
+ {
+ iButton = i;
+ bConverted = true;
+ break;
+ }
+ }
+ if( bConverted )
+ {
+ /* Check for valid parameter */
+ if(iButton > NUM_TOOLTIPS)
+ {
+ _tcscpy(String,TEXT("Invalid Button Index"));
+ }
+ else
+ {
+ _tcscpy(String,szTbStrings[iButton]);
+ }
+ }
+ else if ( iButton <= 2 )
+ {
+ //Statusbar
+ SendMessage(lpttt->hdr.hwndFrom, TTM_SETMAXTIPWIDTH, 0, 200);
+ if( iButton != 1)
+ SendMessage(hStatusBar, SB_GETTEXT, (WPARAM)iButton, (LPARAM)&String );
+ else {
+ //for first pane we get the Status directly, to get the line breaks
+ t_gameinfostatus = ui_wstring_from_utf8( GameInfoStatus(Picker_GetSelectedItem(hwndList), false));
+ if( !t_gameinfostatus )
+ return;
+ _tcscpy(String, t_gameinfostatus);
+ free(t_gameinfostatus);
+ }
+ }
+ else
+ _tcscpy(String,TEXT("Invalid Button Index"));
+
+ lpttt->lpszText = String;
+}
+
+static HWND InitToolbar(HWND hParent)
+{
+ HWND hToolBar = CreateToolbarEx(hParent,
+ WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
+ CCS_TOP | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS, 1, 8,
+ hInst, IDB_TOOLBAR, tbb, NUM_TOOLBUTTONS, 16, 16, 0, 0, sizeof(TBBUTTON));
+ RECT rect;
+ int idx;
+ int iPosX, iPosY, iHeight;
+
+ // get Edit Control position
+ idx = SendMessage(hToolBar, TB_BUTTONCOUNT, (WPARAM)0, (LPARAM)0) - 1;
+ SendMessage(hToolBar, TB_GETITEMRECT, (WPARAM)idx, (LPARAM)&rect);
+ iPosX = rect.right + 10;
+ iPosY = rect.top + 1;
+ iHeight = rect.bottom - rect.top - 2;
+
+ // create Edit Control
+ win_create_window_ex_utf8( 0L, "Edit", SEARCH_PROMPT, WS_CHILD | WS_BORDER | WS_VISIBLE | ES_LEFT,
+ iPosX, iPosY, 200, iHeight, hToolBar, (HMENU)ID_TOOLBAR_EDIT, hInst, NULL );
+
+ return hToolBar;
+}
+
+static HWND InitStatusBar(HWND hParent)
+{
+ HMENU hMenu = GetMenu(hParent);
+
+ popstr[0].hMenu = 0;
+ popstr[0].uiString = 0;
+ popstr[1].hMenu = hMenu;
+ popstr[1].uiString = IDS_UI_FILE;
+ popstr[2].hMenu = GetSubMenu(hMenu, 1);
+ popstr[2].uiString = IDS_VIEW_TOOLBAR;
+ popstr[3].hMenu = 0;
+ popstr[3].uiString = 0;
+
+ return CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
+ CCS_BOTTOM | SBARS_SIZEGRIP | SBT_TOOLTIPS,
+ TEXT("Ready"), hParent, 2);
+}
+
+
+static LRESULT Statusbar_MenuSelect(HWND hwnd, WPARAM wParam, LPARAM lParam)
+{
+ UINT fuFlags = (UINT)HIWORD(wParam);
+ HMENU hMainMenu = NULL;
+ int iMenu = 0;
+
+ /* Handle non-system popup menu descriptions. */
+ if ( (fuFlags & MF_POPUP)
+ && (!(fuFlags & MF_SYSMENU)))
+ {
+ for (iMenu = 1; iMenu < MAX_MENUS; iMenu++)
+ {
+ if ((HMENU)lParam == popstr[iMenu].hMenu)
+ {
+ hMainMenu = (HMENU)lParam;
+ break;
+ }
+ }
+ }
+
+ if (hMainMenu)
+ {
+ /* Display helpful text in status bar */
+ MenuHelp(WM_MENUSELECT, wParam, lParam, hMainMenu, hInst,
+ hStatusBar, (UINT *)&popstr[iMenu]);
+ }
+ else
+ {
+ UINT nZero = 0;
+ MenuHelp(WM_MENUSELECT, wParam, lParam, NULL, hInst,
+ hStatusBar, &nZero);
+ }
+
+ return 0;
+}
+
+static void UpdateStatusBar()
+{
+ LPTREEFOLDER lpFolder = GetCurrentFolder();
+ int games_shown = 0;
+ int i = -1;
+
+ if (!lpFolder)
+ return;
+
+ while (1)
+ {
+ i = FindGame(lpFolder,i+1);
+ if (i == -1)
+ break;
+
+ if (!GameFiltered(i, lpFolder->m_dwFlags))
+ games_shown++;
+ }
+
+ /* Show number of games in the current 'View' in the status bar */
+ SetStatusBarTextF(2, g_szGameCountString, games_shown);
+
+ i = Picker_GetSelectedItem(hwndList);
+
+ if (games_shown == 0)
+ DisableSelection();
+ else
+ {
+ const char* pStatus = GameInfoStatus(i, false);
+ SetStatusBarText(1, pStatus);
+ }
+}
+
+static void UpdateHistory(void)
+{
+ HDC hDC;
+ RECT rect;
+ TEXTMETRIC tm ;
+ int nLines, nLineHeight;
+ //DWORD dwStyle = GetWindowLong(GetDlgItem(hMain, IDC_HISTORY), GWL_STYLE);
+ have_history = false;
+
+ if (GetSelectedPick() >= 0)
+ {
+ char *histText = GetGameHistory(Picker_GetSelectedItem(hwndList));
+
+ have_history = (histText && histText[0]) ? true : false;
+ win_set_window_text_utf8(GetDlgItem(hMain, IDC_HISTORY), histText);
+ }
+
+ if (have_history && BIT(GetWindowPanes(), 3)
+ && ((TabView_GetCurrentTab(hTabCtrl) == TAB_HISTORY) ||
+ (TabView_GetCurrentTab(hTabCtrl) == GetHistoryTab() && GetShowTab(TAB_HISTORY) == false) ||
+ (TAB_ALL == GetHistoryTab() && GetShowTab(TAB_HISTORY) == false) ))
+ {
+ Edit_GetRect(GetDlgItem(hMain, IDC_HISTORY),&rect);
+ nLines = Edit_GetLineCount(GetDlgItem(hMain, IDC_HISTORY) );
+ hDC = GetDC(GetDlgItem(hMain, IDC_HISTORY));
+ GetTextMetrics (hDC, &tm);
+ nLineHeight = tm.tmHeight - tm.tmInternalLeading;
+ if( ( (rect.bottom - rect.top) / nLineHeight) < (nLines) )
+ {
+ //more than one Page, so show Scrollbar
+ SetScrollRange(GetDlgItem(hMain, IDC_HISTORY), SB_VERT, 0, nLines, true);
+ }
+ else
+ {
+ //hide Scrollbar
+ SetScrollRange(GetDlgItem(hMain, IDC_HISTORY),SB_VERT, 0, 0, true);
+
+ }
+ ShowWindow(GetDlgItem(hMain, IDC_HISTORY), SW_SHOW);
+ }
+ else
+ ShowWindow(GetDlgItem(hMain, IDC_HISTORY), SW_HIDE);
+
+}
+
+
+static void DisableSelection()
+{
+ MENUITEMINFO mmi;
+ HMENU hMenu = GetMenu(hMain);
+ BOOL prev_have_selection = have_selection;
+
+ mmi.cbSize = sizeof(mmi);
+ mmi.fMask = MIIM_TYPE;
+ mmi.fType = MFT_STRING;
+ mmi.dwTypeData = (TCHAR *) TEXT("&Play");
+ mmi.cch = _tcslen(mmi.dwTypeData);
+ SetMenuItemInfo(hMenu, ID_FILE_PLAY, false, &mmi);
+
+ EnableMenuItem(hMenu, ID_FILE_PLAY, MF_GRAYED);
+ EnableMenuItem(hMenu, ID_FILE_PLAY_RECORD, MF_GRAYED);
+ EnableMenuItem(hMenu, ID_GAME_PROPERTIES, MF_GRAYED);
+
+ SetStatusBarText(0, "No Selection");
+ SetStatusBarText(1, "");
+ SetStatusBarText(3, "");
+
+ have_selection = false;
+
+ if (prev_have_selection != have_selection)
+ UpdateScreenShot();
+}
+
+static void EnableSelection(int nGame)
+{
+ TCHAR buf[200];
+ const char * pText;
+ MENUITEMINFO mmi;
+ HMENU hMenu = GetMenu(hMain);
+ TCHAR* t_description;
+
+ t_description = ui_wstring_from_utf8(ConvertAmpersandString(ModifyThe(driver_list::driver(nGame).type.fullname())));
+ if( !t_description )
+ return;
+
+ _sntprintf(buf, sizeof(buf) / sizeof(buf[0]), g_szPlayGameString, t_description);
+ mmi.cbSize = sizeof(mmi);
+ mmi.fMask = MIIM_TYPE;
+ mmi.fType = MFT_STRING;
+ mmi.dwTypeData = buf;
+ mmi.cch = _tcslen(mmi.dwTypeData);
+ SetMenuItemInfo(hMenu, ID_FILE_PLAY, false, &mmi);
+
+ pText = ModifyThe(driver_list::driver(nGame).type.fullname());
+ SetStatusBarText(0, pText);
+ /* Add this game's status to the status bar */
+ pText = GameInfoStatus(nGame, false);
+ SetStatusBarText(1, pText);
+ SetStatusBarText(3, "");
+
+ /* If doing updating game status and the game name is NOT pacman.... */
+
+ EnableMenuItem(hMenu, ID_FILE_PLAY, MF_ENABLED);
+ EnableMenuItem(hMenu, ID_FILE_PLAY_RECORD, MF_ENABLED);
+
+ if (!oldControl)
+ EnableMenuItem(hMenu, ID_GAME_PROPERTIES, MF_ENABLED);
+
+ if (bProgressShown && bListReady == true)
+ SetDefaultGame(nGame);
+
+ have_selection = true;
+
+ UpdateScreenShot();
+
+ free(t_description);
+}
+
+static void PaintBackgroundImage(HWND hWnd, HRGN hRgn, int x, int y)
+{
+ RECT rcClient;
+ HRGN rgnBitmap;
+ HPALETTE hPAL;
+ HDC hDC = GetDC(hWnd);
+ int i, j;
+ HDC htempDC;
+ HBITMAP oldBitmap;
+
+ /* x and y are offsets within the background image that should be at 0,0 in hWnd */
+
+ /* So we don't paint over the control's border */
+ GetClientRect(hWnd, &rcClient);
+
+ htempDC = CreateCompatibleDC(hDC);
+ oldBitmap = (HBITMAP)SelectObject(htempDC, hBackground);
+
+ if (hRgn == NULL)
+ {
+ /* create a region of our client area */
+ rgnBitmap = CreateRectRgnIndirect(&rcClient);
+ SelectClipRgn(hDC, rgnBitmap);
+ DeleteBitmap(rgnBitmap);
+ }
+ else
+ {
+ /* use the passed in region */
+ SelectClipRgn(hDC, hRgn);
+ }
+
+ hPAL = GetBackgroundPalette();
+ if (hPAL == NULL)
+ hPAL = CreateHalftonePalette(hDC);
+
+ if (GetDeviceCaps(htempDC, RASTERCAPS) & RC_PALETTE && hPAL)
+ {
+ SelectPalette(htempDC, hPAL, false);
+ RealizePalette(htempDC);
+ }
+
+ for (i = rcClient.left-x; i < rcClient.right; i += bmDesc.bmWidth)
+ for (j = rcClient.top-y; j < rcClient.bottom; j += bmDesc.bmHeight)
+ BitBlt(hDC, i, j, bmDesc.bmWidth, bmDesc.bmHeight, htempDC, 0, 0, SRCCOPY);
+
+ SelectObject(htempDC, oldBitmap);
+ DeleteDC(htempDC);
+
+ if (GetBackgroundPalette() == NULL)
+ {
+ DeletePalette(hPAL);
+ hPAL = NULL;
+ }
+
+ ReleaseDC(hWnd, hDC);
+}
+
+static LPCSTR GetCloneParentName(int nItem)
+{
+ int nParentIndex = -1;
+
+ if (DriverIsClone(nItem) == true)
+ {
+ nParentIndex = GetParentIndex(&driver_list::driver(nItem));
+ if( nParentIndex >= 0)
+ return ModifyThe(driver_list::driver(nParentIndex).type.fullname());
+ }
+ return "";
+}
+
+static BOOL TreeViewNotify(LPNMHDR nm)
+{
+ switch (nm->code)
+ {
+ case TVN_SELCHANGED :
+ {
+ HTREEITEM hti = TreeView_GetSelection(hTreeView);
+ TVITEM tvi;
+
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE;
+ tvi.hItem = hti;
+
+ if (TreeView_GetItem(hTreeView, &tvi))
+ {
+ SetCurrentFolder((LPTREEFOLDER)tvi.lParam);
+ if (bListReady)
+ {
+ ResetListView();
+ UpdateScreenShot();
+ }
+ }
+ return true;
+ }
+ case TVN_BEGINLABELEDIT :
+ {
+ TV_DISPINFO *ptvdi = (TV_DISPINFO *)nm;
+ LPTREEFOLDER folder = (LPTREEFOLDER)ptvdi->item.lParam;
+
+ if (folder->m_dwFlags & F_CUSTOM)
+ {
+ // user can edit custom folder names
+ g_in_treeview_edit = true;
+ return false;
+ }
+ // user can't edit built in folder names
+ return true;
+ }
+ case TVN_ENDLABELEDIT :
+ {
+ TV_DISPINFO *ptvdi = (TV_DISPINFO *)nm;
+ LPTREEFOLDER folder = (LPTREEFOLDER)ptvdi->item.lParam;
+ char* utf8_szText;
+ BOOL result;
+
+ g_in_treeview_edit = false;
+
+ if (ptvdi->item.pszText == NULL || _tcslen(ptvdi->item.pszText) == 0)
+ return false;
+
+ utf8_szText = ui_utf8_from_wstring(ptvdi->item.pszText);
+ if( !utf8_szText )
+ return false;
+
+ result = TryRenameCustomFolder(folder, utf8_szText);
+
+ free(utf8_szText);
+
+ return result;
+ }
+ }
+ return false;
+}
+
+
+
+static void GamePicker_OnHeaderContextMenu(POINT pt, int nColumn)
+{
+ // Right button was clicked on header
+ HMENU hMenuLoad;
+ HMENU hMenu;
+
+ hMenuLoad = LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTEXT_HEADER));
+ hMenu = GetSubMenu(hMenuLoad, 0);
+ lastColumnClick = nColumn;
+ TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_RIGHTBUTTON,pt.x,pt.y,0,hMain,NULL);
+
+ DestroyMenu(hMenuLoad);
+}
+
+
+
+char* ConvertAmpersandString(const char *s)
+{
+ /* takes a string and changes any ampersands to double ampersands,
+ for setting text of window controls that don't allow us to disable
+ the ampersand underlining.
+ */
+ /* returns a static buffer--use before calling again */
+
+ static char buf[200];
+ char *ptr;
+
+ ptr = buf;
+ while (*s)
+ {
+ if (*s == '&')
+ *ptr++ = *s;
+ *ptr++ = *s++;
+ }
+ *ptr = 0;
+
+ return buf;
+}
+
+static int GUI_seq_pressed(const input_seq *seq)
+{
+ int codenum;
+ int res = 1;
+ bool invert = 0;
+ int count = 0;
+
+ for (codenum = 0; (*seq)[codenum] != input_seq::end_code; codenum++)
+ {
+ input_code code = (*seq)[codenum];
+
+ if (code == input_seq::not_code)
+ invert = !invert;
+
+ else if (code == input_seq::or_code)
+ {
+ if (res && count)
+ return 1;
+ res = 1;
+ count = 0;
+ }
+ else
+ {
+ if (res)
+ {
+ if ((keyboard_state[(int)(code.item_id())] != 0) == invert)
+ res = 0;
+ }
+ invert = 0;
+ ++count;
+ }
+ }
+ return res && count;
+}
+
+static void check_for_GUI_action(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_GUI_SEQUENCES; i++)
+ {
+ const input_seq *is = &(GUISequenceControl[i].is);
+
+ if (GUI_seq_pressed(is))
+ {
+ dprintf("seq =%s pressed\n", GUISequenceControl[i].name);
+ switch (GUISequenceControl[i].func_id)
+ {
+ case ID_GAME_AUDIT:
+ case ID_GAME_PROPERTIES:
+ case ID_CONTEXT_FILTERS:
+ case ID_UI_START:
+ KeyboardStateClear(); /* because whe won't receive KeyUp mesage when we lose focus */
+ break;
+ default:
+ break;
+ }
+ SendMessage(hMain, WM_COMMAND, GUISequenceControl[i].func_id, 0);
+ }
+ }
+}
+
+static void KeyboardStateClear(void)
+{
+ memset(keyboard_state, 0, sizeof(keyboard_state));
+ dprintf("keyboard gui state cleared.\n");
+}
+
+
+static void KeyboardKeyDown(int syskey, int vk_code, int special)
+{
+ int i, found = 0;
+ int icode = 0;
+ int special_code = (special >> 24) & 1;
+ int scancode = (special>>16) & 0xff;
+
+ if ((vk_code==VK_MENU) || (vk_code==VK_CONTROL) || (vk_code==VK_SHIFT))
+ {
+ found = 1;
+
+ /* a hack for right shift - it's better to use Direct X for keyboard input it seems......*/
+ if (vk_code==VK_SHIFT)
+ if (scancode>0x30) /* on my keyboard left shift scancode is 0x2a, right shift is 0x36 */
+ special_code = 1;
+
+ if (special_code) /* right hand keys */
+ {
+ switch(vk_code)
+ {
+ case VK_MENU:
+ icode = (int)(KEYCODE_RALT.item_id());
+ break;
+ case VK_CONTROL:
+ icode = (int)(KEYCODE_RCONTROL.item_id());
+ break;
+ case VK_SHIFT:
+ icode = (int)(KEYCODE_RSHIFT.item_id());
+ break;
+ }
+ }
+ else /* left hand keys */
+ {
+ switch(vk_code)
+ {
+ case VK_MENU:
+ icode = (int)(KEYCODE_LALT.item_id());
+ break;
+ case VK_CONTROL:
+ icode = (int)(KEYCODE_LCONTROL.item_id());
+ break;
+ case VK_SHIFT:
+ icode = (int)(KEYCODE_LSHIFT.item_id());
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < ARRAY_LENGTH(win_key_trans_table); i++)
+ {
+ if ( vk_code == win_key_trans_table[i][VIRTUAL_KEY])
+ {
+ icode = win_key_trans_table[i][MAME_KEY];
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ dprintf("VK_code pressed not found = %i\n",vk_code);
+ //MessageBox(NULL,"keydown message arrived not processed","TitleBox",MB_OK);
+ return;
+ }
+ dprintf("VK_code pressed found = %i, sys=%i, mame_keycode=%i special=%08x\n", vk_code, syskey, icode, special);
+ keyboard_state[icode] = true;
+ check_for_GUI_action();
+}
+
+static void KeyboardKeyUp(int syskey, int vk_code, int special)
+{
+ int i, found = 0;
+ int icode = 0;
+ int special_code = (special >> 24) & 1;
+ int scancode = (special>>16) & 0xff;
+
+ if ((vk_code==VK_MENU) || (vk_code==VK_CONTROL) || (vk_code==VK_SHIFT))
+ {
+ found = 1;
+
+ /* a hack for right shift - it's better to use Direct X for keyboard input it seems......*/
+ if (vk_code==VK_SHIFT)
+ if (scancode>0x30) /* on my keyboard left shift scancode is 0x2a, right shift is 0x36 */
+ special_code = 1;
+
+ if (special_code) /* right hand keys */
+ {
+ switch(vk_code)
+ {
+ case VK_MENU:
+ icode = (int)(KEYCODE_RALT.item_id());
+ break;
+ case VK_CONTROL:
+ icode = (int)(KEYCODE_RCONTROL.item_id());
+ break;
+ case VK_SHIFT:
+ icode = (int)(KEYCODE_RSHIFT.item_id());
+ break;
+ }
+ }
+ else /* left hand keys */
+ {
+ switch(vk_code)
+ {
+ case VK_MENU:
+ icode = (int)(KEYCODE_LALT.item_id());
+ break;
+ case VK_CONTROL:
+ icode = (int)(KEYCODE_LCONTROL.item_id());
+ break;
+ case VK_SHIFT:
+ icode = (int)(KEYCODE_LSHIFT.item_id());
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < ARRAY_LENGTH(win_key_trans_table); i++)
+ {
+ if (vk_code == win_key_trans_table[i][VIRTUAL_KEY])
+ {
+ icode = win_key_trans_table[i][MAME_KEY];
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ dprintf("VK_code released not found = %i\n",vk_code);
+ //MessageBox(NULL,"keyup message arrived not processed","TitleBox",MB_OK);
+ return;
+ }
+ keyboard_state[icode] = false;
+ dprintf("VK_code released found= %i, sys=%i, mame_keycode=%i special=%08x\n", vk_code, syskey, icode, special );
+ check_for_GUI_action();
+}
+
+static void PollGUIJoystick()
+{
+ if (in_emulation)
+ return;
+
+ if (g_pJoyGUI == NULL)
+ return;
+
+ g_pJoyGUI->poll_joysticks();
+
+ // User pressed UP
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyUp(0), GetUIJoyUp(1), GetUIJoyUp(2), GetUIJoyUp(3))))
+ SendMessage(hMain, WM_COMMAND, ID_UI_UP, 0);
+
+ // User pressed DOWN
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyDown(0), GetUIJoyDown(1), GetUIJoyDown(2), GetUIJoyDown(3))))
+ SendMessage(hMain, WM_COMMAND, ID_UI_DOWN, 0);
+
+ // User pressed LEFT
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyLeft(0), GetUIJoyLeft(1), GetUIJoyLeft(2), GetUIJoyLeft(3))))
+ SendMessage(hMain, WM_COMMAND, ID_UI_LEFT, 0);
+
+ // User pressed RIGHT
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyRight(0), GetUIJoyRight(1), GetUIJoyRight(2), GetUIJoyRight(3))))
+ SendMessage(hMain, WM_COMMAND, ID_UI_RIGHT, 0);
+
+ // User pressed START GAME
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyStart(0), GetUIJoyStart(1), GetUIJoyStart(2), GetUIJoyStart(3))))
+ SendMessage(hMain, WM_COMMAND, ID_UI_START, 0);
+
+ // User pressed PAGE UP
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyPageUp(0), GetUIJoyPageUp(1), GetUIJoyPageUp(2), GetUIJoyPageUp(3))))
+ SendMessage(hMain, WM_COMMAND, ID_UI_PGUP, 0);
+
+ // User pressed PAGE DOWN
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyPageDown(0), GetUIJoyPageDown(1), GetUIJoyPageDown(2), GetUIJoyPageDown(3))))
+ SendMessage(hMain, WM_COMMAND, ID_UI_PGDOWN, 0);
+
+ // User pressed HOME
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyHome(0), GetUIJoyHome(1), GetUIJoyHome(2), GetUIJoyHome(3))))
+ SendMessage(hMain, WM_COMMAND, ID_UI_HOME, 0);
+
+ // User pressed END
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyEnd(0), GetUIJoyEnd(1), GetUIJoyEnd(2), GetUIJoyEnd(3))))
+ SendMessage(hMain, WM_COMMAND, ID_UI_END, 0);
+
+ // User pressed CHANGE SCREENSHOT
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoySSChange(0), GetUIJoySSChange(1), GetUIJoySSChange(2), GetUIJoySSChange(3))))
+ SendMessage(hMain, WM_COMMAND, IDC_SSFRAME, 0);
+
+ // User pressed SCROLL HISTORY UP
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyHistoryUp(0), GetUIJoyHistoryUp(1), GetUIJoyHistoryUp(2), GetUIJoyHistoryUp(3))))
+ SendMessage(hMain, WM_COMMAND, ID_UI_HISTORY_UP, 0);
+
+ // User pressed SCROLL HISTORY DOWN
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyHistoryDown(0), GetUIJoyHistoryDown(1), GetUIJoyHistoryDown(2), GetUIJoyHistoryDown(3))))
+ SendMessage(hMain, WM_COMMAND, ID_UI_HISTORY_DOWN, 0);
+
+ // For the exec timer, will keep track of how long the button has been pressed
+ static int exec_counter = 0;
+
+ // User pressed EXECUTE COMMANDLINE
+ // Note: this option is not documented, nor supported in the GUI.
+ if (g_pJoyGUI->is_joy_pressed(JOYCODE(GetUIJoyExec(0), GetUIJoyExec(1), GetUIJoyExec(2), GetUIJoyExec(3))))
+ {
+ // validate
+ int execwait = GetExecWait();
+ if (execwait < 1)
+ return;
+ if (++exec_counter >= execwait) // Button has been pressed > exec timeout
+ {
+ // validate
+ string exec_command = GetExecCommand();
+ if (exec_command.empty())
+ return;
+ TCHAR *t_exec_command = ui_wstring_from_utf8(exec_command.c_str());
+ if( !t_exec_command )
+ return;
+
+ // Reset counter
+ exec_counter = 0;
+
+ STARTUPINFO si;
+ ZeroMemory( &si, sizeof(si) );
+ si.dwFlags = STARTF_FORCEONFEEDBACK;
+ si.cb = sizeof(si);
+
+ PROCESS_INFORMATION pi;
+ ZeroMemory( &pi, sizeof(pi) );
+
+ CreateProcess(NULL, t_exec_command, NULL, NULL, false, 0, NULL, NULL, &si, &pi);
+
+ free(t_exec_command);
+
+ // We will not wait for the process to finish cause it might be a background task
+ // The process won't get closed when MAME32 closes either.
+
+ // But close the handles cause we won't need them anymore. Will not close process.
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
+ }
+ else
+ {
+ // Button has been released within the timeout period, reset the counter
+ exec_counter = 0;
+ }
+}
+
+static void SetView(int menu_id)
+{
+ BOOL force_reset = false;
+ int i;
+
+ // first uncheck previous menu item, check new one
+ CheckMenuRadioItem(GetMenu(hMain), ID_VIEW_LARGE_ICON, ID_VIEW_GROUPED, menu_id, MF_CHECKED);
+ ToolBar_CheckButton(s_hToolBar, menu_id, MF_CHECKED);
+
+ if (Picker_GetViewID(hwndList) == VIEW_GROUPED || menu_id == ID_VIEW_GROUPED)
+ {
+ // this changes the sort order, so redo everything
+ force_reset = true;
+ }
+
+ for (i = 0; i < sizeof(s_nPickers) / sizeof(s_nPickers[0]); i++)
+ Picker_SetViewID(GetDlgItem(hMain, s_nPickers[i]), menu_id - ID_VIEW_LARGE_ICON);
+
+ if (force_reset)
+ {
+ for (i = 0; i < sizeof(s_nPickers) / sizeof(s_nPickers[0]); i++)
+ Picker_Sort(GetDlgItem(hMain, s_nPickers[i]));
+ }
+}
+
+static void ResetListView()
+{
+ int i;
+ int current_game;
+ LV_ITEM lvi;
+ BOOL no_selection = false;
+ LPTREEFOLDER lpFolder = GetCurrentFolder();
+ HRESULT res;
+ BOOL b_res;
+
+ if (!lpFolder)
+ return;
+
+ /* If the last folder was empty, no_selection is true */
+ if (have_selection == false)
+ no_selection = true;
+
+ current_game = Picker_GetSelectedItem(hwndList);
+ if (current_game < 0)
+ no_selection = true;
+
+ SetWindowRedraw(hwndList,false);
+
+ b_res = ListView_DeleteAllItems(hwndList);
+
+ // hint to have it allocate it all at once
+ ListView_SetItemCount(hwndList,driver_list::total());
+
+ lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
+ lvi.stateMask = 0;
+
+ i = -1;
+
+ do
+ {
+ /* Add the games that are in this folder */
+ if ((i = FindGame(lpFolder, i + 1)) != -1)
+ {
+ if (GameFiltered(i, lpFolder->m_dwFlags))
+ continue;
+
+ lvi.iItem = i;
+ lvi.iSubItem = 0;
+ lvi.lParam = i;
+ lvi.pszText = LPSTR_TEXTCALLBACK;
+ lvi.iImage = I_IMAGECALLBACK;
+ res = ListView_InsertItem(hwndList, &lvi);
+ }
+ } while (i != -1);
+
+ Picker_Sort(hwndList);
+
+ if (bListReady)
+ {
+ /* If last folder was empty, select the first item in this folder */
+ if (no_selection)
+ Picker_SetSelectedPick(hwndList, 0);
+ else
+ Picker_SetSelectedItem(hwndList, current_game);
+ }
+
+ /*RS Instead of the Arrange Call that was here previously on all Views
+ We now need to set the ViewMode for SmallIcon again,
+ for an explanation why, see SetView*/
+ if (GetViewMode() == VIEW_SMALL_ICONS)
+ SetView(ID_VIEW_SMALL_ICON);
+
+ SetWindowRedraw(hwndList, true);
+
+ UpdateStatusBar();
+ res++;
+ b_res++;
+}
+
+static void UpdateGameList(BOOL bUpdateRomAudit, BOOL bUpdateSampleAudit)
+{
+ for (int i = 0; i < driver_list::total(); i++)
+ {
+ if (bUpdateRomAudit && DriverUsesRoms(i))
+ SetRomAuditResults(i, UNKNOWN);
+ if (bUpdateSampleAudit && DriverUsesSamples(i))
+ SetSampleAuditResults(i, UNKNOWN);
+ }
+
+ idle_work = true;
+ bDoGameCheck = true;
+ game_index = 0;
+
+ ReloadIcons();
+
+ // Let REFRESH also load new background if found
+ LoadBackgroundBitmap();
+ InvalidateRect(hMain,NULL,true);
+ Picker_ResetIdle(hwndList);
+}
+
+static void UpdateCache()
+{
+ int current_id = GetCurrentFolderID(); // remember selected folder
+ SetWindowRedraw(hwndList, false); // stop screen updating
+ ForceRebuild(); // tell system that cache needs redoing
+ (void)OptionsInit(); // reload options and fix game cache
+ //extern const FOLDERDATA g_folderData[];
+ //extern const FILTER_ITEM g_filterList[];
+ //InitTree(g_folderData, g_filterList); // redo folders... This crashes, leave out for now
+ ResetTreeViewFolders(); // something with folders
+ SelectTreeViewFolder(current_id); // select previous folder
+ SetWindowRedraw(hwndList, true); // refresh screen
+}
+
+UINT_PTR CALLBACK CFHookProc(
+ HWND hdlg, // handle to dialog box
+ UINT uiMsg, // message identifier
+ WPARAM wParam, // message parameter
+ LPARAM lParam // message parameter
+)
+{
+ int iIndex, i;
+ COLORREF cCombo, cList;
+ switch (uiMsg)
+ {
+ case WM_INITDIALOG:
+ SendDlgItemMessage(hdlg, cmb4, CB_ADDSTRING, 0, (LPARAM)TEXT("Custom"));
+ iIndex = SendDlgItemMessage(hdlg, cmb4, CB_GETCOUNT, 0, 0);
+ cList = GetListFontColor();
+ SendDlgItemMessage(hdlg, cmb4, CB_SETITEMDATA,(WPARAM)iIndex-1,(LPARAM)cList );
+ for( i = 0; i< iIndex; i++)
+ {
+ cCombo = SendDlgItemMessage(hdlg, cmb4, CB_GETITEMDATA,(WPARAM)i,0 );
+ if( cList == cCombo)
+ {
+ SendDlgItemMessage(hdlg, cmb4, CB_SETCURSEL,(WPARAM)i,0 );
+ break;
+ }
+ }
+ break;
+ case WM_COMMAND:
+ if( LOWORD(wParam) == cmb4)
+ {
+ switch (HIWORD(wParam))
+ {
+ case CBN_SELCHANGE: // The color ComboBox changed selection
+ iIndex = (int)SendDlgItemMessage(hdlg, cmb4,
+ CB_GETCURSEL, 0, 0L);
+ if( iIndex == SendDlgItemMessage(hdlg, cmb4, CB_GETCOUNT, 0, 0)-1)
+ {
+ //Custom color selected
+ cList = GetListFontColor();
+ PickColor(&cList);
+ SendDlgItemMessage(hdlg, cmb4, CB_DELETESTRING, iIndex, 0);
+ SendDlgItemMessage(hdlg, cmb4, CB_ADDSTRING, 0, (LPARAM)TEXT("Custom"));
+ SendDlgItemMessage(hdlg, cmb4, CB_SETITEMDATA,(WPARAM)iIndex,(LPARAM)cList);
+ SendDlgItemMessage(hdlg, cmb4, CB_SETCURSEL,(WPARAM)iIndex,0 );
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+static void PickFont(void)
+{
+ LOGFONT font;
+ CHOOSEFONT cf;
+ TCHAR szClass[128];
+ HWND hWnd;
+ HRESULT res;
+ BOOL b_res;
+
+ GetListFont(&font);
+ font.lfQuality = DEFAULT_QUALITY;
+
+ cf.lStructSize = sizeof(CHOOSEFONT);
+ cf.hwndOwner = hMain;
+ cf.lpLogFont = &font;
+ cf.lpfnHook = &CFHookProc;
+ cf.rgbColors = GetListFontColor();
+ cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_EFFECTS | CF_ENABLEHOOK;
+ if (!ChooseFont(&cf))
+ return;
+
+ SetListFont(&font);
+ if (hFont)
+ DeleteFont(hFont);
+ hFont = CreateFontIndirect(&font);
+ if (hFont)
+ {
+ COLORREF textColor = cf.rgbColors;
+
+ if (textColor == RGB(255,255,255))
+ {
+ textColor = RGB(240, 240, 240);
+ }
+
+ SetAllWindowsFont(hMain, &main_resize, hFont, true);
+
+ hWnd = GetWindow(hMain, GW_CHILD);
+ while(hWnd)
+ {
+ if (GetClassName(hWnd, szClass, sizeof(szClass) / sizeof(szClass[0])))
+ {
+ if (!_tcscmp(szClass, TEXT("SysListView32")))
+ {
+ b_res = ListView_SetTextColor(hWnd, textColor);
+ b_res++;
+ }
+ else if (!_tcscmp(szClass, TEXT("SysTreeView32")))
+ {
+ res = TreeView_SetTextColor(hTreeView, textColor);
+ res++;
+ }
+ }
+ hWnd = GetWindow(hWnd, GW_HWNDNEXT);
+ }
+ SetListFontColor(cf.rgbColors);
+ ResetListView();
+ }
+}
+
+static void PickColor(COLORREF *cDefault)
+{
+ CHOOSECOLOR cc;
+ COLORREF choice_colors[16];
+ int i;
+
+ for (i=0;i<16;i++)
+ choice_colors[i] = GetCustomColor(i);
+
+ cc.lStructSize = sizeof(CHOOSECOLOR);
+ cc.hwndOwner = hMain;
+ cc.rgbResult = *cDefault;
+ cc.lpCustColors = choice_colors;
+ cc.Flags = CC_ANYCOLOR | CC_RGBINIT | CC_SOLIDCOLOR | CC_FULLOPEN;
+ if (!ChooseColor(&cc))
+ return;
+ for (i=0;i<16;i++)
+ SetCustomColor(i,choice_colors[i]);
+ *cDefault = cc.rgbResult;
+}
+
+static void PickCloneColor(void)
+{
+ COLORREF cClonecolor;
+ cClonecolor = GetListCloneColor();
+ PickColor( &cClonecolor);
+ SetListCloneColor(cClonecolor);
+ InvalidateRect(hwndList,NULL,false);
+}
+
+static BOOL MameCommand(HWND hwnd,int id, HWND hwndCtl, UINT codeNotify)
+{
+ int i = 0;
+ LPTREEFOLDER folder;
+ char* utf8_szFile;
+ BOOL res = 0;
+ int current_game = Picker_GetSelectedItem(hwndList);
+
+ switch (id)
+ {
+ case ID_FILE_PLAY:
+ MamePlayGame();
+ return true;
+
+ case ID_FILE_PLAY_RECORD:
+ MamePlayRecordGame();
+ return true;
+
+ case ID_FILE_PLAY_BACK:
+ MamePlayBackGame();
+ return true;
+
+ case ID_FILE_PLAY_RECORD_WAVE:
+ MamePlayRecordWave();
+ return true;
+
+ case ID_FILE_PLAY_RECORD_MNG:
+ MamePlayRecordMNG();
+ return true;
+
+ case ID_FILE_PLAY_RECORD_AVI:
+ MamePlayRecordAVI();
+ return true;
+
+ case ID_FILE_LOADSTATE :
+ MameLoadState();
+ return true;
+
+ case ID_FILE_AUDIT:
+ AuditDialog(hMain, 1);
+ ResetWhichGamesInFolders();
+ ResetListView();
+ SetFocus(hwndList);
+ return true;
+
+ case ID_FILE_AUDIT_X:
+ AuditDialog(hMain, 2);
+ ResetWhichGamesInFolders();
+ ResetListView();
+ SetFocus(hwndList);
+ return true;
+
+ case ID_FILE_EXIT:
+ PostMessage(hMain, WM_CLOSE, 0, 0);
+ return true;
+
+ case ID_VIEW_LARGE_ICON:
+ SetView(ID_VIEW_LARGE_ICON);
+ return true;
+
+ case ID_VIEW_SMALL_ICON:
+ SetView(ID_VIEW_SMALL_ICON);
+ ResetListView();
+ return true;
+
+ case ID_VIEW_LIST_MENU:
+ SetView(ID_VIEW_LIST_MENU);
+ return true;
+
+ case ID_VIEW_DETAIL:
+ SetView(ID_VIEW_DETAIL);
+ return true;
+
+ case ID_VIEW_GROUPED:
+ SetView(ID_VIEW_GROUPED);
+ return true;
+
+ /* Arrange Icons submenu */
+ case ID_VIEW_BYGAME:
+ SetSortReverse(false);
+ SetSortColumn(COLUMN_GAMES);
+ Picker_Sort(hwndList);
+ break;
+
+ case ID_VIEW_BYDIRECTORY:
+ SetSortReverse(false);
+ SetSortColumn(COLUMN_DIRECTORY);
+ Picker_Sort(hwndList);
+ break;
+
+ case ID_VIEW_BYMANUFACTURER:
+ SetSortReverse(false);
+ SetSortColumn(COLUMN_MANUFACTURER);
+ Picker_Sort(hwndList);
+ break;
+
+ case ID_VIEW_BYTIMESPLAYED:
+ SetSortReverse(false);
+ SetSortColumn(COLUMN_PLAYED);
+ Picker_Sort(hwndList);
+ break;
+
+ case ID_VIEW_BYTYPE:
+ SetSortReverse(false);
+ SetSortColumn(COLUMN_TYPE);
+ Picker_Sort(hwndList);
+ break;
+
+ case ID_VIEW_BYYEAR:
+ SetSortReverse(false);
+ SetSortColumn(COLUMN_YEAR);
+ Picker_Sort(hwndList);
+ break;
+
+ case ID_VIEW_FOLDERS:
+ {
+ int val = GetWindowPanes() ^ 1;
+ BOOL bShowTree = BIT(val, 0);
+ SetWindowPanes(val);
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_FOLDERS, (bShowTree) ? MF_CHECKED : MF_UNCHECKED);
+ ToolBar_CheckButton(s_hToolBar, ID_VIEW_FOLDERS, (bShowTree) ? MF_CHECKED : MF_UNCHECKED);
+ UpdateScreenShot();
+ break;
+ }
+
+ case ID_VIEW_TOOLBARS:
+ bShowToolBar = !bShowToolBar;
+ SetShowToolBar(bShowToolBar);
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_TOOLBARS, (bShowToolBar) ? MF_CHECKED : MF_UNCHECKED);
+ ToolBar_CheckButton(s_hToolBar, ID_VIEW_TOOLBARS, (bShowToolBar) ? MF_CHECKED : MF_UNCHECKED);
+ ShowWindow(s_hToolBar, (bShowToolBar) ? SW_SHOW : SW_HIDE);
+ ResizePickerControls(hMain);
+ UpdateScreenShot();
+ break;
+
+ case ID_VIEW_STATUS:
+ bShowStatusBar = !bShowStatusBar;
+ SetShowStatusBar(bShowStatusBar);
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_STATUS, (bShowStatusBar) ? MF_CHECKED : MF_UNCHECKED);
+ ToolBar_CheckButton(s_hToolBar, ID_VIEW_STATUS, (bShowStatusBar) ? MF_CHECKED : MF_UNCHECKED);
+ ShowWindow(hStatusBar, (bShowStatusBar) ? SW_SHOW : SW_HIDE);
+ ResizePickerControls(hMain);
+ UpdateScreenShot();
+ break;
+
+ case ID_VIEW_PAGETAB:
+ bShowTabCtrl = !bShowTabCtrl;
+ SetShowTabCtrl(bShowTabCtrl);
+ ShowWindow(hTabCtrl, (bShowTabCtrl) ? SW_SHOW : SW_HIDE);
+ ResizePickerControls(hMain);
+ UpdateScreenShot();
+ InvalidateRect(hMain,NULL,true);
+ break;
+
+ /*
+ Switches to fullscreen mode. No check mark handling
+ for this item cause in fullscreen mode the menu won't
+ be visible anyways.
+ */
+ case ID_VIEW_FULLSCREEN:
+ SwitchFullScreenMode();
+ break;
+
+ case ID_TOOLBAR_EDIT:
+ {
+ string buf;
+ HWND hToolbarEdit;
+
+ buf = win_get_window_text_utf8(hwndCtl);
+ switch (codeNotify)
+ {
+ case TOOLBAR_EDIT_ACCELERATOR_PRESSED:
+ hToolbarEdit = GetDlgItem( s_hToolBar, ID_TOOLBAR_EDIT);
+ SetFocus(hToolbarEdit);
+ break;
+ case EN_CHANGE:
+ //put search routine here first, add a 200ms timer later.
+ if ((!_stricmp(buf.c_str(), SEARCH_PROMPT) && !_stricmp(g_SearchText, "")))
+ strcpy(g_SearchText, buf.c_str());
+ else
+ {
+ strcpy(g_SearchText, buf.c_str());
+ ResetListView();
+ }
+ break;
+ case EN_SETFOCUS:
+ if (!_stricmp(buf.c_str(), SEARCH_PROMPT))
+ win_set_window_text_utf8(hwndCtl, "");
+ break;
+ case EN_KILLFOCUS:
+ if (*buf.c_str() == 0)
+ win_set_window_text_utf8(hwndCtl, SEARCH_PROMPT);
+ break;
+ }
+ }
+ break;
+
+ case ID_GAME_AUDIT:
+ InitGameAudit(0);
+ if (!oldControl && (current_game >= 0))
+ InitPropertyPageToPage(hInst, hwnd, GetSelectedPickItemIcon(), OPTIONS_GAME, -1, current_game, AUDIT_PAGE);
+
+ /* Just in case the toggle MMX on/off */
+ UpdateStatusBar();
+ break;
+
+ /* ListView Context Menu */
+ case ID_CONTEXT_ADD_CUSTOM:
+ {
+ if (current_game >= 0)
+ DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_CUSTOM_FILE), hMain,AddCustomFileDialogProc, current_game);
+ SetFocus(hwndList);
+ break;
+ }
+
+ case ID_CONTEXT_REMOVE_CUSTOM:
+ {
+ RemoveCurrentGameCustomFolder();
+ break;
+ }
+
+ /* Tree Context Menu */
+ case ID_CONTEXT_FILTERS:
+ if (DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_FILTERS), hMain, FilterDialogProc) == true)
+ ResetListView();
+ SetFocus(hwndList);
+ return true;
+
+ // ScreenShot Context Menu
+ // select current tab
+ case ID_VIEW_TAB_SCREENSHOT:
+ case ID_VIEW_TAB_TITLE:
+ case ID_VIEW_TAB_SCORES:
+ case ID_VIEW_TAB_HOWTO:
+ case ID_VIEW_TAB_SELECT:
+ case ID_VIEW_TAB_VERSUS:
+ case ID_VIEW_TAB_BOSSES:
+ case ID_VIEW_TAB_COVER:
+ case ID_VIEW_TAB_ENDS:
+ case ID_VIEW_TAB_GAMEOVER:
+ case ID_VIEW_TAB_LOGO:
+ case ID_VIEW_TAB_ARTWORK:
+ case ID_VIEW_TAB_FLYER:
+ case ID_VIEW_TAB_CABINET:
+ case ID_VIEW_TAB_MARQUEE:
+ case ID_VIEW_TAB_CONTROL_PANEL:
+ case ID_VIEW_TAB_PCB:
+ case ID_VIEW_TAB_HISTORY:
+ if (id == ID_VIEW_TAB_HISTORY && GetShowTab(TAB_HISTORY) == false)
+ break;
+
+ TabView_SetCurrentTab(hTabCtrl, id - ID_VIEW_TAB_ARTWORK);
+ UpdateScreenShot();
+ TabView_UpdateSelection(hTabCtrl);
+ break;
+
+ // toggle tab's existence
+ case ID_TOGGLE_TAB_SCREENSHOT:
+ case ID_TOGGLE_TAB_TITLE:
+ case ID_TOGGLE_TAB_SCORES:
+ case ID_TOGGLE_TAB_HOWTO:
+ case ID_TOGGLE_TAB_SELECT:
+ case ID_TOGGLE_TAB_VERSUS:
+ case ID_TOGGLE_TAB_BOSSES:
+ case ID_TOGGLE_TAB_COVER:
+ case ID_TOGGLE_TAB_ENDS:
+ case ID_TOGGLE_TAB_GAMEOVER:
+ case ID_TOGGLE_TAB_LOGO:
+ case ID_TOGGLE_TAB_ARTWORK:
+ case ID_TOGGLE_TAB_FLYER:
+ case ID_TOGGLE_TAB_CABINET:
+ case ID_TOGGLE_TAB_MARQUEE:
+ case ID_TOGGLE_TAB_CONTROL_PANEL:
+ case ID_TOGGLE_TAB_PCB:
+ case ID_TOGGLE_TAB_HISTORY:
+ {
+ int toggle_flag = id - ID_TOGGLE_TAB_ARTWORK;
+
+ if (AllowedToSetShowTab(toggle_flag,!GetShowTab(toggle_flag)) == false)
+ {
+ // attempt to hide the last tab
+ // should show error dialog? hide picture area? or ignore?
+ break;
+ }
+
+ SetShowTab(toggle_flag,!GetShowTab(toggle_flag));
+
+ TabView_Reset(hTabCtrl);
+
+ if (TabView_GetCurrentTab(hTabCtrl) == toggle_flag && GetShowTab(toggle_flag) == false)
+ {
+ // we're deleting the tab we're on, so go to the next one
+ TabView_CalculateNextTab(hTabCtrl);
+ }
+
+
+ // Resize the controls in case we toggled to another history
+ // mode (and the history control needs resizing).
+
+ ResizePickerControls(hMain);
+ UpdateScreenShot();
+
+ TabView_UpdateSelection(hTabCtrl);
+
+ break;
+ }
+
+ /* Header Context Menu */
+ case ID_SORT_ASCENDING:
+ SetSortReverse(false);
+ SetSortColumn(Picker_GetRealColumnFromViewColumn(hwndList, lastColumnClick));
+ Picker_Sort(hwndList);
+ break;
+
+ case ID_SORT_DESCENDING:
+ SetSortReverse(true);
+ SetSortColumn(Picker_GetRealColumnFromViewColumn(hwndList, lastColumnClick));
+ Picker_Sort(hwndList);
+ break;
+
+ case ID_CUSTOMIZE_FIELDS:
+ if (DialogBox(GetModuleHandle(NULL),
+ MAKEINTRESOURCE(IDD_COLUMNS), hMain, ColumnDialogProc) == true)
+ ResetColumnDisplay(false);
+ SetFocus(hwndList);
+ return true;
+
+ /* View Menu */
+ case ID_VIEW_LINEUPICONS:
+ if( codeNotify == false)
+ ResetListView();
+ else
+ {
+ /*it was sent after a refresh (F5) was done, we only reset the View if "available" is the selected folder
+ as it doesn't affect the others*/
+ folder = GetSelectedFolder();
+ if( folder )
+ if (folder->m_nFolderId == FOLDER_AVAILABLE )
+ ResetListView();
+ }
+ break;
+
+ case ID_GAME_PROPERTIES:
+ if (!oldControl && (current_game >= 0))
+ InitPropertyPageToPage(hInst, hwnd, GetSelectedPickItemIcon(), OPTIONS_GAME, -1, current_game, PROPERTIES_PAGE);
+
+ /* Just in case the toggle MMX on/off */
+ UpdateStatusBar();
+ break;
+
+ // NOT WORKING
+ case ID_FOLDER_PROPERTIES:
+ if (!oldControl && (current_game >= 0))
+ {
+ OPTIONS_TYPE curOptType = OPTIONS_SOURCE;
+ folder = GetSelectedFolder();
+ if (folder)
+ {
+ if(folder->m_nFolderId == FOLDER_VECTOR)
+ curOptType = OPTIONS_VECTOR;
+
+ InitPropertyPage(hInst, hwnd, GetSelectedFolderIcon(), curOptType, folder->m_nFolderId, current_game);
+ }
+ }
+ /* Just in case the toggle MMX on/off */
+ UpdateStatusBar();
+ break;
+
+ case ID_FOLDER_SOURCEPROPERTIES:
+ if (!oldControl && (current_game >= 0))
+ {
+ //InitPropertyPage(hInst, hwnd, GetSelectedFolderIcon(), (folder->m_nFolderId == FOLDER_VECTOR) ? OPTIONS_VECTOR : OPTIONS_SOURCE , -1, current_game);
+ InitPropertyPage(hInst, hwnd, GetSelectedFolderIcon(), OPTIONS_SOURCE, -1, current_game);
+ }
+ /* Just in case the toggle MMX on/off */
+ UpdateStatusBar();
+ break;
+
+ case ID_FOLDER_VECTORPROPERTIES:
+ if (!oldControl && (current_game >= 0))
+ {
+ folder = GetFolderByID( FOLDER_VECTOR );
+ InitPropertyPage(hInst, hwnd, GetSelectedFolderIcon(), OPTIONS_VECTOR, folder->m_nFolderId, current_game);
+ }
+ /* Just in case the toggle MMX on/off */
+ UpdateStatusBar();
+ break;
+
+ case ID_FOLDER_AUDIT:
+ FolderCheck();
+ /* Just in case the toggle MMX on/off */
+ UpdateStatusBar();
+ break;
+
+ case ID_VIEW_PICTURE_AREA :
+ ToggleScreenShot();
+ break;
+
+ case ID_UPDATE_GAMELIST:
+ UpdateGameList(true, true);
+ break;
+
+ case ID_UPDATE_CACHE:
+ UpdateCache();
+ break;
+
+ case ID_OPTIONS_FONT:
+ PickFont();
+ return true;
+
+ case ID_OPTIONS_CLONE_COLOR:
+ PickCloneColor();
+ return true;
+
+ case ID_OPTIONS_DEFAULTS:
+ /* Check the return value to see if changes were applied */
+ if (!oldControl)
+ {
+ InitDefaultPropertyPage(hInst, hwnd);
+ }
+ SetFocus(hwndList);
+ return true;
+
+ case ID_OPTIONS_DIR:
+ {
+ int nResult = DialogBox(GetModuleHandle(NULL),
+ MAKEINTRESOURCE(IDD_DIRECTORIES),
+ hMain,
+ DirectoriesDialogProc);
+
+ SaveDefaultOptions();
+ SaveOptions();
+
+ BOOL bUpdateRoms = ((nResult & DIRDLG_ROMS) == DIRDLG_ROMS) ? true : false;
+ BOOL bUpdateSamples = ((nResult & DIRDLG_SAMPLES) == DIRDLG_SAMPLES) ? true : false;
+
+ if (s_pWatcher)
+ {
+ if (bUpdateRoms)
+ DirWatcher_Watch(s_pWatcher, 0, GetRomDirs(), true);
+ if (bUpdateSamples)
+ DirWatcher_Watch(s_pWatcher, 1, GetSampleDirs(), true);
+ }
+
+ /* update game list */
+ if (bUpdateRoms == true || bUpdateSamples == true)
+ UpdateGameList(bUpdateRoms, bUpdateSamples);
+
+ SetFocus(hwndList);
+ }
+ return true;
+
+ case ID_OPTIONS_RESET_DEFAULTS:
+ if (DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_RESET), hMain, ResetDialogProc) == true)
+ {
+ // these may have been changed
+ SaveDefaultOptions();
+ SaveOptions();
+ DestroyWindow(hwnd);
+ PostQuitMessage(0);
+ }
+ else
+ {
+ ResetListView();
+ SetFocus(hwndList);
+ }
+ return true;
+
+ case ID_OPTIONS_INTERFACE:
+ DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_INTERFACE_OPTIONS), hMain, InterfaceDialogProc);
+ SaveOptions();
+
+ KillTimer(hMain, SCREENSHOT_TIMER);
+ if( GetCycleScreenshot() > 0)
+ {
+ SetTimer(hMain, SCREENSHOT_TIMER, GetCycleScreenshot()*1000, NULL ); // Scale to seconds
+ }
+
+ return true;
+
+ case ID_VIDEO_SNAP:
+ {
+ int nGame = Picker_GetSelectedItem(hwndList);
+ if (nGame >= 0)
+ {
+ string path = GetVideoDir() + string("\\") + driver_list::driver(nGame).name + string(".mp4");
+ ShellExecuteCommon(hMain, path.c_str());
+ }
+ SetFocus(hwndList);
+ }
+ break;
+
+ case ID_MANUAL:
+ {
+ int nGame = Picker_GetSelectedItem(hwndList);
+ if (nGame >= 0)
+ {
+ string path = GetManualsDir() + string("\\") + driver_list::driver(nGame).name + string(".pdf");
+ ShellExecuteCommon(hMain, path.c_str());
+ }
+ SetFocus(hwndList);
+ }
+ break;
+
+ case ID_OPTIONS_BG:
+ {
+ // Get the path from the existing filename; if no filename go to root
+ TCHAR* t_bgdir = TEXT(".");
+ bool free_bgdir = false;
+ string as, s = GetBgDir();
+ util::zippath_parent(as, s.c_str());
+ size_t t1 = as.length()-1;
+ if (as[t1] == '\\') as.substr(0, t1-1);
+ t1 = as.find(':');
+ if (t1 != string::npos)
+ {
+ t_bgdir = ui_wstring_from_utf8(as.c_str());
+ free_bgdir = true;
+ if( !t_bgdir )
+ return false;
+ }
+
+ OPENFILENAME OFN;
+ TCHAR szFile[MAX_PATH] = TEXT("\0");
+
+ OFN.lStructSize = sizeof(OPENFILENAME);
+ OFN.hwndOwner = hMain;
+ OFN.hInstance = 0;
+ OFN.lpstrFilter = TEXT("Image Files (*.png)\0*.PNG\0");
+ OFN.lpstrCustomFilter = NULL;
+ OFN.nMaxCustFilter = 0;
+ OFN.nFilterIndex = 1;
+ OFN.lpstrFile = szFile;
+ OFN.nMaxFile = sizeof(szFile);
+ OFN.lpstrFileTitle = NULL;
+ OFN.nMaxFileTitle = 0;
+ OFN.lpstrInitialDir = t_bgdir;
+ OFN.lpstrTitle = TEXT("Select a Background Image");
+ OFN.nFileOffset = 0;
+ OFN.nFileExtension = 0;
+ OFN.lpstrDefExt = NULL;
+ OFN.lCustData = 0;
+ OFN.lpfnHook = NULL;
+ OFN.lpTemplateName = NULL;
+ OFN.Flags = OFN_NOCHANGEDIR | OFN_SHOWHELP | OFN_EXPLORER;
+
+ BOOL res = GetOpenFileName(&OFN);
+ if (res)
+ {
+ if (free_bgdir)
+ free(t_bgdir);
+ utf8_szFile = ui_utf8_from_wstring(szFile);
+ if( !utf8_szFile )
+ return false;
+
+ // Make this file as the new default
+ SetBgDir(utf8_szFile);
+
+ // Display new background
+ LoadBackgroundBitmap();
+ InvalidateRect(hMain, NULL, true);
+ free(utf8_szFile);
+ return true;
+ }
+ if (free_bgdir)
+ free(t_bgdir);
+ }
+ break;
+#if 0
+ case ID_OPTIONS_HISTORY:
+ {
+ char filename[MAX_PATH];
+ strcpy(filename, GetHistoryFileName());
+ if (CommonFileDialog(GetOpenFileName, filename, FILETYPE_HISTORY_FILE))
+ {
+ SetHistoryFileName(filename);
+ }
+ return true;
+ }
+ case ID_OPTIONS_MAMEINFO:
+ {
+ char filename[MAX_PATH];
+ strcpy(filename, GetMAMEInfoFileName());
+ if (CommonFileDialog(GetOpenFileName, filename, FILETYPE_MAMEINFO_FILE))
+ {
+ SetMAMEInfoFileName(filename);
+ }
+ return true;
+ }
+#endif
+ case ID_HELP_ABOUT:
+ DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hMain, AboutDialogProc);
+ SetFocus(hwndList);
+ return true;
+
+ case IDOK :
+ /* cmk -- might need to check more codes here, not sure */
+ if (codeNotify != EN_CHANGE && codeNotify != EN_UPDATE)
+ {
+ /* enter key */
+ if (g_in_treeview_edit)
+ {
+ res = TreeView_EndEditLabelNow(hTreeView, false);
+ return true;
+ }
+ else
+ if (have_selection)
+ MamePlayGame();
+ }
+ break;
+
+ case IDCANCEL : /* esc key */
+ if (g_in_treeview_edit)
+ res = TreeView_EndEditLabelNow(hTreeView, true);
+ break;
+
+ case IDC_PLAY_GAME :
+ if (have_selection)
+ MamePlayGame();
+ break;
+
+ case ID_UI_START:
+ SetFocus(hwndList);
+ MamePlayGame();
+ break;
+
+ case ID_UI_UP:
+ Picker_SetSelectedPick(hwndList, GetSelectedPick() - 1);
+ break;
+
+ case ID_UI_DOWN:
+ Picker_SetSelectedPick(hwndList, GetSelectedPick() + 1);
+ break;
+
+ case ID_UI_PGUP:
+ Picker_SetSelectedPick(hwndList, GetSelectedPick() - ListView_GetCountPerPage(hwndList));
+ break;
+
+ case ID_UI_PGDOWN:
+ if ( (GetSelectedPick() + ListView_GetCountPerPage(hwndList)) < ListView_GetItemCount(hwndList) )
+ Picker_SetSelectedPick(hwndList, GetSelectedPick() + ListView_GetCountPerPage(hwndList) );
+ else
+ Picker_SetSelectedPick(hwndList, ListView_GetItemCount(hwndList)-1 );
+ break;
+
+ case ID_UI_HOME:
+ Picker_SetSelectedPick(hwndList, 0);
+ break;
+
+ case ID_UI_END:
+ Picker_SetSelectedPick(hwndList, ListView_GetItemCount(hwndList)-1 );
+ break;
+ case ID_UI_LEFT:
+ /* hmmmmm..... */
+ SendMessage(hwndList,WM_HSCROLL, SB_LINELEFT, 0);
+ break;
+
+ case ID_UI_RIGHT:
+ /* hmmmmm..... */
+ SendMessage(hwndList,WM_HSCROLL, SB_LINERIGHT, 0);
+ break;
+ case ID_UI_HISTORY_UP:
+ /* hmmmmm..... */
+ {
+ HWND hHistory = GetDlgItem(hMain, IDC_HISTORY);
+ SendMessage(hHistory, EM_SCROLL, SB_PAGEUP, 0);
+ }
+ break;
+
+ case ID_UI_HISTORY_DOWN:
+ /* hmmmmm..... */
+ {
+ HWND hHistory = GetDlgItem(hMain, IDC_HISTORY);
+ SendMessage(hHistory, EM_SCROLL, SB_PAGEDOWN, 0);
+ }
+ break;
+
+ case IDC_SSFRAME:
+ TabView_CalculateNextTab(hTabCtrl);
+ UpdateScreenShot();
+ TabView_UpdateSelection(hTabCtrl);
+ break;
+
+ case ID_CONTEXT_SELECT_RANDOM:
+ SetRandomPickItem();
+ break;
+
+ case ID_CONTEXT_RESET_PLAYSTATS:
+ ResetPlayTime(current_game);
+ ResetPlayCount(current_game);
+ res = ListView_RedrawItems(hwndList, GetSelectedPick(), GetSelectedPick());
+ break;
+
+ case ID_CONTEXT_RENAME_CUSTOM :
+ TreeView_EditLabel(hTreeView,TreeView_GetSelection(hTreeView));
+ break;
+
+ default:
+ if (id >= ID_CONTEXT_SHOW_FOLDER_START && id < ID_CONTEXT_SHOW_FOLDER_END)
+ {
+ ToggleShowFolder(id - ID_CONTEXT_SHOW_FOLDER_START);
+ break;
+ }
+ for (i = 0; g_helpInfo[i].nMenuItem > 0; i++)
+ {
+ if (g_helpInfo[i].nMenuItem == id)
+ {
+ printf("%X: %ls\n",g_helpInfo[i].bIsHtmlHelp, g_helpInfo[i].lpFile);
+ if (i == 1) // get current whatsnew.txt from mamedev.org
+ {
+ string version = string(GetVersionString()); // turn version string into std
+ version.erase(1,1); // take out the decimal point
+ version.erase(4, string::npos); // take out the date
+ string url = "https://mamedev.org/releases/whatsnew_" + version + ".txt"; // construct url
+ std::wstring stemp = s2ws(url); // convert to wide string (yeah, typical c++ mess)
+ LPCWSTR result = stemp.c_str(); // then convert to const wchar_t*
+ ShellExecute(hMain, TEXT("open"), result, TEXT(""), NULL, SW_SHOWNORMAL); // show web page
+ }
+ else
+ if (g_helpInfo[i].bIsHtmlHelp)
+// HelpFunction(hMain, g_helpInfo[i].lpFile, HH_DISPLAY_TOPIC, 0);
+ ShellExecute(hMain, TEXT("open"), g_helpInfo[i].lpFile, TEXT(""), NULL, SW_SHOWNORMAL);
+// else
+// DisplayTextFile(hMain, g_helpInfo[i].lpFile);
+ return false;
+ }
+ }
+ break;
+ }
+ res++;
+ return false;
+}
+
+static void LoadBackgroundBitmap()
+{
+ HGLOBAL hDIBbg;
+
+ if (hBackground)
+ {
+ DeleteBitmap(hBackground);
+ hBackground = 0;
+ }
+
+ if (hPALbg)
+ {
+ DeletePalette(hPALbg);
+ hPALbg = 0;
+ }
+
+ if (LoadDIBBG(&hDIBbg, &hPALbg))
+ {
+ HDC hDC = GetDC(hwndList);
+ hBackground = DIBToDDB(hDC, hDIBbg, &bmDesc);
+ GlobalFree(hDIBbg);
+ ReleaseDC(hwndList, hDC);
+ }
+}
+
+static void ResetColumnDisplay(BOOL first_time)
+{
+ if (!first_time)
+ Picker_ResetColumnDisplay(hwndList);
+
+ ResetListView();
+
+ Picker_SetSelectedItem(hwndList, GetDefaultGame());
+}
+
+static int GamePicker_GetItemImage(HWND hwndPicker, int nItem)
+{
+ return GetIconForDriver(nItem);
+}
+
+static const TCHAR *GamePicker_GetItemString(HWND hwndPicker, int nItem, int nColumn, TCHAR *pszBuffer, UINT nBufferLength)
+{
+ const TCHAR *s = NULL;
+ const char* utf8_s = NULL;
+ char playtime_buf[256];
+
+ switch(nColumn)
+ {
+ case COLUMN_GAMES:
+ /* Driver description */
+ utf8_s = ModifyThe(driver_list::driver(nItem).type.fullname());
+ break;
+
+ case COLUMN_ORIENTATION:
+ utf8_s = DriverIsVertical(nItem) ? "Vertical" : "Horizontal";
+ break;
+
+ case COLUMN_ROMS:
+ utf8_s = GetAuditString(GetRomAuditResults(nItem));
+ break;
+
+ case COLUMN_SAMPLES:
+ /* Samples */
+ if (DriverUsesSamples(nItem))
+ utf8_s = GetAuditString(GetSampleAuditResults(nItem));
+ else
+ s = TEXT("-");
+ break;
+
+ case COLUMN_DIRECTORY:
+ /* Driver name (directory) */
+ utf8_s = driver_list::driver(nItem).name;
+ break;
+
+ case COLUMN_SRCDRIVERS:
+ /* Source drivers */
+ utf8_s = GetDriverFilename(nItem);
+ break;
+
+ case COLUMN_PLAYTIME:
+ /* Source drivers */
+ GetTextPlayTime(nItem, playtime_buf);
+ utf8_s = playtime_buf;
+ break;
+
+ case COLUMN_TYPE:
+ /* Vector/Raster */
+ {
+ if (DriverIsVector(nItem))
+ s = TEXT("Vector");
+ else
+ s = TEXT("Raster");
+ break;
+ }
+
+ case COLUMN_TRACKBALL:
+ /* Trackball */
+ if (DriverUsesTrackball(nItem))
+ s = TEXT("Yes");
+ else
+ s = TEXT("No");
+ break;
+
+ case COLUMN_PLAYED:
+ /* times played */
+ _sntprintf(pszBuffer, nBufferLength, TEXT("%i"), GetPlayCount(nItem));
+ s = pszBuffer;
+ break;
+
+ case COLUMN_MANUFACTURER:
+ /* Manufacturer */
+ utf8_s = driver_list::driver(nItem).manufacturer;
+ break;
+
+ case COLUMN_YEAR:
+ /* Year */
+ utf8_s = driver_list::driver(nItem).year;
+ break;
+
+ case COLUMN_CLONE:
+ utf8_s = GetCloneParentName(nItem);
+ break;
+ }
+
+ if( utf8_s )
+ {
+ TCHAR* t_s = ui_wstring_from_utf8(utf8_s);
+ if( !t_s )
+ return s;
+
+ _sntprintf(pszBuffer, nBufferLength, TEXT("%s"), t_s);
+ free(t_s);
+
+ s = pszBuffer;
+ }
+
+ return s;
+}
+
+static void GamePicker_LeavingItem(HWND hwndPicker, int nItem)
+{
+ // leaving item
+ // printf("leaving %s\n",driver_list::driver(nItem).name);
+}
+
+static void GamePicker_EnteringItem(HWND hwndPicker, int nItem)
+{
+ EnableSelection(nItem);
+
+ // decide if it is valid to load a savestate
+ if (DriverSupportsSaveState(nItem))
+ EnableMenuItem(GetMenu(hMain), ID_FILE_LOADSTATE, MFS_ENABLED);
+ else
+ EnableMenuItem(GetMenu(hMain), ID_FILE_LOADSTATE, MFS_GRAYED);
+}
+
+static int GamePicker_FindItemParent(HWND hwndPicker, int nItem)
+{
+ return GetParentRomSetIndex(&driver_list::driver(nItem));
+}
+
+/* Initialize the Picker and List controls */
+static void InitListView()
+{
+ LVBKIMAGE bki;
+ //TCHAR path[MAX_PATH];
+ TCHAR* t_bgdir;
+ BOOL res;
+
+ static const struct PickerCallbacks s_gameListCallbacks =
+ {
+ SetSortColumn, /* pfnSetSortColumn */
+ GetSortColumn, /* pfnGetSortColumn */
+ SetSortReverse, /* pfnSetSortReverse */
+ GetSortReverse, /* pfnGetSortReverse */
+ SetViewMode, /* pfnSetViewMode */
+ GetViewMode, /* pfnGetViewMode */
+ SetColumnWidths, /* pfnSetColumnWidths */
+ GetColumnWidths, /* pfnGetColumnWidths */
+ SetColumnOrder, /* pfnSetColumnOrder */
+ GetColumnOrder, /* pfnGetColumnOrder */
+ SetColumnShown, /* pfnSetColumnShown */
+ GetColumnShown, /* pfnGetColumnShown */
+ GetOffsetClones, /* pfnGetOffsetChildren */
+
+ GamePicker_Compare, /* pfnCompare */
+ MamePlayGame, /* pfnDoubleClick */
+ GamePicker_GetItemString, /* pfnGetItemString */
+ GamePicker_GetItemImage, /* pfnGetItemImage */
+ GamePicker_LeavingItem, /* pfnLeavingItem */
+ GamePicker_EnteringItem, /* pfnEnteringItem */
+ BeginListViewDrag, /* pfnBeginListViewDrag */
+ GamePicker_FindItemParent, /* pfnFindItemParent */
+ OnIdle, /* pfnIdle */
+ GamePicker_OnHeaderContextMenu, /* pfnOnHeaderContextMenu */
+ GamePicker_OnBodyContextMenu /* pfnOnBodyContextMenu */
+ };
+
+ struct PickerOptions opts;
+
+ // subclass the list view
+ memset(&opts, 0, sizeof(opts));
+ opts.pCallbacks = &s_gameListCallbacks;
+ opts.nColumnCount = COLUMN_MAX;
+ opts.ppszColumnNames = column_names;
+ SetupPicker(hwndList, &opts);
+
+ res = ListView_SetTextBkColor(hwndList, CLR_NONE);
+ res = ListView_SetBkColor(hwndList, CLR_NONE);
+ t_bgdir = ui_wstring_from_utf8(GetBgDir().c_str());
+ if( !t_bgdir )
+ return;
+
+ bki.ulFlags = LVBKIF_SOURCE_URL | LVBKIF_STYLE_TILE;
+ bki.pszImage = t_bgdir;
+ if( hBackground )
+ res = ListView_SetBkImage(hwndList, &bki);
+
+ CreateIcons();
+
+ ResetColumnDisplay(true);
+
+ // Allow selection to change the default saved game
+ bListReady = true;
+ res++;
+ free(t_bgdir);
+}
+
+
+static void AddDriverIcon(int nItem,int default_icon_index)
+{
+ HICON hIcon = 0;
+ int nParentIndex = -1;
+
+ /* if already set to rom or clone icon, we've been here before */
+ if (icon_index[nItem] == 1 || icon_index[nItem] == 3)
+ return;
+
+ hIcon = LoadIconFromFile((char *)driver_list::driver(nItem).name);
+ if (hIcon == NULL)
+ {
+ nParentIndex = GetParentIndex(&driver_list::driver(nItem));
+ if( nParentIndex >= 0)
+ {
+ hIcon = LoadIconFromFile((char *)driver_list::driver(nParentIndex).name);
+ nParentIndex = GetParentIndex(&driver_list::driver(nParentIndex));
+ if (hIcon == NULL && nParentIndex >= 0)
+ hIcon = LoadIconFromFile((char *)driver_list::driver(nParentIndex).name);
+ }
+ }
+
+ if (hIcon)
+ {
+ int nIconPos = ImageList_AddIcon(hSmall, hIcon);
+ ImageList_AddIcon(hLarge, hIcon);
+ if (nIconPos != -1)
+ icon_index[nItem] = nIconPos;
+ DestroyIcon(hIcon);
+ }
+ if (icon_index[nItem] == 0)
+ icon_index[nItem] = default_icon_index;
+}
+
+static void DestroyIcons(void)
+{
+ if (hSmall)
+ {
+ ImageList_Destroy(hSmall);
+ hSmall = NULL;
+ }
+
+ if (icon_index)
+ {
+ int i;
+ for (i=0;i<driver_list::total();i++)
+ icon_index[i] = 0; // these are indices into hSmall
+ }
+
+ if (hLarge)
+ {
+ ImageList_Destroy(hLarge);
+ hLarge = NULL;
+ }
+
+ if (hHeaderImages)
+ {
+ ImageList_Destroy(hHeaderImages);
+ hHeaderImages = NULL;
+ }
+
+}
+
+static void ReloadIcons(void)
+{
+ HICON hIcon;
+ INT i;
+
+ // clear out all the images
+ ImageList_RemoveAll(hSmall);
+ ImageList_RemoveAll(hLarge);
+
+ if (icon_index)
+ for (i=0; i<driver_list::total(); i++)
+ icon_index[i] = 0; // these are indices into hSmall
+
+ for (i = 0; g_iconData[i].icon_name; i++)
+ {
+ hIcon = LoadIconFromFile((char *) g_iconData[i].icon_name);
+ if (hIcon == NULL)
+ hIcon = LoadIcon(hInst, MAKEINTRESOURCE(g_iconData[i].resource));
+
+ ImageList_AddIcon(hSmall, hIcon);
+ ImageList_AddIcon(hLarge, hIcon);
+ DestroyIcon(hIcon);
+ }
+}
+
+static DWORD GetShellLargeIconSize(void)
+{
+ DWORD dwSize = 32, dwLength = 512, dwType = REG_SZ;
+ TCHAR szBuffer[512];
+ HKEY hKey;
+ LONG lRes;
+ LPTSTR tErrorMessage = NULL;
+
+ /* Get the Key */
+ lRes = RegOpenKey(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop\\WindowMetrics"), &hKey);
+ if( lRes != ERROR_SUCCESS )
+ {
+ GetSystemErrorMessage(lRes, &tErrorMessage);
+ MessageBox(GetMainWindow(), tErrorMessage, TEXT("Large shell icon size registry access"), MB_OK | MB_ICONERROR);
+ LocalFree(tErrorMessage);
+ return dwSize;
+ }
+
+ /* Save the last size */
+ lRes = RegQueryValueEx(hKey, TEXT("Shell Icon Size"), NULL, &dwType, (LPBYTE)szBuffer, &dwLength);
+ if( lRes != ERROR_SUCCESS )
+ {
+ GetSystemErrorMessage(lRes, &tErrorMessage);
+ MessageBox(GetMainWindow(), tErrorMessage, TEXT("Large shell icon size registry query"), MB_OK | MB_ICONERROR);
+ LocalFree(tErrorMessage);
+ RegCloseKey(hKey);
+ return dwSize;
+ }
+
+ dwSize = _ttol(szBuffer);
+ if (dwSize < 32)
+ dwSize = 32;
+
+ if (dwSize > 48)
+ dwSize = 48;
+
+ /* Clean up */
+ RegCloseKey(hKey);
+ return dwSize;
+}
+
+static DWORD GetShellSmallIconSize(void)
+{
+ DWORD dwSize = ICONMAP_WIDTH;
+
+ if (dwSize < 48)
+ {
+ if (dwSize < 32)
+ dwSize = 16;
+ else
+ dwSize = 32;
+ }
+ else
+ {
+ dwSize = 48;
+ }
+ return dwSize;
+}
+
+// create iconlist for Listview control
+static void CreateIcons(void)
+{
+ DWORD dwSmallIconSize = GetShellSmallIconSize();
+ DWORD dwLargeIconSize = GetShellLargeIconSize();
+ HICON hIcon;
+ int icon_count;
+ DWORD dwStyle;
+ int i;
+ int grow = 5000;
+
+ icon_count = 0;
+ while(g_iconData[icon_count].icon_name)
+ icon_count++;
+
+ // the current window style affects the sizing of the rows when changing
+ // between list views, so put it in small icon mode temporarily while we associate
+ // our image list
+ //
+ // using large icon mode instead kills the horizontal scrollbar when doing
+ // full refresh, which seems odd (it should recreate the scrollbar when
+ // set back to report mode, for example, but it doesn't).
+
+ dwStyle = GetWindowLong(hwndList,GWL_STYLE);
+ SetWindowLong(hwndList,GWL_STYLE,(dwStyle & ~LVS_TYPEMASK) | LVS_ICON);
+
+ hSmall = ImageList_Create(dwSmallIconSize, dwSmallIconSize,
+ ILC_COLORDDB | ILC_MASK, icon_count, icon_count + grow);
+
+ if (NULL == hSmall)
+ {
+ win_message_box_utf8(hwndList, "Cannot allocate small icon image list", "Allocation error - Exiting", IDOK);
+ PostQuitMessage(0);
+ }
+
+ hLarge = ImageList_Create(dwLargeIconSize, dwLargeIconSize,
+ ILC_COLORDDB | ILC_MASK, icon_count, icon_count + grow);
+
+ if (NULL == hLarge) {
+ win_message_box_utf8(hwndList, "Cannot allocate large icon image list", "Allocation error - Exiting", IDOK);
+ PostQuitMessage(0);
+ }
+
+ ReloadIcons();
+
+ // Associate the image lists with the list view control.
+ (void)ListView_SetImageList(hwndList, hSmall, LVSIL_SMALL);
+ (void)ListView_SetImageList(hwndList, hLarge, LVSIL_NORMAL);
+
+ // restore our view
+ SetWindowLong(hwndList,GWL_STYLE,dwStyle);
+
+ // Now set up header specific stuff
+ hHeaderImages = ImageList_Create(16,16,ILC_COLORDDB | ILC_MASK,2,2);
+ hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_HEADER_UP));
+ ImageList_AddIcon(hHeaderImages,hIcon);
+ hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_HEADER_DOWN));
+ ImageList_AddIcon(hHeaderImages,hIcon);
+
+ for (i = 0; i < sizeof(s_nPickers) / sizeof(s_nPickers[0]); i++)
+ Picker_SetHeaderImageList(GetDlgItem(hMain, s_nPickers[i]), hHeaderImages);
+}
+
+
+
+static int GamePicker_Compare(HWND hwndPicker, int index1, int index2, int sort_subitem)
+{
+ int value = 0; /* Default to 0, for unknown case */
+ const char *name1 = NULL;
+ const char *name2 = NULL;
+ char file1[20];
+ char file2[20];
+ int nTemp1, nTemp2;
+
+ switch (sort_subitem)
+ {
+ case COLUMN_GAMES:
+ return core_stricmp(ModifyThe(driver_list::driver(index1).type.fullname()), ModifyThe(driver_list::driver(index2).type.fullname()));
+
+ case COLUMN_ORIENTATION:
+ nTemp1 = DriverIsVertical(index1) ? 1 : 0;
+ nTemp2 = DriverIsVertical(index2) ? 1 : 0;
+ value = nTemp1 - nTemp2;
+ break;
+
+ case COLUMN_SAMPLES:
+ nTemp1 = -1;
+ if (DriverUsesSamples(index1))
+ {
+ int audit_result = GetSampleAuditResults(index1);
+ if (IsAuditResultKnown(audit_result))
+ {
+ if (IsAuditResultYes(audit_result))
+ nTemp1 = 1;
+ else
+ nTemp1 = 0;
+ }
+ else
+ nTemp1 = 2;
+ }
+
+ nTemp2 = -1;
+ if (DriverUsesSamples(index2))
+ {
+ int audit_result = GetSampleAuditResults(index1);
+ if (IsAuditResultKnown(audit_result))
+ {
+ if (IsAuditResultYes(audit_result))
+ nTemp2 = 1;
+ else
+ nTemp2 = 0;
+ }
+ else
+ nTemp2 = 2;
+ }
+ value = nTemp2 - nTemp1;
+ break;
+
+ case COLUMN_DIRECTORY:
+ value = core_stricmp(driver_list::driver(index1).name, driver_list::driver(index2).name);
+ break;
+
+ case COLUMN_SRCDRIVERS:
+ strcpy(file1, GetDriverFilename(index1));
+ strcpy(file2, GetDriverFilename(index2));
+ value = core_stricmp(file1, file2);
+ break;
+
+ case COLUMN_PLAYTIME:
+ value = GetPlayTime(index1) - GetPlayTime(index2);
+ break;
+
+ case COLUMN_TYPE:
+ {
+ value = DriverIsVector(index1) - DriverIsVector(index2);
+ break;
+ }
+
+ case COLUMN_TRACKBALL:
+ value = DriverUsesTrackball(index1) - DriverUsesTrackball(index2);
+ break;
+
+ case COLUMN_PLAYED:
+ value = GetPlayCount(index1) - GetPlayCount(index2);
+ break;
+
+ case COLUMN_MANUFACTURER:
+ value = core_stricmp(driver_list::driver(index1).manufacturer, driver_list::driver(index2).manufacturer);
+ break;
+
+ case COLUMN_YEAR:
+ value = core_stricmp(driver_list::driver(index1).year, driver_list::driver(index2).year);
+ break;
+
+ case COLUMN_CLONE:
+ name1 = GetCloneParentName(index1);
+ name2 = GetCloneParentName(index2);
+
+ if (*name1 == '\0')
+ name1 = NULL;
+ if (*name2 == '\0')
+ name2 = NULL;
+
+ if (NULL == name1 && NULL == name2)
+ value = 0;
+ else if (name2 == NULL)
+ value = -1;
+ else if (name1 == NULL)
+ value = 1;
+ else
+ value = core_stricmp(name1, name2);
+ break;
+ }
+
+ // Handle same comparisons here
+ if (0 == value && COLUMN_GAMES != sort_subitem)
+ {
+ value = GamePicker_Compare(hwndPicker, index1, index2, COLUMN_GAMES);
+ }
+
+ return value;
+}
+
+int GetSelectedPick()
+{
+ /* returns index of listview selected item */
+ /* This will return -1 if not found */
+ return ListView_GetNextItem(hwndList, -1, LVIS_SELECTED | LVIS_FOCUSED);
+}
+
+static HICON GetSelectedPickItemIcon()
+{
+ LV_ITEM lvi;
+ lvi.iItem = GetSelectedPick();
+ lvi.iSubItem = 0;
+ lvi.mask = LVIF_IMAGE;
+ BOOL res = ListView_GetItem(hwndList, &lvi);
+ res++;
+ return ImageList_GetIcon(hLarge, lvi.iImage, ILD_TRANSPARENT);
+}
+
+static void SetRandomPickItem()
+{
+ int nListCount = ListView_GetItemCount(hwndList);
+
+ if (nListCount > 0)
+ Picker_SetSelectedPick(hwndList, rand() % nListCount);
+}
+
+BOOL CommonFileDialog(common_file_dialog_proc cfd, char *filename, int filetype)
+{
+ BOOL success;
+ UINT16 i;
+ OPENFILENAME ofn;
+ string dirname;
+ TCHAR* t_filename;
+ TCHAR t_filename_buffer[MAX_PATH] = {0, };
+ char *utf8_filename;
+
+ // convert the filename to UTF-8 and copy into buffer
+ t_filename = ui_wstring_from_utf8(filename);
+ if (t_filename)
+ {
+ _sntprintf(t_filename_buffer, ARRAY_LENGTH(t_filename_buffer), TEXT("%s"), t_filename);
+ free(t_filename);
+ }
+
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = hMain;
+ ofn.hInstance = NULL;
+ switch (filetype)
+ {
+ case FILETYPE_INPUT_FILES :
+ ofn.lpstrFilter = TEXT("input files (*.inp,*.zip,*.7z)\0*.inp;*.zip;*.7z\0All files (*.*)\0*.*\0");
+ ofn.lpstrDefExt = TEXT("inp");
+ dirname = GetInpDir();
+ break;
+ case FILETYPE_SAVESTATE_FILES :
+ ofn.lpstrFilter = TEXT("savestate files (*.sta)\0*.sta;\0All files (*.*)\0*.*\0");
+ ofn.lpstrDefExt = TEXT("sta");
+ dirname = GetStateDir();
+ break;
+ case FILETYPE_WAVE_FILES :
+ ofn.lpstrFilter = TEXT("sounds (*.wav)\0*.wav;\0All files (*.*)\0*.*\0");
+ ofn.lpstrDefExt = TEXT("wav");
+ dirname = GetImgDir();
+ break;
+ case FILETYPE_MNG_FILES :
+ ofn.lpstrFilter = TEXT("videos (*.mng)\0*.mng;\0All files (*.*)\0*.*\0");
+ ofn.lpstrDefExt = TEXT("mng");
+ dirname = GetImgDir();
+ break;
+ case FILETYPE_AVI_FILES :
+ ofn.lpstrFilter = TEXT("videos (*.avi)\0*.avi;\0All files (*.*)\0*.*\0");
+ ofn.lpstrDefExt = TEXT("avi");
+ dirname = GetImgDir();
+ break;
+ case FILETYPE_EFFECT_FILES :
+ ofn.lpstrFilter = TEXT("effects (*.png)\0*.png;\0All files (*.*)\0*.*\0");
+ ofn.lpstrDefExt = TEXT("png");
+ dirname = GetArtDir();
+ break;
+ case FILETYPE_JOYMAP_FILES :
+ ofn.lpstrFilter = TEXT("maps (*.map,*.txt)\0*.map;*.txt;\0All files (*.*)\0*.*\0");
+ ofn.lpstrDefExt = TEXT("map");
+ dirname = GetCtrlrDir();
+ break;
+ case FILETYPE_DEBUGSCRIPT_FILES :
+ ofn.lpstrFilter = TEXT("scripts (*.txt,*.dat)\0*.txt;*.dat;\0All files (*.*)\0*.*\0");
+ ofn.lpstrDefExt = TEXT("txt");
+ dirname = GetInpDir();
+ break;
+ }
+ ofn.lpstrCustomFilter = NULL;
+ ofn.nMaxCustFilter = 0;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = t_filename_buffer;
+ ofn.nMaxFile = ARRAY_LENGTH(t_filename_buffer);
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+
+ // Only want first directory
+ i = dirname.find(";");
+ if (i > 0)
+ dirname.resize(i);
+ if (dirname.empty())
+ dirname = ".";
+ ofn.lpstrInitialDir = ui_wstring_from_utf8(dirname.c_str());
+
+ ofn.lpstrTitle = NULL;
+ ofn.Flags = OFN_EXPLORER | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nFileOffset = 0;
+ ofn.nFileExtension = 0;
+ ofn.lCustData = 0;
+ ofn.lpfnHook = NULL;
+ ofn.lpTemplateName = NULL;
+
+ success = cfd(&ofn);
+ if (success)
+ {
+ //dprintf("got filename %s nFileExtension %u\n",filename,ofn.nFileExtension);
+ /*GetDirectory(filename,last_directory,sizeof(last_directory));*/
+ }
+
+ utf8_filename = ui_utf8_from_wstring(t_filename_buffer);
+ if (utf8_filename)
+ {
+ snprintf(filename, MAX_PATH, "%s", utf8_filename);
+ free(utf8_filename);
+ }
+
+ return success;
+}
+
+void SetStatusBarText(int part_index, const char *message)
+{
+ TCHAR* t_message = ui_wstring_from_utf8(message);
+ if( !t_message )
+ return;
+ SendMessage(hStatusBar, SB_SETTEXT, (WPARAM) part_index, (LPARAM)(LPCTSTR) win_tstring_strdup(t_message));
+ free(t_message);
+}
+
+void SetStatusBarTextF(int part_index, const char *fmt, ...)
+{
+ char buf[256];
+ va_list va;
+
+ va_start(va, fmt);
+ vsprintf(buf, fmt, va);
+ va_end(va);
+
+ SetStatusBarText(part_index, buf);
+}
+
+static void CLIB_DECL ATTR_PRINTF(1,2) MameMessageBox(const char *fmt, ...)
+{
+ char buf[2048];
+ va_list va;
+
+ va_start(va, fmt);
+ vsprintf(buf, fmt, va);
+ win_message_box_utf8(GetMainWindow(), buf, MAMEUINAME, MB_OK | MB_ICONERROR);
+ va_end(va);
+}
+
+static void MamePlayBackGame()
+{
+ char filename[MAX_PATH];
+ *filename = 0;
+
+ int nGame = Picker_GetSelectedItem(hwndList);
+ if (nGame != -1)
+ strcpy(filename, driver_list::driver(nGame).name);
+
+ if (CommonFileDialog(GetOpenFileName, filename, FILETYPE_INPUT_FILES))
+ {
+ osd_file::error fileerr;
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char bare_fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+ char path[MAX_PATH];
+ char fname[MAX_PATH];
+ play_options playopts;
+
+ _splitpath(filename, drive, dir, bare_fname, ext);
+
+ sprintf(path,"%s%s",drive,dir);
+ sprintf(fname,"%s%s",bare_fname,ext);
+ if (path[strlen(path)-1] == '\\')
+ path[strlen(path)-1] = 0; // take off trailing back slash
+
+ emu_file pPlayBack(MameUIGlobal().input_directory(), OPEN_FLAG_READ);
+ fileerr = pPlayBack.open(fname);
+ if (fileerr != osd_file::error::NONE)
+ {
+ MameMessageBox("Could not open '%s' as a valid input file.", filename);
+ return;
+ }
+
+ // check for game name embedded in .inp header
+ inp_header header;
+
+ /* read the header and verify that it is a modern version; if not, print an error */
+ if (!header.read(pPlayBack))
+ {
+ MameMessageBox("Input file is corrupt or invalid (missing header)");
+ return;
+ }
+ if ((!header.check_magic()) || (header.get_majversion() != inp_header::MAJVERSION))
+ {
+ MameMessageBox("Input file invalid or in an older, unsupported format");
+ return;
+ }
+
+ string const sysname = header.get_sysname();
+ nGame = -1;
+ for (int i = 0; i < driver_list::total(); i++) // find game and play it
+ {
+ if (driver_list::driver(i).name == sysname)
+ {
+ nGame = i;
+ break;
+ }
+ }
+ if (nGame == -1)
+ {
+ MameMessageBox("Game \"%s\" cannot be found", sysname.c_str());
+ return;
+ }
+
+ memset(&playopts, 0, sizeof(playopts));
+ playopts.playback = fname;
+ playopts_apply = 0x57;
+ MamePlayGameWithOptions(nGame, &playopts);
+ }
+}
+
+static void MameLoadState()
+{
+ int nGame;
+ char filename[MAX_PATH];
+ char selected_filename[MAX_PATH];
+ play_options playopts;
+
+ *filename = 0;
+
+ nGame = Picker_GetSelectedItem(hwndList);
+ if (nGame != -1)
+ {
+ strcpy(filename, driver_list::driver(nGame).name);
+ strcpy(selected_filename, driver_list::driver(nGame).name);
+ }
+ if (CommonFileDialog(GetOpenFileName, filename, FILETYPE_SAVESTATE_FILES))
+ {
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char ext[_MAX_EXT];
+
+ char path[MAX_PATH];
+ char fname[MAX_PATH];
+ char bare_fname[_MAX_FNAME];
+ char *state_fname;
+ //int rc;
+
+ _splitpath(filename, drive, dir, bare_fname, ext);
+
+ // parse path
+ sprintf(path,"%s%s",drive,dir);
+ sprintf(fname,"%s%s",bare_fname,ext);
+ if (path[strlen(path)-1] == '\\')
+ path[strlen(path)-1] = 0; // take off trailing back slash
+
+#ifdef MESS
+ {
+ state_fname = filename;
+ }
+#else // !MESS
+ {
+ char *cPos=0;
+ int iPos=0;
+ char romname[MAX_PATH];
+
+ cPos = strchr(bare_fname, '-' );
+ iPos = cPos ? cPos - bare_fname : strlen(bare_fname);
+ strncpy(romname, bare_fname, iPos );
+ romname[iPos] = '\0';
+ if( strcmp(selected_filename,romname) != 0 )
+ {
+ MameMessageBox("'%s' is not a valid savestate file for game '%s'.", filename, selected_filename);
+ return;
+ }
+ state_fname = fname;
+ }
+#endif // MESS
+ emu_file pSaveState(MameUIGlobal().state_directory(), OPEN_FLAG_READ);
+ osd_file::error fileerr = pSaveState.open(state_fname);
+ if (fileerr != osd_file::error::NONE)
+ {
+ MameMessageBox("Could not open '%s' as a valid savestate file.", filename);
+ return;
+ }
+
+ // call the MAME core function to check the save state file
+ //rc = state_manager::check_file(NULL, pSaveState, selected_filename, MameMessageBox);
+ //if (rc)
+// return;
+
+ memset(&playopts, 0, sizeof(playopts));
+#ifdef MESS
+ playopts.state = state_fname;
+ playopts_apply = 0x57;
+#else
+ {
+ char *cPos;
+ cPos = strrchr(bare_fname, '-' );
+ cPos = cPos+1;
+ if (*cPos != 0)
+ {
+ playopts.state = cPos;
+ }
+ }
+#endif
+
+ MamePlayGameWithOptions(nGame, &playopts);
+ }
+}
+
+static void MamePlayRecordGame()
+{
+ int nGame;
+ char filename[MAX_PATH];
+ *filename = 0;
+
+ nGame = Picker_GetSelectedItem(hwndList);
+ if (nGame != -1)
+ strcpy(filename, driver_list::driver(nGame).name);
+
+ if (CommonFileDialog(GetSaveFileName, filename, FILETYPE_INPUT_FILES))
+ {
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+ char path[MAX_PATH];
+ play_options playopts;
+
+ _splitpath(filename, drive, dir, fname, ext);
+
+ sprintf(path,"%s%s",drive,dir);
+ if (path[strlen(path)-1] == '\\')
+ path[strlen(path)-1] = 0; // take off trailing back slash
+
+ memset(&playopts, 0, sizeof(playopts));
+ strcat(fname, ".inp");
+ playopts.record = fname;
+ playopts_apply = 0x57;
+ MamePlayGameWithOptions(nGame, &playopts);
+ }
+}
+
+void MamePlayGame(void)
+{
+ int nGame;
+ play_options playopts;
+
+ nGame = Picker_GetSelectedItem(hwndList);
+ if (nGame != -1)
+ {
+ memset(&playopts, 0, sizeof(playopts));
+ MamePlayGameWithOptions(nGame, &playopts);
+ }
+}
+
+static void MamePlayRecordWave()
+{
+ int nGame;
+ char filename[MAX_PATH];
+ play_options playopts;
+
+ nGame = Picker_GetSelectedItem(hwndList);
+ if (nGame != -1)
+ strcpy(filename, driver_list::driver(nGame).name);
+
+ if (CommonFileDialog(GetSaveFileName, filename, FILETYPE_WAVE_FILES))
+ {
+ memset(&playopts, 0, sizeof(playopts));
+ playopts.wavwrite = filename;
+ playopts_apply = 0x57;
+ MamePlayGameWithOptions(nGame, &playopts);
+ }
+}
+
+static void MamePlayRecordMNG()
+{
+ int nGame;
+ char filename[MAX_PATH] = { 0, };
+
+ nGame = Picker_GetSelectedItem(hwndList);
+ if (nGame != -1)
+ strcpy(filename, driver_list::driver(nGame).name);
+
+ if (CommonFileDialog(GetSaveFileName, filename, FILETYPE_MNG_FILES))
+ {
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+ char path[MAX_PATH];
+ play_options playopts;
+
+ _splitpath(filename, drive, dir, fname, ext);
+
+ sprintf(path,"%s%s",drive,dir);
+ if (path[strlen(path)-1] == '\\')
+ path[strlen(path)-1] = 0; // take off trailing back slash
+
+ memset(&playopts, 0, sizeof(playopts));
+ strcat(fname, ".mng");
+ playopts.mngwrite = fname;
+ playopts_apply = 0x57;
+ MamePlayGameWithOptions(nGame, &playopts);
+ }
+}
+
+static void MamePlayRecordAVI()
+{
+ int nGame;
+ char filename[MAX_PATH] = { 0, };
+
+ nGame = Picker_GetSelectedItem(hwndList);
+ if (nGame != -1)
+ strcpy(filename, driver_list::driver(nGame).name);
+
+ if (CommonFileDialog(GetSaveFileName, filename, FILETYPE_AVI_FILES))
+ {
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+ char path[MAX_PATH];
+ play_options playopts;
+
+ _splitpath(filename, drive, dir, fname, ext);
+
+ sprintf(path,"%s%s",drive,dir);
+ if (path[strlen(path)-1] == '\\')
+ path[strlen(path)-1] = 0; // take off trailing back slash
+
+ memset(&playopts, 0, sizeof(playopts));
+ strcat(fname, ".avi");
+ playopts.aviwrite = fname;
+ playopts_apply = 0x57;
+ MamePlayGameWithOptions(nGame, &playopts);
+ }
+}
+
+
+static void MamePlayGameWithOptions(int nGame, const play_options *playopts)
+{
+ DWORD dwExitCode;
+ BOOL res;
+
+ if (g_pJoyGUI)
+ KillTimer(hMain, JOYGUI_TIMER);
+ if (GetCycleScreenshot() > 0)
+ KillTimer(hMain, SCREENSHOT_TIMER);
+
+ in_emulation = true;
+
+ dwExitCode = RunMAME(nGame, playopts);
+ if (dwExitCode == 0)
+ {
+ IncrementPlayCount(nGame);
+ res = ListView_RedrawItems(hwndList, GetSelectedPick(), GetSelectedPick());
+ }
+ else
+ {
+ ShowWindow(hMain, SW_SHOW);
+ }
+
+ in_emulation = false;
+
+ // re-sort if sorting on # of times played
+ if (GetSortColumn() == COLUMN_PLAYED)
+ Picker_Sort(hwndList);
+
+ UpdateStatusBar();
+
+ ShowWindow(hMain, SW_SHOW);
+ SetFocus(hwndList);
+
+ if (g_pJoyGUI)
+ SetTimer(hMain, JOYGUI_TIMER, JOYGUI_MS, NULL);
+ if (GetCycleScreenshot() > 0)
+ SetTimer(hMain, SCREENSHOT_TIMER, GetCycleScreenshot()*1000, NULL); //scale to seconds
+ res++;
+}
+
+/* Toggle ScreenShot ON/OFF */
+static void ToggleScreenShot(void)
+{
+ UINT val = GetWindowPanes() ^ 8;
+ BOOL show = BIT(val, 3);
+ SetWindowPanes(val);
+ UpdateScreenShot();
+
+ /* Redraw list view */
+ if (hBackground && show)
+ InvalidateRect(hwndList, NULL, false);
+}
+
+static void AdjustMetrics(void)
+{
+ HDC hDC;
+ TEXTMETRIC tm;
+ int xtraX, xtraY;
+ AREA area;
+ int offX, offY;
+ int maxX, maxY;
+ COLORREF textColor;
+ TCHAR szClass[128];
+ HWND hWnd;
+ HRESULT res;
+ BOOL b_res;
+
+ /* WM_SETTINGCHANGE also */
+ xtraX = GetSystemMetrics(SM_CXFIXEDFRAME); /* Dialog frame width */
+ xtraY = GetSystemMetrics(SM_CYFIXEDFRAME); /* Dialog frame height */
+ xtraY += GetSystemMetrics(SM_CYMENUSIZE); /* Menu height */
+ xtraY += GetSystemMetrics(SM_CYCAPTION); /* Caption Height */
+ maxX = GetSystemMetrics(SM_CXSCREEN); /* Screen Width */
+ maxY = GetSystemMetrics(SM_CYSCREEN); /* Screen Height */
+
+ hDC = GetDC(hMain);
+ GetTextMetrics (hDC, &tm);
+
+ /* Convert MIN Width/Height from Dialog Box Units to pixels. */
+ MIN_WIDTH = (int)((tm.tmAveCharWidth / 4.0) * DBU_MIN_WIDTH) + xtraX;
+ MIN_HEIGHT = (int)((tm.tmHeight / 8.0) * DBU_MIN_HEIGHT) + xtraY;
+ ReleaseDC(hMain, hDC);
+
+ if ((textColor = GetListFontColor()) == RGB(255, 255, 255))
+ textColor = RGB(240, 240, 240);
+
+ hWnd = GetWindow(hMain, GW_CHILD);
+ while(hWnd)
+ {
+ if (GetClassName(hWnd, szClass, sizeof(szClass) / sizeof(szClass[0])))
+ {
+ if (!_tcscmp(szClass, TEXT("SysListView32")))
+ {
+ b_res = ListView_SetBkColor(hWnd, GetSysColor(COLOR_WINDOW));
+ b_res = ListView_SetTextColor(hWnd, textColor);
+ }
+ else if (!_tcscmp(szClass, TEXT("SysTreeView32")))
+ {
+ res = TreeView_SetBkColor(hTreeView, GetSysColor(COLOR_WINDOW));
+ res = TreeView_SetTextColor(hTreeView, textColor);
+ }
+ }
+ hWnd = GetWindow(hWnd, GW_HWNDNEXT);
+ }
+
+ GetWindowArea(&area);
+
+ offX = area.x + area.width;
+ offY = area.y + area.height;
+
+ if (offX > maxX)
+ {
+ offX = maxX;
+ area.x = (offX - area.width > 0) ? (offX - area.width) : 0;
+ }
+ if (offY > maxY)
+ {
+ offY = maxY;
+ area.y = (offY - area.height > 0) ? (offY - area.height) : 0;
+ }
+
+ SetWindowArea(&area);
+ SetWindowPos(hMain, 0, area.x, area.y, area.width, area.height, SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE);
+ res++;
+ b_res++;
+}
+
+int FindIconIndex(int nIconResource)
+{
+ int i;
+ for(i = 0; g_iconData[i].icon_name; i++)
+ {
+ if (g_iconData[i].resource == nIconResource)
+ return i;
+ }
+ return -1;
+}
+
+int FindIconIndexByName(const char *icon_name)
+{
+ int i;
+ for (i = 0; g_iconData[i].icon_name; i++)
+ {
+ if (!strcmp(g_iconData[i].icon_name, icon_name))
+ return i;
+ }
+ return -1;
+}
+
+static int GetIconForDriver(int nItem)
+{
+ int iconRoms = 1;
+
+ if (DriverUsesRoms(nItem))
+ {
+ int audit_result = GetRomAuditResults(nItem);
+ if (audit_result == -1)
+ return 2;
+ else
+ if (IsAuditResultYes(audit_result))
+ iconRoms = 1;
+ else
+ iconRoms = 0;
+ }
+
+ // iconRoms is now either 0 (no roms), 1 (roms), or 2 (unknown)
+
+ /* these are indices into icon_names, which maps into our image list
+ * also must match IDI_WIN_NOROMS + iconRoms
+ */
+
+ if (iconRoms == 1)
+ {
+ // Show Red-X if the ROMs are present and flagged as NOT WORKING
+ if (DriverIsBroken(nItem))
+ iconRoms = FindIconIndex(IDI_WIN_REDX); // iconRoms now = 4
+ else
+ // Show imperfect if the ROMs are present and flagged as imperfect
+ if (DriverIsImperfect(nItem))
+ iconRoms = FindIconIndex(IDI_WIN_IMPERFECT); // iconRoms now = 5
+ else
+ // show clone icon if we have roms and game is working
+ if (DriverIsClone(nItem))
+ iconRoms = FindIconIndex(IDI_WIN_CLONE); // iconRoms now = 3
+ }
+
+ // if we have the roms, then look for a custom per-game icon to override
+ // not 2, because this indicates F5 must be done; not 0, because this indicates roms are missing; only use 4 if user chooses it
+ BOOL redx = GetOverrideRedX() & (iconRoms == 4);
+ if (iconRoms == 1 || iconRoms == 3 || iconRoms == 5 || redx)
+ {
+ if (icon_index[nItem] == 0)
+ AddDriverIcon(nItem,iconRoms);
+ iconRoms = icon_index[nItem];
+ }
+
+ return iconRoms;
+}
+
+static BOOL HandleTreeContextMenu(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+ HMENU hTreeMenu;
+ HMENU hMenu;
+ TVHITTESTINFO hti;
+ POINT pt;
+ BOOL res;
+
+ if ((HWND)wParam != GetDlgItem(hWnd, IDC_TREE))
+ return false;
+
+ pt.x = GET_X_LPARAM(lParam);
+ pt.y = GET_Y_LPARAM(lParam);
+ if (pt.x < 0 && pt.y < 0)
+ GetCursorPos(&pt);
+
+ /* select the item that was right clicked or shift-F10'ed */
+ hti.pt = pt;
+ ScreenToClient(hTreeView,&hti.pt);
+ (void)TreeView_HitTest(hTreeView,&hti);
+ if ((hti.flags & TVHT_ONITEM) != 0)
+ res = TreeView_SelectItem(hTreeView,hti.hItem);
+
+ hTreeMenu = LoadMenu(hInst,MAKEINTRESOURCE(IDR_CONTEXT_TREE));
+
+ InitTreeContextMenu(hTreeMenu);
+
+ hMenu = GetSubMenu(hTreeMenu, 0);
+
+ UpdateMenu(hMenu);
+
+ TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_RIGHTBUTTON,pt.x,pt.y,0,hWnd,NULL);
+
+ DestroyMenu(hTreeMenu);
+ res++;
+ return true;
+}
+
+
+
+static void GamePicker_OnBodyContextMenu(POINT pt)
+{
+ HMENU hMenuLoad;
+ HMENU hMenu;
+
+ hMenuLoad = LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTEXT_MENU));
+ hMenu = GetSubMenu(hMenuLoad, 0);
+ InitBodyContextMenu(hMenu);
+
+ UpdateMenu(hMenu);
+
+ TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_RIGHTBUTTON,pt.x,pt.y,0,hMain,NULL);
+
+ DestroyMenu(hMenuLoad);
+}
+
+
+
+static BOOL HandleScreenShotContextMenu(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+ HMENU hMenuLoad;
+ HMENU hMenu;
+ POINT pt;
+
+ if ((HWND)wParam != GetDlgItem(hWnd, IDC_SSPICTURE) && (HWND)wParam != GetDlgItem(hWnd, IDC_SSFRAME))
+ return false;
+
+ pt.x = GET_X_LPARAM(lParam);
+ pt.y = GET_Y_LPARAM(lParam);
+ if (pt.x < 0 && pt.y < 0)
+ GetCursorPos(&pt);
+
+ hMenuLoad = LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTEXT_SCREENSHOT));
+ hMenu = GetSubMenu(hMenuLoad, 0);
+
+ UpdateMenu(hMenu);
+
+ TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_RIGHTBUTTON,pt.x,pt.y,0,hWnd,NULL);
+
+ DestroyMenu(hMenuLoad);
+
+ return true;
+}
+
+static void UpdateMenu(HMENU hMenu)
+{
+ TCHAR buf[200];
+ MENUITEMINFO mItem;
+ int nGame = Picker_GetSelectedItem(hwndList);
+ if (nGame < 0)
+ have_selection = 0;
+
+ LPTREEFOLDER lpFolder = GetCurrentFolder();
+ int i;
+ TCHAR* t_description;
+
+ if (have_selection)
+ {
+ t_description = ui_wstring_from_utf8(ConvertAmpersandString(ModifyThe(driver_list::driver(nGame).type.fullname())));
+ if( !t_description )
+ return;
+
+ _sntprintf(buf, ARRAY_LENGTH(buf), g_szPlayGameString, t_description);
+
+ mItem.cbSize = sizeof(mItem);
+ mItem.fMask = MIIM_TYPE;
+ mItem.fType = MFT_STRING;
+ mItem.dwTypeData = buf;
+ mItem.cch = _tcslen(mItem.dwTypeData);
+
+ SetMenuItemInfo(hMenu, ID_FILE_PLAY, false, &mItem);
+
+ EnableMenuItem(hMenu, ID_CONTEXT_SELECT_RANDOM, MF_ENABLED);
+
+ free(t_description);
+ }
+ else
+ {
+ EnableMenuItem(hMenu, ID_FILE_PLAY, MF_GRAYED);
+ EnableMenuItem(hMenu, ID_FILE_PLAY_RECORD, MF_GRAYED);
+ EnableMenuItem(hMenu, ID_GAME_PROPERTIES, MF_GRAYED);
+ EnableMenuItem(hMenu, ID_CONTEXT_SELECT_RANDOM, MF_GRAYED);
+ }
+
+ if (oldControl)
+ {
+ EnableMenuItem(hMenu, ID_CUSTOMIZE_FIELDS, MF_GRAYED);
+ EnableMenuItem(hMenu, ID_GAME_PROPERTIES, MF_GRAYED);
+ EnableMenuItem(hMenu, ID_OPTIONS_DEFAULTS, MF_GRAYED);
+ }
+
+ if (lpFolder->m_dwFlags & F_CUSTOM)
+ {
+ EnableMenuItem(hMenu,ID_CONTEXT_REMOVE_CUSTOM,MF_ENABLED);
+ EnableMenuItem(hMenu,ID_CONTEXT_RENAME_CUSTOM,MF_ENABLED);
+ }
+ else
+ {
+ EnableMenuItem(hMenu,ID_CONTEXT_REMOVE_CUSTOM,MF_GRAYED);
+ EnableMenuItem(hMenu,ID_CONTEXT_RENAME_CUSTOM,MF_GRAYED);
+ }
+ //pParent = GetFolderNameByID(lpFolder->m_nParent+1);
+
+ EnableMenuItem(hMenu, ID_FOLDER_PROPERTIES, (lpFolder->m_dwFlags & F_INIEDIT) ? MF_ENABLED : MF_GRAYED);
+
+ CheckMenuRadioItem(hMenu, ID_VIEW_TAB_ARTWORK, ID_VIEW_TAB_HISTORY, ID_VIEW_TAB_ARTWORK + TabView_GetCurrentTab(hTabCtrl), MF_BYCOMMAND);
+
+ // set whether we're showing the tab control or not
+ if (bShowTabCtrl)
+ CheckMenuItem(hMenu,ID_VIEW_PAGETAB,MF_BYCOMMAND | MF_CHECKED);
+ else
+ CheckMenuItem(hMenu,ID_VIEW_PAGETAB,MF_BYCOMMAND | MF_UNCHECKED);
+
+ for (i=0;i<MAX_TAB_TYPES;i++)
+ {
+ // disable menu items for tabs we're not currently showing
+ if (GetShowTab(i))
+ EnableMenuItem(hMenu,ID_VIEW_TAB_ARTWORK + i,MF_BYCOMMAND | MF_ENABLED);
+ else
+ EnableMenuItem(hMenu,ID_VIEW_TAB_ARTWORK + i,MF_BYCOMMAND | MF_GRAYED);
+
+ // check toggle menu items
+ if (GetShowTab(i))
+ CheckMenuItem(hMenu, ID_TOGGLE_TAB_ARTWORK + i,MF_BYCOMMAND | MF_CHECKED);
+ else
+ CheckMenuItem(hMenu, ID_TOGGLE_TAB_ARTWORK + i,MF_BYCOMMAND | MF_UNCHECKED);
+ }
+
+ for (i=0;i<MAX_FOLDERS;i++)
+ {
+ if (GetShowFolder(i))
+ CheckMenuItem(hMenu,ID_CONTEXT_SHOW_FOLDER_START + i,MF_BYCOMMAND | MF_CHECKED);
+ else
+ CheckMenuItem(hMenu,ID_CONTEXT_SHOW_FOLDER_START + i,MF_BYCOMMAND | MF_UNCHECKED);
+ }
+}
+
+void InitTreeContextMenu(HMENU hTreeMenu)
+{
+ extern const FOLDERDATA g_folderData[];
+
+ MENUITEMINFO mii;
+ ZeroMemory(&mii,sizeof(mii));
+ mii.cbSize = sizeof(mii);
+ mii.wID = -1;
+ mii.fMask = MIIM_SUBMENU | MIIM_ID;
+
+ HMENU hMenu = GetSubMenu(hTreeMenu, 0);
+
+ if (GetMenuItemInfo(hMenu,3,true,&mii) == false)
+ {
+ printf("can't find show folders context menu\n");fflush(stdout);
+ return;
+ }
+
+ if (mii.hSubMenu == NULL)
+ {
+ printf("can't find submenu for show folders context menu\n");fflush(stdout);
+ return;
+ }
+
+ hMenu = mii.hSubMenu;
+
+ for (int i=0; g_folderData[i].m_lpTitle; i++)
+ {
+ if (!g_folderData[i].m_process)
+ {
+ TCHAR* t_title = ui_wstring_from_utf8(g_folderData[i].m_lpTitle);
+ if( !t_title )
+ return;
+
+ mii.fMask = MIIM_TYPE | MIIM_ID;
+ mii.fType = MFT_STRING;
+ mii.dwTypeData = t_title;
+ mii.cch = _tcslen(mii.dwTypeData);
+ mii.wID = ID_CONTEXT_SHOW_FOLDER_START + g_folderData[i].m_nFolderId;
+
+ // menu in resources has one empty item (needed for the submenu to setup properly)
+ // so overwrite this one, append after
+ if (i == 0)
+ SetMenuItemInfo(hMenu,ID_CONTEXT_SHOW_FOLDER_START,false,&mii);
+ else
+ InsertMenuItem(hMenu,i,false,&mii);
+
+ free(t_title);
+ }
+ }
+}
+
+
+void InitBodyContextMenu(HMENU hBodyContextMenu)
+{
+ int current_game = Picker_GetSelectedItem(hwndList);
+ if (current_game < 0)
+ return;
+
+ TCHAR tmp[30];
+ MENUITEMINFO mii;
+ ZeroMemory(&mii,sizeof(mii));
+ mii.cbSize = sizeof(mii);
+
+ if (GetMenuItemInfo(hBodyContextMenu,ID_FOLDER_SOURCEPROPERTIES,false,&mii) == false)
+ {
+ dprintf("can't find show folders context menu\n");
+ return;
+ }
+
+ _sntprintf(tmp,ARRAY_LENGTH(tmp),TEXT("Properties for %s"), ui_wstring_from_utf8(GetDriverFilename(current_game) ));
+ mii.fMask = MIIM_TYPE | MIIM_ID;
+ mii.fType = MFT_STRING;
+ mii.dwTypeData = tmp;
+ mii.cch = _tcslen(mii.dwTypeData);
+ mii.wID = ID_FOLDER_SOURCEPROPERTIES;
+
+
+ // menu in resources has one default item
+ // so overwrite this one
+ SetMenuItemInfo(hBodyContextMenu,ID_FOLDER_SOURCEPROPERTIES,false,&mii);
+ EnableMenuItem(hBodyContextMenu, ID_FOLDER_VECTORPROPERTIES, DriverIsVector(current_game) ? MF_ENABLED : MF_GRAYED);
+}
+
+
+void ToggleShowFolder(int folder)
+{
+ int current_id = GetCurrentFolderID();
+
+ SetWindowRedraw(hwndList,false);
+
+ SetShowFolder(folder,!GetShowFolder(folder));
+
+ ResetTreeViewFolders();
+ SelectTreeViewFolder(current_id);
+
+ SetWindowRedraw(hwndList,true);
+}
+
+static LRESULT CALLBACK HistoryWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (hBackground)
+ {
+ switch (uMsg)
+ {
+ case WM_MOUSEMOVE:
+ {
+ if (MouseHasBeenMoved())
+ ShowCursor(true);
+ break;
+ }
+
+ case WM_ERASEBKGND:
+ return true;
+ case WM_PAINT:
+ {
+ POINT p = { 0, 0 };
+
+ /* get base point of background bitmap */
+ MapWindowPoints(hWnd,hTreeView,&p,1);
+ PaintBackgroundImage(hWnd, NULL, p.x, p.y);
+ /* to ensure our parent procedure repaints the whole client area */
+ InvalidateRect(hWnd, NULL, false);
+ break;
+ }
+ }
+ }
+ return CallWindowProc(g_lpHistoryWndProc, hWnd, uMsg, wParam, lParam);
+}
+
+static LRESULT CALLBACK PictureFrameWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_MOUSEMOVE:
+ {
+ if (MouseHasBeenMoved())
+ ShowCursor(true);
+ break;
+ }
+
+ case WM_NCHITTEST :
+ {
+ POINT pt;
+ RECT rect;
+ HWND hHistory = GetDlgItem(hMain, IDC_HISTORY);
+
+ pt.x = LOWORD(lParam);
+ pt.y = HIWORD(lParam);
+ GetWindowRect(hHistory, &rect);
+ // check if they clicked on the picture area (leave 6 pixel no man's land
+ // by the history window to reduce mistaken clicks)
+ // no more no man's land, the Cursor changes when Edit control is left, should be enough feedback
+ if (have_history &&
+ ( ( (TabView_GetCurrentTab(hTabCtrl) == TAB_HISTORY) ||
+ (TabView_GetCurrentTab(hTabCtrl) == GetHistoryTab() && GetShowTab(TAB_HISTORY) == false) ||
+ (TAB_ALL == GetHistoryTab() && GetShowTab(TAB_HISTORY) == false) ) &&
+// (rect.top - 6) < pt.y && pt.y < (rect.bottom + 6) ) )
+ PtInRect( &rect, pt ) ) )
+
+ {
+ return HTTRANSPARENT;
+ }
+ else
+ {
+ return HTCLIENT;
+ }
+ }
+ break;
+ case WM_CONTEXTMENU:
+ if ( HandleScreenShotContextMenu(hWnd, wParam, lParam))
+ return false;
+ break;
+ }
+
+ if (hBackground)
+ {
+ switch (uMsg)
+ {
+ case WM_ERASEBKGND :
+ return true;
+ case WM_PAINT :
+ {
+ RECT rect,nodraw_rect;
+ HRGN region,nodraw_region;
+ POINT p = { 0, 0 };
+
+ /* get base point of background bitmap */
+ MapWindowPoints(hWnd,hTreeView,&p,1);
+
+ /* get big region */
+ GetClientRect(hWnd,&rect);
+ region = CreateRectRgnIndirect(&rect);
+
+ if (IsWindowVisible(GetDlgItem(hMain,IDC_HISTORY)))
+ {
+ /* don't draw over this window */
+ GetWindowRect(GetDlgItem(hMain,IDC_HISTORY),&nodraw_rect);
+ MapWindowPoints(HWND_DESKTOP,hWnd,(LPPOINT)&nodraw_rect,2);
+ nodraw_region = CreateRectRgnIndirect(&nodraw_rect);
+ CombineRgn(region,region,nodraw_region,RGN_DIFF);
+ DeleteObject(nodraw_region);
+ }
+ if (IsWindowVisible(GetDlgItem(hMain,IDC_SSPICTURE)))
+ {
+ /* don't draw over this window */
+ GetWindowRect(GetDlgItem(hMain,IDC_SSPICTURE),&nodraw_rect);
+ MapWindowPoints(HWND_DESKTOP,hWnd,(LPPOINT)&nodraw_rect,2);
+ nodraw_region = CreateRectRgnIndirect(&nodraw_rect);
+ CombineRgn(region,region,nodraw_region,RGN_DIFF);
+ DeleteObject(nodraw_region);
+ }
+
+ PaintBackgroundImage(hWnd,region,p.x,p.y);
+
+ DeleteObject(region);
+
+ /* to ensure our parent procedure repaints the whole client area */
+ InvalidateRect(hWnd, NULL, false);
+
+ break;
+ }
+ }
+ }
+ return CallWindowProc(g_lpPictureFrameWndProc, hWnd, uMsg, wParam, lParam);
+}
+
+static LRESULT CALLBACK PictureWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_ERASEBKGND :
+ return true;
+ case WM_PAINT :
+ {
+ PAINTSTRUCT ps;
+ HDC hdc,hdc_temp;
+ RECT rect;
+ HBITMAP old_bitmap;
+
+ int width,height;
+
+ RECT rect2;
+ HBRUSH hBrush;
+ HBRUSH holdBrush;
+ HRGN region1, region2;
+ int nBordersize;
+ nBordersize = GetScreenshotBorderSize();
+ hBrush = CreateSolidBrush(GetScreenshotBorderColor());
+
+ hdc = BeginPaint(hWnd,&ps);
+
+ hdc_temp = CreateCompatibleDC(hdc);
+ if (ScreenShotLoaded())
+ {
+ width = GetScreenShotWidth();
+ height = GetScreenShotHeight();
+
+ old_bitmap = (HBITMAP)SelectObject(hdc_temp,GetScreenShotHandle());
+ }
+ else
+ {
+ BITMAP bmp;
+
+ GetObject(hMissing_bitmap,sizeof(BITMAP),&bmp);
+ width = bmp.bmWidth;
+ height = bmp.bmHeight;
+
+ old_bitmap = (HBITMAP)SelectObject(hdc_temp,hMissing_bitmap);
+ }
+
+ GetClientRect(hWnd,&rect);
+
+ rect2 = rect;
+ //Configurable Borders around images
+ rect.bottom -= nBordersize;
+ if( rect.bottom < 0)
+ rect.bottom = rect2.bottom;
+ rect.right -= nBordersize;
+ if( rect.right < 0)
+ rect.right = rect2.right;
+ rect.top += nBordersize;
+ if( rect.top > rect.bottom )
+ rect.top = rect2.top;
+ rect.left += nBordersize;
+ if( rect.left > rect.right )
+ rect.left = rect2.left;
+ region1 = CreateRectRgnIndirect(&rect);
+ region2 = CreateRectRgnIndirect(&rect2);
+ CombineRgn(region2,region2,region1,RGN_DIFF);
+ holdBrush = (HBRUSH)SelectObject(hdc, hBrush);
+
+ FillRgn(hdc,region2, hBrush );
+ SelectObject(hdc, holdBrush);
+ DeleteBrush(hBrush);
+
+ SetStretchBltMode(hdc,STRETCH_HALFTONE);
+ StretchBlt(hdc,nBordersize,nBordersize,rect.right-rect.left,rect.bottom-rect.top,
+ hdc_temp,0,0,width,height,SRCCOPY);
+ SelectObject(hdc_temp,old_bitmap);
+ DeleteDC(hdc_temp);
+ DeleteObject(region1);
+ DeleteObject(region2);
+
+ EndPaint(hWnd,&ps);
+
+ return true;
+ }
+ }
+
+ return CallWindowProc(g_lpPictureWndProc, hWnd, uMsg, wParam, lParam);
+}
+
+static void RemoveCurrentGameCustomFolder(void)
+{
+ if (Picker_GetSelectedItem(hwndList) >= 0)
+ RemoveGameCustomFolder(Picker_GetSelectedItem(hwndList));
+}
+
+static void RemoveGameCustomFolder(int driver_index)
+{
+ int i;
+ TREEFOLDER **folders;
+ int num_folders;
+
+ GetFolders(&folders,&num_folders);
+
+ for (i=0; i<num_folders; i++)
+ {
+ if (folders[i]->m_dwFlags & F_CUSTOM && folders[i]->m_nFolderId == GetCurrentFolderID())
+ {
+ int current_pick_index;
+
+ RemoveFromCustomFolder(folders[i],driver_index);
+
+ if (driver_index == Picker_GetSelectedItem(hwndList))
+ {
+ /* if we just removed the current game,
+ move the current selection so that when we rebuild the listview it
+ leaves the cursor on next or previous one */
+
+ current_pick_index = GetSelectedPick();
+ Picker_SetSelectedPick(hwndList, GetSelectedPick() + 1);
+ if (current_pick_index == GetSelectedPick()) /* we must have deleted the last item */
+ Picker_SetSelectedPick(hwndList, GetSelectedPick() - 1);
+ }
+
+ ResetListView();
+ return;
+ }
+ }
+ MessageBox(GetMainWindow(), TEXT("Error searching for custom folder"), (LPCTSTR)MAMEUINAME, MB_OK | MB_ICONERROR);
+}
+
+
+static void BeginListViewDrag(NM_LISTVIEW *pnmv)
+{
+ LV_ITEM lvi;
+ lvi.iItem = pnmv->iItem;
+ lvi.mask = LVIF_PARAM;
+ BOOL res = ListView_GetItem(hwndList, &lvi);
+ res++;
+
+ game_dragged = lvi.lParam;
+
+ POINT pt;
+ pt.x = 0;
+ pt.y = 0;
+
+ /* Tell the list view control to create an image to use for dragging. */
+ himl_drag = ListView_CreateDragImage(hwndList,pnmv->iItem,&pt);
+
+ /* Start the drag operation. */
+ ImageList_BeginDrag(himl_drag, 0, 0, 0);
+
+ pt = pnmv->ptAction;
+ ClientToScreen(hwndList,&pt);
+ ImageList_DragEnter(GetDesktopWindow(),pt.x,pt.y);
+
+ /* Hide the mouse cursor, and direct mouse input to the parent window. */
+ SetCapture(hMain);
+
+ prev_drag_drop_target = NULL;
+
+ g_listview_dragging = true;
+}
+
+static void MouseMoveListViewDrag(POINTS p)
+{
+ HTREEITEM htiTarget;
+ TV_HITTESTINFO tvht;
+ BOOL res;
+
+ POINT pt;
+ pt.x = p.x;
+ pt.y = p.y;
+
+ ClientToScreen(hMain,&pt);
+
+ ImageList_DragMove(pt.x,pt.y);
+
+ MapWindowPoints(GetDesktopWindow(),hTreeView,&pt,1);
+
+ tvht.pt = pt;
+ htiTarget = TreeView_HitTest(hTreeView,&tvht);
+
+ if (htiTarget != prev_drag_drop_target)
+ {
+ ImageList_DragShowNolock(false);
+ if (htiTarget)
+ res = TreeView_SelectDropTarget(hTreeView,htiTarget);
+ else
+ res = TreeView_SelectDropTarget(hTreeView,NULL);
+ ImageList_DragShowNolock(true);
+
+ prev_drag_drop_target = htiTarget;
+ }
+ res++;
+}
+
+static void ButtonUpListViewDrag(POINTS p)
+{
+ POINT pt;
+ HTREEITEM htiTarget;
+ TV_HITTESTINFO tvht;
+ TVITEM tvi;
+
+ ReleaseCapture();
+
+ ImageList_DragLeave(hwndList);
+ ImageList_EndDrag();
+ ImageList_Destroy(himl_drag);
+
+ BOOL res = TreeView_SelectDropTarget(hTreeView,NULL);
+ res++;
+
+ g_listview_dragging = false;
+
+ /* see where the game was dragged */
+
+ pt.x = p.x;
+ pt.y = p.y;
+
+ MapWindowPoints(hMain,hTreeView,&pt,1);
+
+ tvht.pt = pt;
+ htiTarget = TreeView_HitTest(hTreeView,&tvht);
+ if (htiTarget == NULL)
+ {
+ LVHITTESTINFO lvhtti;
+ LPTREEFOLDER folder;
+ RECT rcList;
+
+ /* the user dragged a game onto something other than the treeview */
+ /* try to remove if we're in a custom folder */
+
+ /* see if it was dragged within the list view; if so, ignore */
+
+ MapWindowPoints(hTreeView,hwndList,&pt,1);
+ lvhtti.pt = pt;
+ GetWindowRect(hwndList, &rcList);
+ ClientToScreen(hwndList, &pt);
+ if( PtInRect(&rcList, pt) != 0 )
+ return;
+
+ folder = GetCurrentFolder();
+ if (folder->m_dwFlags & F_CUSTOM)
+ {
+ /* dragged out of a custom folder, so let's remove it */
+ RemoveCurrentGameCustomFolder();
+ }
+ return;
+ }
+
+ tvi.lParam = 0;
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE;
+ tvi.hItem = htiTarget;
+
+ if (TreeView_GetItem(hTreeView, &tvi))
+ {
+ LPTREEFOLDER folder = (LPTREEFOLDER)tvi.lParam;
+ AddToCustomFolder(folder,game_dragged);
+ }
+}
+
+static LPTREEFOLDER GetSelectedFolder(void)
+{
+ HTREEITEM htree = TreeView_GetSelection(hTreeView);
+ if(htree)
+ {
+ TVITEM tvi;
+ tvi.hItem = htree;
+ tvi.mask = TVIF_PARAM;
+ BOOL res = TreeView_GetItem(hTreeView,&tvi);
+ res++;
+ return (LPTREEFOLDER)tvi.lParam;
+ }
+ return NULL;
+}
+
+static HICON GetSelectedFolderIcon(void)
+{
+ HTREEITEM htree = TreeView_GetSelection(hTreeView);
+ if (htree)
+ {
+ TVITEM tvi;
+ tvi.hItem = htree;
+ tvi.mask = TVIF_PARAM;
+ BOOL res = TreeView_GetItem(hTreeView,&tvi);
+ res++;
+ //LPTREEFOLDER folder = (LPTREEFOLDER)tvi.lParam;
+ //hSmall_icon = TreeView_GetImageList(hTreeView,(int)tvi.iImage);
+ HIMAGELIST hSmall_icon = NULL;
+ return ImageList_GetIcon(hSmall_icon, tvi.iImage, ILD_TRANSPARENT);
+ }
+ return NULL;
+}
+
+/* Updates all currently displayed Items in the List with the latest Data*/
+void UpdateListView(void)
+{
+ BOOL res;
+
+ if( (GetViewMode() == VIEW_GROUPED) || (GetViewMode() == VIEW_DETAILS ) )
+ res = ListView_RedrawItems(hwndList,ListView_GetTopIndex(hwndList), ListView_GetTopIndex(hwndList)+ ListView_GetCountPerPage(hwndList) );
+
+ res++;
+}
+
+static void CalculateBestScreenShotRect(HWND hWnd, RECT *pRect, BOOL restrict_height)
+{
+ int destX, destY;
+ int destW, destH;
+ int nBorder;
+ RECT rect;
+ /* for scaling */
+ int x, y;
+ int rWidth, rHeight;
+ double scale;
+ BOOL bReduce = false;
+
+ GetClientRect(hWnd, &rect);
+
+ // Scale the bitmap to the frame specified by the passed in hwnd
+ if (ScreenShotLoaded())
+ {
+ x = GetScreenShotWidth();
+ y = GetScreenShotHeight();
+ }
+ else
+ {
+ BITMAP bmp;
+ GetObject(hMissing_bitmap,sizeof(BITMAP),&bmp);
+
+ x = bmp.bmWidth;
+ y = bmp.bmHeight;
+ }
+ rWidth = (rect.right - rect.left);
+ rHeight = (rect.bottom - rect.top);
+
+ /* Limit the screen shot to max height of 264 */
+ if (restrict_height == true && rHeight > 264)
+ {
+ rect.bottom = rect.top + 264;
+ rHeight = 264;
+ }
+
+ /* If the bitmap does NOT fit in the screenshot area */
+ if (x > rWidth - 10 || y > rHeight - 10)
+ {
+ rect.right -= 10;
+ rect.bottom -= 10;
+ rWidth -= 10;
+ rHeight -= 10;
+ bReduce = true;
+ /* Try to scale it properly */
+ /* assumes square pixels, doesn't consider aspect ratio */
+ if (x > y)
+ scale = (double)rWidth / x;
+ else
+ scale = (double)rHeight / y;
+
+ destW = (int)(x * scale);
+ destH = (int)(y * scale);
+
+ /* If it's still too big, scale again */
+ if (destW > rWidth || destH > rHeight)
+ {
+ if (destW > rWidth)
+ scale = (double)rWidth / destW;
+ else
+ scale = (double)rHeight / destH;
+
+ destW = (int)(destW * scale);
+ destH = (int)(destH * scale);
+ }
+ }
+ else
+ {
+ if (GetStretchScreenShotLarger())
+ {
+ rect.right -= 10;
+ rect.bottom -= 10;
+ rWidth -= 10;
+ rHeight -= 10;
+ bReduce = true;
+ // Try to scale it properly
+ // assumes square pixels, doesn't consider aspect ratio
+ if (x < y)
+ scale = (double)rWidth / x;
+ else
+ scale = (double)rHeight / y;
+
+ destW = (int)(x * scale);
+ destH = (int)(y * scale);
+
+ // If it's too big, scale again
+ if (destW > rWidth || destH > rHeight)
+ {
+ if (destW > rWidth)
+ scale = (double)rWidth / destW;
+ else
+ scale = (double)rHeight / destH;
+
+ destW = (int)(destW * scale);
+ destH = (int)(destH * scale);
+ }
+ }
+ else
+ {
+ // Use the bitmaps size if it fits
+ destW = x;
+ destH = y;
+ }
+
+ }
+
+
+ destX = (rWidth - destW) / 2;
+ destY = (rHeight - destH) / 2;
+
+ if (bReduce)
+ {
+ destX += 5;
+ destY += 5;
+ }
+ nBorder = GetScreenshotBorderSize();
+ if( destX > nBorder+1)
+ pRect->left = destX - nBorder;
+ else
+ pRect->left = 2;
+ if( destY > nBorder+1)
+ pRect->top = destY - nBorder;
+ else
+ pRect->top = 2;
+ if( rWidth >= destX + destW + nBorder)
+ pRect->right = destX + destW + nBorder;
+ else
+ pRect->right = rWidth - pRect->left;
+ if( rHeight >= destY + destH + nBorder)
+ pRect->bottom = destY + destH + nBorder;
+ else
+ pRect->bottom = rHeight - pRect->top;
+}
+
+/*
+ Switches to either fullscreen or normal mode, based on the
+ current mode.
+
+ POSSIBLE BUGS:
+ Removing the menu might cause problems later if some
+ function tries to poll info stored in the menu. Don't
+ know if you've done that, but this was the only way I
+ knew to remove the menu dynamically.
+*/
+
+static void SwitchFullScreenMode(void)
+{
+ LONG lMainStyle;
+
+ if (GetRunFullScreen())
+ {
+ // Return to normal
+
+ // Restore the menu
+ SetMenu(hMain, LoadMenu(hInst,MAKEINTRESOURCE(IDR_UI_MENU)));
+
+ // Refresh the checkmarks
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_FOLDERS, BIT(GetWindowPanes(), 0) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_TOOLBARS, GetShowToolBar() ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_STATUS, GetShowStatusBar() ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(GetMenu(hMain), ID_VIEW_PAGETAB, GetShowTabCtrl() ? MF_CHECKED : MF_UNCHECKED);
+
+ // Add frame to dialog again
+ lMainStyle = GetWindowLong(hMain, GWL_STYLE);
+ lMainStyle = lMainStyle | WS_BORDER;
+ SetWindowLong(hMain, GWL_STYLE, lMainStyle);
+
+ // Show the window maximized
+ if( GetWindowState() == SW_MAXIMIZE )
+ {
+ ShowWindow(hMain, SW_NORMAL);
+ ShowWindow(hMain, SW_MAXIMIZE);
+ }
+ else
+ ShowWindow(hMain, SW_RESTORE);
+
+ SetRunFullScreen(false);
+ }
+ else
+ {
+ // Set to fullscreen
+
+ // Remove menu
+ SetMenu(hMain,NULL);
+
+ // Frameless dialog (fake fullscreen)
+ lMainStyle = GetWindowLong(hMain, GWL_STYLE);
+ lMainStyle = lMainStyle & (WS_BORDER ^ 0xffffffff);
+ SetWindowLong(hMain, GWL_STYLE, lMainStyle);
+ if( IsMaximized(hMain) )
+ {
+ ShowWindow(hMain, SW_NORMAL);
+ SetWindowState( SW_MAXIMIZE );
+ }
+ else
+ {
+ SetWindowState( SW_NORMAL );
+ }
+
+ ShowWindow(hMain, SW_MAXIMIZE);
+
+ SetRunFullScreen(true);
+ }
+}
+
+/*
+ Checks to see if the mouse has been moved since this func
+ was first called (which is at startup). The reason for
+ storing the startup coordinates of the mouse is that when
+ a window is created it generates WM_MOUSEOVER events, even
+ though the user didn't actually move the mouse. So we need
+ to know when the WM_MOUSEOVER event is user-triggered.
+
+ POSSIBLE BUGS:
+ Gets polled at every WM_MOUSEMOVE so it might cause lag,
+ but there's probably another way to code this that's
+ way better?
+
+*/
+
+BOOL MouseHasBeenMoved(void)
+{
+ static int mouse_x = -1;
+ static int mouse_y = -1;
+ POINT p;
+
+ GetCursorPos(&p);
+
+ if (mouse_x == -1) // First time
+ {
+ mouse_x = p.x;
+ mouse_y = p.y;
+ }
+
+ return (p.x != mouse_x || p.y != mouse_y);
+}
+
+/* End of source file */