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/StringLibraryDialog.cpp

655 lines
15 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/>.
*/
// StringLibraryDialog.cpp : implementation file
//
#include "stdafx.h"
#include "leveledit.h"
#include "stringlibrarydialog.h"
#include "translatedb.h"
#include "translateobj.h"
#include "editstringdialog.h"
#include "utils.h"
#include "stringscategoryviewdialog.h"
#include "stringscategorynamedialog.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// Contants
/////////////////////////////////////////////////////////////////////////////
static const int BORDER_X = 10;
static const int BORDER_Y = 10;
static const int SPACING_X = 10;
static const int SPACING_Y = 10;
/////////////////////////////////////////////////////////////////////////////
//
// StringLibraryDialogClass
//
/////////////////////////////////////////////////////////////////////////////
StringLibraryDialogClass::StringLibraryDialogClass (CWnd *pParent) :
IsInitialized (false),
CurrentTab (0),
Mode (MODE_STRING),
CDialog(StringLibraryDialogClass::IDD, pParent)
{
//{{AFX_DATA_INIT(StringLibraryDialogClass)
//}}AFX_DATA_INIT
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// ~StringLibraryDialogClass
//
/////////////////////////////////////////////////////////////////////////////
StringLibraryDialogClass::~StringLibraryDialogClass (void)
{
Clear_Clipboard ();
//
// Free the child dialog objects
//
for (int index = 0; index < CategoryPages.Count (); index ++) {
delete CategoryPages[index];
}
CategoryPages.Delete_All ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// DoDataExchange
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::DoDataExchange (CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(StringLibraryDialogClass)
DDX_Control(pDX, IDC_TAB_CTRL, m_TabCtrl);
//}}AFX_DATA_MAP
return ;
}
BEGIN_MESSAGE_MAP(StringLibraryDialogClass, CDialog)
//{{AFX_MSG_MAP(StringLibraryDialogClass)
ON_WM_SIZE()
ON_NOTIFY(TCN_SELCHANGE, IDC_TAB_CTRL, OnSelchangeTabCtrl)
ON_BN_CLICKED(IDC_ADD, OnAdd)
ON_BN_CLICKED(IDC_REMOVE, OnRemove)
ON_BN_CLICKED(IDC_RENAME, OnRename)
ON_COMMAND(IDM_MODE_TWIDDLER, OnModeTwiddler)
ON_COMMAND(IDM_MODE_STRING, OnModeString)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//
// OnInitDialog
//
/////////////////////////////////////////////////////////////////////////////
BOOL
StringLibraryDialogClass::OnInitDialog (void)
{
CDialog::OnInitDialog ();
//
// Loop over all the categories in the database
//
int count = TranslateDBClass::Get_Category_Count ();
for (int index = 0; index < count; index ++) {
//
// Lookup this category
//
TDBCategoryClass *category = TranslateDBClass::Get_Category (index);
if (category != NULL) {
Add_Category_Page (category);
}
}
//
// Display the first category page
//
if (CategoryPages.Count () > 0) {
CategoryPages[0]->ShowWindow (SW_SHOW);
}
Resize_Controls ();
Enable_Buttons ();
Update_Mode ();
IsInitialized = true;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnSize
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::OnSize
(
UINT nType,
int cx,
int cy
)
{
CDialog::OnSize (nType, cx, cy);
if (IsInitialized) {
Resize_Controls ();
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Resize_Controls
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::Resize_Controls (void)
{
//
// Get the window and button bounding rectangles
//
CRect rect;
CRect button_rect;
GetClientRect (&rect);
::GetWindowRect (::GetDlgItem (m_hWnd, IDOK), &button_rect);
//
// Calculate some positions and widths
//
int width = rect.Width ();
int height = rect.Height ();
int button_width = button_rect.Width ();
int button_height = button_rect.Height ();
int tab_width = width - (BORDER_X * 2);
int tab_height = height - ((BORDER_Y * 2) + (SPACING_Y) + button_height);
int button_y_pos = BORDER_Y + tab_height + SPACING_Y;
int button_x_pos = (width / 2) - (((button_width * 2) + (SPACING_X * 1)) / 2);
//
// Resize the tab control
//
m_TabCtrl.SetWindowPos (NULL, BORDER_X, BORDER_Y, tab_width, tab_height, SWP_NOZORDER | SWP_NOCOPYBITS);
//
// Get the display rectangle of the tab control
//
CRect tab_rect;
m_TabCtrl.GetWindowRect (&tab_rect);
m_TabCtrl.AdjustRect (FALSE, &tab_rect);
ScreenToClient (&tab_rect);
//
// Resize all the category page controls
//
for (int index = 0; index < CategoryPages.Count (); index ++) {
CategoryPages[index]->SetWindowPos (NULL, tab_rect.left + BORDER_X, tab_rect.top + BORDER_Y,
tab_rect.Width () - BORDER_X * 2, tab_rect.Height () - BORDER_Y * 2, SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOACTIVATE);
}
//
// Reposition the buttons
//
::SetWindowPos (::GetDlgItem (m_hWnd, IDOK), NULL, button_x_pos, button_y_pos,
0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOCOPYBITS | SWP_NOACTIVATE);
button_x_pos += button_width + SPACING_X;
::SetWindowPos (::GetDlgItem (m_hWnd, IDCANCEL), NULL, button_x_pos, button_y_pos,
0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOCOPYBITS | SWP_NOACTIVATE);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnOK
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::OnOK (void)
{
//
// Reset the database
//
TranslateDBClass::Remove_All ();
//
// Ask each category page to save its contents into the database
//
int count = CategoryPages.Count ();
bool update_version_number = false;
for (int index = 0; index < count; index ++) {
update_version_number |= CategoryPages[index]->Is_Version_Number_Dirty ();
CategoryPages[index]->Apply_Changes ();
}
//
// Increment the version number
//
if (update_version_number) {
TranslateDBClass::Update_Version ();
}
CDialog::OnOK ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnSelchangeTabCtrl
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::OnSelchangeTabCtrl
(
NMHDR * pNMHDR,
LRESULT * pResult
)
{
(*pResult) = 0;
Update_Page_Visibility ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Update_Page_Visibility
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::Update_Page_Visibility (void)
{
//
// Check to see if the user has selected a new tab
//
int newtab = m_TabCtrl.GetCurSel ();
if (CurrentTab != newtab) {
//
// Hide the old tab
//
if (CurrentTab < CategoryPages.Count () && CategoryPages[CurrentTab] != NULL) {
CategoryPages[CurrentTab]->ShowWindow (SW_HIDE);
}
//
// Show the new tab
//
if (CategoryPages[newtab] != NULL) {
CategoryPages[newtab]->ShowWindow (SW_SHOW);
}
//
// Remember what our new current tab is
//
CurrentTab = newtab;
}
Enable_Buttons ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Enable_Buttons
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::Enable_Buttons (void)
{
CMenu *menu = GetMenu ();
if (menu != NULL) {
CMenu *sub_menu = menu->GetSubMenu (0);
if (sub_menu != NULL) {
//
// Update the enable state of these menu entries
//
int value = MF_BYCOMMAND | ((CurrentTab != 0) ? MF_ENABLED : MF_GRAYED);
sub_menu->EnableMenuItem (IDC_REMOVE, value);
sub_menu->EnableMenuItem (IDC_RENAME, value);
}
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnAdd
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::OnAdd (void)
{
StringsCategoryNameDialogClass dialog (this);
if (dialog.DoModal () == IDOK) {
//
// Create the new category
//
TDBCategoryClass *category = TranslateDBClass::Add_Category (dialog.Get_Name ());
if (category != NULL) {
//
// Add some UI for this new category
//
Add_Category_Page (category);
//
// Ensure the new category page is the right size
//
Resize_Controls ();
}
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnRemove
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::OnRemove (void)
{
//
// The user can't remove the first (default) category
//
int index = CurrentTab;
if (index > 0) {
TDBCategoryClass *category = TranslateDBClass::Get_Category (index);
if (category != NULL) {
//
// Prompt the user to ensure they really want to remove the category
//
CString message;
message.Format ("Are you sure you wish to remove the %s category?", (LPCTSTR)category->Get_Name ());
if (::MessageBox (m_hWnd, message, "Remove Category", MB_ICONQUESTION | MB_YESNO) == IDYES) {
//
// Transfer the data from the old category to the default category
//
Clear_Clipboard ();
CategoryPages[index]->Cut (LocalClipboard, false);
CategoryPages[0]->Paste (LocalClipboard);
Clear_Clipboard ();
//
// Remove the category from the database
//
TranslateDBClass::Remove_Category (index);
//
// Remove the category's tab
//
m_TabCtrl.DeleteItem (index);
//
// Free the UI object and remove it from our list
//
CategoryPages[index]->DestroyWindow ();
delete CategoryPages[index];
CategoryPages.Delete (index);
//
// Change focus back to the first page
//
m_TabCtrl.SetCurSel (0);
Update_Page_Visibility ();
}
}
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Add_Category_Page
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::Add_Category_Page (TDBCategoryClass *category)
{
//
// Add a tab to the dialog for this category
//
TC_ITEM tab_info = { 0 };
tab_info.mask = TCIF_TEXT;
tab_info.pszText = (char *)(LPCTSTR)category->Get_Name ();
m_TabCtrl.InsertItem (0xFF, &tab_info);
//
// Create a page for this new category
//
StringsCategoryViewDialogClass *child_wnd = new StringsCategoryViewDialogClass;
child_wnd->Set_Category_ID (category->Get_ID ());
child_wnd->Set_Callback (this);
child_wnd->Create (this);
CategoryPages.Add (child_wnd);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// On_Cut
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::On_Cut (void)
{
Clear_Clipboard ();
CategoryPages[CurrentTab]->Cut (LocalClipboard);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// On_Paste
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::On_Paste (void)
{
CategoryPages[CurrentTab]->Paste (LocalClipboard);
Clear_Clipboard ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Clear_Clipboard
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::Clear_Clipboard (void)
{
for (int index = 0; index < LocalClipboard.Count (); index ++) {
SAFE_DELETE (LocalClipboard[index]);
}
LocalClipboard.Delete_All ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnRename
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::OnRename (void)
{
//
// The user can't rename the first (default) category
//
int index = CurrentTab;
if (index > 0) {
TDBCategoryClass *category = TranslateDBClass::Get_Category (index);
if (category != NULL) {
//
// Show a dialog to the user where they can enter a new name
//
StringsCategoryNameDialogClass dialog (this);
dialog.Set_Name (category->Get_Name ());
if (dialog.DoModal () == IDOK) {
//
// Rename the category and tab UI
//
const char *new_name = dialog.Get_Name ();
category->Set_Name (new_name);
//
// Update the tab's text
//
TC_ITEM tab_info = { 0 };
tab_info.mask = TCIF_TEXT;
tab_info.pszText = (char *)new_name;
m_TabCtrl.SetItem (index, &tab_info);
//
// HACK - Not really sure why, but the current page disappears
// when the tab ctrl is renamed (and it has nothing to do with repainting).
//
CategoryPages[index]->ShowWindow (SW_HIDE);
CategoryPages[index]->ShowWindow (SW_SHOW);
}
}
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnModeTwiddler
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::OnModeTwiddler (void)
{
Mode = MODE_TWIDDLER;
Update_Mode ();
//
// Let each category know the new editing mode
//
for (int index = 0; index < CategoryPages.Count (); index ++) {
CategoryPages[index]->Set_Edit_Mode (StringsCategoryViewDialogClass::EDIT_MODE_TWIDDLER);
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnModeString
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::OnModeString (void)
{
Mode = MODE_STRING;
Update_Mode ();
//
// Let each category know the new editing mode
//
for (int index = 0; index < CategoryPages.Count (); index ++) {
CategoryPages[index]->Set_Edit_Mode (StringsCategoryViewDialogClass::EDIT_MODE_STRING);
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Update_Mode
//
/////////////////////////////////////////////////////////////////////////////
void
StringLibraryDialogClass::Update_Mode (void)
{
CMenu *menu = GetMenu ();
if (menu != NULL) {
CMenu *sub_menu = menu->GetSubMenu (1);
if (sub_menu != NULL) {
//
// Determine which menu entry should get the check
//
int id = 0;
if (Mode == MODE_STRING) {
id = IDM_MODE_STRING;
} else {
id = IDM_MODE_TWIDDLER;
}
//
// Check the appropriate radio button
//
sub_menu->CheckMenuRadioItem (0, 1, Mode, MF_BYPOSITION);
}
}
return ;
}