1. Further reconstruct the hotkey menu item code, menus belongs different parent menus with the same id can be defined in one struct rather than four. Removing the repeated menu hotkey update, only update the needed range. I wish this is not too complicated.

2. Map Hotkey dialog items now can be sorted by click on the column header.
3. Fix a logic bug when user cancels open archive dialog.
4. Trying to fix Linux build (not sure).
This commit is contained in:
owomomo 2019-01-03 20:38:33 +08:00
parent 29b06101d7
commit d9d3f1b56b
8 changed files with 313 additions and 208 deletions

View File

@ -285,8 +285,6 @@ static BOOL CALLBACK ArchiveFileSelectorCallback(HWND hwndDlg, UINT uMsg, WPARAM
{
case WM_INITDIALOG:
{
// TODO: find a better way to do this.
archiveManuallyCanceled = false;
HWND hwndListbox = GetDlgItem(hwndDlg,IDC_LIST1);
for(uint32 i=0;i<currFileSelectorContext->size();i++)
{

View File

@ -9,6 +9,11 @@
#include "window.h"
#include "taseditor/taseditor_window.h"
// whitch column does the sort based on, the default status -1 is natrually not sorted (or sort by FCEUI_CommandTable)
static int mapInputSortCol = -1;
// whether it's asc or desc sorting, when sortCol is -1, this value has no effect
static bool mapInputSortAsc = true;
void KeyboardUpdateState(void); //mbg merge 7/17/06 yech had to add this
struct INPUTDLGTHREADARGS
@ -552,6 +557,29 @@ void PopulateMappingDisplay(HWND hwndDlg)
{
free(conflictTable);
}
if (mapInputSortCol != -1)
{
NMHDR hdr;
hdr.hwndFrom = hwndListView;
hdr.code = LVN_COLUMNCLICK;
NMLISTVIEW listView;
listView.hdr = hdr;
// when showing the conflict table, always sorted by "Input" column first,
// So the user can easily find out which are conflicting.
if (filter == EMUCMDTYPE_MAX + 3)
listView.iSubItem = 2;
// only one type is in the list, just sort with "Command" column
// "Unassigned" has no text in "Input", just sort with "Command" column
else if (filter > EMUCMDTYPE_MISC && filter < EMUCMDTYPE_MAX || filter == EMUCMDTYPE_MAX + 2)
listView.iSubItem = 1;
else
listView.iSubItem = mapInputSortCol;
SendMessage(hwndListView, LVM_SORTITEMS, (WPARAM)&listView, (LPARAM)ItemSortFunc);
}
}
/**
@ -712,12 +740,14 @@ BOOL CALLBACK MapInputDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM
switch(LOWORD(wParam))
{
case IDOK:
UpdateMenuHotkeys();
EndDialog(hwndDlg, 1);
// Update TAS Editor's tooltips if it's opening.
extern TASEDITOR_WINDOW taseditorWindow;
if (taseditorWindow.hwndTASEditor)
taseditorWindow.updateTooltips();
EndDialog(hwndDlg, 1);
// main menu is always shown, so we only need to update it,
// the context menus are updated only when they are created
UpdateMenuHotkeys(FCEUMENU_MAIN);
return TRUE;
case BTN_CANCEL: // here true cause of ESC button handling as EXIT ;)
@ -746,23 +776,46 @@ BOOL CALLBACK MapInputDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM
case LV_MAPPING:
if (lParam)
{
NMHDR* pnm = (NMHDR*)lParam;
if (pnm->code == LVN_ITEMACTIVATE)
NMLISTVIEW* lpListView = (NMLISTVIEW*)lParam;
UINT code = lpListView->hdr.code;
HWND hwndListView = lpListView->hdr.hwndFrom;
switch (code)
{
HWND hwndListView = GetDlgItem(hwndDlg, LV_MAPPING);
case LVN_ITEMACTIVATE:
AskForHotkey(hwndListView);
AskForHotkey(hwndListView);
// TODO: Only redraw if Conflicts filter
// is active.
PopulateMappingDisplay(hwndDlg);
break;
case LVN_COLUMNCLICK:
// Sort the items
if (mapInputSortCol != lpListView->iSubItem) {
mapInputSortCol= lpListView->iSubItem;
mapInputSortAsc = true;
}
else
mapInputSortAsc = !mapInputSortAsc;
// TODO: Only redraw if Conflicts filter
// is active.
PopulateMappingDisplay(hwndDlg);
int filter = (int)SendDlgItemMessage(hwndDlg, COMBO_FILTER, CB_GETCURSEL, 0, 0);
// when showing the conflict table, always sorted by "Input" column first,
// So the user can easily find out which are conflicting.
if (filter == EMUCMDTYPE_MAX + 3)
lpListView->iSubItem = 2;
// only one type is in the list, just sort with "Command" column
// "Unassigned" has no text in "Input", just sort with "Command" column
else if (filter > EMUCMDTYPE_MISC && filter < EMUCMDTYPE_MAX || filter == EMUCMDTYPE_MAX + 2)
lpListView->iSubItem = 1;
else
lpListView->iSubItem = mapInputSortCol;
// TODO: Add an icon to show which column the sorting is currently based on
SendMessage(hwndListView, LVM_SORTITEMS, (WPARAM)lpListView, (LPARAM)ItemSortFunc);
}
return TRUE;
}
break;
default:
break;
}
@ -792,3 +845,51 @@ void MapInput(void)
free(backupmapping);
}
int CALLBACK ItemSortFunc(LPARAM lp1, LPARAM lp2, LPARAM lpSort)
{
NMLISTVIEW* lpListView = (NMLISTVIEW*)lpSort;
HWND hwndListView = lpListView->hdr.hwndFrom;
LVFINDINFO info1, info2;
LVITEM item1, item2;
memset(&info1, 0, sizeof(LVFINDINFO));
memset(&info2, 0, sizeof(LVFINDINFO));
memset(&item1, 0, sizeof(LVITEM));
memset(&item2, 0, sizeof(LVITEM));
info1.flags = LVFI_PARAM;
info2.flags = LVFI_PARAM;
info1.lParam = lp1;
info2.lParam = lp2;
int index1 = SendMessage(hwndListView, LVM_FINDITEM, -1, (LPARAM)&info1);
int index2 = SendMessage(hwndListView, LVM_FINDITEM, -1, (LPARAM)&info2);
item1.pszText = new char[64];
item2.pszText = new char[64];
item1.cchTextMax = 64;
item2.cchTextMax = 64;
item1.iSubItem = lpListView->iSubItem;
item2.iSubItem = lpListView->iSubItem;
SendMessage(hwndListView, LVM_GETITEMTEXT, index1, (LPARAM)&item1);
SendMessage(hwndListView, LVM_GETITEMTEXT, index2, (LPARAM)&item2);
int ret = strcmp(item1.pszText, item2.pszText);
// "Type" and "Input" column can have repeated items, uses "Command" line for another sorting
if (ret == 0 && (lpListView->iSubItem == 0 || lpListView->iSubItem == 2))
{
item1.iSubItem = 1;
item2.iSubItem = 1;
SendMessage(hwndListView, LVM_GETITEMTEXT, index1, (LPARAM)&item1);
SendMessage(hwndListView, LVM_GETITEMTEXT, index2, (LPARAM)&item2);
ret = strcmp(item1.pszText, item2.pszText);
}
if (!mapInputSortAsc)
ret = -ret;
delete[] item1.pszText;
delete[] item2.pszText;
return ret;
}

View File

@ -1,4 +1,5 @@
#ifndef WIN_MAPINPUT_h
#define WIN_MAPINPUT_h
char* GetKeyComboName(int c);
int CALLBACK ItemSortFunc(LPARAM lp1, LPARAM lp2, LPARAM lpSort);
#endif

View File

@ -108,9 +108,6 @@ HMENU hfceuxcontext; //Handle to context menu
HMENU hfceuxcontextsub; //Handle to context sub menu
HWND MainhWnd; //Main FCEUX(Parent) window Handle. Dialogs should use GetMainHWND() to get this
// HWND list for menu update, refers to FCEU_MENU_HWND
HMENU hmenuList[FCEUMENU_LIMIT];
//Extern variables-------------------------------------
extern bool movieSubtitles;
extern FCEUGI *GameInfo;
@ -489,6 +486,7 @@ void UpdateCheckedMenuItems()
default:
break;
}
UpdateMenuHotkeys(FCEUMENU_MAIN_INPUTDISPLAY);
}
void UpdateContextMenuItems(HMENU context, int whichContext)
@ -579,6 +577,7 @@ void UpdateContextMenuItems(HMENU context, int whichContext)
// At position 4(+1) is after View comments and subtitles. Insert this there:
InsertMenu(context,0x5, MF_BYPOSITION, FCEUX_CONTEXT_DUMPSUBTITLES, "Dump Subtitles to SRT file");
}
}
@ -1402,30 +1401,12 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
if (rightClickEnabled)
{
//If There is a movie loaded
if (GameInfo && FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_FINISHED))
{
if (FCEUMOV_Mode(MOVIEMODE_RECORD))
if (movie_readonly)
whichContext = 4; // Game+Movie+Recording+readonly
else
whichContext = 5; // Game+Movie+Recording+readwrite
else //if (FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_FINISHED))
if (movie_readonly)
whichContext = 2; // Game+Movie+Playing+readonly
else
whichContext = 3; // Game+Movie+Playing+readwrite
//If there is a ROM loaded but no movie
} else if (GameInfo)
whichContext = 1; // Game+NoMovie
//Else no ROM
else
whichContext = 0; // NoGame
int whichContext = GetCurrentContextIndex();
hfceuxcontext = LoadMenu(fceu_hInstance,"FCEUCONTEXTMENUS");
hmenuList[FCEUMENU_HWND::FCEUMENU_CONTEXT] = hfceuxcontext;
hfceuxcontextsub = GetSubMenu(hfceuxcontext, whichContext);
hmenuList[whichContext] = hfceuxcontextsub;
UpdateContextMenuItems(hfceuxcontextsub, whichContext);
UpdateMenuHotkeys(whichContext);
pt.x = LOWORD(lParam); //Get mouse x in terms of client area
pt.y = HIWORD(lParam); //Get mouse y in terms of client area
ClientToScreen(hAppWnd, (LPPOINT) &pt); //Convert client area x,y to screen x,y
@ -2526,7 +2507,6 @@ adelikat: Outsourced this to a remappable hotkey
goto proco;
case WM_ENTERMENULOOP:
UpdateCheckedMenuItems();
UpdateMenuHotkeys();
EnableMenuItem(fceumenu,MENU_RESET,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_RESET)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_POWER,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_POWER)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_EJECT_DISK,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_EJECT_DISK)?MF_ENABLED:MF_GRAYED));
@ -2689,8 +2669,7 @@ int CreateMainWindow()
AdjustWindowRectEx(&tmp, WS_OVERLAPPEDWINDOW, 1, 0);
fceumenu = LoadMenu(fceu_hInstance,"FCEUMENU");
hmenuList[FCEUMENU_MAIN] = fceumenu;
UpdateMenuHotkeys(FCEUMENU_MAIN);
recentmenu = CreateMenu();
recentluamenu = CreateMenu();
recentmoviemenu = CreateMenu();
@ -2896,10 +2875,12 @@ void ChangeMenuItemText(int menuitem, string text)
SetMenuItemInfo(fceumenu, menuitem, FALSE, &moo);
}
string HOTKEYMENUINDEX::getQualifiedMenuText() {
int length = GetMenuString(hmenuList[hmenu_index], menu_id, 0, 0, flags) + 1;
string HOTKEYMENUINDEX::getQualifiedMenuText(FCEUMENU_INDEX menu_index) {
HMENU menu;
GetHMENU(menu_index, menu);
int length = GetMenuString(menu, menu_id, 0, 0, flags) + 1;
char* buffer = new char[length];
GetMenuString(hmenuList[hmenu_index], menu_id, buffer, length, flags);
GetMenuString(menu, menu_id, buffer, length, flags);
if (char* pTab = strrchr(buffer, '\t'))
*pTab = '\0';
std::string menustr = HOTKEYMENUINDEX::getQualifiedMenuText(buffer, cmd_id);
@ -2921,17 +2902,17 @@ string HOTKEYMENUINDEX::getQualifiedMenuText(char* text, int emu_cmd_id) {
return menustr;
}
struct HOTKEYMENUINDEX HOTKEYMENUINDEXs[] = {
struct HOTKEYMENUINDEX hotkeyMenuIndexes[] = {
// "&Open..."
{ MENU_OPEN_FILE,EMUCMD_OPENROM },
// "Open ROM"
{ FCEU_CONTEXT_OPENROM,EMUCMD_OPENROM,FCEUMENU_CONTEXT_OFF },
{ FCEU_CONTEXT_OPENROM,EMUCMD_OPENROM,MENU_BELONG(CONTEXT_OFF) },
// "&Close"
{ MENU_CLOSE_FILE,EMUCMD_CLOSEROM },
// "Close ROM"
{ FCEU_CONTEXT_CLOSEROM,EMUCMD_CLOSEROM,FCEUMENU_CONTEXT_GAME },
{ FCEU_CONTEXT_CLOSEROM,EMUCMD_CLOSEROM,MENU_BELONG(CONTEXT_GAME) },
// "&Load State"
{ MENU_LOADSTATE,EMUCMD_LOAD_STATE,FCEUMENU_CONTEXT_GAME },
{ MENU_LOADSTATE,EMUCMD_LOAD_STATE,MENU_BELONG(CONTEXT_GAME) },
// "&Save State"
{ MENU_SAVESTATE,EMUCMD_SAVE_STATE },
// "Load State &From..."
@ -2945,47 +2926,31 @@ struct HOTKEYMENUINDEX HOTKEYMENUINDEXs[] = {
// "&View save slots"
{ MENU_VIEWSAVESLOTS,EMUCMD_MISC_SHOWSTATES },
// "Record Movie..."
{ FCEUX_CONTEXT_RECORDMOVIE,EMUCMD_MOVIE_RECORD_TO,FCEUMENU_CONTEXT_GAME },
{ FCEUX_CONTEXT_RECORDMOVIE,EMUCMD_MOVIE_RECORD_TO, MENU_BELONG(CONTEXT_GAME) },
// "&Record Movie..."
{ MENU_RECORD_MOVIE,EMUCMD_MOVIE_RECORD_TO },
// "Play Movie..."
{ FCEUX_CONTEXT_REPLAYMOVIE,EMUCMD_MOVIE_REPLAY_FROM,FCEUMENU_CONTEXT_GAME },
{ FCEUX_CONTEXT_REPLAYMOVIE,EMUCMD_MOVIE_REPLAY_FROM,MENU_BELONG(CONTEXT_GAME) },
// "&Play Movie..."
{ MENU_REPLAY_MOVIE,EMUCMD_MOVIE_REPLAY_FROM },
// "&Stop Movie"
{ MENU_STOP_MOVIE,EMUCMD_MOVIE_STOP },
// "Stop Movie Replay"
{ FCEU_CONTEXT_STOPMOVIE,EMUCMD_MOVIE_STOP,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "Stop Movie Replay"
{ FCEU_CONTEXT_STOPMOVIE,EMUCMD_MOVIE_STOP,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "Stop Movie Recording"
{ FCEU_CONTEXT_STOPMOVIE,EMUCMD_MOVIE_STOP,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "Stop Movie Recording"
{ FCEU_CONTEXT_STOPMOVIE,EMUCMD_MOVIE_STOP,FCEUMENU_CONTEXT_RECORDING_READWRITE },
{ MENU_STOP_MOVIE, EMUCMD_MOVIE_STOP },
// "Stop Movie Replay" (Playing)
// "Stop Movie Recording" (Recording)
{ FCEU_CONTEXT_STOPMOVIE,EMUCMD_MOVIE_STOP,BELONG_CONTEXT_MOVIE_ALL },
// "Play Movie from Beginning"
{ FCEU_CONTEXT_PLAYMOVIEFROMBEGINNING,EMUCMD_MOVIE_PLAY_FROM_BEGINNING,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "Play Movie from Beginning"
{ FCEU_CONTEXT_PLAYMOVIEFROMBEGINNING,EMUCMD_MOVIE_PLAY_FROM_BEGINNING,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "Play Movie from Beginning"
{ FCEU_CONTEXT_PLAYMOVIEFROMBEGINNING,EMUCMD_MOVIE_PLAY_FROM_BEGINNING,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "Play Movie from Beginning"
{ FCEU_CONTEXT_PLAYMOVIEFROMBEGINNING,EMUCMD_MOVIE_PLAY_FROM_BEGINNING,FCEUMENU_CONTEXT_RECORDING_READWRITE },
{ FCEU_CONTEXT_PLAYMOVIEFROMBEGINNING,EMUCMD_MOVIE_PLAY_FROM_BEGINNING,BELONG_CONTEXT_MOVIE_ALL },
// "Play from &Beginning"
{ ID_FILE_PLAYMOVIEFROMBEGINNING,EMUCMD_MOVIE_PLAY_FROM_BEGINNING },
// "&Read-only"
{ ID_FILE_MOVIE_TOGGLEREAD,EMUCMD_MOVIE_READONLY_TOGGLE },
// "Toggle to read+write"
{ FCEUX_CONTEXT_READONLYTOGGLE,EMUCMD_MOVIE_READONLY_TOGGLE,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "Toggle to Read-only"
{ FCEUX_CONTEXT_READONLYTOGGLE,EMUCMD_MOVIE_READONLY_TOGGLE,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "Toggle to read+write"
{ FCEUX_CONTEXT_READONLYTOGGLE,EMUCMD_MOVIE_READONLY_TOGGLE,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "Toggle to Read-only"
{ FCEUX_CONTEXT_READONLYTOGGLE,EMUCMD_MOVIE_READONLY_TOGGLE,FCEUMENU_CONTEXT_RECORDING_READWRITE },
// "Toggle to read+write" (Readonly)
// "Toggle to Read-only" (Readwrite)
{ FCEUX_CONTEXT_READONLYTOGGLE,EMUCMD_MOVIE_READONLY_TOGGLE,BELONG_CONTEXT_MOVIE_ALL },
// "&Screenshot"
{ ID_FILE_SCREENSHOT,EMUCMD_SCREENSHOT },
// "Screenshot"
{ FCEUX_CONTEXT_SCREENSHOT,EMUCMD_SCREENSHOT, FCEUMENU_CONTEXT_GAME },
{ FCEUX_CONTEXT_SCREENSHOT,EMUCMD_SCREENSHOT, MENU_BELONG(CONTEXT_GAME) },
// "&Record AVI..."
{ MENU_RECORD_AVI,EMUCMD_AVI_RECORD_AS },
//"&Stop AVI"
@ -3015,15 +2980,7 @@ struct HOTKEYMENUINDEX HOTKEYMENUINDEXs[] = {
// "&Hide Menu"
{ MENU_HIDE_MENU,EMUCMD_HIDE_MENU_TOGGLE },
// "Unhide Menu"
{ FCEUX_CONTEXT_UNHIDEMENU,EMUCMD_HIDE_MENU_TOGGLE,FCEUMENU_CONTEXT_GAME },
// "Unhide Menu"
{ FCEUX_CONTEXT_UNHIDEMENU,EMUCMD_HIDE_MENU_TOGGLE,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "Unhide Menu"
{ FCEUX_CONTEXT_UNHIDEMENU,EMUCMD_HIDE_MENU_TOGGLE,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "Unhide Menu"
{ FCEUX_CONTEXT_UNHIDEMENU,EMUCMD_HIDE_MENU_TOGGLE,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "Unhide Menu"
{ FCEUX_CONTEXT_UNHIDEMENU,EMUCMD_HIDE_MENU_TOGGLE,FCEUMENU_CONTEXT_RECORDING_READWRITE },
{ FCEUX_CONTEXT_UNHIDEMENU,EMUCMD_HIDE_MENU_TOGGLE,BELONG_CONTEXT_RUNNING },
// "&Frame Adv. - Skip Lag"
{ MENU_DISPLAY_FA_LAGSKIP,EMUCMD_FRAMEADV_SKIPLAG },
// "&Lag Counter"
@ -3063,107 +3020,110 @@ struct HOTKEYMENUINDEX HOTKEYMENUINDEXs[] = {
// "&Code/Data Logger..."
{ MENU_CDLOGGER,EMUCMD_TOOL_OPENCDLOGGER },
// "Undo savestate"
{ FCEUX_CONTEXT_UNDOSAVESTATE,EMUCMD_MISC_UNDOREDOSAVESTATE,FCEUMENU_CONTEXT_GAME },
// "Undo savestate"
{ FCEUX_CONTEXT_UNDOSAVESTATE,EMUCMD_MISC_UNDOREDOSAVESTATE,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "Undo savestate"
{ FCEUX_CONTEXT_UNDOSAVESTATE,EMUCMD_MISC_UNDOREDOSAVESTATE,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "Undo savestate"
{ FCEUX_CONTEXT_UNDOSAVESTATE,EMUCMD_MISC_UNDOREDOSAVESTATE,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "Undo savestate"
{ FCEUX_CONTEXT_UNDOSAVESTATE,EMUCMD_MISC_UNDOREDOSAVESTATE,FCEUMENU_CONTEXT_RECORDING_READWRITE },
{ FCEUX_CONTEXT_UNDOSAVESTATE,EMUCMD_MISC_UNDOREDOSAVESTATE,BELONG_CONTEXT_RUNNING },
// "Rewind to last auto-save"
{ FCEUX_CONTEXT_REWINDTOLASTAUTO,EMUCMD_MISC_AUTOSAVE,FCEUMENU_CONTEXT_GAME },
// "Rewind to last auto-save"
{ FCEUX_CONTEXT_REWINDTOLASTAUTO,EMUCMD_MISC_AUTOSAVE,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "Rewind to last auto-save"
{ FCEUX_CONTEXT_REWINDTOLASTAUTO,EMUCMD_MISC_AUTOSAVE,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "Rewind to last auto-save"
{ FCEUX_CONTEXT_REWINDTOLASTAUTO,EMUCMD_MISC_AUTOSAVE,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "Rewind to last auto-save"
{ FCEUX_CONTEXT_REWINDTOLASTAUTO,EMUCMD_MISC_AUTOSAVE,FCEUMENU_CONTEXT_RECORDING_READWRITE },
// "Toggle to Recording"
{ FCEUX_CONTEXT_TOGGLE_RECORDING,EMUCMD_MOVIE_TOGGLE_RECORDING,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "Toggle to Recording"
{ FCEUX_CONTEXT_TOGGLE_RECORDING,EMUCMD_MOVIE_TOGGLE_RECORDING,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "Toggle to Playing"
{ FCEUX_CONTEXT_TOGGLE_RECORDING,EMUCMD_MOVIE_TOGGLE_RECORDING,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "Toggle to Playing"
{ FCEUX_CONTEXT_TOGGLE_RECORDING,EMUCMD_MOVIE_TOGGLE_RECORDING,FCEUMENU_CONTEXT_RECORDING_READWRITE },
{ FCEUX_CONTEXT_REWINDTOLASTAUTO,EMUCMD_MISC_AUTOSAVE,BELONG_CONTEXT_RUNNING },
// "Toggle to Recording" (Playing)
// "Toggle to Playing" (Recording)
{ FCEUX_CONTEXT_TOGGLE_RECORDING,EMUCMD_MOVIE_TOGGLE_RECORDING,BELONG_CONTEXT_MOVIE_ALL },
// "&Toggle Recording/Playing"
{ ID_FILE_TOGGLE_RECORDING_MOVIE,EMUCMD_MOVIE_TOGGLE_RECORDING },
// "&Truncate at Current Frame"
{ ID_FILE_TRUNCATE_MOVIE,EMUCMD_MOVIE_TRUNCATE },
// "Truncate at Current Frame"
{ FCEUX_CONTEXT_TRUNCATE_MOVIE,EMUCMD_MOVIE_TRUNCATE,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "Truncate at Current Frame"
{ FCEUX_CONTEXT_TRUNCATE_MOVIE,EMUCMD_MOVIE_TRUNCATE,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "Truncate at Current Frame"
{ FCEUX_CONTEXT_TRUNCATE_MOVIE,EMUCMD_MOVIE_TRUNCATE,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "Truncate at Current Frame"
{ FCEUX_CONTEXT_TRUNCATE_MOVIE,EMUCMD_MOVIE_TRUNCATE,FCEUMENU_CONTEXT_RECORDING_READWRITE },
{ FCEUX_CONTEXT_TRUNCATE_MOVIE,EMUCMD_MOVIE_TRUNCATE,BELONG_CONTEXT_MOVIE_ALL },
// "&Insert 1 Frame"
{ ID_FILE_INSERT_1_FRAME,EMUCMD_MOVIE_INSERT_1_FRAME },
// "Insert 1 Frame"
{ FCEUX_CONTEXT_INSERT_1_FRAME,EMUCMD_MOVIE_INSERT_1_FRAME,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "Insert 1 Frame"
{ FCEUX_CONTEXT_INSERT_1_FRAME,EMUCMD_MOVIE_INSERT_1_FRAME,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "Insert 1 Frame"
{ FCEUX_CONTEXT_INSERT_1_FRAME,EMUCMD_MOVIE_INSERT_1_FRAME,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "Insert 1 Frame"
{ FCEUX_CONTEXT_INSERT_1_FRAME,EMUCMD_MOVIE_INSERT_1_FRAME,FCEUMENU_CONTEXT_RECORDING_READWRITE },
{ FCEUX_CONTEXT_INSERT_1_FRAME,EMUCMD_MOVIE_INSERT_1_FRAME,BELONG_CONTEXT_MOVIE_ALL },
// "&Delete 1 Frame"
{ ID_FILE_DELETE_1_FRAME,EMUCMD_MOVIE_DELETE_1_FRAME },
// "Delete 1 Frame"
{ FCEUX_CONTEXT_DELETE_1_FRAME,EMUCMD_MOVIE_DELETE_1_FRAME,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "Delete 1 Frame"
{ FCEUX_CONTEXT_DELETE_1_FRAME,EMUCMD_MOVIE_DELETE_1_FRAME,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "Delete 1 Frame"
{ FCEUX_CONTEXT_DELETE_1_FRAME,EMUCMD_MOVIE_DELETE_1_FRAME,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "Delete 1 Frame"
{ FCEUX_CONTEXT_DELETE_1_FRAME,EMUCMD_MOVIE_DELETE_1_FRAME,FCEUMENU_CONTEXT_RECORDING_READWRITE },
{ FCEUX_CONTEXT_DELETE_1_FRAME,EMUCMD_MOVIE_DELETE_1_FRAME,BELONG_CONTEXT_MOVIE_ALL },
// "&Next Record Mode"
{ ID_FILE_NEXTRECORDMODE,EMUCMD_MOVIE_NEXT_RECORD_MODE },
// "&Truncate
{ ID_FILE_RECORDMODE_TRUNCATE,EMUCMD_MOVIE_RECORD_MODE_TRUNCATE },
// "&Truncate"
{ FCEUX_CONTEXT_RECORDMODE_TRUNCATE,EMUCMD_MOVIE_RECORD_MODE_TRUNCATE,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "&Truncate"
{ FCEUX_CONTEXT_RECORDMODE_TRUNCATE,EMUCMD_MOVIE_RECORD_MODE_TRUNCATE,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "&Truncate"
{ FCEUX_CONTEXT_RECORDMODE_TRUNCATE,EMUCMD_MOVIE_RECORD_MODE_TRUNCATE,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "&Truncate"
{ FCEUX_CONTEXT_RECORDMODE_TRUNCATE,EMUCMD_MOVIE_RECORD_MODE_TRUNCATE,FCEUMENU_CONTEXT_RECORDING_READWRITE },
{ FCEUX_CONTEXT_RECORDMODE_TRUNCATE,EMUCMD_MOVIE_RECORD_MODE_TRUNCATE,BELONG_CONTEXT_MOVIE_ALL },
// "&Overwrite[W]"
{ ID_FILE_RECORDMODE_OVERWRITE,EMUCMD_MOVIE_RECORD_MODE_OVERWRITE },
// "&Overwrite[W]"
{ FCEUX_CONTEXT_RECORDMODE_OVERWRITE,EMUCMD_MOVIE_RECORD_MODE_OVERWRITE,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "&Overwrite[W]"
{ FCEUX_CONTEXT_RECORDMODE_OVERWRITE,EMUCMD_MOVIE_RECORD_MODE_OVERWRITE,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "&Overwrite[W]"
{ FCEUX_CONTEXT_RECORDMODE_OVERWRITE,EMUCMD_MOVIE_RECORD_MODE_OVERWRITE,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "&Overwrite[W]"
{ FCEUX_CONTEXT_RECORDMODE_OVERWRITE,EMUCMD_MOVIE_RECORD_MODE_OVERWRITE,FCEUMENU_CONTEXT_RECORDING_READWRITE },
{ FCEUX_CONTEXT_RECORDMODE_OVERWRITE,EMUCMD_MOVIE_RECORD_MODE_OVERWRITE,BELONG_CONTEXT_MOVIE_ALL },
// "&Insert[I]"
{ ID_FILE_RECORDMODE_INSERT,EMUCMD_MOVIE_RECORD_MODE_INSERT },
// "&Insert[I]"
{ FCEUX_CONTEXT_RECORDMODE_INSERT,EMUCMD_MOVIE_RECORD_MODE_INSERT,FCEUMENU_CONTEXT_PLAYING_READONLY },
// "&Insert[I]"
{ FCEUX_CONTEXT_RECORDMODE_INSERT,EMUCMD_MOVIE_RECORD_MODE_INSERT,FCEUMENU_CONTEXT_PLAYING_READWRITE },
// "&Insert[I]"
{ FCEUX_CONTEXT_RECORDMODE_INSERT,EMUCMD_MOVIE_RECORD_MODE_INSERT,FCEUMENU_CONTEXT_RECORDING_READONLY },
// "&Insert[I]"
{ FCEUX_CONTEXT_RECORDMODE_INSERT,EMUCMD_MOVIE_RECORD_MODE_INSERT,FCEUMENU_CONTEXT_RECORDING_READWRITE }
{ FCEUX_CONTEXT_RECORDMODE_INSERT,EMUCMD_MOVIE_RECORD_MODE_INSERT,BELONG_CONTEXT_MOVIE_ALL },
// This is a special one for submenus of "Display Input", its matching hotkey is variable on the fly to the next mode
{ 0, EMUCMD_MOVIE_INPUT_DISPLAY_TOGGLE, MENU_BELONG(MAIN_INPUTDISPLAY) | MENU_BELONG(MAIN)}
};
int HOTKEYMENUINDEX::updateMenuText() {
return ModifyMenu(hmenuList[hmenu_index], menu_id, GetMenuState(hmenuList[hmenu_index], menu_id, flags) | flags, menu_id, getQualifiedMenuText().c_str());
void HOTKEYMENUINDEX::updateMenuText(FCEUMENU_INDEX index) {
if (IsMenuBelongsTo(index, hmenu_ident))
{
HMENU hmenu;
GetHMENU(index, hmenu);
ModifyMenu(hmenu, menu_id, flags | GetMenuState(hmenu, menu_id, flags), menu_id, getQualifiedMenuText(index).c_str());
}
}
void UpdateMenuHotkeys()
void UpdateMenuHotkeys(FCEUMENU_INDEX index)
{
for (int i = 0; i < sizeof(HOTKEYMENUINDEXs) / sizeof(HOTKEYMENUINDEX); ++i)
HOTKEYMENUINDEXs[i].updateMenuText();
for (int i = 0; i < sizeof(hotkeyMenuIndexes) / sizeof(HOTKEYMENUINDEX); ++i)
{
if (IsMenuBelongsTo(index, hotkeyMenuIndexes[i].hmenu_ident))
{
switch (hotkeyMenuIndexes[i].cmd_id)
{
case EMUCMD_MOVIE_INPUT_DISPLAY_TOGGLE:
// "input display" need a special proccess
if (input_display == 0 && hotkeyMenuIndexes[i].menu_id != MENU_INPUTDISPLAY_1 ||
input_display == 1 && hotkeyMenuIndexes[i].menu_id != MENU_INPUTDISPLAY_2 ||
input_display == 2 && hotkeyMenuIndexes[i].menu_id != MENU_INPUTDISPLAY_4 ||
input_display == 4 && hotkeyMenuIndexes[i].menu_id != MENU_INPUTDISPLAY_0)
{
// if the current "input display" hotkey is not on the menu item of the next mode, change it back to normal first.
hotkeyMenuIndexes[i].cmd_id = -1;
hotkeyMenuIndexes[i].updateMenuText(index);
// make the update menu to the next mode
hotkeyMenuIndexes[i].cmd_id = EMUCMD_MOVIE_INPUT_DISPLAY_TOGGLE;
switch (input_display)
{
case 0: hotkeyMenuIndexes[i].menu_id = MENU_INPUTDISPLAY_1; break;
case 1: hotkeyMenuIndexes[i].menu_id = MENU_INPUTDISPLAY_2; break;
case 2: hotkeyMenuIndexes[i].menu_id = MENU_INPUTDISPLAY_4; break;
case 4: hotkeyMenuIndexes[i].menu_id = MENU_INPUTDISPLAY_0; break;
}
}
// there's no break here, since the hotkey should re-add to the correct menu;
default:
hotkeyMenuIndexes[i].updateMenuText(index);
}
}
}
}
int GetCurrentContextIndex()
{
if (GameInfo && FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_FINISHED))
{
if (FCEUMOV_Mode(MOVIEMODE_RECORD))
if (movie_readonly)
return FCEUMENU_CONTEXT_RECORDING_READONLY; // Game+Movie+Recording+readonly
else
return FCEUMENU_CONTEXT_RECORDING_READWRITE; // Game+Movie+Recording+readwrite
else //if (FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_FINISHED))
if (movie_readonly)
return FCEUMENU_CONTEXT_PLAYING_READONLY; // Game+Movie+Playing+readonly
else
return FCEUMENU_CONTEXT_PLAYING_READWRITE; // Game+Movie+Playing+readwrite
//If there is a ROM loaded but no movie
}
else if (GameInfo)
return FCEUMENU_CONTEXT_GAME; // Game+NoMovie
//Else no ROM
else
return FCEUMENU_CONTEXT_OFF; // NoGame
}
//This function is for the context menu item Save Movie As...

View File

@ -38,7 +38,6 @@ void SetMainWindowStuff();
void GetMouseData(uint32 (&md)[3]);
void GetMouseRelative(int32 (&md)[3]);
//void ChangeMenuItemText(int menuitem, string text);
void UpdateMenuHotkeys();
template<int BUFSIZE>
inline std::string GetDlgItemText(HWND hDlg, int nIDDlgItem) {
@ -54,31 +53,78 @@ inline std::wstring GetDlgItemTextW(HWND hDlg, int nIDDlgItem) {
return buf;
}
enum FCEUMENU_HWND {
FCEUMENU_CONTEXT_OFF, // NoGame
FCEUMENU_CONTEXT_GAME, // Game+NoMovie
FCEUMENU_CONTEXT_PLAYING_READONLY, //Game+Movie+Playing+ReadOnly
FCEUMENU_CONTEXT_PLAYING_READWRITE, //Game+Movie+Playing+ReadWrite
FCEUMENU_CONTEXT_RECORDING_READONLY, //Game+Movie+Recording+ReadOnly
FCEUMENU_CONTEXT_RECORDING_READWRITE, //Game+Movie+Recording+Readwrite
FCEUMENU_CONTEXT, // parent menu of all context menus,
// not recommended to use it since there's duplicate ids in context menus,
// unless you're quite sure the id is unique in all submenus.
FCEUMENU_MAIN, // main fceux menu
FCEUMENU_LIMIT
};
#define FCEUMENU_INDEX int
// the index start from 0 should exaclty match the submenu index defined in the resource file until the last one;
#define FCEUMENU_CONTEXT_OFF 0 // NoGame
#define FCEUMENU_CONTEXT_GAME 1 // Game+NoMovie
#define FCEUMENU_CONTEXT_PLAYING_READONLY 2 //Game+Movie+Playing+ReadOnly
#define FCEUMENU_CONTEXT_PLAYING_READWRITE 3 //Game+Movie+Playing+ReadWrite
#define FCEUMENU_CONTEXT_RECORDING_READONLY 4 //Game+Movie+Recording+ReadOnly
#define FCEUMENU_CONTEXT_RECORDING_READWRITE 5 //Game+Movie+Recording+Readwrite
#define FCEUMENU_CONTEXT 6 // parent menu of all context menus,
// not recommended to use it since there's duplicate ids in context menus,
// unless you're quite sure the id is unique in all submenus.
#define FCEUMENU_MAIN 7 // main fceux menu
#define FCEUMENU_MAIN_INPUTDISPLAY 8 // a special one for the input display
// "&Config"->"&Display"-> "&Input Display"
#define FCEUMENU_LIMIT 9
#define GetHMENU(index, hmenu) \
switch (index) \
{ \
case FCEUMENU_MAIN: hmenu = fceumenu; break; \
case FCEUMENU_MAIN_INPUTDISPLAY: hmenu = GetSubMenu(GetSubMenu(GetSubMenu(fceumenu, 2), 2), 0); break; \
case FCEUMENU_CONTEXT: hmenu = hfceuxcontext; break; \
default: hmenu = GetSubMenu(hfceuxcontext, index); \
} \
/* used to indicate which parent menu is the HOTKEYMENUINDEX belongs to.
How to use:
use MENU_BELONG(menu_name) to make it to the correct bit, menu_name must
be the FCEUMENU_XXXX defined above, and FCEUMENU_ should be ignored. For
example, MENU_BELONG(CONTEXT_RECORDING_READONLY) means a menu is belong
to FCEUMENU_CONTEXT_PLAYING_READONLY as Game+Movie+Recording+ReadOnly.
Since the menus with the same id can coexist in different parent menus,
the identifier can be multipled by OR. You can also the predefined
BELONG_XXXX_XXXX.
*/
#define MENU_BELONG_INT int
#define MENU_BELONG(menu_index) (1 << FCEUMENU_##menu_index)
// ReadOnly and ReadWrite in playing status
#define BELONG_CONTEXT_PLAYING (MENU_BELONG(CONTEXT_PLAYING_READONLY) | MENU_BELONG(CONTEXT_PLAYING_READWRITE))
// ReadOnly and ReadWrite in recording status
#define BELONG_CONTEXT_RECORDING (MENU_BELONG(CONTEXT_RECORDING_READONLY) | MENU_BELONG(CONTEXT_RECORDING_READWRITE))
// ReadOnly in playing and recording status
#define BELONG_CONTEXT_READONLY (MENU_BELONG(CONTEXT_PLAYING_READONLY) | MENU_BELONG(CONTEXT_RECORDING_READONLY))
// Readwrite in playing and recording status
#define BELONG_CONTEXT_READWRITE (MENU_BELONG(CONTEXT_PLAYING_READWRITE) | MENU_BELONG(CONTEXT_RECORDING_READWRITE))
// All status with movie
#define BELONG_CONTEXT_MOVIE_ALL (MENU_BELONG(CONTEXT_PLAYING_READONLY) | MENU_BELONG(CONTEXT_PLAYING_READWRITE) | MENU_BELONG(CONTEXT_RECORDING_READONLY) | MENU_BELONG(CONTEXT_RECORDING_READWRITE))
// All status without movie
#define BELONG_CONTEXT_NOMOVIE (MENU_BELONG(CONTEXT_OFF)| MENU_BELONG(CONTEXT_GAME))
// All status when game is loaded
#define BELONG_CONTEXT_RUNNING (BELONG_CONTEXT_MOVIE_ALL | MENU_BELONG(CONTEXT_GAME))
// All context menus
#define BELONG_CONTEXT_ALL (BELONG_CONTEXT_NOMOVIE | BELONG_CONTEXT_MOVIE_ALL)
// ALL menus
#define BELONG_ALL (BELONG_CONTEXT_ALL | MENU_BELONG(MAIN))
#define IsMenuBelongsTo(menu_index, hmenu_ident) (1 << menu_index & hmenu_ident)
struct HOTKEYMENUINDEX {
int menu_id; // menu ID
int cmd_id; // hotkey ID
int hmenu_index = FCEUMENU_MAIN; // whitch menu it belongs to, refers to FCEUMENU_HWND
MENU_BELONG_INT hmenu_ident = MENU_BELONG(MAIN); // whitch menu it belongs to, can be multiple, refers to HOTKEYMENU_PARENTMENU_INDEX
int flags = MF_BYCOMMAND; // flags when searching and modifying menu item, usually MF_BYCOMMAND
// returns an std::string contains original menu text followed with shortcut keys.
std::string getQualifiedMenuText();
std::string getQualifiedMenuText(MENU_BELONG_INT parent_index = MENU_BELONG(MAIN));
// this is used when you only want to create a qualified menu text String
static std::string getQualifiedMenuText(char* text, int cmdid);
int updateMenuText();
HOTKEYMENUINDEX(int id, int cmd, int menu = FCEUMENU_MAIN, int _flags = MF_BYCOMMAND) : menu_id(id), cmd_id(cmd), hmenu_index(menu), flags(_flags) {}
void updateMenuText(FCEUMENU_INDEX index);
HOTKEYMENUINDEX(int _id, int _cmd, MENU_BELONG_INT _menu = MENU_BELONG(MAIN), int _flags = MF_BYCOMMAND) : menu_id(_id), cmd_id(_cmd), hmenu_ident(_menu), flags(_flags) {}
};
void UpdateMenuHotkeys(FCEUMENU_INDEX index);
int GetCurrentContextIndex();
#endif

View File

@ -416,10 +416,13 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
if (!fp)
{
extern bool archiveManuallyCanceled;
// Although !fp, if the operation was canceled from archive select dialog box, don't show the error message;
if (!silent && !archiveManuallyCanceled)
FCEU_PrintError("打开 \"%s\" 错误!", name);
FCEU_PrintError("Error opening \"%s\"!", name);
// Set it back to false, since user might not load ROM from dialog the next time.
// TODO: find a better way to do this.
archiveManuallyCanceled = false;
return 0;
}
else if (fp->archiveFilename != "")

View File

@ -11,6 +11,10 @@
extern bool bindSavestate;
// indicator for the open in archive dialog that if the load was canceled by the user.
// TODO: Since I can't think of a better way to indicate it, hope someone could imporve it.
extern bool archiveManuallyCanceled;
struct FCEUFILE {
//the stream you can use to access the data
//std::iostream *stream;

View File

@ -3348,6 +3348,30 @@ static void gui_drawline_internal(int x1, int y1, int x2, int y2, bool lastPixel
}
}
// draw a rect on gui_data
static void gui_drawbox_internal(int x1, int y1, int x2, int y2, uint32 colour) {
if (x1 > x2)
swap<int>(x1, x2);
if (y1 > y2)
swap<int>(y1, y2);
if (x1 < 0)
x1 = -1;
if (y1 < 0)
y1 = -1;
if (x2 >= LUA_SCREEN_WIDTH)
x2 = LUA_SCREEN_WIDTH;
if (y2 >= LUA_SCREEN_HEIGHT)
y2 = LUA_SCREEN_HEIGHT;
//gui_prepare();
gui_drawline_internal(x1, y1, x2, y1, true, colour);
gui_drawline_internal(x1, y2, x2, y2, true, colour);
gui_drawline_internal(x1, y1, x1, y2, true, colour);
gui_drawline_internal(x2, y1, x2, y2, true, colour);
}
// draw fill rect on gui_data
static void gui_fillbox_internal(int x1, int y1, int x2, int y2, uint32 colour)
{
@ -3375,38 +3399,6 @@ static void gui_fillbox_internal(int x1, int y1, int x2, int y2, uint32 colour)
}
}
// draw a rect on gui_data
static void gui_drawbox_internal(int x1, int y1, int x2, int y2, uint32 colour) {
if (x1 > x2)
swap<int>(x1, x2);
if (y1 > y2)
swap<int>(y1, y2);
if (x1 < 0)
x1 = -1;
if (y1 < 0)
y1 = -1;
if (x2 >= LUA_SCREEN_WIDTH)
x2 = LUA_SCREEN_WIDTH;
if (y2 >= LUA_SCREEN_HEIGHT)
y2 = LUA_SCREEN_HEIGHT;
//gui_prepare();
int h = y2 - y1 + 1;
int w = x2 - x1 + 1;
if(w < 2 || h < 2)
gui_fillbox_internal(x1,y1,x2,y2,colour);
else
{
gui_drawline_internal(x1, y1, x2, y1, true, colour); //top
gui_drawline_internal(x1, y2, x2, y2, true, colour); //bottom
gui_drawline_internal(x1, y1+1, x1, y2-1, true, colour); //left
gui_drawline_internal(x2, y1+1, x2, y2-1, true, colour); //right
}
}
enum
{
GUI_COLOUR_CLEAR