301 lines
9.1 KiB
C++
301 lines
9.1 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/>.
|
||
|
*/
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
*** 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 : Combat *
|
||
|
* *
|
||
|
* $Archive:: /Commando/Code/wwui/dialogparser.cpp $*
|
||
|
* *
|
||
|
* Author:: Patrick Smith *
|
||
|
* *
|
||
|
* $Modtime:: 10/25/01 3:54p $*
|
||
|
* *
|
||
|
* $Revision:: 12 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
|
||
|
#include "dialogparser.h"
|
||
|
#include "win.h"
|
||
|
#include "translatedb.h"
|
||
|
#include <commctrl.h>
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// Macros
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
#define ALIGN_WORD_PTR(p) ((WORD *)(((DWORD)p + 1) & ~1))
|
||
|
#define ALIGN_DWORD_PTR(p) ((DWORD *)(((DWORD)p + 3) & ~3))
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// Local prototypes
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
WORD *Skip_Dlg_Field (WORD *src, WCHAR *buffer = NULL, int buffer_len = 0, WORD *ctrl_type = NULL);
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Skip_Dlg_Field
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
WORD *
|
||
|
Skip_Dlg_Field (WORD *src, WCHAR *buffer, int buffer_len, WORD *ctrl_type)
|
||
|
{
|
||
|
//
|
||
|
// These fields always start on the next word boundary, so align
|
||
|
// the source pointer on this boundary.
|
||
|
//
|
||
|
WORD *retval = ALIGN_WORD_PTR(src);
|
||
|
|
||
|
//
|
||
|
// Note: The field codes are as follows:
|
||
|
//
|
||
|
// 0xFFFF - The following WORD is an ordinal value of a system class.
|
||
|
// 0x0000 - Empty field
|
||
|
// Otherwise - The remaining data is a NULL terminated WCHAR string.
|
||
|
//
|
||
|
if (*retval == 0xFFFF) {
|
||
|
|
||
|
//
|
||
|
// Move past the field designator
|
||
|
//
|
||
|
retval ++;
|
||
|
|
||
|
//
|
||
|
// Does the user want information about the ctrl type?
|
||
|
//
|
||
|
if (ctrl_type != NULL) {
|
||
|
*ctrl_type = *retval;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Move past the ctrl type identifier
|
||
|
//
|
||
|
retval ++;
|
||
|
} else if (*retval == 0x0000) {
|
||
|
|
||
|
//
|
||
|
// Null terminate the string if the user is expecting data
|
||
|
//
|
||
|
if (buffer != NULL) {
|
||
|
*buffer = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Move past the field designator
|
||
|
//
|
||
|
retval ++;
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// The following data is a null-terminated string. Scan
|
||
|
// as much data into our desination buffer as possible.
|
||
|
// Note: The data is stored in wide character format.
|
||
|
//
|
||
|
while (*retval != 0x0000) {
|
||
|
if (buffer != NULL && buffer_len > 1) {
|
||
|
|
||
|
//
|
||
|
// Store this character in the supplied buffer
|
||
|
// and decrement the remaining buffer length.
|
||
|
//
|
||
|
*buffer++ = *retval;
|
||
|
buffer_len --;
|
||
|
}
|
||
|
retval ++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Ensure the supplied buffer is NULL terminated
|
||
|
//
|
||
|
if (buffer != NULL) {
|
||
|
*buffer = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Advance to the next field
|
||
|
//
|
||
|
retval ++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the new buffer position to the caller
|
||
|
//
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Parse_Template
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
DialogParserClass::Parse_Template
|
||
|
(
|
||
|
int res_id,
|
||
|
int * dlg_width,
|
||
|
int * dlg_height,
|
||
|
WideStringClass * dlg_title,
|
||
|
DynamicVectorClass<ControlDefinitionStruct> * control_list
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Load the resource file
|
||
|
//
|
||
|
HRSRC resource = ::FindResource (ProgramInstance, MAKEINTRESOURCE (res_id), RT_DIALOG);
|
||
|
HGLOBAL hglobal = ::LoadResource (ProgramInstance, resource);
|
||
|
LPVOID res_buffer = ::LockResource (hglobal);
|
||
|
if(res_buffer != NULL) {
|
||
|
|
||
|
//
|
||
|
// The first few bytes of the resource buffer are the DLGTEMPLATE structure
|
||
|
//
|
||
|
DLGTEMPLATE *dlg_template = (DLGTEMPLATE *)res_buffer;
|
||
|
(*dlg_width) = (int)dlg_template->cx;
|
||
|
(*dlg_height) = (int)dlg_template->cy;
|
||
|
|
||
|
//
|
||
|
// Move past the DLGTEMPLATE header to the other fields
|
||
|
//
|
||
|
WORD *buffer = (WORD *)(((char *)res_buffer) + sizeof (DLGTEMPLATE));
|
||
|
|
||
|
//
|
||
|
// Skip the menu, and window class
|
||
|
//
|
||
|
buffer = Skip_Dlg_Field (buffer);
|
||
|
buffer = Skip_Dlg_Field (buffer);
|
||
|
|
||
|
//
|
||
|
// Read the title
|
||
|
//
|
||
|
buffer = Skip_Dlg_Field (buffer, dlg_title->Get_Buffer (96), 96);
|
||
|
|
||
|
WCHAR *string_id = ::wcsstr (dlg_title->Peek_Buffer (), L"IDS_");
|
||
|
if (string_id != NULL) {
|
||
|
WideStringClass wide_string_id = string_id;
|
||
|
StringClass ascii_string_id;
|
||
|
wide_string_id.Convert_To (ascii_string_id);
|
||
|
(*dlg_title) = TRANSLATE_BY_DESC(ascii_string_id);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Do we need to skip past the font settings?
|
||
|
//
|
||
|
if (dlg_template->style & DS_SETFONT) {
|
||
|
buffer ++;
|
||
|
while (*buffer != 0x0000) {
|
||
|
buffer ++;
|
||
|
}
|
||
|
buffer ++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Loop over each control and gather information about them
|
||
|
//
|
||
|
for (int index = 0; index < dlg_template->cdit; index ++) {
|
||
|
DLGITEMTEMPLATE *dlg_item_template = (DLGITEMTEMPLATE *)ALIGN_DWORD_PTR((DWORD *)buffer);
|
||
|
buffer = (WORD *)(((char *)dlg_item_template) + sizeof (DLGITEMTEMPLATE));
|
||
|
|
||
|
//
|
||
|
// Read the ctrl type
|
||
|
//
|
||
|
WCHAR text_buffer[256] = { 0 };
|
||
|
WORD ctrl_type = 0x0000;
|
||
|
buffer = Skip_Dlg_Field (buffer, text_buffer, 256, &ctrl_type);
|
||
|
|
||
|
//
|
||
|
// Wasn't one of the standard types, so see if we can determine
|
||
|
// what it is by its class name.
|
||
|
//
|
||
|
if (ctrl_type == 0) {
|
||
|
::_wcsupr (text_buffer);
|
||
|
if (::wcsstr (text_buffer, L"TRACKBAR") != 0) {
|
||
|
ctrl_type = SLIDER;
|
||
|
} else if (::wcsstr (text_buffer, L"TABCONTROL") != 0) {
|
||
|
ctrl_type = TAB;
|
||
|
} else if (::wcsstr (text_buffer, L"LISTVIEW") != 0) {
|
||
|
ctrl_type = LIST_CTRL;
|
||
|
} else if (::wcsstr (text_buffer, L"MAP") != 0) {
|
||
|
ctrl_type = MAP;
|
||
|
} else if (::wcsstr (text_buffer, L"VIEWER") != 0) {
|
||
|
ctrl_type = VIEWER;
|
||
|
} else if (::wcsstr (text_buffer, L"HOTKEY") != 0) {
|
||
|
ctrl_type = HOTKEY;
|
||
|
} else if (::wcsstr (text_buffer, L"SHORTCUTBAR") != 0) {
|
||
|
ctrl_type = SHORTCUT_BAR;
|
||
|
} else if (::wcsstr (text_buffer, L"MERCHANDISE") != 0) {
|
||
|
ctrl_type = MERCHANDISE_CTRL;
|
||
|
} else if (::wcsstr (text_buffer, L"TREEVIEW") != 0) {
|
||
|
ctrl_type = TREE_CTRL;
|
||
|
} else if (::wcsicmp(text_buffer, PROGRESS_CLASSW) == 0) {
|
||
|
ctrl_type = PROGRESS_BAR;
|
||
|
} else if (::wcsstr (text_buffer, L"HEALTHBAR") != 0) {
|
||
|
ctrl_type = HEALTH_BAR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Read the window text
|
||
|
//
|
||
|
buffer = Skip_Dlg_Field (buffer, text_buffer, 256);
|
||
|
|
||
|
WCHAR *string_id = ::wcsstr (text_buffer, L"IDS_");
|
||
|
if (string_id != NULL) {
|
||
|
WideStringClass wide_string_id = string_id;
|
||
|
StringClass ascii_string_id;
|
||
|
wide_string_id.Convert_To (ascii_string_id);
|
||
|
WideStringClass translation = TRANSLATE_BY_DESC(ascii_string_id);
|
||
|
::wcscpy (string_id, translation);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add this control definition to the list
|
||
|
//
|
||
|
ControlDefinitionStruct definition;
|
||
|
definition.id = (int)dlg_item_template->id;
|
||
|
definition.style = dlg_item_template->style;
|
||
|
definition.x = dlg_item_template->x;
|
||
|
definition.y = dlg_item_template->y;
|
||
|
definition.cx = dlg_item_template->cx;
|
||
|
definition.cy = dlg_item_template->cy;
|
||
|
definition.type = (CONTROL_TYPE)ctrl_type;
|
||
|
definition.title = text_buffer;
|
||
|
control_list->Add (definition);
|
||
|
|
||
|
//
|
||
|
// Skip past the extra data
|
||
|
//
|
||
|
WORD extra_data_size = *buffer;
|
||
|
buffer ++;
|
||
|
if (extra_data_size > 0) {
|
||
|
buffer = (WORD *)(((char *)ALIGN_WORD_PTR(buffer)) + extra_data_size);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|