/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : LevelEdit * * * * $Archive:: /Commando/Code/Tools/LevelEdit/InstancesPage.cpp $* * * * Author:: Patrick Smith * * * * $Modtime:: 5/11/01 9:25a $* * * * $Revision:: 14 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "stdafx.h" #include "leveledit.h" #include "instancespage.h" #include "nodemgr.h" #include "node.h" #include "utils.h" #include "cameramgr.h" #include "gotoobjectdialog.h" #include "sceneeditor.h" #include "icons.h" #include "nodecategories.h" #include "definition.h" #include "definitionfactory.h" #include "definitionfactorymgr.h" #include "preset.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif /////////////////////////////////////////////////////////////////////// // Local prototypes /////////////////////////////////////////////////////////////////////// int CALLBACK InstancesListSortCallback (LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort); #ifndef ListView_SetCheckState #define ListView_SetCheckState(hwndLV, i, fCheck) \ ListView_SetItemState(hwndLV, i, \ INDEXTOSTATEIMAGEMASK((fCheck)+1), LVIS_STATEIMAGEMASK) #endif #ifndef ListView_SetOverlay #define ListView_SetOverlay(hwndLV, i, overlay) \ ListView_SetItemState(hwndLV, i, \ INDEXTOOVERLAYMASK(overlay), LVIS_OVERLAYMASK) #endif /////////////////////////////////////////////////////////////////////// // Local structures /////////////////////////////////////////////////////////////////////// typedef enum { TYPE_NAVIGATOR, TYPE_FACTORY, TYPE_NODE, } ITEM_TYPE; typedef struct { ITEM_TYPE type; StringClass name; union { uint32 class_id; NodeClass * node; }; } ITEM_DATA; ///////////////////////////////////////////////////////////////////////////// // Local constants ///////////////////////////////////////////////////////////////////////////// const int TOOLBAR_HEIGHT = 36; const int TOOLBAR_V_SPACING = 5; const int TOOLBAR_V_BORDER = TOOLBAR_V_SPACING * 2; const int TOOLBAR_H_SPACING = 5; const int TOOLBAR_H_BORDER = TOOLBAR_H_SPACING * 2; //const int COLUMN_CHECK = 0; //const int COLUMN_PLUS = 1; const int COLUMN_NAME = 0; ///////////////////////////////////////////////////////////////////////////// // // InstancesPageClass // ///////////////////////////////////////////////////////////////////////////// InstancesPageClass::InstancesPageClass (CWnd *parent_wnd) : m_ClassID (0), CDialog(InstancesPageClass::IDD) { //{{AFX_DATA_INIT(InstancesPageClass) //}}AFX_DATA_INIT Create (InstancesPageClass::IDD, parent_wnd); return ; } ///////////////////////////////////////////////////////////////////////////// // // ~InstancesPageClass // ///////////////////////////////////////////////////////////////////////////// InstancesPageClass::~InstancesPageClass (void) { return ; } ///////////////////////////////////////////////////////////////////////////// // // DoDataExchange // ///////////////////////////////////////////////////////////////////////////// void InstancesPageClass::DoDataExchange (CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(InstancesPageClass) DDX_Control(pDX, IDC_INSTANCE_LIST, m_ListCtrl); //}}AFX_DATA_MAP return ; } BEGIN_MESSAGE_MAP(InstancesPageClass, CDialog) //{{AFX_MSG_MAP(InstancesPageClass) ON_WM_SIZE() ON_WM_DESTROY() ON_COMMAND(IDC_EDIT, OnEdit) ON_COMMAND(IDC_GOTO, OnGoto) ON_COMMAND(IDC_SHOWALL, OnShowAll) ON_COMMAND(IDC_SELECT, OnSelect) ON_COMMAND(IDC_DELETE, OnDelete) ON_NOTIFY(LVN_DELETEITEM, IDC_INSTANCE_LIST, OnDeleteitemInstanceList) ON_NOTIFY(NM_DBLCLK, IDC_INSTANCE_LIST, OnDblclkInstanceList) ON_NOTIFY(LVN_ITEMCHANGED, IDC_INSTANCE_LIST, OnItemchangedInstanceList) //}}AFX_MSG_MAP END_MESSAGE_MAP() #ifdef _DEBUG void InstancesPageClass::AssertValid() const { CDialog::AssertValid(); } void InstancesPageClass::Dump(CDumpContext& dc) const { CDialog::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // // OnSize // ///////////////////////////////////////////////////////////////////////////// void InstancesPageClass::OnSize ( UINT nType, int cx, int cy ) { // Allow the base class to process this message CDialog::OnSize (nType, cx, cy); if (::IsWindow (m_ListCtrl) && (cx > 0) && (cy > 0)) { // Get the bounding rectangle of the form window CRect parentrect; GetWindowRect (&parentrect); // Get the bounding rectangle of the toolbar CRect toolbar_rect; m_Toolbar.GetWindowRect (&toolbar_rect); ScreenToClient (&toolbar_rect); // Move the toolbar so it is in its correct position m_Toolbar.SetWindowPos (NULL, TOOLBAR_H_SPACING, (cy - TOOLBAR_V_SPACING) - toolbar_rect.Height (), cx - TOOLBAR_H_BORDER, toolbar_rect.Height (), SWP_NOZORDER); // Get the bounding rectnagle of the list ctrl RECT list_rect; m_ListCtrl.GetWindowRect (&list_rect); CRect client_rect = list_rect; ScreenToClient (&client_rect); int list_height = ((cy - TOOLBAR_V_BORDER) - toolbar_rect.Height ()) - client_rect.top; // Resize the tab control to fill the entire contents of the client area m_ListCtrl.SetWindowPos ( NULL, 0, 0, cx-((list_rect.left - parentrect.left) << 1), list_height, SWP_NOZORDER | SWP_NOMOVE); } return ; } ///////////////////////////////////////////////////////////////////////////// // // OnDestroy // ///////////////////////////////////////////////////////////////////////////// void InstancesPageClass::OnDestroy (void) { // // Free the state image list we associated with the control // CImageList *imagelist = m_ListCtrl.GetImageList (LVSIL_STATE); m_ListCtrl.SetImageList (NULL, LVSIL_STATE); SAFE_DELETE (imagelist); // // Remove the main image list we associated with the control // m_ListCtrl.SetImageList (NULL, LVSIL_SMALL); m_ListCtrl.DeleteAllItems (); ::RemoveProp (m_ListCtrl, "TRANS_ACCS"); ::RemoveProp (m_hWnd, "TRANS_ACCS"); CDialog::OnDestroy (); return ; } ///////////////////////////////////////////////////////////////////////////// // // OnEdit // ///////////////////////////////////////////////////////////////////////////// void InstancesPageClass::OnEdit (void) { // Show the settings dialog for the currently selected item NodeClass *node = Get_Item_Node (m_ListCtrl.GetNextItem (-1, LVNI_ALL | LVNI_SELECTED)); if (node != NULL) { node->Show_Settings_Dialog (); } return ; } ///////////////////////////////////////////////////////////////////////////// // // OnGoto // ///////////////////////////////////////////////////////////////////////////// void InstancesPageClass::OnGoto (void) { NodeClass *selected_node = NULL; // // Try to find the first selected node (if any) // int index = m_ListCtrl.GetNextItem (-1, LVNI_SELECTED | LVNI_ALL); if (index >= 0) { selected_node = Get_Item_Node (index); } // // Show the 'goto' dialog... // GotoObjectDialogClass dialog (selected_node); dialog.DoModal (); return ; } ///////////////////////////////////////////////////////////////////////////// // // OnShowAll // ///////////////////////////////////////////////////////////////////////////// void InstancesPageClass::OnShowAll (void) { // // Show all the nodes // for ( NodeClass *node = NodeMgrClass::Get_First (); node != NULL; node = NodeMgrClass::Get_Next (node)) { node->Hide (false); } // // Fixup the UI // for (int index = 0; index < m_ListCtrl.GetItemCount (); index ++) { ITEM_DATA *item_data = (ITEM_DATA *)m_ListCtrl.GetItemData (index); if (item_data != NULL && item_data->type != TYPE_NAVIGATOR) { ListView_SetCheckState (m_ListCtrl, index, true); } } // // Make sure the main view is updated // ::Refresh_Main_View (); return ; } //////////////////////////////////////////////////////////////////////////// // // WindowProc // //////////////////////////////////////////////////////////////////////////// LRESULT InstancesPageClass::WindowProc ( UINT message, WPARAM wParam, LPARAM lParam ) { // // Is this the message we are expecting? // if (message == WM_USER+102) { int index = (int)lParam; // // Should we toggle the checkmark for this entry? // ITEM_DATA *item_data = (ITEM_DATA *)m_ListCtrl.GetItemData (index); if (item_data != NULL && item_data->type != TYPE_NAVIGATOR) { // // Either hide or show the selected nodes // bool hidden = (ListView_GetCheckState (m_ListCtrl, index) == false); Hide_Nodes (index, !hidden); ListView_SetCheckState (m_ListCtrl, index, hidden); } } return CDialog::WindowProc(message, wParam, lParam); } //////////////////////////////////////////////////////////////////////////// // // CheckBoxSubclassProc // //////////////////////////////////////////////////////////////////////////// LRESULT CALLBACK CheckBoxSubclassProc ( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ) { WNDPROC pold_proc = (WNDPROC)::GetProp (hwnd, "OLDPROC"); if (message == WM_LBUTTONUP) { // // Find out where the user clicked // LVHITTESTINFO hittest = { 0 }; hittest.pt.x = LOWORD (lparam); hittest.pt.y = HIWORD (lparam); ::SendMessage (hwnd, LVM_HITTEST, 0, (LPARAM)&hittest); // // Did the user click one of the checkboxes? // if (hittest.flags & LVHT_ONITEMSTATEICON) { // // Notify the instances page that the user wants to toggle the checkbox // ::PostMessage (::GetParent (hwnd), WM_USER+102, 0, (LPARAM)hittest.iItem); } } else if (message == WM_DESTROY) { ::SetWindowLong (hwnd, GWL_WNDPROC, (LONG)pold_proc); ::RemoveProp (hwnd, "OLDPROC"); } if (pold_proc != NULL) { return ::CallWindowProc (pold_proc, hwnd, message, wparam, lparam); } else { return ::DefWindowProc (hwnd, message, wparam, lparam); } } //////////////////////////////////////////////////////////////////////////// // // OnDblclkInstanceList // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::OnDblclkInstanceList ( NMHDR * pNMHDR, LRESULT* pResult ) { // Determine what client-coord location was double-clicked on DWORD mouse_pos = ::GetMessagePos (); POINT hit_point = { GET_X_LPARAM (mouse_pos), GET_Y_LPARAM (mouse_pos) }; m_ListCtrl.ScreenToClient (&hit_point); // Goto the node that was double-clicked on (if possible) UINT flags = 0; int index = m_ListCtrl.HitTest (hit_point, &flags); if ((index >= 0) && ((flags & LVHT_ONITEMLABEL) || (flags & LVHT_ONITEMICON))) { ITEM_DATA *item_data = (ITEM_DATA *)m_ListCtrl.GetItemData (index); if (item_data != NULL) { if (item_data->type == TYPE_NAVIGATOR) { // // Determine which class id we should display // int class_id = 0; if (m_ClassIDStack.Count () > 0) { class_id = m_ClassIDStack[m_ClassIDStack.Count ()-1]; m_ClassIDStack.Delete (m_ClassIDStack.Count ()-1); } Populate_List (class_id); } else if (item_data->type == TYPE_FACTORY) { // // Fill the list with children of the given class id // m_ClassIDStack.Add (m_ClassID); Populate_List (item_data->class_id); } else { NodeClass *node = Get_Item_Node (index); if (node != NULL) { // // If this node is a terrain, then display the subojects, // otherwise snap the camera to the node // if (node->Get_Sub_Node_Count () > 0) { m_ClassIDStack.Add (m_ClassID); Populate_List (node); } else { ::Get_Camera_Mgr ()->Goto_Node (node); } } } } } (*pResult) = 0; return ; } //////////////////////////////////////////////////////////////////////////// // // OnSelect // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::OnSelect (void) { // // Clear all selected nodes // ::Get_Scene_Editor ()->Set_Selection (NULL); // // Toggle the selection state of all the nodes in the selection set // int index = -1; while ((index = m_ListCtrl.GetNextItem (index, LVNI_ALL | LVNI_SELECTED)) >= 0) { NodeClass *node = Get_Item_Node (index); if (node != NULL) { ::Get_Scene_Editor ()->Toggle_Selection (node); } } ::Refresh_Main_View (); return ; } //////////////////////////////////////////////////////////////////////////// // // OnDelete // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::OnDelete (void) { CString message = "Are you sure you wish to delete the selected node(s)?"; CString title; title.LoadString (IDS_DELETE_CONFIRM_TITLE); // // Ask the user if they really want to delete the selected item // if (MessageBox (message, title, MB_ICONEXCLAMATION | MB_YESNO) == IDYES) { // // Build a list of all the nodes we need to delete // DynamicVectorClass delete_list; int index = -1; while ((index = m_ListCtrl.GetNextItem (index, LVNI_ALL | LVNI_SELECTED)) >= 0) { NodeClass *node = Get_Item_Node (index); if (node != NULL) { delete_list.Add (node); } } // // Delete all the selected nodes // for (index = 0; index < delete_list.Count (); index ++) { ::Get_Scene_Editor ()->Delete_Node (delete_list[index]); } ::Refresh_Main_View (); } return ; } //////////////////////////////////////////////////////////////////////////// // // OnInitDialog // //////////////////////////////////////////////////////////////////////////// BOOL InstancesPageClass::OnInitDialog (void) { CDialog::OnInitDialog (); m_Toolbar.CreateEx (this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP, CRect(0, 0, 0, 0), 101); m_Toolbar.SetOwner (this); m_Toolbar.LoadToolBar (IDR_INSTANCES_TOOLBAR); m_Toolbar.SetBarStyle (m_Toolbar.GetBarStyle () | CBRS_TOOLTIPS | CBRS_FLYBY); // // Configure the toolbar // CRect parentrect; GetWindowRect (&parentrect); m_Toolbar.SetWindowPos (NULL, 0, 0, parentrect.Width () - TOOLBAR_H_BORDER, TOOLBAR_HEIGHT, SWP_NOZORDER | SWP_NOMOVE); m_Toolbar.Enable_Button (IDC_DELETE, false); m_Toolbar.Enable_Button (IDC_SELECT, false); m_Toolbar.Enable_Button (IDC_EDIT, false); // // Configure the list control's extended styles // //m_ListCtrl.SetExtendedStyle (m_ListCtrl.GetExtendedStyle () | LVS_EX_SUBITEMIMAGES | LVS_EX_FULLROWSELECT); // // Create a state imagelist for the list control to use for checkboxes // CImageList *imagelist = new CImageList; imagelist->Create (MAKEINTRESOURCE (IDB_CHECKBOX_STATES1), 13, 0, RGB (255, 0, 255)); m_ListCtrl.SetImageList (imagelist, LVSIL_STATE); // // Setup the columns of the list control // CRect client_rect; m_ListCtrl.GetClientRect (&client_rect); m_ListCtrl.InsertColumn (COLUMN_NAME, "Name"); m_ListCtrl.SetColumnWidth (COLUMN_NAME, client_rect.Width () - 5); // // Pass the general use imagelist onto the list control // m_ListCtrl.SetImageList (::Get_Global_Image_List (), LVSIL_SMALL); // // Subclass the list control so we can handle the checkstates // LONG oldproc = ::SetWindowLong (m_ListCtrl, GWL_WNDPROC, (LONG)CheckBoxSubclassProc); ::SetProp (m_ListCtrl, "OLDPROC", (HANDLE)oldproc); // // Populate the list control // Reset_List (); SetProp (m_ListCtrl, "TRANS_ACCS", (HANDLE)1); SetProp (m_hWnd, "TRANS_ACCS", (HANDLE)1); return TRUE; } ///////////////////////////////////////////////////////////////////////////// // // Insert_Factory // ///////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Insert_Factory (LPCTSTR name, int class_id) { // // Add an entry to the list control for the factory // int index = m_ListCtrl.InsertItem (0xFF, name, FOLDER_ICON); if (index >= 0) { // // Set the text and the icon for this entry // //m_ListCtrl.SetItem (index, COLUMN_NAME, LVIF_TEXT | LVIF_IMAGE, name, FOLDER_ICON, 0, 0, 0); // // Allocate a new wrapper if we need to // ITEM_DATA *item_data = (ITEM_DATA *)m_ListCtrl.GetItemData (index); if (item_data == NULL) { item_data = new ITEM_DATA; } // // Set a flag in the wrapper so we know what kind of data // this list item contains. // item_data->type = TYPE_FACTORY; item_data->class_id = class_id; item_data->name = name; m_ListCtrl.SetItemData (index, (DWORD)item_data); m_ListCtrl.SetCheck (index, TRUE); } return ; } ///////////////////////////////////////////////////////////////////////////// // // Insert_Node // ///////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Insert_Node (NodeClass *node) { // // Add an entry to the list control for the node // int index = m_ListCtrl.InsertItem (0xFF, node->Get_Name (), node->Get_Icon_Index ()); if (index >= 0) { // // Set the text and the icon for this entry // //m_ListCtrl.SetItem (index, COLUMN_NAME, LVIF_TEXT | LVIF_IMAGE, node->Get_Name (), node->Get_Icon_Index (), 0, 0, 0); // // Allocate a new wrapper if we need to // ITEM_DATA *item_data = (ITEM_DATA *)m_ListCtrl.GetItemData (index); if (item_data == NULL) { item_data = new ITEM_DATA; } // // Set a flag in the wrapper so we know what kind of data // this list item contains. // SAFE_ADD_REF (node); item_data->type = TYPE_NODE; item_data->node = node; item_data->name = node->Get_Name (); m_ListCtrl.SetItemData (index, (DWORD)item_data); ListView_SetCheckState (m_ListCtrl, index, (node->Is_Hidden () == false)); } return ; } ///////////////////////////////////////////////////////////////////////////// // // Insert_Navigator // ///////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Insert_Navigator (void) { // // Add an entry to the list control for the navigator // int index = m_ListCtrl.InsertItem (0xFF, "..", NAVIGATOR_ICON); if (index >= 0) { // // Set the text and the icon for this entry // //m_ListCtrl.SetItem (index, COLUMN_NAME, LVIF_TEXT | LVIF_IMAGE, "..", NAVIGATOR_ICON, 0, 0, 0); // // Allocate a new wrapper if we need to // ITEM_DATA *item_data = (ITEM_DATA *)m_ListCtrl.GetItemData (index); if (item_data == NULL) { item_data = new ITEM_DATA; } // // Set a flag in the wrapper so we know what kind of data // this list item contains. // item_data->type = TYPE_NAVIGATOR; item_data->node = NULL; item_data->name = ".."; m_ListCtrl.SetItemData (index, (DWORD)item_data); } return ; } //////////////////////////////////////////////////////////////////////////// // // Add_Node // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Add_Node (NodeClass *node) { WWASSERT (node != NULL); PresetClass *preset = node->Get_Preset (); if (preset != NULL) { DefinitionClass *definition = preset->Get_Definition (); WWASSERT (definition != NULL); if (definition != NULL) { // // Should the node be inserted into the current view? // if (definition->Get_Class_ID () == m_ClassID) { m_ListCtrl.SetRedraw (FALSE); Insert_Node (node); m_ListCtrl.SortItems (InstancesListSortCallback, 0L); m_ListCtrl.SetRedraw (TRUE); } } } Update_Overlays (); return ; } //////////////////////////////////////////////////////////////////////////// // // Remove_Node // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Remove_Node (NodeClass *node) { WWASSERT (node != NULL); // // Attempt to find this node in the current view // for (int index = 0; index < m_ListCtrl.GetItemCount (); index ++) { NodeClass *curr_node = Get_Item_Node (index); // // If this is the node we are looking for, then remove it from // the view. // if (curr_node == node) { m_ListCtrl.DeleteItem (index); break; } } Update_Overlays (); return ; } ///////////////////////////////////////////////////////////////////////////// // // Get_Item_Node // ///////////////////////////////////////////////////////////////////////////// NodeClass * InstancesPageClass::Get_Item_Node (int index) { NodeClass *node = NULL; // // If this item represents a node, then return the node // pointer to the caller. // ITEM_DATA *item_data = (ITEM_DATA *)m_ListCtrl.GetItemData (index); if ((item_data != NULL) && (item_data->type == TYPE_NODE)) { node = item_data->node; } return node; } //////////////////////////////////////////////////////////////////////////// // // Set_Node_Check // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Set_Node_Check ( int index, bool onoff ) { // First off, show/hide the node /*NodeClass *node = Get_Item_Node (index); if (node != NULL) { node->Hide (!onoff); }*/ // Update the UI for this node //ListView_SetCheckState (m_ListCtrl, index, onoff); return ; } //////////////////////////////////////////////////////////////////////////// // // Reset_List // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Reset_List (void) { m_ClassIDStack.Delete_All (); Populate_List ((uint32)0); return ; } //////////////////////////////////////////////////////////////////////////// // // Populate_List // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Populate_List (uint32 class_id) { m_ListCtrl.SetRedraw (FALSE); m_ListCtrl.DeleteAllItems (); if (class_id == 0) { // // Add all the node categories to the list control // for (int index = 0; index < PRESET_CATEGORY_COUNT; index ++) { Insert_Factory (PRESET_CATEGORIES[index].name, PRESET_CATEGORIES[index].clsid); } } else { Insert_Navigator (); // // Fill all the node instances into the list control // for ( NodeClass *node = NodeMgrClass::Find_First (class_id); node != NULL; node = NodeMgrClass::Find_Next (node, class_id)) { // // Add this node to the list control // Insert_Node (node); } // // Fill all the factory instances into the list control // for ( DefinitionFactoryClass *factory = DefinitionFactoryMgrClass::Get_First (class_id); factory != NULL; factory = DefinitionFactoryMgrClass::Get_Next (factory, class_id)) { // // Add this node to the list control // if (factory->Get_Class_ID () != class_id) { Insert_Factory (factory->Get_Name (), factory->Get_Class_ID ()); } } // // Sort all the items // m_ListCtrl.SortItems (InstancesListSortCallback, 0L); } m_ListCtrl.SetRedraw (TRUE); // // Save this class ID for later // m_ClassID = class_id; // // Make sure the toolbar is up to date // Update_Overlays (); Update_Button_States (); return ; } //////////////////////////////////////////////////////////////////////////// // // Populate_List // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Populate_List (NodeClass *node) { m_ListCtrl.SetRedraw (FALSE); m_ListCtrl.DeleteAllItems (); if (node != NULL) { Insert_Navigator (); // // Add all the sub-nodes to the list control // for (int index = 0; index < node->Get_Sub_Node_Count (); index ++) { NodeClass *sub_node = node->Get_Sub_Node (index); if (sub_node != NULL) { // // Add this node to the list control // Insert_Node (sub_node); } } } // // Sort all the items // m_ListCtrl.SortItems (InstancesListSortCallback, 0L); m_ListCtrl.SetRedraw (TRUE); // // Make sure the toolbar is up to date // Update_Overlays (); Update_Button_States (); return ; } //////////////////////////////////////////////////////////////////////////// // // OnDeleteitemInstanceList // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::OnDeleteitemInstanceList ( NMHDR * pNMHDR, LRESULT * pResult ) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; (*pResult) = 0; // Get the node associated with this entry NodeClass *node = Get_Item_Node (pNMListView->iItem); MEMBER_RELEASE (node); // Free the item data structure associated with this entry ITEM_DATA *item_data = (ITEM_DATA *)m_ListCtrl.GetItemData (pNMListView->iItem); SAFE_DELETE (item_data); m_ListCtrl.SetItemData (pNMListView->iItem, 0L); return ; } //////////////////////////////////////////////////////////////////////////// // // InstancesListSortCallback // //////////////////////////////////////////////////////////////////////////// int CALLBACK InstancesListSortCallback ( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) { int retval = 0; ITEM_DATA *item_data1 = (ITEM_DATA *)lParam1; ITEM_DATA *item_data2 = (ITEM_DATA *)lParam2; if (item_data1 != NULL && item_data2 != NULL) { // // Do the types match? // if (item_data1->type == item_data2->type) { // // Do a simple name comparison // retval = ::lstrcmpi (item_data1->name, item_data2->name); } else { // // Sort based on type // retval = (item_data1->type - item_data2->type); } } return retval; } //////////////////////////////////////////////////////////////////////////// // // OnItemchangedInstanceList // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::OnItemchangedInstanceList ( NMHDR * pNMHDR, LRESULT* pResult ) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; *pResult = 0; if (pNMListView->uChanged & LVIF_STATE) { // // Did the selection set change? // if (pNMListView->uNewState & LVIS_SELECTED || pNMListView->uOldState & LVIS_SELECTED) { Update_Button_States (); } } return ; } //////////////////////////////////////////////////////////////////////////// // // Update_Button_States // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Update_Button_States (void) { // // Determine if there are any nodes in the current selection set. // bool enable = false; int index = -1; while (!enable && (index = m_ListCtrl.GetNextItem (index, LVNI_ALL | LVNI_SELECTED)) >= 0) { enable |= (Get_Item_Node (index) != NULL); } // // Enable or disable the edit button depending on // whether the selected item is a category or a node // m_Toolbar.Enable_Button (IDC_DELETE, enable); m_Toolbar.Enable_Button (IDC_EDIT, enable); m_Toolbar.Enable_Button (IDC_SELECT, enable); return ; } //////////////////////////////////////////////////////////////////////////// // // Hide_Node // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Hide_Node (NodeClass *node, uint32 class_id, bool hide) { PresetClass *preset = node->Get_Preset (); if (preset != NULL) { DefinitionClass *definition = preset->Get_Definition (); if (definition != NULL) { // // Did this node come from the selected factory? // uint32 curr_class_id = definition->Get_Class_ID (); uint32 superclass_id = ::SuperClassID_From_ClassID (curr_class_id); if (curr_class_id == class_id || superclass_id == class_id) { // // Change this node's display state // node->Hide (hide); } } } // // Now, check all this nodes children // for (int index = 0; index < node->Get_Sub_Node_Count (); index ++) { NodeClass *sub_node = node->Get_Sub_Node (index); if (sub_node != NULL) { Hide_Node (sub_node, class_id, hide); } } return ; } //////////////////////////////////////////////////////////////////////////// // // Hide_Nodes // //////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Hide_Nodes (int index, bool hide) { ITEM_DATA *item_data = (ITEM_DATA *)m_ListCtrl.GetItemData (index); if (item_data != NULL) { if (item_data->type == TYPE_FACTORY) { // // Loop over all the nodes in the world // for ( NodeClass *node = NodeMgrClass::Get_First (); node != NULL; node = NodeMgrClass::Get_Next (node)) { // // Hide this node (if necessary) // Hide_Node (node, item_data->class_id, hide); } } else if (item_data->type == TYPE_NODE) { // // Change this node's display state // item_data->node->Hide (hide); } } // // Make sure the main view is updated // ::Refresh_Main_View (); return ; } ///////////////////////////////////////////////////////////////////////////// // // Update_Overlays // ///////////////////////////////////////////////////////////////////////////// void InstancesPageClass::Update_Overlays (void) { // // Loop over all the entries in the current view // for (int index = 0; index < m_ListCtrl.GetItemCount (); index ++) { // // Get information about this entry // ITEM_DATA *item_data = (ITEM_DATA *)m_ListCtrl.GetItemData (index); if (item_data != NULL) { bool needs_overlay = false; // // Check to see if this entry has any sub-entries // if (item_data->type == TYPE_FACTORY) { needs_overlay = Does_Factory_Have_Children (item_data->class_id); } else if (item_data->type == TYPE_NODE && (item_data->node->Get_Sub_Node_Count () > 0)) { needs_overlay = true; } // // Set the appropriate overlay // ListView_SetOverlay (m_ListCtrl, index, needs_overlay ? 1 : 0); } } return ; } ///////////////////////////////////////////////////////////////////////////// // // Does_Factory_Have_Children // ///////////////////////////////////////////////////////////////////////////// bool InstancesPageClass::Does_Factory_Have_Children (uint32 factory_id) { bool retval = false; // // Check to see if there are any instances of this factory // in the world // for ( NodeClass *node = NodeMgrClass::Get_First (); node != NULL && retval == false; node = NodeMgrClass::Get_Next (node)) { PresetClass *preset = node->Get_Preset (); if (preset != NULL) { DefinitionClass *definition = preset->Get_Definition (); if (definition != NULL) { // // Did this node come from the specified factory? // uint32 class_id = definition->Get_Class_ID (); uint32 superclass_id = ::SuperClassID_From_ClassID (class_id); if (class_id == factory_id || superclass_id == factory_id) { retval = true; } } } } // // Check to see if this factory has any sub-factories // if (retval == false) { DefinitionFactoryClass *factory = DefinitionFactoryMgrClass::Get_First (factory_id); if (factory != NULL && factory->Get_Class_ID () != factory_id) { retval = true; } } return retval; }