From d9d3f1b56bbd2048a3ea693f8d972d2c8caa8c1a Mon Sep 17 00:00:00 2001 From: owomomo Date: Thu, 3 Jan 2019 20:38:33 +0800 Subject: [PATCH] 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). --- src/drivers/win/archive.cpp | 2 - src/drivers/win/mapinput.cpp | 125 ++++++++++++++++-- src/drivers/win/mapinput.h | 1 + src/drivers/win/window.cpp | 244 +++++++++++++++-------------------- src/drivers/win/window.h | 82 +++++++++--- src/fceu.cpp | 7 +- src/file.h | 4 + src/lua-engine.cpp | 56 ++++---- 8 files changed, 313 insertions(+), 208 deletions(-) diff --git a/src/drivers/win/archive.cpp b/src/drivers/win/archive.cpp index 118aca61..9e945a80 100644 --- a/src/drivers/win/archive.cpp +++ b/src/drivers/win/archive.cpp @@ -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;isize();i++) { diff --git a/src/drivers/win/mapinput.cpp b/src/drivers/win/mapinput.cpp index 98b97dfe..013b8ada 100644 --- a/src/drivers/win/mapinput.cpp +++ b/src/drivers/win/mapinput.cpp @@ -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; +} \ No newline at end of file diff --git a/src/drivers/win/mapinput.h b/src/drivers/win/mapinput.h index dc6545f0..ff22569a 100644 --- a/src/drivers/win/mapinput.h +++ b/src/drivers/win/mapinput.h @@ -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 diff --git a/src/drivers/win/window.cpp b/src/drivers/win/window.cpp index 37291a21..39d05b00 100644 --- a/src/drivers/win/window.cpp +++ b/src/drivers/win/window.cpp @@ -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... diff --git a/src/drivers/win/window.h b/src/drivers/win/window.h index 9525a077..1364ca9a 100644 --- a/src/drivers/win/window.h +++ b/src/drivers/win/window.h @@ -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 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 diff --git a/src/fceu.cpp b/src/fceu.cpp index cb0d147f..f6763d43 100644 --- a/src/fceu.cpp +++ b/src/fceu.cpp @@ -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 != "") diff --git a/src/file.h b/src/file.h index 20c3dd4a..539936a9 100644 --- a/src/file.h +++ b/src/file.h @@ -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; diff --git a/src/lua-engine.cpp b/src/lua-engine.cpp index 033aabb8..da812a0a 100644 --- a/src/lua-engine.cpp +++ b/src/lua-engine.cpp @@ -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(x1, x2); + if (y1 > y2) + swap(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(x1, x2); - if (y1 > y2) - swap(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