This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Tools/LevelEdit/ParameterInheritanceDialog.cpp

868 lines
23 KiB
C++

/*
** 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 <http://www.gnu.org/licenses/>.
*/
// ParameterInheritanceDialog.cpp : implementation file
//
#include "stdafx.h"
#include "leveledit.h"
#include "ParameterInheritanceDialog.h"
#include "definition.h"
#include "presetmgr.h"
#include "preset.h"
#include "parameter.h"
#include "definitionparameter.h"
#include "combatchunkid.h"
#include "soldier.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// Local macros
/////////////////////////////////////////////////////////////////////////////
#ifndef ListView_SetCheckState
#define ListView_SetCheckState(hwndLV, i, fCheck) \
ListView_SetItemState(hwndLV, i, \
INDEXTOSTATEIMAGEMASK((fCheck)+1), LVIS_STATEIMAGEMASK)
#endif
/////////////////////////////////////////////////////////////////////////////
// Local constants
/////////////////////////////////////////////////////////////////////////////
static const int ICON_GAME_SETTING = 0;
static const int ICON_PHYS_SETTING = 1;
/////////////////////////////////////////////////////////////////////////////
// Local prototypes
/////////////////////////////////////////////////////////////////////////////
static LRESULT CALLBACK CheckBoxSubclassProc (HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
static BOOL TreeView_SetCheckState (HWND hwndTreeView, HTREEITEM hItem, BOOL fCheck);
static bool Find_Parameter_In_List (DynamicVectorClass<DefinitionParameterClass *> &parameter_list, ParameterClass *parameter);
/////////////////////////////////////////////////////////////////////////////
//
// ParameterInheritanceDialogClass
//
/////////////////////////////////////////////////////////////////////////////
ParameterInheritanceDialogClass::ParameterInheritanceDialogClass(CWnd* pParent /*=NULL*/)
: m_Preset (NULL),
CDialog(ParameterInheritanceDialogClass::IDD, pParent)
{
//{{AFX_DATA_INIT(ParameterInheritanceDialogClass)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// DoDataExchange
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(ParameterInheritanceDialogClass)
DDX_Control(pDX, IDC_PARAMETER_LIST, m_ListCtrl);
DDX_Control(pDX, IDC_CHILD_TREE, m_TreeCtrl);
//}}AFX_DATA_MAP
return ;
}
BEGIN_MESSAGE_MAP(ParameterInheritanceDialogClass, CDialog)
//{{AFX_MSG_MAP(ParameterInheritanceDialogClass)
ON_WM_DESTROY()
ON_NOTIFY(LVN_DELETEITEM, IDC_PARAMETER_LIST, OnDeleteitemParameterList)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//
// OnInitDialog
//
/////////////////////////////////////////////////////////////////////////////
BOOL
ParameterInheritanceDialogClass::OnInitDialog (void)
{
CDialog::OnInitDialog ();
//
// Configure the list control
//
CRect rect;
m_ListCtrl.GetClientRect (&rect);
m_ListCtrl.InsertColumn (0, "Name");
m_ListCtrl.SetColumnWidth (0, rect.Width () - ::GetSystemMetrics (SM_CXVSCROLL) - 1);
//
// Create a small imagelist for the list control to use
//
CImageList *imagelist = new CImageList;
imagelist->Create (16, 16, ILC_COLOR | ILC_MASK, 2, 0);
HICON icon1 = (HICON)::LoadImage (::AfxGetInstanceHandle (), MAKEINTRESOURCE(IDI_PARAM), IMAGE_ICON, 16, 16, LR_SHARED | LR_DEFAULTCOLOR);
HICON icon2 = (HICON)::LoadImage (::AfxGetInstanceHandle (), MAKEINTRESOURCE(IDI_PHYS), IMAGE_ICON, 16, 16, LR_SHARED | LR_DEFAULTCOLOR);
imagelist->Add (icon1);
imagelist->Add (icon2);
m_ListCtrl.SetImageList (imagelist, LVSIL_SMALL);
//
// Create a state imagelist for the list control to use for checkboxes
//
imagelist = new CImageList;
imagelist->Create (MAKEINTRESOURCE (IDB_CHECKBOX_STATES1), 13, 0, RGB (255, 0, 255));
m_ListCtrl.SetImageList (imagelist, LVSIL_STATE);
//
// Create a state imagelist for the tree control to use for checkboxes
//
imagelist = new CImageList;
imagelist->Create (MAKEINTRESOURCE (IDB_CHECKBOX_STATES), 13, 0, RGB (255, 0, 255));
m_TreeCtrl.SetImageList (imagelist, TVSIL_STATE);
//
// Fill in the parameter list and preset list
//
Populate_List_Ctrl ();
Populate_Tree_Ctrl ();
//
// Subclass the list and tree controls so we can handle the checkstates
//
LONG oldproc1 = ::SetWindowLong (m_ListCtrl, GWL_WNDPROC, (LONG)CheckBoxSubclassProc);
LONG oldproc2 = ::SetWindowLong (m_TreeCtrl, GWL_WNDPROC, (LONG)CheckBoxSubclassProc);
::SetProp (m_ListCtrl, "OLDPROC", (HANDLE)oldproc1);
::SetProp (m_TreeCtrl, "OLDPROC", (HANDLE)oldproc2);
::SetProp (m_ListCtrl, "IS_LIST_CTRL", (HANDLE)TRUE);
::SetProp (m_TreeCtrl, "IS_LIST_CTRL", (HANDLE)FALSE);
//
// Determine whether or not to enable the dialogue propogation controls
//
bool enable_dialogue_ctrls = false;
if (m_Preset != NULL && m_Preset->Is_Soldier_Preset ()) {
enable_dialogue_ctrls = true;
}
::EnableWindow (::GetDlgItem (m_hWnd, IDC_PROPOGATE_DIALOGUE), enable_dialogue_ctrls);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// Populate_List_Ctrl
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::Populate_List_Ctrl (void)
{
ASSERT (m_Preset != NULL);
//
// Get the definition this preset sits on
//
DefinitionClass *definition = m_Preset->Get_Definition ();
ASSERT (definition != NULL);
if (definition != NULL) {
//
// Recursively add paramters from this definition to the list control
//
Add_Parameters_To_List (definition, NULL, ICON_GAME_SETTING);
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Add_Parameters_To_List
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::Add_Parameters_To_List
(
DefinitionClass * definition,
DefinitionParameterClass * parent,
int icon
)
{
ASSERT (definition != NULL);
//
// Add these parameters to the list control
//
int count = definition->Get_Parameter_Count ();
for (int index = 0; index < count; index ++) {
ParameterClass *parameter = definition->Lock_Parameter (index);
if (parameter != NULL) {
//
// Is this parameter one we need to recurse into?
//
if (parameter->Get_Type () == ParameterClass::TYPE_MODELDEFINITIONID) {
//
// Lookup the definition that this parameter points to
//
int def_id = ((ModelDefParameterClass *)parameter)->Get_Value ();
DefinitionClass *model_def = DefinitionMgrClass::Find_Definition (def_id, false);
if (model_def != NULL) {
DefinitionParameterClass *def_param = new DefinitionParameterClass;
def_param->Set_Definition (definition);
def_param->Set_Parameter (parameter);
def_param->Set_Index (index);
def_param->Set_Parent (parent);
//
// Recurse into this model definition
//
Add_Parameters_To_List (model_def, def_param, ICON_PHYS_SETTING);
MEMBER_RELEASE (def_param);
}
} else {
//
// Insert this preset into the list control
//
int item_index = m_ListCtrl.InsertItem (0xFFFF, parameter->Get_Name (), icon);
if (item_index >= 0) {
DefinitionParameterClass *def_param = new DefinitionParameterClass;
def_param->Set_Definition (definition);
def_param->Set_Parameter (parameter);
def_param->Set_Index (index);
def_param->Set_Parent (parent);
m_ListCtrl.SetItemData (item_index, (LONG)def_param);
ListView_SetCheckState (m_ListCtrl, item_index, false);
}
}
}
definition->Unlock_Parameter (index);
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Populate_Tree_Ctrl
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::Populate_Tree_Ctrl (void)
{
ASSERT (m_Preset != NULL);
int parent_id = m_Preset->Get_ID ();
//
// Add all the presets that 'inherit' from this preset
//
Add_Children_To_Tree (TVI_ROOT, parent_id);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Add_Children_To_Tree
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::Add_Children_To_Tree (HTREEITEM parent_item, int parent_id)
{
//
// Lookup the parent preset
//
PresetClass *parent_preset = PresetMgrClass::Find_Preset (parent_id);
if (parent_preset != NULL) {
//
// Loop over all the children of this preset
//
int count = parent_preset->Get_Child_Preset_Count ();
for (int index = 0; index < count; index ++) {
PresetClass *child_preset = parent_preset->Get_Child_Preset (index);
if (child_preset != NULL) {
//
// Add this preset to the tree
//
HTREEITEM new_item = m_TreeCtrl.InsertItem (child_preset->Get_Name (), parent_item);
if (new_item != NULL) {
//
// Associate the preset pointer with this tree item
//
m_TreeCtrl.SetItemData (new_item, (LONG)child_preset);
//
// Check this preset by default
//
TreeView_SetCheckState (m_TreeCtrl, new_item, true);
//
// Recursively fill in this presets's children
//
Add_Children_To_Tree (new_item, child_preset->Get_ID ());
}
}
}
}
//
// Ensure this leaf is sorted
//
m_TreeCtrl.SortChildren (parent_item);
m_TreeCtrl.Expand (parent_item, TVE_EXPAND);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnDestroy
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::OnDestroy (void)
{
//
// Free the small image list we associated with the list control
//
CImageList *imagelist = m_ListCtrl.GetImageList (LVSIL_SMALL);
m_ListCtrl.SetImageList (NULL, LVSIL_SMALL);
SAFE_DELETE (imagelist);
//
// Free the state image list we associated with the list control
//
imagelist = m_ListCtrl.GetImageList (LVSIL_STATE);
m_ListCtrl.SetImageList (NULL, LVSIL_STATE);
SAFE_DELETE (imagelist);
//
// Free the state image list we associated with the tree control
//
imagelist = m_TreeCtrl.GetImageList (TVSIL_STATE);
m_TreeCtrl.SetImageList (NULL, TVSIL_STATE);
SAFE_DELETE (imagelist);
CDialog::OnDestroy ();
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// CheckBoxSubclassProc
//
////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK
CheckBoxSubclassProc
(
HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam
)
{
WNDPROC old_proc = (WNDPROC)::GetProp (hwnd, "OLDPROC");
if (message == WM_LBUTTONUP) {
//
// Is this the list control or the tree control?
//
BOOL is_list_ctrl = (BOOL)::GetProp (hwnd, "IS_LIST_CTRL");
if (is_list_ctrl) {
//
// 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 dialog that the user wants to toggle the checkbox
//
::PostMessage (::GetParent (hwnd), WM_USER+102, 0, (LPARAM)hittest.iItem);
}
} else {
//
// Find out where the user clicked
//
TVHITTESTINFO hittest = { 0 };
hittest.pt.x = LOWORD (lparam);
hittest.pt.y = HIWORD (lparam);
::SendMessage (hwnd, TVM_HITTEST, 0, (LPARAM)&hittest);
//
// Did the user click one of the checkboxes?
//
if (hittest.flags & TVHT_ONITEMSTATEICON) {
//
// Notify the dialog that the user wants to toggle the checkbox
//
::PostMessage (::GetParent (hwnd), WM_USER+103, 0, (LPARAM)hittest.hItem);
}
}
} else if (message == WM_DESTROY) {
::SetWindowLong (hwnd, GWL_WNDPROC, (LONG)old_proc);
::RemoveProp (hwnd, "OLDPROC");
::RemoveProp (hwnd, "IS_LIST_CTRL");
}
//
// Allow the default message processing to occur
//
LRESULT result = 0L;
if (old_proc != NULL) {
result = ::CallWindowProc (old_proc, hwnd, message, wparam, lparam);
} else {
result = ::DefWindowProc (hwnd, message, wparam, lparam);
}
return result;
}
/////////////////////////////////////////////////////////////////////////////
//
// WindowProc
//
/////////////////////////////////////////////////////////////////////////////
LRESULT
ParameterInheritanceDialogClass::WindowProc
(
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
if (message == WM_USER + 102) {
//
// Invert the checked state of this entry
//
int index = (int)lParam;
BOOL checked = ListView_GetCheckState (m_ListCtrl, index);
Update_List_Entry_Check (index, (bool)(checked != 1));
} else if (message == WM_USER + 103) {
//
// Invert the checked state of this entry
//
HTREEITEM tree_item = (HTREEITEM)lParam;
BOOL checked = m_TreeCtrl.GetCheck (tree_item);
Update_Tree_Entry_Check (tree_item, (bool)(checked != 1));
}
return CDialog::WindowProc (message, wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////
//
// Update_Tree_Entry_Check
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::Update_Tree_Entry_Check (HTREEITEM parent_item, bool checked)
{
//
// Update this entry's check-state
//
TreeView_SetCheckState (m_TreeCtrl, parent_item, checked);
//
// Recurse through all the children
//
for ( HTREEITEM item = m_TreeCtrl.GetChildItem (parent_item);
item != NULL;
item = m_TreeCtrl.GetNextSiblingItem (item))
{
Update_Tree_Entry_Check (item, checked);
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Update_List_Entry_Check
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::Update_List_Entry_Check (int index, bool checked)
{
//
// Is this entry part of a selection?
//
if (m_ListCtrl.GetItemState (index, LVIS_SELECTED) == LVIS_SELECTED) {
//
// Apply the new check state to all the selected entries
//
int sel_index = -1;
while ((sel_index = m_ListCtrl.GetNextItem (sel_index, LVNI_ALL | LVNI_SELECTED)) >= 0) {
ListView_SetCheckState (m_ListCtrl, sel_index, checked);
}
} else {
//
// Simply change the check state of this entry
//
ListView_SetCheckState (m_ListCtrl, index, checked);
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// TreeView_SetCheckState
//
/////////////////////////////////////////////////////////////////////////////
BOOL
TreeView_SetCheckState (HWND hwndTreeView, HTREEITEM hItem, BOOL fCheck)
{
TVITEM tvItem;
tvItem.mask = TVIF_HANDLE | TVIF_STATE;
tvItem.hItem = hItem;
tvItem.stateMask = TVIS_STATEIMAGEMASK;
/*
Since state images are one-based, 1 in this macro turns the check off, and
2 turns it on.
*/
tvItem.state = INDEXTOSTATEIMAGEMASK((fCheck ? 2 : 1));
return TreeView_SetItem(hwndTreeView, &tvItem);
}
/////////////////////////////////////////////////////////////////////////////
//
// OnOK
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::OnOK (void)
{
DynamicVectorClass<PresetClass *> preset_list;
DynamicVectorClass<DefinitionParameterClass *> parameter_list;
//
// Build a list of selected parameters and presets
//
Build_Parameter_List (parameter_list);
Build_Preset_List (TVI_ROOT, preset_list);
//
// Does the user want to propogate the dialogue settings?
//
bool propogate_dialogue_settings = false;
if (SendDlgItemMessage (IDC_PROPOGATE_DIALOGUE, BM_GETCHECK) == 1) {
propogate_dialogue_settings = true;
}
//
// Loop over all the selected presets and propagate the changes
//
DefinitionClass *base_def = m_Preset->Get_Definition ();
for (int index = 0; index < preset_list.Count (); index ++) {
PresetClass *preset = preset_list[index];
DefinitionClass *derived_def = preset->Get_Definition ();
if (base_def != NULL) {
Propagate_Changes (base_def, derived_def, parameter_list);
//
// Propogate the dialogue settings if necessary
//
if ( propogate_dialogue_settings &&
base_def->Get_Class_ID () == CLASSID_GAME_OBJECT_DEF_SOLDIER &&
derived_def->Get_Class_ID () == CLASSID_GAME_OBJECT_DEF_SOLDIER)
{
SoldierGameObjDef *base_soldier = reinterpret_cast<SoldierGameObjDef *> (base_def);
SoldierGameObjDef *derived_soldier = reinterpret_cast<SoldierGameObjDef *> (derived_def);
DialogueClass *src_list = base_soldier->Get_Dialog_List ();
DialogueClass *dest_list = derived_soldier->Get_Dialog_List ();
//
// Copy the settings from the base to the derived...
//
for (int index = 0; index < DIALOG_MAX; index ++) {
dest_list[index] = src_list[index];
}
}
}
}
CDialog::OnOK ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Find_Parameter_In_List
//
/////////////////////////////////////////////////////////////////////////////
bool
Find_Parameter_In_List
(
DynamicVectorClass<DefinitionParameterClass *> &parameter_list,
ParameterClass * parameter
)
{
bool retval = false;
//
// Loop over all the parameters in the list
//
for (int index = 0; index < parameter_list.Count (); index ++) {
DefinitionParameterClass *def_param = parameter_list[index];
//
// Is this the parameter we were looking for?
//
if (def_param != NULL && def_param->Get_Parameter () == parameter) {
retval = true;
break;
}
}
return retval;
}
/////////////////////////////////////////////////////////////////////////////
//
// Propagate_Changes
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::Propagate_Changes
(
DefinitionClass * base_def,
DefinitionClass * derived_def,
DynamicVectorClass<DefinitionParameterClass *> &parameter_list
)
{
bool is_valid = true;
//
// Compare all the parameters with this derived definition to
// find any that are not overridden.
//
int param_count = base_def->Get_Parameter_Count ();
for (int param_index = 0; is_valid && param_index < param_count; param_index ++) {
ParameterClass *parameter = base_def->Lock_Parameter (param_index);
ParameterClass *curr_parameter = derived_def->Lock_Parameter (param_index);
ASSERT (parameter != NULL);
ASSERT (curr_parameter != NULL);
//
// Are we comparing the same parameter? (We better be).
//
if ( parameter->Get_Type () == curr_parameter->Get_Type () &&
::lstrcmpi (parameter->Get_Name (), curr_parameter->Get_Name ()) == 0)
{
//
// Do we need to recurse into this parameter?
//
if (parameter->Get_Type () == ParameterClass::TYPE_MODELDEFINITIONID) {
//
// Lookup the definitions that these parameters reference
//
int base_id = ((ModelDefParameterClass *)parameter)->Get_Value ();
int derived_id = ((ModelDefParameterClass *)curr_parameter)->Get_Value ();
DefinitionClass *base_model_def = DefinitionMgrClass::Find_Definition (base_id, false);
DefinitionClass *derived_model_def = DefinitionMgrClass::Find_Definition (derived_id, false);
//
// Recurse into these definitions
//
if ( base_model_def != NULL && derived_model_def != NULL &&
base_model_def->Get_Class_ID () == derived_model_def->Get_Class_ID ())
{
Propagate_Changes (base_model_def, derived_model_def, parameter_list);
}
} else {
//
// Should we propagate this parameter's value?
//
if (::Find_Parameter_In_List (parameter_list, parameter)) {
//
// Copy the parameter value from the parent.
//
curr_parameter->Copy_Value (*parameter);
}
}
} else {
is_valid = false;
}
//
// Release the parameter pointers
//
base_def->Unlock_Parameter (param_index);
derived_def->Unlock_Parameter (param_index);
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Build_Parameter_List
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::Build_Parameter_List (DynamicVectorClass<DefinitionParameterClass *> &parameter_list)
{
//
// Loop over all the parameters
//
for (int index = 0; index < m_ListCtrl.GetItemCount (); index ++) {
DefinitionParameterClass *parameter = NULL;
parameter = (DefinitionParameterClass *)m_ListCtrl.GetItemData (index);
//
// Add this parameter to the list if the user checked it
//
if (parameter != NULL && ListView_GetCheckState (m_ListCtrl, index)) {
parameter_list.Add (parameter);
}
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Build_Preset_List
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::Build_Preset_List
(
HTREEITEM parent_item,
DynamicVectorClass<PresetClass *> & preset_list
)
{
//
// Loop over all the immediate children
//
for ( HTREEITEM item = m_TreeCtrl.GetChildItem (parent_item);
item != NULL;
item = m_TreeCtrl.GetNextSiblingItem (item))
{
PresetClass *preset = (PresetClass *)m_TreeCtrl.GetItemData (item);
if (preset != NULL) {
//
// Add this preset to the list if necessary
//
if (m_TreeCtrl.GetCheck (item)) {
preset_list.Add (preset);
}
//
// Recurse down the tree
//
Build_Preset_List (item, preset_list);
}
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnDeleteitemParameterList
//
/////////////////////////////////////////////////////////////////////////////
void
ParameterInheritanceDialogClass::OnDeleteitemParameterList
(
NMHDR * pNMHDR,
LRESULT* pResult
)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
(*pResult) = 0;
//
// Free the object we associted with this entry
//
DefinitionParameterClass *def_param = NULL;
def_param = (DefinitionParameterClass *)m_ListCtrl.GetItemData (pNMListView->iItem);
MEMBER_RELEASE (def_param);
m_ListCtrl.SetItemData (pNMListView->iItem, 0);
return ;
}