//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// // PrefabsDlg.cpp : implementation file // #include "stdafx.h" #include "hammer.h" #include "PrefabsDlg.h" #include "Prefabs.h" #include "Prefab3D.h" #include "EditPrefabDlg.h" #include "MapDoc.h" // memdbgon must be the last include file in a .cpp file!!! #include ///////////////////////////////////////////////////////////////////////////// // CPrefabsDlg dialog CPrefabsDlg::CPrefabsDlg(CWnd* pParent /*=NULL*/) : CDialog(CPrefabsDlg::IDD, pParent) { //{{AFX_DATA_INIT(CPrefabsDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT } void CPrefabsDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CPrefabsDlg) DDX_Control(pDX, IDC_OBJECTS, m_Objects); DDX_Control(pDX, IDC_OBJECTNOTES, m_ObjectNotes); DDX_Control(pDX, IDC_LIBRARYNOTES, m_LibraryNotes); DDX_Control(pDX, IDC_LIBRARIES, m_Libraries); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CPrefabsDlg, CDialog) //{{AFX_MSG_MAP(CPrefabsDlg) ON_BN_CLICKED(IDC_ADDLIBRARY, OnAddlibrary) ON_BN_CLICKED(IDC_ADDOBJECT, OnAddobject) ON_BN_CLICKED(IDC_EDITLIBRARY, OnEditlibrary) ON_BN_CLICKED(IDC_EDITOBJECT, OnEditobject) ON_BN_CLICKED(IDC_EXPORTOBJECT, OnExportobject) ON_CBN_SELCHANGE(IDC_LIBRARIES, OnSelchangeLibraries) ON_BN_CLICKED(IDC_REMOVELIBRARY, OnRemovelibrary) ON_BN_CLICKED(IDC_REMOVEOBJECT, OnRemoveobject) ON_NOTIFY(LVN_ITEMCHANGED, IDC_OBJECTS, OnItemchangedObjects) ON_NOTIFY(LVN_ENDLABELEDIT, IDC_OBJECTS, OnEndlabeleditObjects) ON_WM_CLOSE() //}}AFX_MSG_MAP ON_COMMAND_EX(id_EditObjectInfo, HandleEditObjectPopup) ON_COMMAND_EX(id_EditObjectData, HandleEditObjectPopup) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CPrefabsDlg message handlers void CPrefabsDlg::OnAddobject() { CPrefabLibrary *pLibrary = GetCurrentLibrary(); if(!pLibrary) return; // no lib, no add CFileDialog dlg(TRUE, NULL, NULL, OFN_ALLOWMULTISELECT | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_NOCHANGEDIR, "Prefab files (*.map;*.rmf;*.os)|*.map; *.rmf; *.os|" "Game MAP files (*.map)|*.map|" "Worldcraft RMF files (*.rmf)|*.rmf||", this); if(dlg.DoModal() == IDCANCEL) return; // aborted // add all these files .. char szDir[MAX_PATH], szFiles[2048]; memcpy(szFiles, dlg.m_ofn.lpstrFile, dlg.m_ofn.nMaxFile); strcpy(szDir, dlg.m_ofn.lpstrFile); BOOL bOneFile = FALSE; char *p = szFiles + strlen(szDir) + 1; if(!p[0]) { bOneFile = TRUE; p = szDir; // just one file } // disable caching of prefabs CPrefab::EnableCaching(FALSE); // get files char szFile[MAX_PATH]; CString strFullPath; int iItem = m_Objects.GetItemCount(); while(1) { strcpy(szFile, p); if(!szFile[0]) break; p += strlen(szFile) + 1; if(!bOneFile) strFullPath.Format("%s\\%s", szDir, szFile); else strFullPath = szFile; // check file type CPrefab *pPrefab = NULL; switch(CPrefab::CheckFileType(strFullPath)) { case CPrefab::pftUnknown: { continue; // no. } case CPrefab::pftRMF: { CPrefabRMF *pNew = new CPrefabRMF; pNew->Init(strFullPath, TRUE, CPrefab::lsRMF); pPrefab = (CPrefab *)pNew; break; } case CPrefab::pftMAP: { CPrefabRMF *pNew = new CPrefabRMF; pNew->Init(strFullPath, TRUE, CPrefab::lsMAP); pPrefab = (CPrefab *)pNew; break; } case CPrefab::pftScript: { Assert(0); // not supported yet break; } } if (!pPrefab) { continue; } // add to current library pLibrary->Add(pPrefab); // add to objects list AddToObjectList(pPrefab, iItem++); if(bOneFile) break; } // now rewrite library pLibrary->Sort(); pLibrary->Save(); CPrefab::FreeAllData(); // free memory // re-enable prefab caching CPrefab::EnableCaching(TRUE); bCurLibraryModified = FALSE; } void CPrefabsDlg::AddToObjectList(CPrefab *pPrefab, int iItem, BOOL bReplace) { if(iItem == -1) iItem = m_Objects.GetItemCount(); if(bReplace) // replace existing item { m_Objects.DeleteItem(iItem); } iItem = m_Objects.InsertItem(iItem, pPrefab->GetName(), pPrefab->GetType() == CPrefab::pftScript ? 1 : 0); m_Objects.SetItemData(iItem, pPrefab->GetID()); bCurLibraryModified = TRUE; } BOOL CPrefabsDlg::HandleEditObjectPopup(UINT nID) { switch(nID) { case id_EditObjectInfo: EditObjectInfo(); break; case id_EditObjectData: EditObjectData(); break; } return TRUE; } static BOOL IsValidFilename(LPCTSTR pszString) // check for valid windows filename. no drive/dirs allowed. { LPCTSTR p = pszString; while(p[0]) { BYTE ch = BYTE(p[0]); ++p; if(ch > 127 || isalpha(ch) || isdigit(ch) || strchr(" $%`-_@~'!(){}^#&", ch)) continue; // not one of those chars - not correct return FALSE; } return TRUE; } void CPrefabsDlg::EditObjectInfo() { int iSel; CPrefab *pPrefab = GetCurrentObject(&iSel); CEditPrefabDlg dlg; dlg.m_strName = pPrefab->GetName(); dlg.m_strDescript = pPrefab->GetNotes(); dlg.SetRanges(500, -1); if(dlg.DoModal() == IDCANCEL) return; pPrefab->SetName(dlg.m_strName); pPrefab->SetNotes(dlg.m_strDescript); AddToObjectList(pPrefab, iSel, TRUE); bCurLibraryModified = TRUE; } void CPrefabsDlg::EditObjectData() { // get application CHammer *pApp = (CHammer*) AfxGetApp(); if(bCurLibraryModified) { CPrefabLibrary *pLibrary = GetCurrentLibrary(); if(pLibrary) pLibrary->Save(); } CMapDoc *pDoc = (CMapDoc*) pApp->pMapDocTemplate->OpenDocumentFile(NULL); pDoc->EditPrefab3D(GetCurrentObject()->GetID()); EndDialog(IDOK); } void CPrefabsDlg::OnEditobject() { if(!GetCurrentObject()) // nothing return; // two stages - name/description OR data itself CMenu menu; menu.CreatePopupMenu(); menu.AppendMenu(MF_STRING, id_EditObjectInfo, "Name and Description"); menu.AppendMenu(MF_STRING, id_EditObjectData, "Prefab Data"); // track menu CWnd *pButton = GetDlgItem(IDC_EDITOBJECT); CRect r; pButton->GetWindowRect(r); menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, r.left, r.bottom, this, NULL); } void CPrefabsDlg::OnRemoveobject() { // remove marked objectsss int iIndex = m_Objects.GetNextItem(-1, LVNI_SELECTED); BOOL bConfirmed = FALSE; CPrefabLibrary *pLibrary = GetCurrentLibrary(); while(iIndex != -1) { CPrefab *pPrefab = CPrefab::FindID(m_Objects.GetItemData(iIndex)); if(pPrefab) { // delete it if(!bConfirmed) { // do confirmation. if(AfxMessageBox("Are you sure you want to delete these " "items?", MB_YESNO) == IDNO) return; // nope! m_Objects.SetRedraw(FALSE); // no redraw while doing this } bConfirmed = TRUE; // remove from lib & delete pLibrary->Remove(pPrefab); delete pPrefab; // delete from list and shift index down so we keep processing // correctly m_Objects.DeleteItem(iIndex--); } // get next item iIndex = m_Objects.GetNextItem(iIndex, LVNI_SELECTED); } // save library pLibrary->Save(); m_Objects.SetRedraw(TRUE); // redraw objects m_Objects.Invalidate(); } void CPrefabsDlg::OnExportobject() { int iIndex = m_Objects.GetNextItem(-1, LVNI_SELECTED); while(iIndex != -1) { CPrefab *pPrefab = CPrefab::FindID(m_Objects.GetItemData(iIndex)); if(pPrefab) { // export it CString strFilename; strFilename = pPrefab->GetName(); CFileDialog dlg(FALSE, "map", strFilename, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "Map files|*.map;*.rmf|", this); if(dlg.DoModal() == IDCANCEL) return; // nevermind strFilename = dlg.GetPathName(); int iPos = strFilename.Find('.'); DWORD dwFlags = CPrefab::lsRMF; if(iPos != -1) { char *p = strFilename.GetBuffer(0); if(!strnicmp(p+iPos+1, "map", 3)) dwFlags = CPrefab::lsMAP; } pPrefab->Save(strFilename, dwFlags); } // get next item iIndex = m_Objects.GetNextItem(iIndex, LVNI_SELECTED); } } void CPrefabsDlg::SetCurObject(int iItem) { iCurObject = iItem; if(iCurObject == -1) { m_ObjectNotes.SetWindowText(""); return; } // update data.. CPrefab *pPrefab = CPrefab::FindID(m_Objects.GetItemData(iCurObject)); Assert(pPrefab); m_ObjectNotes.SetWindowText(pPrefab->GetNotes()); } void CPrefabsDlg::OnItemchangedObjects(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; *pResult = 0; if(!(pNMListView->uChanged & LVIF_STATE)) return; if(pNMListView->uNewState & LVIS_FOCUSED) { SetCurObject(pNMListView->iItem); } } // // Library mgmt // CPrefabLibrary *CPrefabsDlg::GetCurrentLibrary(int *piSel) { if(piSel) piSel[0] = -1; int iSel = m_Libraries.GetCurSel(); if(iSel == CB_ERR) return NULL; CPrefabLibrary *pLibrary = CPrefabLibrary::FindID( m_Libraries.GetItemData(iSel)); if(piSel) piSel[0] = iSel; return pLibrary; } CPrefab *CPrefabsDlg::GetCurrentObject(int *piSel) { if(piSel) piSel[0] = -1; int iSel = iCurObject; if(iSel == -1) return NULL; CPrefab *pPrefab= CPrefab::FindID(m_Objects.GetItemData(iSel)); if(piSel) piSel[0] = iSel; return pPrefab; } void CPrefabsDlg::OnSelchangeLibraries() { // get last library CPrefabLibrary *pLibrary = CPrefabLibrary::FindID( m_Libraries.GetItemData(iCurLibrary)); // save its index if(bCurLibraryModified) { pLibrary->Save(); } // update objects list m_Objects.DeleteAllItems(); iCurLibrary = m_Libraries.GetCurSel(); bCurLibraryModified = FALSE; pLibrary = GetCurrentLibrary(); if(!pLibrary) return; // add objects to object list m_Objects.SetRedraw(FALSE); POSITION p = ENUM_START; CPrefab *pPrefab = pLibrary->EnumPrefabs(p); int iItem = 0; while(pPrefab) { AddToObjectList(pPrefab, iItem++); pPrefab = pLibrary->EnumPrefabs(p); } m_Objects.SetRedraw(TRUE); m_Objects.Invalidate(); // set description window m_LibraryNotes.SetWindowText(pLibrary->GetNotes()); } static int AskAboutInvalidFilename() { return AfxMessageBox("That's not a valid name - some of the characters aren't\n" "acceptable. Try using a name with only A-Z, 0-9, space,\n" "and these characters: $%`-_@~'!(){}^#&", MB_OKCANCEL); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPrefabsDlg::OnAddlibrary() { Again: CEditPrefabDlg dlg; if(dlg.DoModal() == IDCANCEL) return; // check name if(!IsValidFilename(dlg.m_strName)) { if(AskAboutInvalidFilename() == IDOK) goto Again; return; // nevermind. } CPrefabLibraryRMF *pLibrary = new CPrefabLibraryRMF; pLibrary->SetName(dlg.m_strName); pLibrary->SetNotes(dlg.m_strDescript); // add to list int iIndex = m_Libraries.AddString(pLibrary->GetName()); m_Libraries.SetItemData(iIndex, pLibrary->GetID()); m_Libraries.SetCurSel(iIndex); OnSelchangeLibraries(); // to redraw description window bCurLibraryModified = TRUE; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPrefabsDlg::OnEditlibrary() { // get selection int iSel; CPrefabLibrary *pLibrary = GetCurrentLibrary(&iSel); if(!pLibrary) return; CEditPrefabDlg dlg; dlg.m_strName = pLibrary->GetName(); dlg.m_strDescript = pLibrary->GetNotes(); Again: if(dlg.DoModal() == IDCANCEL) return; // check name if(!IsValidFilename(dlg.m_strName)) { if(AskAboutInvalidFilename() == IDOK) goto Again; return; // nevermind. } pLibrary->SetName(dlg.m_strName); pLibrary->SetNotes(dlg.m_strDescript); // set in list m_Libraries.SetRedraw(FALSE); m_Libraries.DeleteString(iSel); int iIndex = m_Libraries.InsertString(iSel, pLibrary->GetName()); m_Libraries.SetItemData(iIndex, pLibrary->GetID()); m_Libraries.SetRedraw(TRUE); m_Libraries.Invalidate(); m_Libraries.SetCurSel(iSel); OnSelchangeLibraries(); // to redraw description window bCurLibraryModified = TRUE; } void CPrefabsDlg::OnRemovelibrary() { // get cur library int iSel; CPrefabLibrary *pLibrary = GetCurrentLibrary(&iSel); if (pLibrary == NULL) { return; } if (AfxMessageBox("Are you sure you want to delete this library from your hard drive?", MB_YESNO) == IDYES) { pLibrary->DeleteFile(); delete pLibrary; bCurLibraryModified = FALSE; m_Libraries.DeleteString(iSel); m_Libraries.SetCurSel(0); OnSelchangeLibraries(); // to redraw description window } } BOOL CPrefabsDlg::OnInitDialog() { CDialog::OnInitDialog(); SetCurObject(-1); // make imagelist PrefabImages.Create(IDB_PREFABS, 32, 1, RGB(0, 255, 255)); PrefabImages.SetBkColor(m_Objects.GetBkColor()); m_Objects.SetImageList(&PrefabImages, LVSIL_NORMAL); // add libraries to list POSITION p = ENUM_START; CPrefabLibrary *pLibrary = CPrefabLibrary::EnumLibraries(p); while(pLibrary) { int iIndex = m_Libraries.AddString(pLibrary->GetName()); m_Libraries.SetItemData(iIndex, pLibrary->GetID()); pLibrary = CPrefabLibrary::EnumLibraries(p); } iCurLibrary = 0; bCurLibraryModified = FALSE; m_Libraries.SetCurSel(0); OnSelchangeLibraries(); return TRUE; } void CPrefabsDlg::OnEndlabeleditObjects(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; LV_ITEM &item = pDispInfo->item; *pResult = 0; if(item.pszText == NULL) return; CPrefab *pPrefab = CPrefab::FindID(m_Objects.GetItemData(item.iItem)); pPrefab->SetName(item.pszText); m_Objects.SetItemText(item.iItem, 0, item.pszText); bCurLibraryModified = TRUE; } void CPrefabsDlg::OnClose() { // get library CPrefabLibrary *pLibrary = GetCurrentLibrary(); // save it if(bCurLibraryModified && pLibrary) { pLibrary->Save(); } CDialog::OnClose(); }