void UpdateCurFileName(HWND hwndMain, HWND hwndHV, LPCTSTR szFileName, BOOL fChanged) { TCHAR szFullPath[MAX_PATH]; TCHAR *pszFileTitle; if(GetFullPathName(szFileName, MAX_PATH, szFullPath, &pszFileTitle)) { lstrcpy(g_szFileName, szFullPath); lstrcpy(g_szFileTitle, pszFileTitle); SetWindowFileName(hwndMain, pszFileTitle, fChanged, HexView_IsReadOnly(hwndHV)); } AddRecentFile(szFileName); UpdateRecentMenu(GetSubMenu(GetMenu(hwndMain), 0)); }
// // Main Window message handler // LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { NMHDR *hdr; POINT pt; RECT rect; HMENU hMenu; HWND hwndHV = GetActiveHexView(hwnd);//g_hwndHexView; int i; TCITEM tci; MAINWND *mainWnd = (MAINWND *)GetWindowLongPtr(hwnd, 0); switch(msg) { case WM_NCCREATE: if((mainWnd = malloc(sizeof(MAINWND))) == 0) return FALSE; SetWindowLongPtr(hwnd, 0, (LONG_PTR)mainWnd); ZeroMemory(mainWnd, sizeof(MAINWND)); return TRUE; case WM_NCDESTROY: free(mainWnd); return 0; case WM_CREATE: g_hwndMain = hwnd; SetWindowIcon(hwnd, IDI_APP); // create a child-window EDIT control //g_hwndHexView = CreateHexViewCtrl(hwnd); g_hwndTabView = CreateWindow(WC_TABVIEW, TEXT(""), WS_CHILD|WS_VISIBLE,0,0,0,0,hwnd, 0, g_hInstance, 0); g_hwndStatusBar = CreateStatusBar(hwnd); SendMessage(g_hwndTabView, TCM_SETITEMSIZE, 0, MAKELPARAM(150, 0)); SetStatusBarParts(g_hwndStatusBar); hwndHV = g_hwndHexView; mainWnd->hwndMain = hwnd; mainWnd->hwndStatusBar = g_hwndStatusBar; mainWnd->hwndTabView = g_hwndTabView; CreateToolTip(g_hwndHexView); // g_hwndDock[0] = CreateDockWnd(&dock, hwnd, TEXT("Toolbar")); //g_hwndToolbar = InitToolbar(hwnd); //g_hwndSearchBar = CreateSearchBar(hwnd); //g_hwndTypeView = CreateTypeView(hwnd); SetFocus(hwndHV); // tell windows that we can handle drag+drop'd files DragAcceptFiles(hwnd, TRUE); UpdateRecentMenu(GetSubMenu(GetMenu(hwnd), 0)); SetTimer(hwnd, 0xdeadbeef, 1000, 0); return TRUE; case WM_TIMER: if(wParam == 0xdeadbeef) { KillTimer(hwnd, wParam); //FirstTimeOptions(hwnd); } return 0; case WM_DROPFILES: // get the screen coordinates of the drop-location if(DragQueryPoint((HDROP)wParam, &pt)) ClientToScreen(hwnd, &pt); GetWindowRect(hwndHV, &rect); // drop anywhere *except* the hexview, as that does D&D itself if(!PtInRect(&rect, pt)) { HandleDropFiles(hwnd, (HDROP)wParam); } //CreateToolTip(mainWnd->hwndTabView); return 0; case WM_ENABLE: EnableWindow(g_hwndSearch, (BOOL)wParam); EnableWindow(g_hwndGoto, (BOOL)wParam); return 0; case WM_CONTEXTMENU: if((HWND)wParam == DockWnd_GetWindow(hwnd, DWID_TYPEVIEW)) { HMENU hMenu = GetSubMenu(LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_TYPECONTEXT)), 0); UINT u; MenuCheckMark(hMenu, IDM_TYPEVIEW_HEX, g_fDisplayHex); MenuCheckMark(hMenu, IDM_TYPEVIEW_BIGENDIAN, g_fDisplayBigEndian); u = TrackPopupMenu(hMenu, TPM_RETURNCMD, (short)LOWORD(lParam), (short)HIWORD(lParam), 0, hwnd, 0); SendMessage(DockWnd_GetContents(hwnd, DWID_TYPEVIEW), WM_COMMAND, u, 0); } break; case WM_COMMAND: return HexEdit_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); case WM_NOTIFY: hdr = (NMHDR *)lParam; if(hdr->hwndFrom == hwndHV) return HexViewNotifyHandler(mainWnd, hwnd, hdr); else return HexEdit_OnNotify(mainWnd, hwnd, (UINT)wParam, (NMHDR *)lParam); case WM_CLOSE: tci.mask = TCIF_PARAM; for(i = 0; (hwndHV = EnumHexView(hwnd, i)) != NULL; ) { UINT uAnswer = HexFileCloseNotify(hwnd, hwndHV); if(uAnswer == IDCANCEL) { return 0; } else if(uAnswer == IDNO) { SaveHighlights(hwndHV); TabCtrl_DeleteItem(mainWnd->hwndTabView, i); } else { i++; } } // save settings *before* we destroy anything! DockWnd_SaveSettings(hwnd); // shut program down DestroyWindow(hwnd); return 0; case WM_DESTROY: DestroyWindow(hwndHV); // PostQuitMessage(0); return 0; case WM_SETFOCUS: SetFocus(hwndHV); return 0; case WM_SIZE: MainWndSize(mainWnd, LOWORD(lParam), HIWORD(lParam)); UpdateStatusbar(mainWnd->hwndStatusBar); return 0; case WM_INITMENUPOPUP: hMenu = (HMENU)wParam;//GetMenu(hwnd); MenuCheckMark(hMenu, IDM_VIEW_TOOLBAR, DockWnd_IsOpen(hwnd, DWID_TOOLBAR)); MenuCheckMark(hMenu, IDM_TOOLS_TYPEVIEW, DockWnd_IsOpen(hwnd, DWID_TYPEVIEW)); MenuCheckMark(hMenu, IDM_TOOLS_SEARCHBAR, DockWnd_IsOpen(hwnd, DWID_SEARCHBAR)); CheckMenuRadioItem(hMenu, IDM_VIEW_HEX, IDM_VIEW_BIN, IDM_VIEW_HEX + (HexView_GetStyle(hwndHV) & HVS_FORMAT_MASK), MF_BYCOMMAND); { int look[32] = { 0, 0, 1, 0, 2 }; CheckMenuRadioItem(hMenu, IDM_GROUP_BYTE, IDM_GROUP_DWORD, IDM_GROUP_BYTE + look[HexView_GetGrouping(hwndHV)], MF_BYCOMMAND); } { size_w selsize; UINT edmode = HexView_GetEditMode(hwndHV); BOOL cftext = IsClipboardFormatAvailable(CF_TEXT); BOOL canundo = HexView_CanUndo(hwndHV); BOOL canredo = HexView_CanRedo(hwndHV); HexView_GetSelSize(hwndHV, &selsize); //hMenu = GetSubMenu(GetMenu(hwnd), 1); EnableMenuCmdItem(hMenu, IDM_EDIT_UNDO, canundo); EnableMenuCmdItem(hMenu, IDM_EDIT_REDO, canredo); EnableMenuCmdItem(hMenu, IDM_EDIT_CUT, selsize > 0 && edmode == HVMODE_INSERT); EnableMenuCmdItem(hMenu, IDM_EDIT_COPY, selsize > 0); EnableMenuCmdItem(hMenu, IDM_EDIT_COPYAS, selsize > 0); EnableMenuCmdItem(hMenu, IDM_EDIT_PASTE, cftext && edmode != HVMODE_READONLY ); EnableMenuCmdItem(hMenu, IDM_EDIT_PASTESPECIAL, edmode != HVMODE_READONLY ); EnableMenuCmdItem(hMenu, IDM_EDIT_DELETE, selsize > 0 && edmode != HVMODE_READONLY ); EnableMenuCmdItem(hMenu, IDM_EDIT_REVERSE, selsize > 0 && edmode != HVMODE_READONLY ); EnableMenuCmdItem(hMenu, IDM_TOOLS_TRANSFORM, selsize > 0 && edmode != HVMODE_READONLY ); EnableMenuCmdItem(hMenu, IDM_FILE_REVERT, canundo || canredo); } return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); }
/* PropSheetProc: Handles special messages pertaining to the property sheet. Note: See PropSheetProc in the Platform SDK docs for parameters and notes. */ int CALLBACK PropSheetProc(HWND sheet, UINT msgid, LPARAM lParam) { switch (msgid) { case PSCB_PRECREATE: { DLGTEMPLATE *templ = (DLGTEMPLATE*)lParam; templ->cy += 5; //add a minimize box templ->style |= WS_MINIMIZEBOX; } break; case PSCB_INITIALIZED: { HWND tooltip; HICON icon; /* Add Menu. */ propdata.menu = LoadMenu(aokts, (LPCSTR)IDM_MAIN); SetMenu(sheet, propdata.menu); //SetSaveState(sheet, MF_GRAYED); scen.reset(); SendMessage(PropSheet_GetCurrentPageHwnd(sheet), AOKTS_Loading, 0, 0); MapView_Reset(propdata.mapview, true); /* Enable appropriate recent file items. */ UpdateRecentMenu(propdata.menu); /* Remove unused buttons. */ for (int i = 0; i < sizeof(PropSheetButtons) / sizeof(WORD); i++) { HWND hWnd = GetDlgItem(sheet, PropSheetButtons[i]); if (hWnd != NULL) { ShowWindow(hWnd, SW_HIDE); EnableWindow(hWnd, FALSE); } } /* Add a tooltip window */ tooltip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, "AOKTS Tooltip", WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, sheet, NULL, aokts, NULL); TooltipInit(tooltip); /* Set the big icon */ icon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_LOGO)); Window_SetIcon(sheet, ICON_BIG, icon); if (setts.editall) { CheckMenuItem(GetMenu(sheet), ID_EDIT_ALL, MF_BYCOMMAND | MF_CHECKED); } else { CheckMenuItem(GetMenu(sheet), ID_EDIT_ALL, MF_BYCOMMAND); } } break; } return 0; }
/* FileOpen: Handles a request to open a file. (Either by menu or generated by the app.) Parameters: HWND sheet: Handle to the property sheet. bool ask: Should AOKTS ask the user which file? int recent: Optionally open from one of the recent file entries. (-1 to disable.) */ void FileOpen(HWND sheet, bool ask, int recent) { OPENFILENAME ofn; struct RecentFile *file = NULL; //the file info will be stored here one way or another char titleBuffer[100]; const char *filename; Game version = scen.game; HWND page = PropSheet_GetCurrentPageHwnd(sheet); //save the scenario if changes have been made (NOT FUNCTIONAL) if (scen.needsave()) { int sel = MessageBox(sheet, askSaveChanges, "Save", MB_YESNOCANCEL); if (sel == IDYES) FileSave(sheet, false, true); else if (sel == IDCANCEL) return; //stop closing } // Hint about whether to open as AOC or SGWB if (setts.recent_first) { scen.game = (Game)setts.recent_first->game; } /* Using a recent file... */ if (recent >= 0) { ofn.Flags = 0; //make sure no random flags set file = setts.recent_first; /* Parse the linked list to find the one we want */ while (recent--) { if (file) file = file->next; else { MessageBox(sheet, "Warning: Recent File open failed.", "Open Warning", MB_ICONWARNING); } } strcpy(setts.ScenPath, file->path); version = (Game)file->game; } /* Prompt the user for a filename. */ else if (ask) { struct RecentFile *r_parse; char dir[_MAX_PATH]; strcpy(dir, setts.BasePath); strcat(dir, "Scenario"); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = sheet; //ofn.hInstance unused ofn.lpstrFilter = extOpen; ofn.lpstrCustomFilter = NULL; //user should not set custom filters ofn.lpstrFile = setts.ScenPath; ofn.nMaxFile = _MAX_PATH; ofn.lpstrFileTitle = NULL; ofn.lpstrInitialDir = dir; ofn.lpstrTitle = NULL; ofn.Flags = OFN_FILEMUSTEXIST | OFN_NONETWORKBUTTON | OFN_NOCHANGEDIR; if (scen.header.header_type == HT_AOE2SCENARIO) { ofn.nFilterIndex = 1; ofn.lpstrDefExt = "aoe2scenario"; } else { switch (scen.game) { case AOK: case AOC: case AOHD: case AOF: case AOHD4: case AOF4: case AOHD6: case AOF6: ofn.nFilterIndex = 1; ofn.lpstrDefExt = "scx"; break; case SWGB: case SWGBCC: ofn.nFilterIndex = 2; ofn.lpstrDefExt = "scx"; break; } } if (!GetOpenFileName(&ofn)) return; switch (ofn.nFilterIndex) { case 1: version = AOC; printf_log("Selected %d, AOE 2.\n", ofn.nFilterIndex); break; case 2: version = SWGB; printf_log("Selected %d, Star Wars.\n", ofn.nFilterIndex); break; } /* Now check if selected file is already on recent list. */ r_parse = setts.recent_first; while (r_parse) { if (!strcmp(r_parse->path, setts.ScenPath)) { file = r_parse; break; } r_parse = r_parse->next; } } /* Open it! */ SendMessage(page, AOKTS_Closing, 0, 0); // set hourglass, might take more than 1ms HCURSOR previous = SetCursor(LoadCursor(NULL, IDC_WAIT)); scen.reset(); try { version = scen.open(setts.ScenPath, setts.TempPath, version); /* Handle recent file stuff */ if (!file) { file = setts.recent_getnext(); strcpy(file->path, setts.ScenPath); strcpy(file->display, PathFindFileName(setts.ScenPath)); file->game = (int)version; } setts.recent_push(file); UpdateRecentMenu(propdata.menu); SetCursor(previous); // for some reason this is always read only. on Wine at least //SetSaveState(sheet, ofn.Flags & OFN_READONLY ? MF_GRAYED : MF_ENABLED); SetSaveState(sheet, ofn.Flags & OFN_READONLY ? MF_ENABLED : MF_ENABLED); // set status bar text SetWindowTextW(propdata.statusbar, L"Scenario loaded successfully."); SendMessage(page, AOKTS_Loading, 0, 0); SendMessageW(propdata.mapview, MAP_Recreate, 0, 0); MapView_Reset(propdata.mapview, true); filename = getFilenameFromPath(setts.ScenPath); _snprintf(titleBuffer, sizeof(titleBuffer), "%s - %s", szTitle, filename); SetWindowText(sheet, titleBuffer); } catch (std::exception &ex) { // TODO: better atomic cursor handling? SetCursor(previous); // set status bar text SetWindowText(propdata.statusbar, ex.what()); // report error to user std::string desc = "Failed to open as "; desc.append(gameName(scen.game)); desc.append(" scenario file.\n"); switch (scen.game) { case AOC: desc.append("Try opening as a SWGB scx file instead\nusing File->Open\n"); break; case SWGB: desc.append("Try opening as a Conquerors scx file instead\nusing File->Open\n"); break; } desc.append("\nThe problem: "); desc.append(ex.what()); desc.append("\n\nIf the game is able to open the scenario,\nplease report this error. Thanks."); printf_log("User message: %s\n", desc.c_str()); MessageBox(sheet, desc.c_str(), "Scenario Load Error", MB_ICONWARNING); // unless it's a debug build, clear the bad data #ifndef _DEBUG scen.reset(); SendMessage(page, AOKTS_Closing, 0, 0); #endif /* Updates*/ SendMessage(page, AOKTS_Loading, 0, 0); _snprintf(titleBuffer, sizeof(titleBuffer), "%s", szTitle); SetWindowText(sheet, titleBuffer); } //report errors to logfile fflush(stdout); }
/* FileSave: Handles a request to save the currently open file. Parameters: HWND sheet: Handle to the property sheet. bool as: Save or Save As? */ void FileSave(HWND sheet, bool as, bool write) { int error; //error value from Scenario::save() HWND cpage; //the current property page HCURSOR previous; //the mouse cursor before/after save operation OPENFILENAME ofn; char titleBuffer[100]; Game startver; Game conv = NOCONV; SaveFlags::Value flags = SaveFlags::NONE; char w1[] = {84, 104, 105, 115, 32, 115, 99, 101, 110, 97, 114, 105, 111, 32, 105, 115, 32, 112, 114, 111, 116, 101, 99, 116, 101, 100, 0}; char w2[] = {83, 99, 101, 110, 97, 114, 105, 111, 32, 105, 115, 32, 112, 114, 111, 116, 101, 99, 116, 101, 100, 0}; if (setts.disabletips) { MessageBox(sheet, w1, w2, MB_ICONWARNING); return; } //init cpage = PropSheet_GetCurrentPageHwnd(sheet); //Save As: Ask for filename. if (as || *setts.ScenPath == '\0') { char dir[_MAX_PATH]; strcpy(dir, setts.BasePath); strcat(dir, "Scenario"); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = sheet; ofn.lpstrFilter = extSave; ofn.lpstrCustomFilter = NULL; ofn.lpstrFile = setts.ScenPath; ofn.nMaxFile = _MAX_PATH; ofn.lpstrFileTitle = NULL; ofn.lpstrInitialDir = dir; ofn.lpstrTitle = NULL; ofn.Flags = OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT; startver = scen.game; if (scen.header.header_type == HT_AOE2SCENARIO) { ofn.nFilterIndex = 6; ofn.lpstrDefExt = "aoe2scenario"; } else { switch (scen.game) { case AOK: ofn.nFilterIndex = 1; ofn.lpstrDefExt = "scn"; break; case AOC: ofn.nFilterIndex = 2; ofn.lpstrDefExt = "scx"; break; case UP: ofn.nFilterIndex = 3; ofn.lpstrDefExt = "scx"; break; case AOHD: case AOHD4: ofn.nFilterIndex = 4; ofn.lpstrDefExt = "scx"; break; case AOF: case AOF4: ofn.nFilterIndex = 5; ofn.lpstrDefExt = "scx2"; break; case SWGB: ofn.nFilterIndex = 7; ofn.lpstrDefExt = "scx"; break; case SWGBCC: ofn.nFilterIndex = 8; ofn.lpstrDefExt = "sc1"; break; case AOHD6: ofn.nFilterIndex = 9; ofn.lpstrDefExt = "scx"; break; case AOF6: ofn.nFilterIndex = 10; ofn.lpstrDefExt = "scx2"; break; } } if (!GetSaveFileName(&ofn)) return; switch (ofn.nFilterIndex) { case 1: conv = AOK; break; case 2: conv = AOC; break; case 3: conv = UP; break; case 4: conv = AOHD4; break; case 5: conv = AOF4; break; case 6: scen.header.header_type = HT_AOE2SCENARIO; conv = startver; break; case 7: conv = SWGB; break; case 8: conv = SWGBCC; break; case 9: conv = AOHD6; break; case 10: conv = AOF6; break; } if (!*scen.origname) strcpy(scen.origname, setts.ScenPath + ofn.nFileOffset); /* Update window title since filename has probably changed */ _snprintf(titleBuffer, sizeof(titleBuffer), "%s - %s", szTitle, setts.ScenPath + ofn.nFileOffset); SetWindowText(sheet, titleBuffer); } else { conv = scen.game; } if (isHD(startver) && conv == UP) { if (setts.asktoconverteffects && MessageBox(sheet, "Also convert HD effects to UserPatch?", "Convert", MB_YESNOCANCEL) == IDYES) { flags = (SaveFlags::Value)(flags | SaveFlags::CONVERT_EFFECTS); } } if (startver == UP && isHD(conv)) { if (setts.asktoconverteffects && MessageBox(sheet, "Also convert UserPatch effects to HD?", "Convert", MB_YESNOCANCEL) == IDYES) { flags = (SaveFlags::Value)(flags | SaveFlags::CONVERT_EFFECTS); } } //update scenario data SendMessage(cpage, AOKTS_Saving, 0, 0); //perform before-saving operations previous = SetCursor(LoadCursor(NULL, IDC_WAIT)); // Pretend we're "closing" the scenario because it may change during the // save. SendMessage(cpage, AOKTS_Closing, 0, 0); scen.clean_triggers(); //save the scenario try { error = scen.save(setts.ScenPath, setts.TempPath, write, conv, flags); SetCursor(previous); struct RecentFile *file = NULL; //the file info will be stored here one way or another struct RecentFile *r_parse; /* Now check if file is already on recent list. */ r_parse = setts.recent_first; while (r_parse) { if (!strcmp(r_parse->path, setts.ScenPath)) { file = r_parse; break; } r_parse = r_parse->next; } if (file) { file->game = (int)conv; } else { file = setts.recent_getnext(); strcpy(file->path, setts.ScenPath); strcpy(file->display, PathFindFileName(setts.ScenPath)); file->game = (int)conv; setts.recent_push(file); } UpdateRecentMenu(propdata.menu); } catch (std::exception &ex) { // TODO: better atomic cursor handling? SetCursor(previous); MessageBox(sheet, ex.what(), "Scenario Save Error", MB_ICONWARNING); } //perform after-saving operations SendMessage(cpage, AOKTS_Loading, 0, 0); //report any errors if (error) { SetWindowText(propdata.statusbar, scen.msg); //MessageBox(sheet, scen.msg, "Save Error", MB_OK); } }