655 lines
15 KiB
C++
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 ;
|
|
}
|