// AssimilateView.cpp : implementation of the CAssimilateView class // #include "stdafx.h" #include "Includes.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif CAssimilateView* ghAssimilateView = NULL; ///////////////////////////////////////////////////////////////////////////// // CAssimilateView IMPLEMENT_DYNCREATE(CAssimilateView, CTreeView) BEGIN_MESSAGE_MAP(CAssimilateView, CTreeView) //{{AFX_MSG_MAP(CAssimilateView) ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk) ON_WM_DESTROY() ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnItemexpanded) ON_WM_RBUTTONDBLCLK() ON_WM_KEYDOWN() ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged) //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CTreeView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CTreeView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CTreeView::OnFilePrintPreview) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CAssimilateView construction/destruction CAssimilateView::CAssimilateView() { ghAssimilateView = this; } CAssimilateView::~CAssimilateView() { } BOOL CAssimilateView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs if (!CTreeView::PreCreateWindow(cs)) { return FALSE; } cs.style |= TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS/* | TVS_EDITLABELS*/; return TRUE; } ///////////////////////////////////////////////////////////////////////////// // CAssimilateView drawing void CAssimilateView::OnDraw(CDC* pDC) { CAssimilateDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here } ///////////////////////////////////////////////////////////////////////////// // CAssimilateView printing BOOL CAssimilateView::OnPreparePrinting(CPrintInfo* pInfo) { // default preparation return DoPreparePrinting(pInfo); } void CAssimilateView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } void CAssimilateView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing } ///////////////////////////////////////////////////////////////////////////// // CAssimilateView diagnostics #ifdef _DEBUG void CAssimilateView::AssertValid() const { CTreeView::AssertValid(); } void CAssimilateView::Dump(CDumpContext& dc) const { CTreeView::Dump(dc); } CAssimilateDoc* CAssimilateView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CAssimilateDoc))); return (CAssimilateDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CAssimilateView message handlers void CAssimilateView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) { // TODO: Add your specialized code here and/or call the base class CTreeCtrl& tree = GetTreeCtrl(); switch(lHint) { case AS_DELETECONTENTS: tree.DeleteAllItems(); break; case AS_NEWFILE: // findme: hmmm, not sure about this. Adding files zaps the tree? Would look odd to user... tree.DeleteAllItems(); BuildTree(); UpdateTree(); break; case AS_FILESUPDATED: UpdateTree(); // sorts tree according to enum names, sorts model according to new tree, re-draws tree break; default: break; } SetFirstModelTitleAndMode(); } // in practise, the Assimilate app will only ever use one sort type, but wtf... // typedef enum { TS_BY_ENUMTYPE = 0, } TREESORTTYPE; // // tree item compare callback, // // returns (to windows):- (so do NOT change these defines) // #define ITEM1_BEFORE_ITEM2 -1 #define ITEM1_MATCHES_ITEM2 0 #define ITEM1_AFTER_ITEM2 1 // int CALLBACK TreeCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { CSequence* seq1 = (CSequence*) lParam1; CSequence* seq2 = (CSequence*) lParam2; switch (lParamSort) { case TS_BY_ENUMTYPE: { // enumtypes are enum'd lower-numbers-more-important... // if (seq1->GetEnumType() < seq2->GetEnumType()) { return ITEM1_BEFORE_ITEM2; } if (seq1->GetEnumType() > seq2->GetEnumType()) { return ITEM1_AFTER_ITEM2; } // must be same type, so sort alphabetically... // (strcmp almost returns correct values, except the results are signed anynums, not explicitly -1/0/1) // return ITEM1_MATCHES_ITEM2; /* int i = strcmp(seq1->GetEnum(),seq2->GetEnum()); if (i<0) { return ITEM1_BEFORE_ITEM2; } if (i>0) { return ITEM1_AFTER_ITEM2; } return ITEM1_MATCHES_ITEM2; */ } break; } ASSERT(0); return ITEM1_MATCHES_ITEM2; } bool TreeSort(CTreeCtrl& tree, TREESORTTYPE ts) { HTREEITEM hTreeItem_Model = tree.GetRootItem(); // "klingon" while (hTreeItem_Model) { TVSORTCB sortParams; sortParams.hParent = hTreeItem_Model; sortParams.lpfnCompare = TreeCompareFunc; sortParams.lParam = ts; tree.SortChildrenCB(&sortParams); hTreeItem_Model = tree.GetNextSiblingItem(hTreeItem_Model); } return true; } // returns true if any delete has taken place (sequence or model)... // bool CAssimilateView::DeleteCurrentItem(bool bNoQueryForSequenceDelete) { // OutputDebugString(va("DeleteCurrentItem %s\n",bNoQueryForSequenceDelete?"CTRL":"")); // ok, what *is* the current item? // CTreeCtrl& tree = GetTreeCtrl(); HTREEITEM theItem = tree.GetSelectedItem(); if (theItem == NULL) { return false; } // ok, so it's either a model or a sequence... // CModel* curModel = NULL; if (tree.GetParentItem(theItem) == NULL) { curModel = (CModel*)tree.GetItemData(theItem); if (curModel != NULL) { if (GetYesNo(va("Delete whole model \"%s\"?",curModel->GetName()))) { tree.DeleteItem(theItem); GetDocument()->DeleteModel(curModel); GetDocument()->SetModifiedFlag(); return true; } } } else { curModel = (CModel*)tree.GetItemData(tree.GetParentItem(theItem)); CSequence* curSequence = (CSequence*)tree.GetItemData(theItem); if (curSequence != NULL) { // ask them if they're sure, unless the ctrl key is also pressed... // if (bNoQueryForSequenceDelete || GetYesNo(va("Delete sequence \"%s\"?",curSequence->GetName()))) { tree.DeleteItem(theItem); curModel->DeleteSequence(curSequence); GetDocument()->SetModifiedFlag(); return true; } } } return false; } // also re-orders model(s) sequences to match tree order... // void CAssimilateView::SortTree() { TreeSort(GetTreeCtrl(),TS_BY_ENUMTYPE); // now update models to reflect their positions within the tree struct... // HTREEITEM hTreeItem_Model = GetTreeCtrl().GetRootItem(); // "klingon" while (hTreeItem_Model) { CModel* curModel = (CModel*) GetTreeCtrl().GetItemData(hTreeItem_Model); // OutputDebugString(va("item = '%s'\n",(LPCSTR) GetTreeCtrl().GetItemText(hTreeItem_Model))); int iSequenceNum = 0; HTREEITEM hTreeItem_Sequence = GetTreeCtrl().GetChildItem(hTreeItem_Model); while (hTreeItem_Sequence) { CSequence* curSequence = (CSequence*) GetTreeCtrl().GetItemData(hTreeItem_Sequence); curSequence->m_iSequenceNumber = iSequenceNum++; hTreeItem_Sequence = GetTreeCtrl().GetNextSiblingItem(hTreeItem_Sequence); } curModel->ReOrderSequences(); hTreeItem_Model = GetTreeCtrl().GetNextSiblingItem(hTreeItem_Model); } // sod it, too much work to check if re-ordering actually took place. Let's assume it did... :-) // GetDocument()->SetModifiedFlag(); } // sorts tree according to enum names, sorts model according to new tree, re-draws tree // (re-draw = changes icons & text according to enum-validity and prefs) // void CAssimilateView::UpdateTree() { SortTree(); // sorts tree according to enum names, sorts model according to new tree HTREEITEM hTreeItem_Model = GetTreeCtrl().GetRootItem(); // "klingon" while (hTreeItem_Model) { CModel* curModel = (CModel*) GetTreeCtrl().GetItemData(hTreeItem_Model); // OutputDebugString(va("item = '%s'\n",(LPCSTR) GetTreeCtrl().GetItemText(hTreeItem_Model))); HTREEITEM hTreeItem_Sequence = GetTreeCtrl().GetChildItem(hTreeItem_Model); while (hTreeItem_Sequence) { CSequence* curSequence = (CSequence*) GetTreeCtrl().GetItemData(hTreeItem_Sequence); // OutputDebugString(va("item = '%s'\n",(LPCSTR) GetTreeCtrl().GetItemText(hTreeItem_Sequence))); // gQuakeHelperTreeViewhandle->GetTreeCtrl().SetItemState(hTreeItem, bMatch?TVIS_SELECTED:0, TVIS_SELECTED); // update this tree item accordingly... // CDC *pDC = GetDC(); GetTreeCtrl().SetItemText(hTreeItem_Sequence, curSequence->GetDisplayNameForTree(curModel,gbViewAnimEnums,gbViewFrameDetails,gbViewFrameDetails_Additional,pDC)); ReleaseDC(pDC); int iIcon = curSequence->GetDisplayIconForTree(curModel); GetTreeCtrl().SetItemImage(hTreeItem_Sequence, iIcon, iIcon); hTreeItem_Sequence = GetTreeCtrl().GetNextSiblingItem(hTreeItem_Sequence); } hTreeItem_Model = GetTreeCtrl().GetNextSiblingItem(hTreeItem_Model); } } PlayerMode_e CAssimilateView::GetSingleOrMultiPlayerMode() { PlayerMode_e ePlayerMode = eMODE_BAD; LPCSTR psEnumFilename = ((CAssimilateApp*)AfxGetApp())->GetEnumFilename(); if (psEnumFilename && !stricmp(psEnumFilename,sDEFAULT_ENUM_FILENAME)) ePlayerMode = eMODE_SINGLE; else if (psEnumFilename && !stricmp(psEnumFilename,sDEFAULT_ENUM_FILENAME_MULTI)) ePlayerMode = eMODE_MULTI; return ePlayerMode; } void CAssimilateView::SetFirstModelTitleAndMode() { PlayerMode_e ePlayerMode = GetSingleOrMultiPlayerMode(); CTreeCtrl& tree = GetTreeCtrl(); CModel* curModel = GetDocument()->GetFirstModel(); if (curModel) { HTREEITEM hTreeItem = tree.GetRootItem(); tree.SetItemText(hTreeItem, va("%s: ( %s )",curModel->GetName(), (ePlayerMode == eMODE_SINGLE)?"Single-Player Mode":(ePlayerMode == eMODE_MULTI)?"Multi-Player Mode":"Unknown Mode - Prefs not setup?")); } } void CAssimilateView::BuildTree() { CTreeCtrl& tree = GetTreeCtrl(); CModel* curModel = GetDocument()->GetFirstModel(); while(curModel != NULL) { HTREEITEM item = tree.InsertItem(curModel->GetName()); tree.SetItemData(item, DWORD(curModel)); tree.SetItemImage(item, ObjID_Folder, ObjID_Folder); CSequence* curSequence = curModel->GetFirstSequence(); while(curSequence != NULL) { CDC *pDC = GetDC(); HTREEITEM seqItem = tree.InsertItem(curSequence->GetDisplayNameForTree(curModel,gbViewAnimEnums,gbViewFrameDetails,gbViewFrameDetails_Additional,pDC), item); ReleaseDC(pDC); tree.SetItemData(seqItem, DWORD(curSequence)); /* if (curSequence->ValidEnum()) { tree.SetItemImage(seqItem, ObjID_Sequence, ObjID_Sequence); } else { tree.SetItemImage(seqItem, ObjID_MissingEnum, ObjID_MissingEnum); }*/ int iIcon = curSequence->GetDisplayIconForTree(curModel); tree.SetItemImage(seqItem, iIcon, iIcon); curSequence = curSequence->GetNext(); } curModel = curModel->GetNext(); } SetFirstModelTitleAndMode(); } void CAssimilateView::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult) { // OutputDebugString("double\n"); *pResult = 0; CTreeCtrl& tree = GetTreeCtrl(); HTREEITEM theItem = tree.GetSelectedItem(); if (theItem == NULL) { return; } if (tree.GetParentItem(theItem) == NULL) { CModel* theModel = (CModel*)tree.GetItemData(theItem); if (theModel != NULL) { if (theModel->DoProperties()) { GetDocument()->SetModifiedFlag(); } *pResult = 1; } } else { CSequence* theSequence = (CSequence*)tree.GetItemData(theItem); if (theSequence != NULL) { if (theSequence->DoProperties()) { GetDocument()->SetModifiedFlag(); } *pResult = 1; } } } void CAssimilateView::OnInitialUpdate() { CTreeView::OnInitialUpdate(); // TODO: Add your specialized code here and/or call the base class CImageList *pimagelist; pimagelist = new CImageList(); pimagelist->Create(IDB_TREEIMAGES, 16, FALSE, 0x00ffffff); CTreeCtrl& theTree = GetTreeCtrl(); CImageList* oldImageList; oldImageList = theTree.GetImageList(TVSIL_NORMAL); if (oldImageList != NULL) delete(oldImageList); theTree.SetImageList(pimagelist, TVSIL_NORMAL); } void CAssimilateView::OnDestroy() { CTreeCtrl& theTree = GetTreeCtrl(); CImageList *pimagelist; pimagelist = theTree.GetImageList(TVSIL_NORMAL); if (pimagelist != NULL) { pimagelist->DeleteImageList(); delete pimagelist; } CTreeView::OnDestroy(); // TODO: Add your message handler code here } void CAssimilateView::OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; // TODO: Add your control notification handler code here CTreeCtrl& theTree = GetTreeCtrl(); HTREEITEM curSelection = pNMTreeView->itemNew.hItem; if (theTree.GetParentItem(curSelection) == NULL) { int expandState = theTree.GetItemState(curSelection, TVIS_EXPANDED); if (theTree.GetItemState(curSelection, TVIS_EXPANDED) & TVIS_EXPANDED) { theTree.SetItemImage(curSelection, ObjID_OpenFolder, ObjID_OpenFolder); } else { theTree.SetItemImage(curSelection, ObjID_Folder, ObjID_Folder); } } *pResult = 0; } void CAssimilateView::OnRButtonDblClk(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CTreeCtrl& tree = GetTreeCtrl(); HTREEITEM theItem = tree.GetSelectedItem(); if (theItem == NULL) { CTreeView::OnRButtonDblClk(nFlags, point); return; //don't have an item, don't go on } if (tree.GetParentItem(theItem) == NULL) { CModel* theModel = (CModel*)tree.GetItemData(theItem); if (theModel != NULL) { if (theModel->DoProperties()) { GetDocument()->SetModifiedFlag(); } } } else { /* // fixme: update this stuff some other time CSequence* theSequence = (CSequence*)tree.GetItemData(theItem); if (theSequence != NULL) { if (theSequence->Parse()) { GetDocument()->SetModifiedFlag(); } } */ } } void CAssimilateView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { switch (nChar) { case VK_DELETE: { if (DeleteCurrentItem(!!(GetAsyncKeyState(VK_CONTROL)))) // NoQueryForSequenceDelete if CTRL pressed { UpdateTree(); // sorts tree according to enum names, sorts model according to new tree, re-draws tree } } break; } CTreeView::OnKeyDown(nChar, nRepCnt, nFlags); } // currently tells the document which model is the one the user considers current (ie which one is blue in tree) // void CAssimilateView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) { // OutputDebugString("OnSelchanged TOP\n"); GetDocument()->ClearModelUserSelectionBools(); NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; HTREEITEM theItem = pNMTreeView->itemNew.hItem; if (!theItem) { return; } CTreeCtrl& tree = GetTreeCtrl(); CModel *theModel = NULL; if (tree.GetParentItem(theItem) == NULL) { theModel = (CModel*)tree.GetItemData(theItem); ASSERT(theModel); if (theModel) { theModel->SetUserSelectionBool(); } } else { theModel = (CModel*)tree.GetItemData(tree.GetParentItem(theItem)); ASSERT(theModel); if (theModel) { theModel->SetUserSelectionBool(); } } // OutputDebugString("OnSelchanged\n"); // if (theModel) // { // OutputDebugString(va("Model = %s\n",theModel->GetName())); // } }