]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/materialeditor/StageView.cpp
hello world
[icculus/iodoom3.git] / neo / tools / materialeditor / StageView.cpp
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 "../../idlib/precompiled.h"
29 #pragma hdrstop
30
31 #include "StageView.h"
32
33 IMPLEMENT_DYNCREATE(StageView, ToggleListView)
34
35 BEGIN_MESSAGE_MAP(StageView, ToggleListView)
36         ON_WM_CREATE()
37         ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, OnLvnItemchanged)
38         ON_NOTIFY_REFLECT(LVN_DELETEALLITEMS, OnLvnDeleteallitems)
39         ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnLvnBegindrag)
40         ON_WM_LBUTTONUP()
41         ON_WM_MOUSEMOVE()
42         ON_NOTIFY_REFLECT(NM_RCLICK, OnNMRclick)
43
44         ON_COMMAND(ID_STAGEPOPUP_RENAMESTAGE, OnRenameStage)
45         ON_COMMAND(ID_STAGEPOPUP_DELETESTAGE, OnDeleteStage)
46         ON_COMMAND(ID_STAGEPOPUP_DELETEALLSTAGES, OnDeleteAllStages)
47         ON_COMMAND(ID_STAGEPOPUP_ADDSTAGE, OnAddStage)
48         ON_COMMAND(ID_STAGEPOPUP_ADDBUMPMAP, OnAddBumpmapStage)
49         ON_COMMAND(ID_STAGEPOPUP_ADDDIFFUSEMAP, OnAddDiffuseStage)
50         ON_COMMAND(ID_STAGEPOPUP_ADDSPECULAR, OnAddSpecualarStage)
51
52         ON_COMMAND(ID_STAGEPOPUP_COPY, OnCopy)
53         ON_COMMAND(ID_STAGEPOPUP_PASTE, OnPaste)
54
55         ON_NOTIFY_REFLECT(LVN_BEGINLABELEDIT, OnLvnBeginlabeledit)
56         ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnLvnEndlabeledit)
57         ON_WM_CHAR()
58 END_MESSAGE_MAP()
59
60 /**
61 * Constructor for StageView.
62 */
63 StageView::StageView() {
64         currentMaterial = NULL;
65         bDragging = false;
66         internalChange = false;
67 }
68
69 /**
70 * Destructor for StageView.
71 */
72 StageView::~StageView() {
73 }
74
75 /**
76 * Called when the selected material has changed.
77 * @param pMaterial The newly selected material.
78 */
79 void StageView::MV_OnMaterialSelectionChange(MaterialDoc* pMaterial) {
80
81         currentMaterial = pMaterial;
82
83         RefreshStageList();     
84 }
85
86 /**
87 * Called when the material changes have been saved. 
88 * @param pMaterial The saved material.
89 */
90 void StageView::MV_OnMaterialSaved(MaterialDoc* pMaterial) {
91
92         CListCtrl& list = GetListCtrl();
93
94         //Saving a material reenables all of the stages
95         if(pMaterial == currentMaterial) {
96                 for(int i = 1; i < list.GetItemCount(); i++) {
97                         SetToggleState(i, ToggleListView::TOGGLE_STATE_ON);
98                 }
99         }
100 }
101
102 /**
103 * Called when a stage is added
104 * @param pMaterial The material that was affected.
105 * @param stageNum The index of the stage that was added
106 */
107 void StageView::MV_OnMaterialStageAdd(MaterialDoc* pMaterial, int stageNum) {
108
109         CListCtrl& list = GetListCtrl();
110
111         idStr name = pMaterial->GetAttribute(stageNum, "name");
112
113         int index = list.InsertItem(stageNum+1, name.c_str());
114         SetToggleState(index, ToggleListView::TOGGLE_STATE_ON);
115 }
116
117 /**
118 * Called when a stage is deleted
119 * @param pMaterial The material that was affected.
120 * @param stageNum The index of the stage that was deleted
121 */
122 void StageView::MV_OnMaterialStageDelete(MaterialDoc* pMaterial, int stageNum) {
123         CListCtrl& list = GetListCtrl();
124         list.DeleteItem(stageNum+1);
125 }
126
127 /**
128 * Called when a stage is moved
129 * @param pMaterial The material that was deleted.
130 * @param from The from index
131 * @param to The to index
132 */
133 void StageView::MV_OnMaterialStageMove(MaterialDoc* pMaterial, int from, int to) {
134
135         if(!internalChange) {
136                 from++;
137                 to++;
138
139                 CListCtrl& list = GetListCtrl();
140
141                 char szLabel[256];
142                 LV_ITEM lvi;
143                 ZeroMemory(&lvi, sizeof(LV_ITEM));
144                 lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM;
145                 lvi.stateMask = LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED;
146                 lvi.pszText = szLabel;
147                 lvi.iItem = from;
148                 lvi.cchTextMax = 255;
149                 list.GetItem(&lvi);
150
151                 //Delete the original item
152                 list.DeleteItem(from);
153
154                 //Insert the item
155                 lvi.iItem = to;
156                 list.InsertItem(&lvi);
157
158                 int type = -1;
159
160                 int stageType = currentMaterial->GetAttributeInt(to-1, "stagetype");
161                 switch(stageType) {
162                                 case MaterialDoc::STAGE_TYPE_NORMAL:
163                                         type = MaterialDefManager::MATERIAL_DEF_STAGE;
164                                         break;
165                                 case MaterialDoc::STAGE_TYPE_SPECIALMAP:
166                                         type = MaterialDefManager::MATERIAL_DEF_SPECIAL_STAGE;
167                                         break;
168                 }
169
170                 m_propView->SetPropertyListType(type, to-1);
171
172                 Invalidate();
173
174         }
175 }
176
177 /**
178 * Called when an attribute is changed
179 * @param pMaterial The material that was deleted.
180 * @param stage The stage that contains the change.
181 * @param attribName The attribute that has changed.
182 */
183 void StageView::MV_OnMaterialAttributeChanged(MaterialDoc* pMaterial, int stage, const char* attribName) {
184
185         //Refresh this stage list if a material name has changed
186         if(!internalChange && currentMaterial == pMaterial && stage >= 0 && attribName && !strcmp(attribName, "name") ) {
187                 CListCtrl& list = GetListCtrl();
188                 list.SetItemText(stage+1, 0, currentMaterial->GetAttribute(stage, attribName));
189         }
190 }
191
192 /**
193 * Returns true if the current state of the stage view will allow a copy operation
194 */
195 bool StageView::CanCopy() {
196
197         CListCtrl& list = GetListCtrl();
198         POSITION pos = list.GetFirstSelectedItemPosition();
199         int nItem = -1;
200         if(pos)
201                 nItem = list.GetNextSelectedItem(pos);
202
203         if(nItem > 0) {
204                 return true;
205         } else {
206                 return false;
207         }
208 }
209
210 /**
211 * Returns true if the current state of the stage view will allow a paste operation
212 */
213 bool StageView::CanPaste() {
214         return materialDocManager->IsCopyStage();
215 }
216
217 /**
218 * Cut is not supported for stages.
219 */
220 bool StageView::CanCut() {
221         //No cut for stages
222         return false;
223 }
224
225 /**
226 * Returns true if the current state of the stage view will allow a delete operation
227 */
228 bool StageView::CanDelete() {
229         CListCtrl& list = GetListCtrl();
230         POSITION pos = list.GetFirstSelectedItemPosition();
231         int nItem = -1;
232         if(pos) {
233                 nItem = list.GetNextSelectedItem(pos);
234         }
235
236         if(nItem > 0)
237                 return true;
238
239         return false;
240 }
241
242 /**
243 * Returns true if the current state of the stage view will allow a rename operation
244 */
245 bool StageView::CanRename() {
246         CListCtrl& list = GetListCtrl();
247
248         POSITION pos = list.GetFirstSelectedItemPosition();
249         int nItem = -1;
250         if(pos) {
251                 nItem = list.GetNextSelectedItem(pos);
252         }
253
254         if(nItem > 0) {
255                 MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
256                 if(nItem > 0 && material->GetAttributeInt(nItem-1, "stagetype") == MaterialDoc::STAGE_TYPE_NORMAL) {
257                         return true;
258                 }
259         }
260
261         return false;
262 }
263
264 /**
265 * Rebuilds the list of stages based on the currently selected material
266 */
267 void StageView::RefreshStageList() {
268         
269         CListCtrl& list = GetListCtrl();
270
271         POSITION pos = list.GetFirstSelectedItemPosition();
272         int selectedItem = -1;
273         if(pos)
274                 selectedItem = list.GetNextSelectedItem(pos);
275
276         list.DeleteAllItems();
277
278         if(currentMaterial) {
279
280                 //Always add the material item for the main material properties
281                 list.InsertItem(0, "Material");
282                 SetToggleState(0, ToggleListView::TOGGLE_STATE_DISABLED);
283
284                 //Get the stage info
285                 int stageCount = currentMaterial->GetStageCount();
286                 for(int i = 0; i < stageCount; i++) {
287                         const char* name = currentMaterial->GetAttribute(i, "name");
288
289                         int itemNum = list.InsertItem(list.GetItemCount(), name);
290
291                         if(currentMaterial->IsStageEnabled(i)) {
292                                 SetToggleState(itemNum, ToggleListView::TOGGLE_STATE_ON);
293                         } else {
294                                 SetToggleState(itemNum, ToggleListView::TOGGLE_STATE_OFF);
295                         }
296                 }
297
298                 if(selectedItem < 0) {
299                         //Select the material
300                         list.SetItemState(0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
301                 } else {
302                         list.SetItemState(selectedItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
303                 }
304         }
305 }
306
307 /** 
308 * Called by the MFC framework when the view is being created.
309 */
310 int StageView::OnCreate(LPCREATESTRUCT lpCreateStruct) {
311         if (ToggleListView::OnCreate(lpCreateStruct) == -1)
312                 return -1;
313
314         SetToggleIcons(MAKEINTRESOURCE(IDI_ME_DISABLED_ICON), MAKEINTRESOURCE(IDI_ME_ON_ICON), MAKEINTRESOURCE(IDI_ME_OFF_ICON));
315
316         return 0;
317 }
318
319 /** 
320 * Called when the user changes the selection in the list box. This method will notify the 
321 * property view of the change so that it can display the appropriate properties.
322 */
323 void StageView::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult) {
324         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
325
326         if(!bDragging) {
327
328                 //The state has changed and changed to selected
329                 if(pNMLV->uChanged && LVIF_STATE && pNMLV->uNewState & LVIS_SELECTED) {
330
331                         int type = -1;
332
333                         if(pNMLV->iItem >= 0) {
334                                 if(pNMLV->iItem == 0)
335                                         type = MaterialDefManager::MATERIAL_DEF_MATERIAL;
336                                 else {
337                                         int stageType = currentMaterial->GetAttributeInt(pNMLV->iItem-1, "stagetype");
338                                         switch(stageType) {
339                                                 case MaterialDoc::STAGE_TYPE_NORMAL:
340                                                         type = MaterialDefManager::MATERIAL_DEF_STAGE;
341                                                         break;
342                                                 case MaterialDoc::STAGE_TYPE_SPECIALMAP:
343                                                         type = MaterialDefManager::MATERIAL_DEF_SPECIAL_STAGE;
344                                                         break;
345                                         }
346                                 }
347                         }
348
349                         m_propView->SetPropertyListType(type, pNMLV->iItem-1);
350                 }
351
352                 if(pNMLV->uChanged && LVIF_STATE && pNMLV->uOldState & LVIS_SELECTED && !(pNMLV->uNewState & LVIS_SELECTED)) {
353                         //This item was deselected.
354                         //If there is no item selected then clear the prop list
355                         CListCtrl& list = GetListCtrl();
356                         POSITION pos = list.GetFirstSelectedItemPosition();
357                         if(!pos)
358                                 m_propView->SetPropertyListType(-1);
359                 }
360         }
361         *pResult = 0;
362 }
363
364 /** 
365 * Notifies the property view that all stages have been removed.
366 */
367 void StageView::OnLvnDeleteallitems(NMHDR *pNMHDR, LRESULT *pResult) {
368         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
369
370         //The list has been cleared so clear the prop view
371         m_propView->SetPropertyListType(-1);
372
373         *pResult = 0;
374 }
375
376 /** 
377 * Starts the stage drag operation.
378 */
379 void StageView::OnLvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult) {
380         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
381
382         CListCtrl& list = GetListCtrl();
383
384         //Start a drag if the item isn't the material
385         if(pNMLV->iItem > 0) {
386
387
388                 dragIndex = pNMLV->iItem;
389
390                 //Trun off ownerdrawn to create the drag image correctly
391                 list.ModifyStyle(LVS_OWNERDRAWFIXED, 0);
392
393                 //Create the drag image
394                 POINT pt;
395                 pt.x = 8;
396                 pt.y = 8;
397                 dragImage = list.CreateDragImage(dragIndex, &pt);
398                 dragImage->BeginDrag(0, CPoint (8, 8));
399                 dragImage->DragEnter(GetDesktopWindow(), pNMLV->ptAction);
400
401                 //Turn the owner draw back on
402                 list.ModifyStyle(0, LVS_OWNERDRAWFIXED);
403
404                 //Drag is in progress
405                 bDragging = true;
406                 dropIndex = -1;
407                 dropWnd = &list;
408
409                 //Capture the messages
410                 SetCapture();
411         }
412
413         *pResult = 0;
414 }
415
416 /** 
417 * Finishes a stage drag operation of the user was dragging a stage.
418 */
419 void StageView::OnLButtonUp(UINT nFlags, CPoint point) {
420         if( bDragging ) {
421                 //Release mouse capture
422                 ReleaseCapture();
423
424                 //Delete the drag image
425                 dragImage->DragLeave(GetDesktopWindow());
426                 dragImage->EndDrag();
427
428                 //Where did we drop
429                 CPoint pt(point);
430                 ClientToScreen(&pt);
431                 dropWnd = WindowFromPoint(pt);
432
433                 if( dropWnd->IsKindOf(RUNTIME_CLASS(StageView)) )
434                         DropItemOnList();
435
436                 bDragging = false;
437         }
438
439         ToggleListView::OnLButtonUp(nFlags, point);
440 }
441
442 /** 
443 * Handles drawing the drag image when a user is draging a stage.
444 */
445 void StageView::OnMouseMove(UINT nFlags, CPoint point) {
446         if( bDragging ) {
447                 dropPoint = point;
448                 ClientToScreen(&dropPoint);
449
450                 //Move the drag image
451                 dragImage->DragMove(dropPoint);
452                 dragImage->DragShowNolock(FALSE);
453
454                 dropWnd = WindowFromPoint(dropPoint);
455                 dropWnd->ScreenToClient(&dropPoint);
456
457                 dragImage->DragShowNolock(TRUE);
458         }
459         ToggleListView::OnMouseMove(nFlags, point);
460 }
461
462 /** 
463 * Displays the popup menu when the user performs a right mouse click.
464 */
465 void StageView::OnNMRclick(NMHDR *pNMHDR, LRESULT *pResult) {
466         if(materialDocManager->GetCurrentMaterialDoc()) {
467                 CListCtrl& list = GetListCtrl();
468
469                 DWORD dwPos = GetMessagePos();
470
471                 CPoint pt( LOWORD( dwPos ), HIWORD ( dwPos ) );
472
473                 CPoint spt = pt;
474                 list.ScreenToClient( &spt );
475
476                 PopupMenu(&spt);
477         }
478         *pResult = 0;
479 }
480
481 /** 
482 * Begins a label edit when the user selects the rename menu option.
483 */
484 void StageView::OnRenameStage() {
485
486         CListCtrl& list = GetListCtrl();
487         POSITION pos = list.GetFirstSelectedItemPosition();
488         int nItem = -1;
489         if(pos) {
490                 nItem = list.GetNextSelectedItem(pos);
491                 list.EditLabel(nItem);
492         }
493 }
494
495 /** 
496 * Deletes the selected stage when the user selects the delete menu option.
497 */
498 void StageView::OnDeleteStage() {
499
500         CListCtrl& list = GetListCtrl();
501         POSITION pos = list.GetFirstSelectedItemPosition();
502         int nItem = -1;
503         if(pos) {
504                 nItem = list.GetNextSelectedItem(pos);
505                 if(nItem > 0) {
506                         int result = MessageBox("Are you sure you want to delete this stage?", "Delete?", MB_ICONQUESTION | MB_YESNO);
507                         if(result == IDYES) {
508
509                                 MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
510                                 material->RemoveStage(nItem-1);
511                         }
512                 }
513         }
514 }
515
516 /** 
517 * Conforms the user wants to delete all stages and then performs the operation.
518 */
519 void StageView::OnDeleteAllStages() {
520         int result = MessageBox("Are you sure you want to delete all stages?", "Delete?", MB_ICONQUESTION | MB_YESNO);
521         if(result == IDYES) {
522                 MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
523                 material->ClearStages();
524         }
525 }
526
527 /** 
528 * Adds a new stage when the user selects the menu option.
529 */
530 void StageView::OnAddStage() {
531         MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
532
533         idStr name = va("Stage %d", material->GetStageCount()+1);
534         material->AddStage(MaterialDoc::STAGE_TYPE_NORMAL, name.c_str());
535 }
536
537 /** 
538 * Adds a new bumpmap stage when the user selects the menu option.
539 */
540 void StageView::OnAddBumpmapStage() {
541         MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
542         material->AddStage(MaterialDoc::STAGE_TYPE_SPECIALMAP, "bumpmap");
543 }
544
545 /** 
546 * Adds a new diffusemap stage when the user selects the menu option.
547 */
548 void StageView::OnAddDiffuseStage() {
549         MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
550         material->AddStage(MaterialDoc::STAGE_TYPE_SPECIALMAP, "diffusemap");
551 }
552
553 /** 
554 * Adds a new specularmap stage when the user selects the menu option.
555 */
556 void StageView::OnAddSpecualarStage() {
557         MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
558         material->AddStage(MaterialDoc::STAGE_TYPE_SPECIALMAP, "specularmap");
559 }
560
561 /** 
562 * Performs a copy operation when the user selects the menu option.
563 */
564 void StageView::OnCopy() {
565
566         MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
567
568         CListCtrl& list = GetListCtrl();
569
570         POSITION pos = list.GetFirstSelectedItemPosition();
571         int nItem = -1;
572         if(pos)
573                 nItem = list.GetNextSelectedItem(pos);
574
575         if(nItem > 0) {
576                 materialDocManager->CopyStage(material, nItem-1);
577         }
578 }
579
580 /** 
581 * Performs a paste operation when the user selects the menu option.
582 */
583 void StageView::OnPaste() {
584         if(materialDocManager->IsCopyStage()) {
585
586                 MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
587
588                 int type;
589                 idStr name;
590
591                 materialDocManager->GetCopyStageInfo(type, name);
592
593                 int existingIndex = material->FindStage(type, name);
594
595                 if(type != MaterialDoc::STAGE_TYPE_SPECIALMAP || existingIndex == -1) {
596                         materialDocManager->PasteStage(material);
597                 } else {
598                         if(MessageBox(va("Do you want to replace '%s' stage?", name.c_str()), "Replace?", MB_ICONQUESTION | MB_YESNO) == IDYES) {
599                                 material->RemoveStage(existingIndex);
600                                 materialDocManager->PasteStage(material);
601                         }
602                 }
603         }
604 }
605
606 /** 
607 * Determines is a label edit can be performed on the selected stage.
608 */
609 void StageView::OnLvnBeginlabeledit(NMHDR *pNMHDR, LRESULT *pResult) {
610         NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
611
612         //if this is a special stage then don't allow edit
613         int index = pDispInfo->item.iItem;
614
615         MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
616         if(index <= 0 || material->GetAttributeInt(index-1, "stagetype") != MaterialDoc::STAGE_TYPE_NORMAL)
617         {
618                 *pResult = 1;
619                 return;
620         }
621
622         //ToDo: Can we move the edit box
623         /*HWND edit = ListView_GetEditControl(m_hWnd);
624         CWnd* editWnd = CWnd::FromHandle(edit);
625         CRect rect;
626         editWnd->GetWindowRect(rect);
627         rect.left += 22;
628         rect.right += 22;
629         editWnd->MoveWindow(rect);*/
630
631
632         *pResult = 0;
633 }
634
635 /** 
636 * Performs the stage name change after the label edit is done.
637 */
638 void StageView::OnLvnEndlabeledit(NMHDR *pNMHDR, LRESULT *pResult) {
639         NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
640
641         if(pDispInfo->item.pszText) {
642                 MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
643                 internalChange = true;
644                 material->SetAttribute(pDispInfo->item.iItem-1, "name", pDispInfo->item.pszText);
645                 internalChange = false;
646                 *pResult = 1;
647         } else {
648                 *pResult = 0;
649         }
650 }
651
652 /** 
653 * Handles keyboard shortcuts for copy and paste operations.
654 */
655 void StageView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) {
656         if(nChar == 3 && GetKeyState(VK_CONTROL)) {
657                 OnCopy();
658         }
659
660         if(nChar == 22 && GetKeyState(VK_CONTROL)) {
661                 OnPaste();
662         }
663
664
665         ToggleListView::OnChar(nChar, nRepCnt, nFlags);
666 }
667
668 /** 
669 * Handles keyboard shortcut for the delete operations.
670 */
671 BOOL StageView::PreTranslateMessage(MSG* pMsg) {
672
673         CListCtrl& list = GetListCtrl();
674         if (pMsg->hwnd == list.GetSafeHwnd()) {
675
676                 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_DELETE) {
677                         OnDeleteStage();
678                         return TRUE;
679                 }
680         }
681         return FALSE;
682 }
683
684 /** 
685 * Sets window styles before the window is created.
686 */
687 BOOL StageView::PreCreateWindow(CREATESTRUCT& cs) {
688         cs.style &= ~LVS_TYPEMASK;
689         cs.style |= LVS_SINGLESEL | LVS_EDITLABELS;
690
691         return ToggleListView::PreCreateWindow(cs);
692 }
693
694 /** 
695 * Called by the ToggleListView when the toggle state has changed.
696 */
697 void StageView::OnStateChanged(int index, int toggleState) {
698         MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
699         if(material && index > 0) {
700                 if (toggleState == ToggleListView::TOGGLE_STATE_ON) {
701                         material->EnableStage(index-1, true);
702                 } else if (toggleState == ToggleListView::TOGGLE_STATE_OFF) {
703                         material->EnableStage(index-1, false);
704                 }
705         }
706 }
707
708 /** 
709 * Dispalys the popup menu with the appropriate menu items enabled.
710 */
711 void StageView::PopupMenu(CPoint* pt) {
712
713         //Determine the type of object clicked on
714         CListCtrl& list = GetListCtrl();
715
716
717         ClientToScreen (pt);
718
719         CMenu FloatingMenu;
720         VERIFY(FloatingMenu.LoadMenu(IDR_ME_STAGELIST_POPUP));
721         CMenu* pPopupMenu = FloatingMenu.GetSubMenu (0);
722         ASSERT(pPopupMenu != NULL);
723
724         POSITION pos = list.GetFirstSelectedItemPosition();
725         int nItem = -1;
726         if(pos)
727                 nItem = list.GetNextSelectedItem(pos);
728
729         if(nItem <= 0) {
730                 pPopupMenu->EnableMenuItem(ID_STAGEPOPUP_RENAMESTAGE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
731                 pPopupMenu->EnableMenuItem(ID_STAGEPOPUP_DELETESTAGE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
732
733                 pPopupMenu->EnableMenuItem(ID_STAGEPOPUP_CUT, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
734                 pPopupMenu->EnableMenuItem(ID_STAGEPOPUP_COPY, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
735         } else {
736                 MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
737                 if(material->GetAttributeInt(nItem-1, "stagetype") != MaterialDoc::STAGE_TYPE_NORMAL) {
738                         pPopupMenu->EnableMenuItem(ID_STAGEPOPUP_RENAMESTAGE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
739                 }
740         }
741
742         MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
743         if(material->FindStage(MaterialDoc::STAGE_TYPE_SPECIALMAP, "bumpmap") >= 0) {
744                 pPopupMenu->EnableMenuItem(ID_STAGEPOPUP_ADDBUMPMAP, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
745         }
746         if(material->FindStage(MaterialDoc::STAGE_TYPE_SPECIALMAP, "diffusemap") >= 0) {
747                 pPopupMenu->EnableMenuItem(ID_STAGEPOPUP_ADDDIFFUSEMAP, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
748         }
749         if(material->FindStage(MaterialDoc::STAGE_TYPE_SPECIALMAP, "specularmap") >= 0) {
750                 pPopupMenu->EnableMenuItem(ID_STAGEPOPUP_ADDSPECULAR, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
751         }
752
753         if(materialDocManager->IsCopyStage()) {
754                 pPopupMenu->EnableMenuItem(ID_STAGEPOPUP_PASTE, MF_BYCOMMAND | MF_ENABLED);
755         } else {
756                 pPopupMenu->EnableMenuItem(ID_STAGEPOPUP_PASTE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
757         }
758
759         pPopupMenu->TrackPopupMenu (TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt->x, pt->y, &list);
760 }
761
762 /** 
763 * Performs the stage move when the user has dragged and dropped a stage.
764 */
765 void StageView::DropItemOnList() {
766         CListCtrl& list = GetListCtrl();
767
768         int toStage;
769
770         //Get and adjust the drop index based on the direction of the move
771         dropIndex = list.HitTest(dropPoint);
772         if(dropIndex < 0) dropIndex = list.GetItemCount()-1;
773
774         //Ignore the drop if the index is the same or they are droping on the material
775         if(dropIndex == dragIndex || dropIndex == 0)
776                 return;
777
778         //Move the stage data
779         MaterialDoc* material = materialDocManager->GetCurrentMaterialDoc();
780         
781         internalChange = true;
782         toStage = dropIndex-1;
783         material->MoveStage(dragIndex-1, dropIndex-1);
784         internalChange = false;
785                 
786         if(dragIndex < dropIndex) {
787                 dropIndex++;
788         }
789
790         //Get the item
791         char szLabel[256];
792         LV_ITEM lvi;
793         ZeroMemory(&lvi, sizeof(LV_ITEM));
794         lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM;
795         lvi.stateMask = LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED;
796         lvi.pszText = szLabel;
797         lvi.iItem = dragIndex;
798         lvi.cchTextMax = 255;
799         list.GetItem(&lvi);
800
801         //Insert the item
802         lvi.iItem = dropIndex;
803         list.InsertItem(&lvi);
804
805         //Adjust the drag index if the move was up in the list
806         if(dragIndex > dropIndex) {
807                 dragIndex++;
808         }
809
810         //Delete the original item
811         list.DeleteItem(dragIndex);
812
813         int type = -1;
814         int stageType = currentMaterial->GetAttributeInt(toStage, "stagetype");
815         switch(stageType) {
816                 case MaterialDoc::STAGE_TYPE_NORMAL:
817                         type = MaterialDefManager::MATERIAL_DEF_STAGE;
818                         break;
819                 case MaterialDoc::STAGE_TYPE_SPECIALMAP:
820                         type = MaterialDefManager::MATERIAL_DEF_SPECIAL_STAGE;
821                         break;
822         }
823         m_propView->SetPropertyListType(type, toStage);
824 }
825
826
827
828