jedioutcast/utils/Assimilate/AssimilateView.cpp
2013-04-04 13:07:40 -05:00

617 lines
16 KiB
C++

// 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()));
// }
}