1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 #include "tools/edit_gui_common.h"
29 
30 
31 #include "MaterialTreeView.h"
32 
33 #define IMAGE_FOLDER				0
34 #define IMAGE_FILE					1
35 #define IMAGE_MATERIAL				2
36 #define IMAGE_MATERIAL_FOLDER		3
37 #define IMAGE_FILE_MOD				4
38 #define IMAGE_MATERIAL_MOD			5
39 #define IMAGE_MATERIAL_MOD_APPLY	6
40 
41 #define HOVER_EXPAND_DELAY 500
42 
43 #define MSG_RENAME_FOLDER_COMPLETE (WM_USER + 1000)
44 #define MSG_RENAME_MATERIAL_COMPLETE (WM_USER + 1001)
45 
IMPLEMENT_DYNCREATE(MaterialTreeView,CTreeView)46 IMPLEMENT_DYNCREATE(MaterialTreeView, CTreeView)
47 
48 BEGIN_MESSAGE_MAP(MaterialTreeView, CTreeView)
49 	ON_WM_CREATE()
50 	ON_NOTIFY_REFLECT(TVN_SELCHANGED,		OnTvnSelchanged)
51 	ON_NOTIFY_REFLECT(TVN_BEGINLABELEDIT,	OnTvnBeginlabeledit)
52 	ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT,		OnTvnEndlabeledit)
53 	ON_WM_CONTEXTMENU()
54 	ON_NOTIFY_REFLECT(NM_RCLICK,			OnNMRclick)
55 	ON_WM_CHAR()
56 	ON_NOTIFY_REFLECT(TVN_BEGINDRAG,		OnTvnBegindrag)
57 	ON_WM_MOUSEMOVE()
58 	ON_WM_LBUTTONUP()
59 
60 	ON_COMMAND(ID_POPUP_APPLYMATERIAL,		OnApplyMaterial)
61 	ON_COMMAND(ID_POPUP_APPLYFILE,			OnApplyFile)
62 	ON_COMMAND(ID_POPUP_APPLYALL,			OnApplyAll)
63 	ON_COMMAND(ID_POPUP_SAVEMATERIAL,		OnSaveMaterial)
64 	ON_COMMAND(ID_POPUP_SAVEFILE,			OnSaveFile)
65 	ON_COMMAND(ID_POPUP_SAVEALL,			OnSaveAll)
66 	ON_COMMAND(ID_POPUP_RENAMEMATERIAL,		OnRenameMaterial)
67 	ON_COMMAND(ID_POPUP_ADDMATERIAL,		OnAddMaterial)
68 	ON_COMMAND(ID_POPUP_ADDFOLDER,			OnAddFolder)
69 	ON_COMMAND(ID_POPUP_DELETEMATERIAL,		OnDeleteMaterial)
70 	ON_COMMAND(ID_POPUP_RELOADFILE,			OnReloadFile)
71 
72 	ON_COMMAND(ID_POPUP_CUT,				OnCut)
73 	ON_COMMAND(ID_POPUP_COPY,				OnCopy)
74 	ON_COMMAND(ID_POPUP_PASTE,				OnPaste)
75 
76 	ON_MESSAGE(MSG_RENAME_FOLDER_COMPLETE, OnRenameFolderComplete)
77 	ON_MESSAGE(MSG_RENAME_MATERIAL_COMPLETE, OnRenameMaterialComplete)
78 END_MESSAGE_MAP()
79 
80 /**
81 * Constructor for MaterialTreeView
82 */
83 MaterialTreeView::MaterialTreeView() {
84 	treeWithFile = false;
85 	bDragging = false;
86 	hoverItem = NULL;
87 	internalChange = false;
88 }
89 
90 /**
91 * Destructor for MaterialTreeView
92 */
~MaterialTreeView()93 MaterialTreeView::~MaterialTreeView() {
94 }
95 
96 /**
97 * Clears the tree and rebuilds it.
98 * @param includeFile Should the list include the filename
99 * @param filename The file to load or NULL to load all files.
100 */
InitializeMaterialList(bool includeFile,const char * filename)101 void MaterialTreeView::InitializeMaterialList(bool includeFile, const char* filename) {
102 
103 	treeWithFile = includeFile;
104 
105 	CTreeCtrl& tree = GetTreeCtrl();
106 
107 	tree.DeleteAllItems();
108 	quickTree.Clear();
109 	materialToTree.Clear();
110 	fileToTree.Clear();
111 
112 	BuildMaterialList(includeFile, filename);
113 }
114 
115 /**
116 * Builds the tree of materials.
117 * @param includeFile Should the list include the filename
118 * @param filename The file to load or NULL to load all files.
119 */
BuildMaterialList(bool includeFile,const char * filename)120 void MaterialTreeView::BuildMaterialList(bool includeFile, const char* filename) {
121 
122 	CTreeCtrl& tree = GetTreeCtrl();
123 
124 	idStrList list(1024);
125 
126 	int count = declManager->GetNumDecls( DECL_MATERIAL );
127 	if (count > 0) {
128 		for (int i = 0; i < count; i++) {
129 			const idMaterial	*mat = declManager->MaterialByIndex(i, false);
130 
131 			if(filename && strcmp(filename, mat->GetFileName())) {
132 				continue;
133 			}
134 
135 			idStr temp;
136 
137 			//Do Not Include Implicit File Definitions
138 			idStr filename = mat->GetFileName();
139 			if(!filename.Icmp("<implicit file>")) {
140 				continue;
141 			}
142 
143 			if(filename.Find("def") != -1) {
144 				int x = 0;
145 			}
146 
147 			if(includeFile) {
148 				filename.StripPath();
149 				temp = idStr(mat->GetFileName()) + "/" + idStr(mat->GetName()) + "|" + filename;
150 			} else {
151 				temp = mat->GetName();
152 			}
153 
154 			list.Append(temp);
155 		}
156 		AddStrList(NULL, &list, includeFile);
157 	}
158 }
159 
160 /**
161 * Called when the material has changed but not applied.
162 * @param pMaterial The selected material.
163 */
MV_OnMaterialChange(MaterialDoc * pMaterial)164 void MaterialTreeView::MV_OnMaterialChange(MaterialDoc* pMaterial) {
165 
166 	CTreeCtrl& tree = GetTreeCtrl();
167 
168 	//When a material changes place an asterik next to the material and the file
169 	HTREEITEM* materialItem = NULL;
170 	materialToTree.Get(pMaterial->name, &materialItem);
171 
172 
173 	if(!materialItem)
174 		return;
175 
176 	tree.SetItemImage(*materialItem, IMAGE_MATERIAL_MOD_APPLY, IMAGE_MATERIAL_MOD_APPLY);
177 
178 
179 	if(treeWithFile) {
180 		HTREEITEM* fileItem = NULL;
181 		idStr file = pMaterial->renderMaterial->GetFileName();
182 
183 		//common->Printf("Filename = %s\n", file.c_str());
184 
185 		if(fileToTree.Get(file, &fileItem)){
186 			//common->Printf("Found: %d\n", *fileItem);
187 			tree.SetItemImage(*fileItem, IMAGE_FILE_MOD, IMAGE_FILE_MOD);
188 		}
189 	}
190 }
191 
192 /**
193 * Called when the material changes have been applied.
194 * @param pMaterial The selected material.
195 */
MV_OnMaterialApply(MaterialDoc * pMaterial)196 void MaterialTreeView::MV_OnMaterialApply(MaterialDoc* pMaterial) {
197 	CTreeCtrl& tree = GetTreeCtrl();
198 
199 	//When a material is applied then just change the image to material modified
200 	HTREEITEM* materialItem = NULL;
201 	materialToTree.Get(pMaterial->name, &materialItem);
202 
203 	if(!materialItem)
204 		return;
205 
206 	tree.SetItemImage(*materialItem, IMAGE_MATERIAL_MOD, IMAGE_MATERIAL_MOD);
207 }
208 
209 /**
210 * Called when the material changes have been saved.
211 * @param pMaterial The saved material.
212 */
MV_OnMaterialSaved(MaterialDoc * pMaterial)213 void MaterialTreeView::MV_OnMaterialSaved(MaterialDoc* pMaterial) {
214 	CTreeCtrl& tree = GetTreeCtrl();
215 
216 	//Remove the asterik
217 	HTREEITEM* materialItem = NULL;
218 	materialToTree.Get(pMaterial->name, &materialItem);
219 
220 	//We will get this message for a delete file so the material will not be in the tree
221 	if(materialItem) {
222 		tree.SetItemImage(*materialItem, IMAGE_MATERIAL, IMAGE_MATERIAL);
223 	}
224 
225 	//Check if the file is completely saved
226 	if(treeWithFile) {
227 
228 		if(!materialDocManager->IsFileModified(pMaterial->renderMaterial->GetFileName())) {
229 
230 			HTREEITEM* fileItem = NULL;
231 			idStr file = pMaterial->renderMaterial->GetFileName();
232 
233 			if(fileToTree.Get(file, &fileItem)) {
234 				tree.SetItemImage(*fileItem, IMAGE_FILE, IMAGE_FILE);
235 			}
236 		}
237 	}
238 }
239 
240 /**
241 * Called when a material is added
242 * @param pMaterial The material that was added.
243 */
MV_OnMaterialAdd(MaterialDoc * pMaterial)244 void MaterialTreeView::MV_OnMaterialAdd(MaterialDoc* pMaterial) {
245 
246 	idStrList list(1024);
247 
248 	idMaterial	*mat = pMaterial->renderMaterial;
249 	idStr temp;
250 
251 	if(treeWithFile) {
252 		idStr filename = mat->GetFileName();
253 		filename.StripPath();
254 		temp = idStr(mat->GetFileName()) + "/" + idStr(mat->GetName()) + "|" + filename;
255 	} else {
256 		temp = mat->GetName();
257 	}
258 
259 	list.Append(temp);
260 	AddStrList(NULL, &list, treeWithFile);
261 
262 	//Keep the items sorted
263 	HTREEITEM* item = NULL;
264 	materialToTree.Get(pMaterial->name, &item);
265 	if(*item) {
266 		CTreeCtrl& tree = GetTreeCtrl();
267 		HTREEITEM parent = tree.GetParentItem(*item);
268 		tree.SortChildren(parent);
269 	}
270 
271 	MV_OnMaterialChange(pMaterial);
272 }
273 
274 /**
275 * Called when a material is deleted
276 * @param pMaterial The material that was deleted.
277 */
MV_OnMaterialDelete(MaterialDoc * pMaterial)278 void MaterialTreeView::MV_OnMaterialDelete(MaterialDoc* pMaterial) {
279 
280 	//Our doc told us a material has been deleted. Lets find and remove the item from our tree
281 	HTREEITEM* materialItem = NULL;
282 	materialToTree.Get(pMaterial->name, &materialItem);
283 
284 	CTreeCtrl& tree = GetTreeCtrl();
285 	tree.DeleteItem(*materialItem);
286 
287 	//Remove our old quick lookup value
288 	materialToTree.Remove(pMaterial->name.c_str());
289 }
290 
291 /**
292 * Called when the material name has changed
293 * @param pMaterial The material that was deleted.
294 * @param oldName The old name of the material.
295 */
MV_OnMaterialNameChanged(MaterialDoc * pMaterial,const char * oldName)296 void MaterialTreeView::MV_OnMaterialNameChanged(MaterialDoc* pMaterial, const char* oldName) {
297 
298 	CTreeCtrl& tree = GetTreeCtrl();
299 
300 	if(!internalChange) {
301 
302 		//Delete the old tree item
303 		HTREEITEM* item = NULL;
304 		materialToTree.Get(oldName, &item);
305 		CTreeCtrl& tree = GetTreeCtrl();
306 		HTREEITEM tempItem = *item;
307 		CleanLookupTrees(tempItem);
308 		tree.DeleteItem(tempItem);
309 
310 
311 		//Now add it back
312 		idStrList list(1024);
313 		idMaterial	*mat = pMaterial->renderMaterial;
314 		idStr temp;
315 
316 		if(treeWithFile) {
317 			idStr filename = mat->GetFileName();
318 			filename.StripPath();
319 			temp = idStr(mat->GetFileName()) + "/" + idStr(mat->GetName()) + "|" + filename;
320 		} else {
321 			temp = mat->GetName();
322 		}
323 
324 		list.Append(temp);
325 		AddStrList(NULL, &list, treeWithFile);
326 
327 		//Keep the items sorted
328 		//item = NULL;
329 		materialToTree.Get(pMaterial->name.c_str(), &item);
330 		if(*item) {
331 			CTreeCtrl& tree = GetTreeCtrl();
332 			HTREEITEM parent = tree.GetParentItem(*item);
333 			tree.SortChildren(parent);
334 		}
335 
336 		MV_OnMaterialChange(pMaterial);
337 
338 	}
339 }
340 
341 /**
342 * Called when a file has been reloaded
343 * @param filename The file that was reloaded.
344 */
MV_OnFileReload(const char * filename)345 void MaterialTreeView::MV_OnFileReload(const char* filename) {
346 
347 	HTREEITEM* fileItem = NULL;
348 	fileToTree.Get(filename, &fileItem);
349 
350 	HTREEITEM item = *fileItem;
351 
352 	CTreeCtrl& tree = GetTreeCtrl();
353 	CleanLookupTrees(item);
354 	tree.DeleteItem(item);
355 
356 	BuildMaterialList(treeWithFile, filename);
357 
358 	//Resort the parent to make sure the file is back where it was
359 	HTREEITEM* newItem = NULL;
360 	fileToTree.Get(filename, &newItem);
361 	if(*newItem) {
362 		CTreeCtrl& tree = GetTreeCtrl();
363 		HTREEITEM parent = tree.GetParentItem(*newItem);
364 		tree.SortChildren(parent);
365 	}
366 }
367 
368 /**
369 * Returns true if the user can copy the selected item.
370 */
CanCopy()371 bool MaterialTreeView::CanCopy() {
372 
373 	CTreeCtrl& tree = GetTreeCtrl();
374 
375 	HTREEITEM item = tree.GetSelectedItem();
376 	DWORD itemType = tree.GetItemData(item);
377 
378 	if(item && itemType == TYPE_MATERIAL) {
379 		return true;
380 	} else {
381 		return false;
382 	}
383 }
384 
385 /**
386 * Returns true if the user can paste an item in the copy buffer.
387 */
CanPaste()388 bool MaterialTreeView::CanPaste() {
389 	return materialDocManager->IsCopyMaterial();
390 }
391 
392 /**
393 * Returns true if the user can cut the selected item.
394 */
CanCut()395 bool MaterialTreeView::CanCut() {
396 
397 	CTreeCtrl& tree = GetTreeCtrl();
398 
399 	HTREEITEM item = tree.GetSelectedItem();
400 	DWORD itemType = tree.GetItemData(item);
401 
402 	if(item && itemType == TYPE_MATERIAL) {
403 		return true;
404 	} else {
405 		return false;
406 	}
407 }
408 
409 /**
410 * Returns true if the user can delete the selected item.
411 */
CanDelete()412 bool MaterialTreeView::CanDelete() {
413 
414 	CTreeCtrl& tree = GetTreeCtrl();
415 
416 	HTREEITEM item = tree.GetSelectedItem();
417 	DWORD itemType = tree.GetItemData(item);
418 
419 	if(itemType == TYPE_MATERIAL_FOLDER || itemType == TYPE_MATERIAL) {
420 		return true;
421 	}
422 
423 	return false;
424 }
425 
426 /**
427 * Returns true if the user can rename the selected item.
428 */
CanRename()429 bool MaterialTreeView::CanRename() {
430 
431 	CTreeCtrl& tree = GetTreeCtrl();
432 
433 	HTREEITEM item = tree.GetSelectedItem();
434 	DWORD itemType = tree.GetItemData(item);
435 
436 	if(itemType == TYPE_MATERIAL_FOLDER || itemType == TYPE_MATERIAL) {
437 		return true;
438 	}
439 	return false;
440 }
441 
442 /**
443 * Returns true if the currently selected file needs to be saved.
444 */
CanSaveFile()445 bool MaterialTreeView::CanSaveFile() {
446 
447 	CTreeCtrl& tree = GetTreeCtrl();
448 	HTREEITEM item = tree.GetSelectedItem();
449 
450 	idStr filename;
451 	if(item && GetFileName(item, filename)) {
452 		if(materialDocManager->IsFileModified(filename.c_str()))
453 			return true;
454 		else
455 			return false;
456 	} else {
457 		return false;
458 	}
459 }
460 
461 /**
462 * Returns the filename of currently selected file.
463 */
GetSaveFilename()464 idStr MaterialTreeView::GetSaveFilename() {
465 
466 	CTreeCtrl& tree = GetTreeCtrl();
467 	HTREEITEM item = tree.GetSelectedItem();
468 
469 	idStr filename = "";
470 	if(item) {
471 		if(!GetFileName(item, filename)) {
472 			filename = "";
473 		}
474 	}
475 
476 	return filename;
477 }
478 
479 /**
480 * Searches for a material given the supplied search parameters.
481 * @param searchData The parameters to use for the search.
482 */
FindNextMaterial(MaterialSearchData_t * searchData)483 bool MaterialTreeView::FindNextMaterial(MaterialSearchData_t* searchData) {
484 
485 	CTreeCtrl& tree = GetTreeCtrl();
486 
487 	HTREEITEM selected = tree.GetSelectedItem();
488 	if(!selected) {
489 		selected = tree.GetRootItem();
490 		if(!selected) {
491 			return false;
492 		}
493 	}
494 
495 	//Make sure we are in a file
496 	if(searchData->searchScope == 0) {
497 		DWORD type = tree.GetItemData(selected);
498 		if(type == TYPE_FOLDER || type == TYPE_ROOT)
499 			return false;
500 	}
501 
502 	HTREEITEM search =selected;
503 
504 	while((search = GetNextSeachItem(search, (searchData->searchScope == 0))) != NULL) {
505 		HTREEITEM found = FindNextMaterial(search, searchData);
506 		if(found) {
507 			tree.SelectItem(found);
508 			return true;
509 		}
510 	}
511 	return false;
512 }
513 
514 /**
515 * Searches for a material given the supplied search parameters. Returns the tree item where
516 * the item was found or NULL if no material was found.
517 * @param item The tree item from where to start the search.
518 * @param searchData The parameters to use for the search.
519 */
FindNextMaterial(HTREEITEM item,MaterialSearchData_t * searchData)520 HTREEITEM MaterialTreeView::FindNextMaterial(HTREEITEM item, MaterialSearchData_t* searchData) {
521 
522 	CTreeCtrl& tree = GetTreeCtrl();
523 	DWORD type = tree.GetItemData(item);
524 
525 	if(type == TYPE_MATERIAL) {
526 		//check the tree name first
527 		idStr itemName = tree.GetItemText(item);
528 		int findPos = itemName.Find(searchData->searchText, false);
529 		if(findPos != -1) {
530 			//Todo: Include match whole word
531 			return item;
532 		}
533 
534 		if(!searchData->nameOnly) {
535 			//Check the material
536 			idStr materialName = GetMediaPath(item, TYPE_MATERIAL);
537 			if(materialDocManager->FindMaterial(materialName, searchData, false)) {
538 				return item;
539 			}
540 		}
541 	} else {
542 		//Just check the tree name
543 		idStr itemName = tree.GetItemText(item);
544 
545 		int findPos = itemName.Find(searchData->searchText, false);
546 		if(findPos != -1) {
547 			//Todo: Include match whole word
548 			return item;
549 		}
550 	}
551 	return NULL;
552 }
553 
554 /**
555 * Returns the next item to search or NULL if there is nothing else to search.
556 * @param item The last item searched.
557 * @param stayInFile True if the search should stay in the current file.
558 */
GetNextSeachItem(HTREEITEM item,bool stayInFile)559 HTREEITEM MaterialTreeView::GetNextSeachItem(HTREEITEM item, bool stayInFile) {
560 	CTreeCtrl& tree = GetTreeCtrl();
561 
562 	HTREEITEM nextItem = NULL;
563 
564 	//Check our children
565 	if(tree.ItemHasChildren(item)) {
566 		nextItem = tree.GetChildItem(item);
567 		return nextItem;
568 	}
569 
570 	//Check our siblings
571 	nextItem = tree.GetNextSiblingItem(item);
572 	if(nextItem) {
573 		return nextItem;
574 	}
575 
576 	//Check our parents next sibiling
577 	HTREEITEM parent = item;
578 	while((parent = tree.GetParentItem(parent)) != NULL) {
579 		DWORD parType = tree.GetItemData(parent);
580 		if(stayInFile && parType == TYPE_FILE)
581 			break;
582 
583 		HTREEITEM sib = tree.GetNextSiblingItem(parent);
584 		if(sib) {
585 			nextItem = sib;
586 			break;
587 		}
588 	}
589 	return nextItem;
590 }
591 
592 /**
593 * Deletes a given folder.
594 * @param item The folder to delete.
595 * @param addUndo True if this operation can be undone.
596 */
DeleteFolder(HTREEITEM item,bool addUndo)597 void  MaterialTreeView::DeleteFolder(HTREEITEM item, bool addUndo) {
598 
599 	CTreeCtrl& tree = GetTreeCtrl();
600 
601 	idList<MaterialTreeItem_t> materialsToDelete;
602 
603 	//Get the complete list of materials to delete
604 	GetMaterialPaths(item, &materialsToDelete);
605 
606 	idStrList affectedMaterials;
607 
608 	//Now delete the materials
609 	for(int i = 0; i < materialsToDelete.Num(); i++) {
610 
611 		affectedMaterials.Append(materialsToDelete[i].materialName);
612 
613 		const idMaterial* material = declManager->FindMaterial(materialsToDelete[i].materialName);
614 
615 		MaterialDoc* pMaterial = NULL;
616 		pMaterial = materialDocManager->CreateMaterialDoc(const_cast<idMaterial *>(material));
617 		materialDocManager->DeleteMaterial(pMaterial, false);
618 	}
619 
620 	//Make our undo modifier
621 	if(addUndo) {
622 		DeleteMaterialFolderModifier* mod = new DeleteMaterialFolderModifier(materialDocManager, tree.GetItemText(item), this, tree.GetParentItem(item), &affectedMaterials);
623 		materialDocManager->AddMaterialUndoModifier(mod);
624 	}
625 
626 
627 	//Now clean up the folders and quicktree
628 	CleanLookupTrees(item);
629 
630 	//Remove any folders that were there
631 	tree.DeleteItem(item);
632 }
633 
634 /**
635 * Adds a new material folder.
636 * @param name The name of the folder.
637 * @param parent The parent item of the folder.
638 */
AddFolder(const char * name,HTREEITEM parent)639 HTREEITEM MaterialTreeView::AddFolder(const char* name, HTREEITEM parent) {
640 
641 	CTreeCtrl& tree = GetTreeCtrl();
642 
643 	HTREEITEM newItem = tree.InsertItem(name, parent);
644 	tree.SetItemImage(newItem, IMAGE_MATERIAL_FOLDER, IMAGE_MATERIAL_FOLDER);
645 	tree.SetItemData(newItem, TYPE_MATERIAL_FOLDER);
646 	tree.Expand(newItem, TVE_EXPAND);
647 
648 	//Make sure the tree is still sorted
649 	tree.SortChildren(parent);
650 
651 	//Build the entire path to this item for the quicktree
652 	idStr qt = GetQuicktreePath(newItem);
653 	quickTree.Set(qt, newItem);
654 
655 	return newItem;
656 }
657 
658 /**
659 * Renames a material folder.
660 * @param item The folder tree item.
661 * @param name The new name of the material folder.
662 */
RenameFolder(HTREEITEM item,const char * name)663 void MaterialTreeView::RenameFolder(HTREEITEM item, const char* name) {
664 
665 	CTreeCtrl& tree = GetTreeCtrl();
666 
667 	//Clean up the quicktree with the current tree before we allow the edit to commit
668 	CleanLookupTrees(item);
669 
670 	//Store some data so the we can make the appropriate changes after the commit
671 	renamedFolder = item;
672 
673 	affectedMaterials.Clear();
674 	GetMaterialPaths(renamedFolder, &affectedMaterials);
675 
676 	tree.SetItemText(item, name);
677 
678 	PostMessage(MSG_RENAME_FOLDER_COMPLETE);
679 }
680 
681 /**
682 * Handles the keyboard shortcut for delete.
683 */
PreTranslateMessage(MSG * pMsg)684 BOOL MaterialTreeView::PreTranslateMessage(MSG* pMsg) {
685 
686 	CTreeCtrl& tree = GetTreeCtrl();
687 	if (pMsg->hwnd == tree.GetSafeHwnd()) {
688 
689 		if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_DELETE) {
690 			OnDeleteMaterial();
691 			return TRUE;
692 		}
693 	}
694 	return FALSE;
695 }
696 
697 /**
698 * Called by the MFC framework as the view is being created.
699 */
OnCreate(LPCREATESTRUCT lpCreateStruct)700 int MaterialTreeView::OnCreate(LPCREATESTRUCT lpCreateStruct) {
701 
702 	lpCreateStruct->style |= TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_EDITLABELS | TVS_SHOWSELALWAYS | TVS_INFOTIP;
703 	if (CTreeView::OnCreate(lpCreateStruct) == -1)
704 		return -1;
705 
706 	CTreeCtrl& tree = GetTreeCtrl();
707 	m_image.Create(IDB_ME_TREEBITMAP, 16, 1, RGB(255, 255, 255));
708 	tree.SetImageList(&m_image, TVSIL_NORMAL);
709 
710 	return 0;
711 }
712 
713 /**
714 * Changes the selected material when the select tree item changes.
715 */
OnTvnSelchanged(NMHDR * pNMHDR,LRESULT * pResult)716 void MaterialTreeView::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult) {
717 
718 	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
719 
720 	if(pNMTreeView->itemNew.hItem) {
721 		CTreeCtrl& tree = GetTreeCtrl();
722 
723 		DWORD type = tree.GetItemData(pNMTreeView->itemNew.hItem);
724 		if(type == TYPE_MATERIAL) {
725 			idStr mediaName = GetMediaPath(pNMTreeView->itemNew.hItem, type);
726 			const idMaterial* material = declManager->FindMaterial(mediaName);
727 
728 			materialDocManager->SetSelectedMaterial(const_cast<idMaterial*>(material));
729 
730 		} else {
731 
732 			materialDocManager->SetSelectedMaterial(NULL);
733 		}
734 
735 	} else {
736 
737 		materialDocManager->SetSelectedMaterial(NULL);
738 	}
739 
740 	*pResult = 0;
741 }
742 
743 /**
744 * Determines if a tree item's label can be edited.
745 */
OnTvnBeginlabeledit(NMHDR * pNMHDR,LRESULT * pResult)746 void MaterialTreeView::OnTvnBeginlabeledit(NMHDR *pNMHDR, LRESULT *pResult) {
747 
748 	LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
749 
750 	CTreeCtrl& tree = GetTreeCtrl();
751 	DWORD type = tree.GetItemData(pTVDispInfo->item.hItem);
752 
753 	//Only allow renaming of materials and material folders
754 	if(type == TYPE_MATERIAL || type == TYPE_MATERIAL_FOLDER) {
755 		*pResult = 0;
756 	} else {
757 		*pResult = 1;
758 	}
759 }
760 
761 /**
762 * Makes sure that a rename operation can be performed after a label edit is complete and
763 * performs the folder or material rename.
764 */
OnTvnEndlabeledit(NMHDR * pNMHDR,LRESULT * pResult)765 void MaterialTreeView::OnTvnEndlabeledit(NMHDR *pNMHDR, LRESULT *pResult) {
766 
767 	LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
768 
769 	*pResult = 0;
770 
771 	if(pTVDispInfo->item.pszText) {
772 
773 		//Convert any edited text to lower case to keep the name canonical
774 		idStr newLabel = pTVDispInfo->item.pszText;
775 		newLabel.ToLower();
776 		strncpy( pTVDispInfo->item.pszText, newLabel.c_str(), pTVDispInfo->item.cchTextMax);
777 
778 		CTreeCtrl& tree = GetTreeCtrl();
779 		DWORD type = tree.GetItemData(pTVDispInfo->item.hItem);
780 
781 		if(type == TYPE_MATERIAL) {
782 
783 			MaterialDoc* pMaterial = materialDocManager->GetCurrentMaterialDoc();
784 
785 			//Remove our old quick lookup value
786 			materialToTree.Remove(pMaterial->name.c_str());
787 
788 			//Generate the new name
789 			idStr material;
790 			HTREEITEM parent = tree.GetParentItem(pTVDispInfo->item.hItem);
791 			DWORD parentType = tree.GetItemData(parent);
792 			if(parentType == TYPE_MATERIAL_FOLDER) {
793 				//Need to include the material folder
794 				material = GetMediaPath(parent, TYPE_MATERIAL_FOLDER);
795 				material += "/";
796 			}
797 
798 			material += pTVDispInfo->item.pszText;
799 
800 			if(declManager->FindMaterial(material, false)) {
801 				//Can't rename because it conflicts with an existing file
802 				MessageBox("Unable to rename material because it conflicts with another material", "Error");
803 			} else {
804 				//Add it to our quick lookup
805 				materialToTree.Set(material, pTVDispInfo->item.hItem);
806 
807 				//Finally make the change
808 				internalChange = true;
809 				pMaterial->SetMaterialName(material);
810 				internalChange = false;
811 
812 				renamedFolder = pTVDispInfo->item.hItem;
813 				PostMessage(MSG_RENAME_MATERIAL_COMPLETE);
814 
815 				*pResult = 1;
816 			}
817 
818 		} else if (type == TYPE_MATERIAL_FOLDER) {
819 
820 			//Clean up the quicktree with the current tree before we allow the edit to commit
821 			CleanLookupTrees(pTVDispInfo->item.hItem);
822 
823 			//Store some data so the we can make the appropriate changes after the commit
824 			renamedFolder = pTVDispInfo->item.hItem;
825 
826 			affectedMaterials.Clear();
827 			GetMaterialPaths(renamedFolder, &affectedMaterials);
828 
829 			PostMessage(MSG_RENAME_FOLDER_COMPLETE);
830 
831 			RenameMaterialFolderModifier* mod = new RenameMaterialFolderModifier(materialDocManager, pTVDispInfo->item.pszText, this, pTVDispInfo->item.hItem, tree.GetItemText(pTVDispInfo->item.hItem));
832 			materialDocManager->AddMaterialUndoModifier(mod);
833 
834 			*pResult = 1;
835 		}
836 	}
837 }
838 
839 /**
840 * Displays the popup menu.
841 */
OnContextMenu(CWnd * pWnd,CPoint point)842 void MaterialTreeView::OnContextMenu(CWnd* pWnd, CPoint point)
843 {
844 	ScreenToClient (&point);
845 	PopupMenu (&point);
846 }
847 
848 /**
849 * Displays the popup menu.
850 */
OnNMRclick(NMHDR * pNMHDR,LRESULT * pResult)851 void MaterialTreeView::OnNMRclick(NMHDR *pNMHDR, LRESULT *pResult)
852 {
853 	CTreeCtrl& tree = GetTreeCtrl();
854 
855 	DWORD dwPos = GetMessagePos();
856 
857 	CPoint pt( LOWORD( dwPos ), HIWORD ( dwPos ) );
858 
859 	CPoint spt = pt;
860 	tree.ScreenToClient( &spt );
861 
862 	UINT test;
863 	HTREEITEM item = tree.HitTest( spt, &test );
864 
865 	if ( item != NULL  )
866 	{
867 		if ( test & TVHT_ONITEM )
868 		{
869 			//Select the item
870 			tree.SelectItem(item);
871 			OnContextMenu( this, pt );
872 		}
873 	}
874 
875 	*pResult = 0;
876 }
877 
878 /**
879 * Handles keyboard shortcut for cut, copy and paste
880 */
OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)881 void MaterialTreeView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
882 {
883 	if(nChar == 3 && GetKeyState(VK_CONTROL)) {
884 		OnCopy();
885 	}
886 
887 	if(nChar == 22 && GetKeyState(VK_CONTROL)) {
888 		OnPaste();
889 	}
890 
891 	if(nChar == 24 && GetKeyState(VK_CONTROL)) {
892 		OnCut();
893 	}
894 
895 	CTreeView::OnChar(nChar, nRepCnt, nFlags);
896 }
897 
898 /**
899 * Begins the process of a drag cut/copy.
900 */
OnTvnBegindrag(NMHDR * pNMHDR,LRESULT * pResult)901 void MaterialTreeView::OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
902 {
903 	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
904 
905 	CTreeCtrl& tree = GetTreeCtrl();
906 
907 	HTREEITEM selecteditem = tree.GetSelectedItem();
908 
909 	//Check to see if the are clicking on an item
910 	UINT flags;
911 	HTREEITEM item = tree.HitTest(pNMTreeView->ptDrag, &flags);
912 
913 	if(item && (TVHT_ONITEM & flags)) {
914 		if(item != selecteditem) {
915 			tree.SelectItem(item);
916 		}
917 	}
918 
919 	DWORD itemType = tree.GetItemData(item);
920 
921 	if(itemType == TYPE_MATERIAL) {
922 
923 		//Create the drag image
924 		dragImage = tree.CreateDragImage(item);
925 		dragImage->BeginDrag(0, CPoint (8, 8));
926 		dragImage->DragEnter(GetDesktopWindow(), pNMTreeView->ptDrag);
927 
928 		//Drag is in progress
929 		bDragging = true;
930 
931 		dragItem = item;
932 
933 		//Capture the messages
934 		SetCapture();
935 	}
936 
937 	*pResult = 0;
938 }
939 
940 /**
941 * Handles mouse movement as an item is being dragged.
942 */
OnMouseMove(UINT nFlags,CPoint point)943 void MaterialTreeView::OnMouseMove(UINT nFlags, CPoint point) {
944 	if( bDragging ) {
945 		CTreeCtrl& tree = GetTreeCtrl();
946 
947 		dropPoint = point;
948 		ClientToScreen(&dropPoint);
949 
950 		//Move the drag image
951 		dragImage->DragMove(dropPoint);
952 		dragImage->DragShowNolock(FALSE);
953 
954 		dragImage->DragShowNolock(TRUE);
955 	}
956 
957 	if(bDragging) {
958 		//Test the hover item
959 
960 		CTreeCtrl& tree = GetTreeCtrl();
961 
962 		CPoint point;
963 		GetCursorPos(&point);
964 		ScreenToClient(&point);
965 
966 		UINT flags;
967 		HTREEITEM item = tree.HitTest(point, &flags);
968 		if(item && (TVHT_ONITEM & flags)) {
969 			if(item != hoverItem) {
970 				hoverItem = item;
971 				hoverStartTime = Sys_Milliseconds();
972 			} else {
973 				DWORD currentTime = Sys_Milliseconds();
974 				if(currentTime - hoverStartTime > HOVER_EXPAND_DELAY) {
975 
976 					UINT state = tree.GetItemState(hoverItem, TVIS_EXPANDED);
977 					if(state != TVIS_EXPANDED && tree.ItemHasChildren(hoverItem)) {
978 						tree.Expand(hoverItem, TVE_EXPAND);
979 					}
980 
981 				}
982 			}
983 		}
984 	}
985 
986 	CTreeView::OnMouseMove(nFlags, point);
987 }
988 
989 /**
990 * Handles the end of a drag copy/move when the user releases the left mouse button.
991 */
OnLButtonUp(UINT nFlags,CPoint point)992 void MaterialTreeView::OnLButtonUp(UINT nFlags, CPoint point) {
993 	CTreeCtrl& tree = GetTreeCtrl();
994 
995 	if( bDragging ) {
996 		//Release mouse capture
997 		ReleaseCapture();
998 
999 		//Delete the drag image
1000 		dragImage->DragLeave(GetDesktopWindow());
1001 		dragImage->EndDrag();
1002 
1003 		bDragging = false;
1004 
1005 		delete dragImage;
1006 
1007 		UINT flags;
1008 		HTREEITEM item = tree.HitTest(point, &flags);
1009 		if(item && (TVHT_ONITEM & flags)) {
1010 
1011 			DWORD itemType = tree.GetItemData(item);
1012 
1013 			if(itemType == TYPE_MATERIAL) //Backup one if a file is selected
1014 				item = tree.GetParentItem(item);
1015 
1016 			//Make sure we aren't dragging to the same place
1017 			HTREEITEM dragItemParent = tree.GetParentItem(dragItem);
1018 			if(dragItemParent != item) {
1019 
1020 
1021 				idStr dragFile;
1022 				GetFileName(dragItem, dragFile);
1023 
1024 				idStr filename;
1025 				GetFileName(item, filename);
1026 
1027 				//Move within a file copy across files
1028 				if(!dragFile.Icmp(filename)) {
1029 					materialDocManager->CopyMaterial(materialDocManager->GetCurrentMaterialDoc(), true);
1030 				} else {
1031 					materialDocManager->CopyMaterial(materialDocManager->GetCurrentMaterialDoc(), false);
1032 				}
1033 
1034 				//Generate the name
1035 
1036 				idStr materialName = GetMediaPath(item, itemType);
1037 
1038 				idStr copyName = materialDocManager->GetCopyMaterialName();
1039 				idStr copyMaterialName;
1040 				copyName.ExtractFileName(copyMaterialName);
1041 				materialName += "/" + copyMaterialName;
1042 
1043 				//If the material name already exists add numbers until we don't find it
1044 				materialName = materialDocManager->GetUniqueMaterialName(materialName);
1045 
1046 				//Paste
1047 				materialDocManager->PasteMaterial(materialName, filename);
1048 			}
1049 		}
1050 	}
1051 
1052 	CTreeView::OnLButtonUp(nFlags, point);
1053 }
1054 
1055 /**
1056 * Applies the current material.
1057 */
OnApplyMaterial()1058 void MaterialTreeView::OnApplyMaterial() {
1059 	materialDocManager->ApplyMaterial(materialDocManager->GetCurrentMaterialDoc());
1060 }
1061 
1062 /**
1063 * Applies all materials in the currently selected file.
1064 */
OnApplyFile()1065 void MaterialTreeView::OnApplyFile() {
1066 	idStr filename;
1067 	HTREEITEM item = GetTreeCtrl().GetSelectedItem();
1068 	if(GetFileName(item, filename)) {
1069 		materialDocManager->ApplyFile(filename.c_str());
1070 	}
1071 }
1072 
1073 /**
1074 * Applies all materials that need to be applied.
1075 */
OnApplyAll()1076 void MaterialTreeView::OnApplyAll() {
1077 	materialDocManager->ApplyAll();
1078 }
1079 
1080 /**
1081 * Saves the selected material.
1082 */
OnSaveMaterial()1083 void MaterialTreeView::OnSaveMaterial() {
1084 	materialDocManager->SaveMaterial(materialDocManager->GetCurrentMaterialDoc());
1085 }
1086 
1087 /**
1088 * Saves all materials in the selected file.
1089 */
OnSaveFile()1090 void MaterialTreeView::OnSaveFile() {
1091 	idStr filename;
1092 	HTREEITEM item = GetTreeCtrl().GetSelectedItem();
1093 	if(GetFileName(item, filename)) {
1094 		materialDocManager->SaveFile(filename.c_str());
1095 	}
1096 }
1097 
1098 /**
1099 * Save all materials that have been changed.
1100 */
OnSaveAll()1101 void MaterialTreeView::OnSaveAll() {
1102 	materialDocManager->SaveAllMaterials();
1103 }
1104 
1105 /**
1106 * Begins a label edit to rename a material or material folder.
1107 */
OnRenameMaterial()1108 void MaterialTreeView::OnRenameMaterial() {
1109 
1110 	CTreeCtrl& tree = GetTreeCtrl();
1111 
1112 	HTREEITEM item = tree.GetSelectedItem();
1113 	tree.EditLabel(item);
1114 }
1115 
1116 /**
1117 * Adds a new material.
1118 */
OnAddMaterial()1119 void MaterialTreeView::OnAddMaterial() {
1120 
1121 	CTreeCtrl& tree = GetTreeCtrl();
1122 
1123 	HTREEITEM item = tree.GetSelectedItem();
1124 	DWORD itemType = tree.GetItemData(item);
1125 
1126 	//Determine the file
1127 	HTREEITEM parent = NULL;
1128 	if(itemType != TYPE_FILE) {
1129 
1130 		parent = tree.GetParentItem(item);
1131 		while(1) {
1132 			if(tree.GetItemData(parent) == TYPE_FILE)
1133 				break;
1134 			parent = tree.GetParentItem(parent);
1135 		}
1136 	} else {
1137 		parent = item;
1138 	}
1139 	idStr filename = GetMediaPath(parent, TYPE_FILE);
1140 
1141 
1142 	//Determine the material folder
1143 	idStr materialFolder = "";
1144 	switch(itemType) {
1145 		case TYPE_MATERIAL:
1146 			{
1147 				HTREEITEM parentFolderItem = tree.GetParentItem(item);
1148 				if(tree.GetItemData(parentFolderItem) == TYPE_MATERIAL_FOLDER)
1149 					materialFolder = GetMediaPath(parentFolderItem, TYPE_MATERIAL_FOLDER);
1150 			}
1151 			break;
1152 		case TYPE_MATERIAL_FOLDER:
1153 			materialFolder = GetMediaPath(item, TYPE_MATERIAL_FOLDER);
1154 			break;
1155 		case TYPE_FILE:
1156 			//There is no material folder
1157 			break;
1158 	}
1159 
1160 	idStr name;
1161 	int num = 1;
1162 	while(1) {
1163 		if(materialFolder.Length() > 0) {
1164 			name = va("%s/newmaterial%d", materialFolder.c_str(), num);
1165 		} else {
1166 			name = va("newmaterial%d", num);
1167 		}
1168 		if(!declManager->FindMaterial(name, false))
1169 			break;
1170 		num++;
1171 	}
1172 
1173 	materialDocManager->AddMaterial(name.c_str(), filename.c_str());
1174 
1175 }
1176 
1177 /**
1178 * Adds a new folder
1179 */
OnAddFolder()1180 void MaterialTreeView::OnAddFolder() {
1181 
1182 	CTreeCtrl& tree = GetTreeCtrl();
1183 
1184 	HTREEITEM item = tree.GetSelectedItem();
1185 	DWORD itemType = tree.GetItemData(item);
1186 
1187 
1188 	//Backup if the selected item is a material
1189 	if(itemType == TYPE_MATERIAL) {
1190 		item = tree.GetParentItem(item);
1191 	}
1192 
1193 	//Pick a unique material name
1194 	idStr newFolder;
1195 	int num = 1;
1196 	while(1) {
1197 		newFolder = va("newfolder%d", num);
1198 		if(tree.ItemHasChildren(item)) {
1199 			HTREEITEM hChildItem = tree.GetChildItem(item);
1200 			bool found = false;
1201 			while (hChildItem != NULL)
1202 			{
1203 				if(!newFolder.Icmp(tree.GetItemText(hChildItem))) {
1204 					found = true;
1205 					break;
1206 				}
1207 				hChildItem = tree.GetNextSiblingItem(hChildItem);
1208 			}
1209 			if(!found)
1210 				break;
1211 		} else {
1212 			break;
1213 		}
1214 		num++;
1215 	}
1216 
1217 	HTREEITEM newItem = AddFolder(newFolder, item);
1218 
1219 	AddMaterialFolderModifier* mod = new AddMaterialFolderModifier(materialDocManager, newFolder, this, newItem, item);
1220 	materialDocManager->AddMaterialUndoModifier(mod);
1221 }
1222 
1223 /**
1224 * Deletes a material or material folder.
1225 */
OnDeleteMaterial()1226 void MaterialTreeView::OnDeleteMaterial() {
1227 
1228 	CTreeCtrl& tree = GetTreeCtrl();
1229 
1230 	HTREEITEM item = tree.GetSelectedItem();
1231 	DWORD itemType = tree.GetItemData(item);
1232 
1233 	if(itemType == TYPE_MATERIAL_FOLDER) {
1234 		int result = MessageBox("Are you sure you want to delete this folder?", "Delete?", MB_ICONQUESTION | MB_YESNO);
1235 		if(result == IDYES) {
1236 			DeleteFolder(item);
1237 		}
1238 	} else if (itemType == TYPE_MATERIAL) {
1239 		int result = MessageBox("Are you sure you want to delete this material?", "Delete?", MB_ICONQUESTION | MB_YESNO);
1240 		if(result == IDYES) {
1241 			materialDocManager->DeleteMaterial(materialDocManager->GetCurrentMaterialDoc());
1242 		}
1243 	}
1244 }
1245 
1246 /**
1247 * Reloads the selected file.
1248 */
OnReloadFile()1249 void MaterialTreeView::OnReloadFile() {
1250 
1251 	CTreeCtrl& tree = GetTreeCtrl();
1252 
1253 	HTREEITEM item = tree.GetSelectedItem();
1254 	DWORD itemType = tree.GetItemData(item);
1255 
1256 	if(itemType == TYPE_MATERIAL || itemType == TYPE_FILE || itemType == TYPE_MATERIAL_FOLDER) {
1257 		idStr filename;
1258 		GetFileName(item, filename);
1259 
1260 		if(materialDocManager->IsFileModified(filename)) {
1261 			int result = MessageBox("This file has been modified. Are you sure you want to reload this file?", "Reload?", MB_ICONQUESTION | MB_YESNO);
1262 			if(result != IDYES) {
1263 				return;
1264 			}
1265 		}
1266 		materialDocManager->ReloadFile(filename);
1267 	}
1268 }
1269 
1270 /**
1271 * Performs a cut operation.
1272 */
OnCut()1273 void MaterialTreeView::OnCut() {
1274 	CTreeCtrl& tree = GetTreeCtrl();
1275 
1276 	HTREEITEM item = tree.GetSelectedItem();
1277 	DWORD itemType = tree.GetItemData(item);
1278 
1279 	if(item && itemType == TYPE_MATERIAL) {
1280 		materialDocManager->CopyMaterial(materialDocManager->GetCurrentMaterialDoc(), true);
1281 	} else if (itemType == TYPE_MATERIAL_FOLDER) {
1282 	}
1283 }
1284 
1285 /**
1286 * Performs a copy operation.
1287 */
OnCopy()1288 void MaterialTreeView::OnCopy() {
1289 
1290 	CTreeCtrl& tree = GetTreeCtrl();
1291 
1292 	HTREEITEM item = tree.GetSelectedItem();
1293 	DWORD itemType = tree.GetItemData(item);
1294 
1295 	if(itemType == TYPE_MATERIAL) {
1296 		materialDocManager->CopyMaterial(materialDocManager->GetCurrentMaterialDoc(), false);
1297 	} else if (itemType == TYPE_MATERIAL_FOLDER) {
1298 	}
1299 }
1300 
1301 /**
1302 * Performs a paste operation.
1303 */
OnPaste()1304 void MaterialTreeView::OnPaste() {
1305 
1306 	CTreeCtrl& tree = GetTreeCtrl();
1307 
1308 	HTREEITEM item = tree.GetSelectedItem();
1309 	DWORD itemType = tree.GetItemData(item);
1310 
1311 	//Paste a material
1312 	if(item && materialDocManager->IsCopyMaterial() && itemType >= TYPE_FILE) {
1313 
1314 		//Generate the name
1315 		if(itemType == TYPE_MATERIAL) {//Backup one if a file is selected
1316 			item = tree.GetParentItem(item);
1317 			itemType = tree.GetItemData(item);
1318 		}
1319 
1320 		idStr materialName = "";
1321 		if(itemType != TYPE_FILE) {
1322 			materialName = GetMediaPath(item, itemType) + "/";
1323 		}
1324 
1325 		idStr copyName = materialDocManager->GetCopyMaterialName();
1326 		idStr copyMaterialName;
1327 		copyName.ExtractFileName(copyMaterialName);
1328 		materialName += copyMaterialName;
1329 
1330 		idStr filename;
1331 		GetFileName(item, filename);
1332 
1333 		//If the material name already exists add numbers until we don't find it
1334 		materialName = materialDocManager->GetUniqueMaterialName(materialName);
1335 
1336 		//Paste
1337 		materialDocManager->PasteMaterial(materialName, filename);
1338 
1339 	}
1340 }
1341 
1342 /**
1343 * This message is sent after the label edit is complete to actually perform the rename
1344 * operation.
1345 */
OnRenameFolderComplete(WPARAM wParam,LPARAM lParam)1346 LRESULT MaterialTreeView::OnRenameFolderComplete(WPARAM wParam, LPARAM lParam) {
1347 
1348 	//Generate new quick tree info for all material folders
1349 	BuildLookupTrees(renamedFolder);
1350 
1351 	//Go through the list of affected materials and rename them
1352 	for(int i = 0; i < affectedMaterials.Num(); i++) {
1353 		RenameMaterial(affectedMaterials[i].treeItem, affectedMaterials[i].materialName);
1354 	}
1355 
1356 	//Make sure the tree stays sorted
1357 	CTreeCtrl& tree = GetTreeCtrl();
1358 	HTREEITEM parent = tree.GetParentItem(renamedFolder);
1359 	tree.SortChildren(parent);
1360 
1361 	return 0;
1362 }
1363 
1364 /**
1365 * This message is sent after the label edit is complete to ensure that the sorting stays consistent.
1366 */
OnRenameMaterialComplete(WPARAM wParam,LPARAM lParam)1367 LRESULT MaterialTreeView::OnRenameMaterialComplete(WPARAM wParam, LPARAM lParam) {
1368 
1369 	//Make sure the tree stays sorted
1370 	CTreeCtrl& tree = GetTreeCtrl();
1371 	HTREEITEM parent = tree.GetParentItem(renamedFolder);
1372 	tree.SortChildren(parent);
1373 
1374 	return 0;
1375 }
1376 
1377 /**
1378 * Handles all of the little problems associated with renaming a folder.
1379 */
RenameMaterial(HTREEITEM item,const char * originalName)1380 void MaterialTreeView::RenameMaterial(HTREEITEM item, const char* originalName) {
1381 
1382 	CTreeCtrl& tree = GetTreeCtrl();
1383 
1384 	const idMaterial* material = declManager->FindMaterial(originalName);
1385 
1386 	MaterialDoc* pMaterial;
1387 	//pMaterial = materialDocManager->GetInProgressDoc(material);
1388 
1389 	//if(!pMaterial) {
1390 	pMaterial = materialDocManager->CreateMaterialDoc(const_cast<idMaterial *>(material));
1391 	//}
1392 
1393 	//Remove our old quick lookup value
1394 	materialToTree.Remove(originalName);
1395 
1396 	//Generate the new name
1397 	idStr materialName;
1398 	HTREEITEM parent = tree.GetParentItem(item);
1399 	DWORD parentType = tree.GetItemData(parent);
1400 	if(parentType == TYPE_MATERIAL_FOLDER) {
1401 		//Need to include the material folder
1402 		materialName = GetMediaPath(parent, TYPE_MATERIAL_FOLDER);
1403 		materialName += "/";
1404 	}
1405 	materialName += tree.GetItemText(item);
1406 
1407 
1408 	//Add it to our quick lookup
1409 	materialToTree.Set(materialName, item);
1410 
1411 	//Finally make the change
1412 	internalChange = true;
1413 	pMaterial->SetMaterialName(materialName, false);
1414 	internalChange = false;
1415 }
1416 
1417 /**
1418 * Returns the filename of the provided item.
1419 * @param item The item for which to generate the filename
1420 * @param out The location the filename will be placed.
1421 */
GetFileName(HTREEITEM item,idStr & out)1422 bool MaterialTreeView::GetFileName(HTREEITEM item, idStr& out) {
1423 
1424 	out = "";
1425 
1426 	CTreeCtrl& tree = GetTreeCtrl();
1427 	DWORD type = tree.GetItemData(item);
1428 
1429 	if(type != TYPE_MATERIAL && type != TYPE_MATERIAL_FOLDER && type != TYPE_FILE)
1430 		return false;
1431 
1432 	if(type == TYPE_FILE) {
1433 		out = GetMediaPath(item, TYPE_FILE);
1434 		return true;
1435 	}
1436 
1437 	HTREEITEM parent = tree.GetParentItem( item );
1438 	while ( parent != NULL ) {
1439 		DWORD parentType = tree.GetItemData(parent);
1440 		if(parentType == TYPE_FILE) {
1441 			out = GetMediaPath(parent, TYPE_FILE);
1442 			return true;
1443 		}
1444 		parent = tree.GetParentItem( parent );
1445 	}
1446 
1447 	return false;
1448 }
1449 
1450 /**
1451 * Returns the Doom III name for the provided item
1452 * @param item The item for which to generate the name
1453 * @param type The type of the selected item
1454 */
GetMediaPath(HTREEITEM item,DWORD type)1455 idStr MaterialTreeView::GetMediaPath(HTREEITEM item, DWORD type) {
1456 
1457 	//Determine when to stop building the path
1458 	DWORD stopType = TYPE_ROOT;
1459 	switch(type) {
1460 		case TYPE_MATERIAL:
1461 			stopType = TYPE_FILE;
1462 			break;
1463 		case TYPE_MATERIAL_FOLDER:
1464 			stopType = TYPE_FILE;
1465 			break;
1466 		case TYPE_FILE:
1467 			stopType = TYPE_ROOT;
1468 			break;
1469 	};
1470 
1471 	CTreeCtrl& tree = GetTreeCtrl();
1472 
1473 	idStr mediaName = tree.GetItemText( item );
1474 
1475 	// have to build the name back up
1476 	HTREEITEM parent = tree.GetParentItem( item );
1477 	while ( parent != NULL ) {
1478 
1479 		//stop the iteration once we have found a specific type
1480 		DWORD parentType = tree.GetItemData(parent);
1481 		if(parentType == stopType) {
1482 			break;
1483 		}
1484 
1485 		idStr strParent = tree.GetItemText( parent );
1486 		strParent += "/";
1487 		strParent += mediaName;
1488 		mediaName = strParent;
1489 		parent = tree.GetParentItem( parent );
1490 
1491 	}
1492 
1493 	return mediaName;
1494 }
1495 
1496 /**
1497 * Creates a list of material paths for all materials under the provided item.
1498 * @param item The base item for which to generate the list
1499 * @param list The list in which the paths will be stored.
1500 */
GetMaterialPaths(HTREEITEM item,idList<MaterialTreeItem_t> * list)1501 void MaterialTreeView::GetMaterialPaths(HTREEITEM item, idList<MaterialTreeItem_t>* list) {
1502 
1503 	CTreeCtrl& tree = GetTreeCtrl();
1504 	if(tree.ItemHasChildren(item)) {
1505 
1506 		HTREEITEM childItem = tree.GetChildItem(item);
1507 		while(childItem != NULL) {
1508 
1509 			DWORD childType = tree.GetItemData(childItem);
1510 			if (childType == TYPE_MATERIAL) {
1511 				MaterialTreeItem_t mat;
1512 				mat.materialName = GetMediaPath(childItem, TYPE_MATERIAL);
1513 				mat.treeItem = childItem;
1514 				list->Append(mat);
1515 			} else if (childType == TYPE_MATERIAL_FOLDER) {
1516 				GetMaterialPaths(childItem, list);
1517 			}
1518 			childItem = tree.GetNextSiblingItem(childItem);
1519 		}
1520 	}
1521 }
1522 
1523 /**
1524 * Adds a string list of materials to the tree creating the proper hierarchy.
1525 * @param root The name of the root item or NULL for no root item.
1526 * @param list The list of materials.
1527 * @param includeFile If true the materials will be sorted by file.
1528 */
AddStrList(const char * root,idStrList * list,bool includeFile)1529 void MaterialTreeView::AddStrList(const char *root, idStrList *list, bool includeFile) {
1530 
1531 	CTreeCtrl& treeMedia = GetTreeCtrl();
1532 
1533 	idStr		out, path;
1534 	HTREEITEM	base = NULL;
1535 
1536 	if(root) {
1537 		base = treeMedia.GetRootItem();
1538 		if (base) {
1539 			out = treeMedia.GetItemText(base);
1540 			if (stricmp(root, out)) {
1541 				base = NULL;
1542 			}
1543 		}
1544 
1545 		if (base == NULL) {
1546 			base = treeMedia.InsertItem(root);
1547 			treeMedia.SetItemData(base, TYPE_ROOT);
1548 		}
1549 	}
1550 
1551 	HTREEITEM	item = base;
1552 	HTREEITEM	add;
1553 
1554 	list->Sort();
1555 	int	count = list->Num();
1556 
1557 	idStr	last, qt;
1558 	for (int i = 0; i < count; i++) {
1559 		idStr *strItem = &(*list)[i];
1560 
1561 
1562 		idStr name = strItem->c_str();
1563 
1564 		idStr filename;
1565 		bool afterFile = true;
1566 		if(includeFile) {
1567 			int index = name.Find("|");
1568 			if(index >= 0) {
1569 				afterFile = false;
1570 				filename = name.Right(name.Length() - index - 1);
1571 				name = name.Left(index);
1572 			}
1573 		}
1574 
1575 		// now break the name down convert to slashes
1576 		name.BackSlashesToSlashes();
1577 		name.Strip(' ');
1578 
1579 		int index;
1580 		int len = last.Length();
1581 		if (len == 0) {
1582 			index = name.Last('/');
1583 			if (index >= 0) {
1584 				name.Left(index, last);
1585 			}
1586 		}
1587 		else if (idStr::Icmpn(last, name, len) == 0 && name.Last('/') <= len) {
1588 			name.Right(name.Length() - len - 1, out);
1589 			add = treeMedia.InsertItem(out, item);
1590 			qt = root;
1591 			qt += "/";
1592 			qt += name;
1593 			quickTree.Set(qt, add);
1594 			treeMedia.SetItemImage(add, IMAGE_MATERIAL, IMAGE_MATERIAL);
1595 			treeMedia.SetItemData(add, TYPE_MATERIAL);
1596 
1597 			//Add the item to a quick lookup table
1598 			idStr material = GetMediaPath(add, TYPE_MATERIAL);
1599 			materialToTree.Set(material, add);
1600 
1601 			continue;
1602 		}
1603 		else {
1604 			last.Empty();
1605 		}
1606 
1607 		index = 0;
1608 		item = base;
1609 		path = "";
1610 		while (index >= 0) {
1611 			index = name.Find('/');
1612 			if (index >= 0) {
1613 				HTREEITEM newItem = NULL;
1614 				HTREEITEM *check = NULL;
1615 				name.Left(index, out);
1616 				path += out;
1617 				qt = root;
1618 				qt += "/";
1619 				qt += path;
1620 				if (quickTree.Get(qt, &check)) {
1621 					newItem = *check;
1622 				}
1623 
1624 				bool thisisfile = false;
1625 				if(out == filename) {
1626 					thisisfile = true;
1627 					afterFile = true;
1628 
1629 				}
1630 
1631 				if (newItem == NULL) {
1632 					newItem = treeMedia.InsertItem(out, item);
1633 					qt = root;
1634 					qt += "/";
1635 					qt += path;
1636 					quickTree.Set(qt, newItem);
1637 
1638 
1639 					if(!afterFile || thisisfile) {
1640 						if(thisisfile) {
1641 							afterFile = true;
1642 							treeMedia.SetItemImage(newItem, IMAGE_FILE, IMAGE_FILE);
1643 							treeMedia.SetItemData(newItem, TYPE_FILE);
1644 
1645 							//Add the item to a quick lookup table
1646 							idStr file = GetMediaPath(newItem, TYPE_FILE);
1647 							//common->Printf("Adding fileToTree: %s - %d\n", file.c_str(), newItem);
1648 							fileToTree.Set(file, newItem);
1649 
1650 						} else {
1651 							treeMedia.SetItemImage(newItem, IMAGE_FOLDER, IMAGE_FOLDER);
1652 							treeMedia.SetItemData(newItem, TYPE_FOLDER);
1653 						}
1654 					} else {
1655 						treeMedia.SetItemImage(newItem, IMAGE_MATERIAL_FOLDER, IMAGE_MATERIAL_FOLDER);
1656 						treeMedia.SetItemData(newItem, TYPE_MATERIAL_FOLDER);
1657 
1658 					}
1659 				}
1660 
1661 
1662 				item = newItem;
1663 				name.Right(name.Length() - index - 1, out);
1664 				name = out;
1665 				path += "/";
1666 			}
1667 			else {
1668 				add = treeMedia.InsertItem(name, item);
1669 				qt = root;
1670 				qt += "/";
1671 				qt += path;
1672 				qt += name;
1673 				quickTree.Set(qt, add);
1674 				treeMedia.SetItemImage(add, IMAGE_MATERIAL, IMAGE_MATERIAL);
1675 				treeMedia.SetItemData(add, TYPE_MATERIAL);
1676 				path = "";
1677 
1678 				//Add the item to a quick lookup table
1679 				idStr material = GetMediaPath(add, TYPE_MATERIAL);
1680 				materialToTree.Set(material, add);
1681 			}
1682 		}
1683 	}
1684 }
1685 
1686 /**
1687 * Displays the popup menu with all of the appropriate menu items enabled.
1688 * @param pt The location where the menu should be displayed.
1689 */
PopupMenu(CPoint * pt)1690 void MaterialTreeView::PopupMenu(CPoint* pt) {
1691 
1692 	//Determine the type of object clicked on
1693 	CTreeCtrl& tree = GetTreeCtrl();
1694 	UINT test;
1695 	HTREEITEM item = tree.HitTest( *pt, &test );
1696 	if ( item == NULL ||  !(test & TVHT_ONITEM) )
1697 		return;
1698 
1699 	ClientToScreen (pt);
1700 
1701 	CMenu FloatingMenu;
1702 	VERIFY(FloatingMenu.LoadMenu(IDR_ME_MATERIALTREE_POPUP));
1703 	CMenu* pPopupMenu = FloatingMenu.GetSubMenu (0);
1704 
1705 	DWORD itemType = tree.GetItemData(item);
1706 
1707 	//Enable/Disable based on the state
1708 	MaterialDoc* pDoc = materialDocManager->GetCurrentMaterialDoc();
1709 
1710 
1711 	//Apply Changes
1712 	if(pDoc && pDoc->applyWaiting) {
1713 		pPopupMenu->EnableMenuItem(ID_POPUP_APPLYMATERIAL, MF_BYCOMMAND | MF_ENABLED);
1714 	} else {
1715 		pPopupMenu->EnableMenuItem(ID_POPUP_APPLYMATERIAL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1716 	}
1717 
1718 	//Apply File
1719 	idStr filename;
1720 	if(GetFileName(item, filename)) {
1721 		if(materialDocManager->DoesFileNeedApply(filename.c_str()))
1722 			pPopupMenu->EnableMenuItem(ID_POPUP_APPLYFILE, MF_BYCOMMAND | MF_ENABLED);
1723 		else
1724 			pPopupMenu->EnableMenuItem(ID_POPUP_APPLYFILE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1725 	} else {
1726 		pPopupMenu->EnableMenuItem(ID_POPUP_APPLYFILE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1727 	}
1728 
1729 	//Apply All
1730 	if(materialDocManager->DoesAnyNeedApply()) {
1731 		pPopupMenu->EnableMenuItem(ID_POPUP_APPLYALL, MF_BYCOMMAND | MF_ENABLED);
1732 	} else {
1733 		pPopupMenu->EnableMenuItem(ID_POPUP_APPLYALL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1734 	}
1735 
1736 	//Save Material
1737 	if(pDoc && pDoc->modified) {
1738 		pPopupMenu->EnableMenuItem(ID_POPUP_SAVEMATERIAL, MF_BYCOMMAND | MF_ENABLED);
1739 	} else {
1740 		pPopupMenu->EnableMenuItem(ID_POPUP_SAVEMATERIAL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1741 	}
1742 
1743 	//Save File
1744 	if(GetFileName(item, filename)) {
1745 		if(materialDocManager->IsFileModified(filename.c_str()))
1746 			pPopupMenu->EnableMenuItem(ID_POPUP_SAVEFILE, MF_BYCOMMAND | MF_ENABLED);
1747 		else
1748 			pPopupMenu->EnableMenuItem(ID_POPUP_SAVEFILE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1749 	} else {
1750 		pPopupMenu->EnableMenuItem(ID_POPUP_SAVEFILE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1751 	}
1752 
1753 	//Save All
1754 	if(materialDocManager->IsAnyModified()) {
1755 		pPopupMenu->EnableMenuItem(ID_POPUP_SAVEALL, MF_BYCOMMAND | MF_ENABLED);
1756 	} else {
1757 		pPopupMenu->EnableMenuItem(ID_POPUP_SAVEALL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1758 	}
1759 
1760 	if(itemType == TYPE_MATERIAL || itemType == TYPE_MATERIAL_FOLDER) {
1761 		pPopupMenu->EnableMenuItem(ID_POPUP_RENAMEMATERIAL, MF_BYCOMMAND | MF_ENABLED);
1762 		pPopupMenu->EnableMenuItem(ID_POPUP_DELETEMATERIAL, MF_BYCOMMAND | MF_ENABLED);
1763 	} else {
1764 		pPopupMenu->EnableMenuItem(ID_POPUP_RENAMEMATERIAL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1765 		pPopupMenu->EnableMenuItem(ID_POPUP_DELETEMATERIAL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1766 	}
1767 
1768 	if(itemType == TYPE_FILE || itemType == TYPE_MATERIAL_FOLDER || itemType == TYPE_MATERIAL) {
1769 		pPopupMenu->EnableMenuItem(ID_POPUP_ADDMATERIAL, MF_BYCOMMAND | MF_ENABLED);
1770 		pPopupMenu->EnableMenuItem(ID_POPUP_ADDFOLDER, MF_BYCOMMAND | MF_ENABLED);
1771 	} else {
1772 		pPopupMenu->EnableMenuItem(ID_POPUP_ADDMATERIAL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1773 		pPopupMenu->EnableMenuItem(ID_POPUP_ADDFOLDER, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1774 	}
1775 
1776 	if(itemType == TYPE_MATERIAL) {
1777 		pPopupMenu->EnableMenuItem(ID_POPUP_CUT, MF_BYCOMMAND | MF_ENABLED);
1778 		pPopupMenu->EnableMenuItem(ID_POPUP_COPY, MF_BYCOMMAND | MF_ENABLED);
1779 	} else {
1780 		pPopupMenu->EnableMenuItem(ID_POPUP_CUT, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1781 		pPopupMenu->EnableMenuItem(ID_POPUP_COPY, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1782 	}
1783 
1784 	if((itemType == TYPE_MATERIAL || itemType == TYPE_FILE || itemType == TYPE_MATERIAL_FOLDER) && materialDocManager->IsCopyMaterial()) {
1785 		pPopupMenu->EnableMenuItem(ID_POPUP_PASTE, MF_BYCOMMAND | MF_ENABLED);
1786 	} else {
1787 		pPopupMenu->EnableMenuItem(ID_POPUP_PASTE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1788 	}
1789 
1790 	if(itemType == TYPE_MATERIAL || itemType == TYPE_FILE || itemType == TYPE_MATERIAL_FOLDER) {
1791 		pPopupMenu->EnableMenuItem(ID_POPUP_RELOADFILE, MF_BYCOMMAND | MF_ENABLED);
1792 	} else {
1793 		pPopupMenu->EnableMenuItem(ID_POPUP_RELOADFILE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1794 	}
1795 
1796 	pPopupMenu->TrackPopupMenu (TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt->x, pt->y, &GetTreeCtrl());
1797 }
1798 
1799 /**
1800 * Sets the appropriate item image based on the state of the item.
1801 * @param item The item to set.
1802 * @param mod Is the item modified
1803 * @param apply Does the item need an apply
1804 * @param children Should this method recurse through the items children and set their icons.
1805 */
SetItemImage(HTREEITEM item,bool mod,bool apply,bool children)1806 void MaterialTreeView::SetItemImage(HTREEITEM item, bool mod, bool apply, bool children) {
1807 
1808 	CTreeCtrl& tree = GetTreeCtrl();
1809 
1810 	int image;
1811 
1812 	DWORD itemType = tree.GetItemData(item);
1813 	switch(itemType) {
1814 		case TYPE_FILE:
1815 			if(mod)
1816 				image = IMAGE_FILE_MOD;
1817 			else
1818 				image = IMAGE_FILE;
1819 			break;
1820 		case TYPE_MATERIAL_FOLDER:
1821 			image = IMAGE_MATERIAL_FOLDER;
1822 			break;
1823 		case TYPE_MATERIAL:
1824 			if(mod && apply)
1825 				image = IMAGE_MATERIAL_MOD_APPLY;
1826 			else if(mod)
1827 				image = IMAGE_MATERIAL_MOD;
1828 			else
1829 				image = IMAGE_MATERIAL;
1830 			break;
1831 	}
1832 
1833 	tree.SetItemImage(item, image, image);
1834 
1835 	if(children) {
1836 		if(tree.ItemHasChildren(item)) {
1837 			HTREEITEM hChildItem = tree.GetChildItem(item);
1838 			while (hChildItem != NULL) {
1839 				SetItemImage(hChildItem, mod, apply, children);
1840 				hChildItem = tree.GetNextSiblingItem(hChildItem);
1841 			}
1842 		}
1843 	}
1844 }
1845 
1846 /**
1847 * Cleans the lookup tables for the provided item and all children.
1848 * @param item The item to start from
1849 */
CleanLookupTrees(HTREEITEM item)1850 void MaterialTreeView::CleanLookupTrees(HTREEITEM item) {
1851 
1852 	idStr qt = GetQuicktreePath(item);
1853 	quickTree.Remove(qt);
1854 
1855 	CTreeCtrl& tree = GetTreeCtrl();
1856 
1857 	//Clean special lookup tables
1858 	DWORD type = tree.GetItemData(item);
1859 	if(type == TYPE_FILE) {
1860 		idStr file = GetMediaPath(item, TYPE_FILE);
1861 		fileToTree.Remove(file);
1862 	} else if(type == TYPE_MATERIAL) {
1863 		idStr name = GetMediaPath(item, TYPE_MATERIAL);
1864 		materialToTree.Remove(name);
1865 	}
1866 
1867 	//Clean all my children
1868 	if(tree.ItemHasChildren(item)) {
1869 		HTREEITEM childItem = tree.GetChildItem(item);
1870 		while(childItem != NULL) {
1871 			CleanLookupTrees(childItem);
1872 			childItem = tree.GetNextSiblingItem(childItem);
1873 		}
1874 	}
1875 }
1876 
1877 /**
1878 * Build the lookup tree for a given item and all of its children.
1879 * @param item The item to start from
1880 */
BuildLookupTrees(HTREEITEM item)1881 void MaterialTreeView::BuildLookupTrees(HTREEITEM item) {
1882 
1883 	//Add my quicktree item
1884 	idStr qt = GetQuicktreePath(item);
1885 	quickTree.Set(qt, item);
1886 
1887 	CTreeCtrl& tree = GetTreeCtrl();
1888 	if(tree.ItemHasChildren(item)) {
1889 		HTREEITEM childItem = tree.GetChildItem(item);
1890 		while(childItem != NULL) {
1891 			DWORD childType = tree.GetItemData(childItem);
1892 			if(childType == TYPE_MATERIAL_FOLDER) {
1893 				//Recursively call this method for all my child folders
1894 				BuildLookupTrees(childItem);
1895 			}
1896 			childItem = tree.GetNextSiblingItem(childItem);
1897 		}
1898 	}
1899 }
1900 
1901 /**
1902 * Returns the quicktree path for a given item.
1903 * @param item The item for which to generate the quicktree path
1904 */
GetQuicktreePath(HTREEITEM item)1905 idStr MaterialTreeView::GetQuicktreePath(HTREEITEM item) {
1906 	CTreeCtrl& tree = GetTreeCtrl();
1907 
1908 	idStr qt = "";
1909 	HTREEITEM pathItem = item;
1910 	while(pathItem != NULL) {
1911 		qt = "/" + idStr(tree.GetItemText(pathItem)) + qt;
1912 		pathItem = tree.GetParentItem(pathItem);
1913 	}
1914 	return qt;
1915 }
1916