681 lines
16 KiB
C++
681 lines
16 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/>.
|
|
*/
|
|
|
|
// PresetListDialog.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "leveledit.h"
|
|
#include "PresetListDialog.h"
|
|
#include "presetmgr.h"
|
|
#include "definition.h"
|
|
#include "definitionfactory.h"
|
|
#include "definitionfactorymgr.h"
|
|
#include "icons.h"
|
|
#include "utils.h"
|
|
#include "preset.h"
|
|
#include "persistfactory.h"
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PresetListDialogClass
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
PresetListDialogClass::PresetListDialogClass (CWnd *pParent)
|
|
: m_List (NULL),
|
|
m_ClassID (0),
|
|
m_RootClassID (0),
|
|
m_EnableTypeSel (true),
|
|
CDialog(PresetListDialogClass::IDD, pParent)
|
|
{
|
|
//{{AFX_DATA_INIT(PresetListDialogClass)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DoDataExchange
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::DoDataExchange (CDataExchange *pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(PresetListDialogClass)
|
|
DDX_Control(pDX, IDC_TYPE_COMBO, m_ComboBox);
|
|
DDX_Control(pDX, IDC_PRESET_TREE, m_PresetTreeCtrl);
|
|
DDX_Control(pDX, IDC_PRESET_LIST, m_PresetListCtrl);
|
|
//}}AFX_DATA_MAP
|
|
return ;
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(PresetListDialogClass, CDialog)
|
|
//{{AFX_MSG_MAP(PresetListDialogClass)
|
|
ON_BN_CLICKED(IDC_ADD, OnAdd)
|
|
ON_BN_CLICKED(IDC_REMOVE, OnRemove)
|
|
ON_NOTIFY(NM_DBLCLK, IDC_PRESET_LIST, OnDblclkPresetList)
|
|
ON_NOTIFY(NM_DBLCLK, IDC_PRESET_TREE, OnDblclkPresetTree)
|
|
ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRESET_LIST, OnItemchangedPresetList)
|
|
ON_NOTIFY(TVN_SELCHANGED, IDC_PRESET_TREE, OnSelchangedPresetTree)
|
|
ON_WM_DESTROY()
|
|
ON_CBN_SELENDOK(IDC_TYPE_COMBO, OnSelendokTypeCombo)
|
|
ON_CBN_SELCHANGE(IDC_TYPE_COMBO, OnSelchangeTypeCombo)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OnInitDialog
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
PresetListDialogClass::OnInitDialog (void)
|
|
{
|
|
CDialog::OnInitDialog ();
|
|
ASSERT (m_List != NULL);
|
|
|
|
//
|
|
// Configure the preset list control
|
|
//
|
|
m_PresetListCtrl.InsertColumn (0, "Name");
|
|
m_PresetListCtrl.InsertColumn (1, "Type");
|
|
|
|
//
|
|
// Configure the type combobox
|
|
//
|
|
Generate_Type_List ();
|
|
|
|
//
|
|
// Add the previously selected presets to the list control
|
|
//
|
|
for (int index = 0; index < m_List->Count (); index ++) {
|
|
|
|
//
|
|
// Lookup this preset
|
|
//
|
|
int preset_id = (*m_List)[index];
|
|
PresetClass *preset = PresetMgrClass::Find_Preset (preset_id);
|
|
|
|
//
|
|
// Add the preset to the list control
|
|
//
|
|
Add_Preset (preset);
|
|
}
|
|
|
|
//
|
|
// Fill in the tree control
|
|
//
|
|
m_PresetTreeCtrl.SetImageList (::Get_Global_Image_List (), TVSIL_NORMAL);
|
|
Populate_Preset_Tree ();
|
|
|
|
//
|
|
// Size the columns
|
|
//
|
|
CRect rect;
|
|
m_PresetListCtrl.GetClientRect (&rect);
|
|
m_PresetListCtrl.SetColumnWidth (0, rect.Width () * 2 / 3);
|
|
m_PresetListCtrl.SetColumnWidth (1, (rect.Width () / 3) - 2);
|
|
|
|
Update_Button_State ();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Update_Button_State
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::Update_Button_State (void)
|
|
{
|
|
bool enable_add = false;
|
|
bool enable_remove = (m_PresetListCtrl.GetNextItem (-1, LVNI_ALL | LVNI_SELECTED) >= 0);
|
|
|
|
//
|
|
// Should the add button be enabled?
|
|
//
|
|
HTREEITEM tree_item = m_PresetTreeCtrl.GetSelectedItem ();
|
|
if (tree_item != NULL) {
|
|
PresetClass *preset = (PresetClass *)m_PresetTreeCtrl.GetItemData (tree_item);
|
|
if (preset != NULL) {
|
|
enable_add = true;
|
|
}
|
|
}
|
|
|
|
::EnableWindow (::GetDlgItem (m_hWnd, IDC_ADD), enable_add);
|
|
::EnableWindow (::GetDlgItem (m_hWnd, IDC_REMOVE), enable_remove);
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Sort_Nodes
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::Sort_Nodes (HTREEITEM root_item, bool recursive)
|
|
{
|
|
for ( HTREEITEM tree_item = m_PresetTreeCtrl.GetChildItem (root_item);
|
|
tree_item != NULL;
|
|
tree_item = m_PresetTreeCtrl.GetNextSiblingItem (tree_item))
|
|
{
|
|
//
|
|
// Sort the children
|
|
//
|
|
m_PresetTreeCtrl.SortChildren (tree_item);
|
|
|
|
//
|
|
// Recurse through the hierarchy
|
|
//
|
|
if (recursive && m_PresetTreeCtrl.ItemHasChildren (tree_item)) {
|
|
Sort_Nodes (tree_item, recursive);
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Add_Preset
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::Add_Preset (PresetClass *preset)
|
|
{
|
|
if (preset != NULL && preset->Get_Definition () != NULL) {
|
|
|
|
//
|
|
// Insert this preset into the list control
|
|
//
|
|
int list_index = m_PresetListCtrl.InsertItem (0xFFF, preset->Get_Name ());
|
|
if (list_index >= 0) {
|
|
|
|
//
|
|
// Set the entry's type name
|
|
//
|
|
int class_id = preset->Get_Definition ()->Get_Class_ID ();
|
|
DefinitionFactoryClass *factory = DefinitionFactoryMgrClass::Find_Factory (class_id);
|
|
if (factory != NULL) {
|
|
LPCTSTR type_name = factory->Get_Name ();
|
|
m_PresetListCtrl.SetItemText (list_index, 1, type_name);
|
|
}
|
|
|
|
//
|
|
// Associate the preset ID with this list entry
|
|
//
|
|
m_PresetListCtrl.SetItemData (list_index, preset->Get_ID ());
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OnOK
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::OnOK (void)
|
|
{
|
|
m_List->Delete_All ();
|
|
|
|
int count = m_PresetListCtrl.GetItemCount ();
|
|
for (int index = 0; index < count; index ++) {
|
|
int preset_id = m_PresetListCtrl.GetItemData (index);
|
|
m_List->Add (preset_id);
|
|
}
|
|
|
|
CDialog::OnOK ();
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OnAdd
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::OnAdd (void)
|
|
{
|
|
HTREEITEM tree_item = m_PresetTreeCtrl.GetSelectedItem ();
|
|
if (tree_item != NULL) {
|
|
|
|
//
|
|
// Add the preset from the currently selected tree item to the list
|
|
//
|
|
PresetClass *preset = (PresetClass *)m_PresetTreeCtrl.GetItemData (tree_item);
|
|
if (preset != NULL) {
|
|
Add_Preset (preset);
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OnRemove
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::OnRemove (void)
|
|
{
|
|
int index = m_PresetListCtrl.GetNextItem (-1, LVNI_ALL | LVNI_SELECTED);
|
|
if (index >= 0) {
|
|
m_PresetListCtrl.DeleteItem (index);
|
|
|
|
//
|
|
// Select the previous entry in the list
|
|
//
|
|
int count = m_PresetListCtrl.GetItemCount ();
|
|
if (count > 0) {
|
|
if (index >= (count-1)) {
|
|
index --;
|
|
}
|
|
index = max (index, 0);
|
|
m_PresetListCtrl.SetItemState (index, LVNI_SELECTED, LVNI_SELECTED);
|
|
}
|
|
|
|
Update_Button_State ();
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OnDblclkPresetList
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::OnDblclkPresetList
|
|
(
|
|
NMHDR * pNMHDR,
|
|
LRESULT * pResult
|
|
)
|
|
{
|
|
(*pResult) = 0;
|
|
|
|
OnRemove ();
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OnDblclkPresetTree
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::OnDblclkPresetTree
|
|
(
|
|
NMHDR * pNMHDR,
|
|
LRESULT * pResult
|
|
)
|
|
{
|
|
(*pResult) = 0;
|
|
|
|
OnAdd ();
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OnItemchangedPresetList
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::OnItemchangedPresetList
|
|
(
|
|
NMHDR * pNMHDR,
|
|
LRESULT * pResult
|
|
)
|
|
{
|
|
(*pResult) = 0;
|
|
|
|
Update_Button_State ();
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OnSelchangedPresetTree
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::OnSelchangedPresetTree
|
|
(
|
|
NMHDR * pNMHDR,
|
|
LRESULT * pResult
|
|
)
|
|
{
|
|
(*pResult) = 0;
|
|
|
|
Update_Button_State ();
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OnDestroy
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::OnDestroy (void)
|
|
{
|
|
m_PresetTreeCtrl.SetImageList (NULL, TVSIL_NORMAL);
|
|
CDialog::OnDestroy ();
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Generate_Type_List
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::Generate_Type_List (void)
|
|
{
|
|
//
|
|
// Configure the combo-box
|
|
//
|
|
m_ComboBox.SetImageList (::Get_Global_Image_List ());
|
|
m_ComboBox.EnableWindow (m_EnableTypeSel);
|
|
|
|
//
|
|
// Build a tree of factories
|
|
//
|
|
FACTORY_TREE factory_tree;
|
|
PresetMgrClass::Build_Factory_Tree (m_RootClassID, factory_tree);
|
|
|
|
//
|
|
// Default to game-objects if no other type is selected
|
|
//
|
|
if (m_ClassID == 0) {
|
|
m_ClassID = CLASSID_GAME_OBJECTS;
|
|
}
|
|
|
|
//
|
|
// Put these factories into the combobox
|
|
//
|
|
int index = 0;
|
|
Add_Factories_To_Combo (factory_tree.Peek_Root (), 0, index);
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Add_Factories_To_Combo
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::Add_Factories_To_Combo
|
|
(
|
|
NTreeLeafClass<uint32> *leaf,
|
|
int indent,
|
|
int & index
|
|
)
|
|
{
|
|
do
|
|
{
|
|
uint32 class_id = leaf->Get_Value ();
|
|
|
|
//
|
|
// Add this factory to the combobox
|
|
//
|
|
COMBOBOXEXITEM item = { 0 };
|
|
item.mask = CBEIF_IMAGE | CBEIF_INDENT | CBEIF_LPARAM | CBEIF_TEXT | CBEIF_SELECTEDIMAGE;
|
|
item.pszText = (char *)::Get_Factory_Name (class_id);
|
|
item.iImage = FOLDER_ICON;
|
|
item.iSelectedImage = FOLDER_ICON;
|
|
item.iIndent = indent;
|
|
item.lParam = (long)class_id;
|
|
item.iItem = index ++;
|
|
int item_index = m_ComboBox.InsertItem (&item);
|
|
|
|
//
|
|
// Is this the factory we need to select?
|
|
//
|
|
if (class_id == m_ClassID) {
|
|
m_ComboBox.SetCurSel (item_index);
|
|
}
|
|
|
|
//
|
|
// Recurse if necessary
|
|
//
|
|
NTreeLeafClass<uint32> *child = leaf->Peek_Child ();
|
|
if (child != NULL) {
|
|
Add_Factories_To_Combo (child, indent + 1, index);
|
|
}
|
|
|
|
} while ((leaf = leaf->Peek_Next ()) != NULL);
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Populate_Preset_Tree
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::Populate_Preset_Tree (void)
|
|
{
|
|
//
|
|
// Start fresh
|
|
//
|
|
CWaitCursor wait_cursor;
|
|
m_PresetTreeCtrl.DeleteAllItems ();
|
|
|
|
//
|
|
// Should we add any sub-factories to the tree?
|
|
//
|
|
if (DefinitionFactoryMgrClass::Find_Factory (m_ClassID) == NULL) {
|
|
|
|
//
|
|
// Generate the tree from its sub-factories
|
|
//
|
|
DefinitionFactoryClass *factory = NULL;
|
|
for ( factory = DefinitionFactoryMgrClass::Get_First (m_ClassID);
|
|
factory != NULL;
|
|
factory = DefinitionFactoryMgrClass::Get_Next (factory, m_ClassID))
|
|
{
|
|
if (factory->Is_Displayed ()) {
|
|
HTREEITEM folder_item = m_PresetTreeCtrl.InsertItem (factory->Get_Name (), FOLDER_ICON, FOLDER_ICON);
|
|
|
|
//
|
|
// Generate the tree of presets
|
|
//
|
|
PRESET_TREE preset_tree;
|
|
PresetMgrClass::Build_Preset_Tree (factory->Get_Class_ID (), preset_tree);
|
|
|
|
//
|
|
// Populate the tree control
|
|
//
|
|
Fill_Tree (preset_tree.Peek_Root (), folder_item);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Generate the tree of presets
|
|
//
|
|
PRESET_TREE preset_tree;
|
|
PresetMgrClass::Build_Preset_Tree (m_ClassID, preset_tree);
|
|
|
|
//
|
|
// Populate the tree control
|
|
//
|
|
Fill_Tree (preset_tree.Peek_Root (), TVI_ROOT);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Fill_Tree
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::Fill_Tree (NTreeLeafClass<PresetClass *> *leaf, HTREEITEM parent_item)
|
|
{
|
|
//
|
|
// Loop over all the presets
|
|
//
|
|
for ( ; leaf != NULL; leaf = leaf->Peek_Next ()) {
|
|
PresetClass *preset = leaf->Get_Value ();
|
|
|
|
ASSERT (preset != NULL);
|
|
if (preset != NULL) {
|
|
|
|
//
|
|
// Insert the new preset into the tree
|
|
//
|
|
int icon = preset->Get_Icon_Index ();
|
|
HTREEITEM new_item = m_PresetTreeCtrl.InsertItem (preset->Get_Name (), icon, icon, parent_item);
|
|
if (new_item != NULL) {
|
|
|
|
//
|
|
// Associate the preset with its tree entry
|
|
//
|
|
m_PresetTreeCtrl.SetItemData (new_item, (LONG)preset);
|
|
|
|
//
|
|
// Recurse if necessary
|
|
//
|
|
NTreeLeafClass<PresetClass *> *child = leaf->Peek_Child ();
|
|
if (child != NULL) {
|
|
Fill_Tree (child, new_item);
|
|
m_PresetTreeCtrl.SortChildren (parent_item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
//
|
|
// Add all the presets (by category) to the tree control
|
|
//
|
|
DefinitionFactoryClass *factory = NULL;
|
|
for ( factory = DefinitionFactoryMgrClass::Get_First (m_ClassID);
|
|
factory != NULL;
|
|
factory = DefinitionFactoryMgrClass::Get_Next (factory, m_ClassID))
|
|
{
|
|
//
|
|
// Add this folder to the tree ctrl
|
|
//
|
|
HTREEITEM folder_item = m_PresetTreeCtrl.InsertItem (factory->Get_Name (), FOLDER_ICON, FOLDER_ICON);
|
|
|
|
//
|
|
// Add all the folder contents to the tree ctrl
|
|
//
|
|
PresetClass *preset = NULL;
|
|
uint32 factory_id = factory->Get_Class_ID ();
|
|
for ( preset = PresetMgrClass::Get_First (factory_id, PresetMgrClass::ID_CLASS);
|
|
preset != NULL;
|
|
preset = PresetMgrClass::Get_Next (preset, factory_id, PresetMgrClass::ID_CLASS))
|
|
{
|
|
//
|
|
// Add this preset to the tree ctrl
|
|
//
|
|
HTREEITEM preset_item = m_PresetTreeCtrl.InsertItem ( preset->Get_Name (),
|
|
OBJECT_ICON,
|
|
OBJECT_ICON,
|
|
folder_item);
|
|
|
|
m_PresetTreeCtrl.SetItemData (preset_item, (ULONG)preset);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Sort the tree control
|
|
//
|
|
Sort_Nodes (TVI_ROOT, true);
|
|
m_PresetTreeCtrl.SortChildren (TVI_ROOT);
|
|
return ;
|
|
}*/
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OnSelendokTypeCombo
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
PresetListDialogClass::OnSelendokTypeCombo (void)
|
|
{
|
|
}
|
|
|
|
|
|
void PresetListDialogClass::OnSelchangeTypeCombo()
|
|
{
|
|
//
|
|
// Get the currently selected type from the combobox
|
|
//
|
|
int cur_sel = m_ComboBox.GetCurSel ();
|
|
if (cur_sel >= 0) {
|
|
|
|
//
|
|
// Repopulate the tree control if the type changed
|
|
//
|
|
uint32 new_class_id = m_ComboBox.GetItemData (cur_sel);
|
|
if (new_class_id != m_ClassID) {
|
|
m_ClassID = new_class_id;
|
|
Populate_Preset_Tree ();
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|