1012 lines
24 KiB
C++
1012 lines
24 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/Combat/textwindow.cpp $*
|
||
|
* *
|
||
|
* Author:: Patrick Smith *
|
||
|
* *
|
||
|
* $Modtime:: 11/06/01 11:05a $*
|
||
|
* *
|
||
|
* $Revision:: 19 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
|
||
|
#include "textwindow.h"
|
||
|
#include "render2dsentence.h"
|
||
|
#include "assetmgr.h"
|
||
|
#include "texture.h"
|
||
|
#include "font3d.h"
|
||
|
#include "objectives.h"
|
||
|
#include "translatedb.h"
|
||
|
#include "wwaudio.h"
|
||
|
#include "globalsettings.h"
|
||
|
#include "scene.h"
|
||
|
#include "rendobj.h"
|
||
|
#include "stylemgr.h"
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
// Static member initialization
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
SceneClass *TextWindowClass::Scene = NULL;
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
// Local constants
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
static const char * FONT_NAME = "Arial MT";
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// TextWindowClass
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
TextWindowClass::TextWindowClass (void) :
|
||
|
FirstLineIndex (0),
|
||
|
CurrentDisplayCount (0),
|
||
|
IsDisplayed (false),
|
||
|
AreColumnsDisplayed (false),
|
||
|
IsViewDirty (true),
|
||
|
TextRect (0, 0, 0, 0),
|
||
|
ColumnHeight (0),
|
||
|
LineSpacing (0)
|
||
|
{
|
||
|
TextRenderers[0] = NULL;
|
||
|
TextRenderers[1] = NULL;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// ~TextWindowClass
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
TextWindowClass::~TextWindowClass (void)
|
||
|
{
|
||
|
Free_Backdrop ();
|
||
|
Free_Contents ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Initialize
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Initialize (SceneClass *scene)
|
||
|
{
|
||
|
REF_PTR_SET (Scene, scene);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Shutdown
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Shutdown (void)
|
||
|
{
|
||
|
REF_PTR_RELEASE (Scene);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Free_Backdrop
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Free_Backdrop (void)
|
||
|
{
|
||
|
//
|
||
|
// Reset the rest of the data that is dependent on the backdrop
|
||
|
//
|
||
|
FirstLineIndex = 0;
|
||
|
IsDisplayed = false;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Free_Contents
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Free_Contents (void)
|
||
|
{
|
||
|
//
|
||
|
// Free each row of renderer's
|
||
|
//
|
||
|
Delete_All_Columns ();
|
||
|
Free_Renderers ();
|
||
|
|
||
|
//
|
||
|
// Reset the rest of the data that is dependent on the contents
|
||
|
//
|
||
|
FirstLineIndex = 0;
|
||
|
IsDisplayed = false;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Free_Renderers
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Free_Renderers (void)
|
||
|
{
|
||
|
//
|
||
|
// Free each text renderer object
|
||
|
//
|
||
|
delete TextRenderers[0];
|
||
|
delete TextRenderers[1];
|
||
|
TextRenderers[0] = NULL;
|
||
|
TextRenderers[1] = NULL;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Set_Backdrop
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Set_Backdrop
|
||
|
(
|
||
|
const char * texture_name,
|
||
|
const RectClass & screen_rect,
|
||
|
const Vector2 & texture_size,
|
||
|
const RectClass & endcap_rect,
|
||
|
const RectClass & fadeout_rect,
|
||
|
const RectClass & textback_rect
|
||
|
)
|
||
|
{
|
||
|
Free_Backdrop ();
|
||
|
|
||
|
//
|
||
|
// Load the backdrop texture
|
||
|
//
|
||
|
TextureClass *texture = WW3DAssetManager::Get_Instance()->Get_Texture (texture_name, TextureClass::MIP_LEVELS_1);
|
||
|
if (texture != NULL) {
|
||
|
|
||
|
//
|
||
|
// Pass the texture onto the renderer
|
||
|
//
|
||
|
Backdrop.Reset ();
|
||
|
Backdrop.Set_Texture (texture);
|
||
|
|
||
|
//
|
||
|
// Configure the renderer
|
||
|
//
|
||
|
Backdrop.Set_Coordinate_Range (Render2DClass::Get_Screen_Resolution ());
|
||
|
|
||
|
//
|
||
|
// Calculate the width and height of the sections
|
||
|
//
|
||
|
int endcap_width = endcap_rect.Width ();
|
||
|
int fadeout_width = fadeout_rect.Width ();
|
||
|
int textback_width = screen_rect.Width () - ((endcap_width + fadeout_width) * 2);
|
||
|
|
||
|
int endcap_height = endcap_rect.Height ();
|
||
|
int fadeout_height = fadeout_rect.Height ();
|
||
|
int textback_height = textback_rect.Height ();
|
||
|
|
||
|
//
|
||
|
// Calculate the UV coordinates for each section
|
||
|
//
|
||
|
RectClass endcap_uvs1 (endcap_rect);
|
||
|
RectClass endcap_uvs2 (endcap_rect);
|
||
|
RectClass fadeout_uvs1 (fadeout_rect);
|
||
|
RectClass fadeout_uvs2 (fadeout_rect);
|
||
|
RectClass textback_uvs (textback_rect);
|
||
|
endcap_uvs1.Inverse_Scale (texture_size);
|
||
|
endcap_uvs2.Inverse_Scale (texture_size);
|
||
|
fadeout_uvs1.Inverse_Scale (texture_size);
|
||
|
fadeout_uvs2.Inverse_Scale (texture_size);
|
||
|
textback_uvs.Inverse_Scale (texture_size);
|
||
|
|
||
|
//
|
||
|
// Reverse the UVs of the endcap and fadeaways on the right
|
||
|
//
|
||
|
float temp_float = endcap_uvs2.Left;
|
||
|
endcap_uvs2.Left = endcap_uvs2.Right;
|
||
|
endcap_uvs2.Right = temp_float;
|
||
|
|
||
|
temp_float = fadeout_uvs2.Left;
|
||
|
fadeout_uvs2.Left = fadeout_uvs2.Right;
|
||
|
fadeout_uvs2.Right = temp_float;
|
||
|
|
||
|
//
|
||
|
// Calculate the screen rectangle (in pixels) for each of the sections
|
||
|
//
|
||
|
RectClass endcap_screen_rect1 (0, 0, endcap_width, endcap_height);
|
||
|
RectClass fadeout_screen_rect1 (0, 0, fadeout_width, fadeout_height);
|
||
|
RectClass textback_screen_rect (0, 0, textback_width, textback_height);
|
||
|
RectClass fadeout_screen_rect2 (0, 0, fadeout_width, fadeout_height);
|
||
|
RectClass endcap_screen_rect2 (0, 0, endcap_width, endcap_height);
|
||
|
|
||
|
endcap_screen_rect1 += screen_rect.Upper_Left ();
|
||
|
fadeout_screen_rect1 += endcap_screen_rect1.Upper_Right ();
|
||
|
textback_screen_rect += fadeout_screen_rect1.Upper_Right ();
|
||
|
fadeout_screen_rect2 += textback_screen_rect.Upper_Right ();
|
||
|
endcap_screen_rect2 += fadeout_screen_rect2.Upper_Right ();
|
||
|
|
||
|
//
|
||
|
// Determine what area we have to draw the text into
|
||
|
//
|
||
|
const float border_size = 10.0F;
|
||
|
TextRect = textback_screen_rect;
|
||
|
TextRect.Inflate (Vector2 (-border_size, -border_size));
|
||
|
|
||
|
//
|
||
|
// Calculate how many times we should vertically tile the text backdrop
|
||
|
//
|
||
|
int largest_height = min (endcap_height, fadeout_height);
|
||
|
largest_height = min (largest_height, textback_height);
|
||
|
int section_count = (screen_rect.Height () / largest_height);
|
||
|
|
||
|
//
|
||
|
// Tile the text backdrop sections
|
||
|
//
|
||
|
for (int index = 0; index < section_count; index ++) {
|
||
|
|
||
|
//
|
||
|
// Submit the geometry
|
||
|
//
|
||
|
Backdrop.Add_Quad (fadeout_screen_rect1, fadeout_uvs1);
|
||
|
Backdrop.Add_Quad (fadeout_screen_rect2, fadeout_uvs2);
|
||
|
Backdrop.Add_Quad (textback_screen_rect, textback_uvs);
|
||
|
|
||
|
fadeout_screen_rect1 += Vector2 (0, fadeout_height);
|
||
|
fadeout_screen_rect2 += Vector2 (0, fadeout_height);
|
||
|
textback_screen_rect += Vector2 (0, textback_height);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add a chopped off section of an endcap onto the end (if necessary)
|
||
|
//
|
||
|
float percent = (screen_rect.Height () / largest_height) - section_count;
|
||
|
if (percent > 0) {
|
||
|
|
||
|
textback_uvs.Bottom = textback_uvs.Top + (textback_uvs.Height () * percent);
|
||
|
fadeout_uvs1.Bottom = fadeout_uvs1.Top + (fadeout_uvs1.Height () * percent);
|
||
|
fadeout_uvs2.Bottom = fadeout_uvs2.Top + (fadeout_uvs2.Height () * percent);
|
||
|
|
||
|
textback_screen_rect.Bottom = textback_screen_rect.Top + (textback_screen_rect.Height () * percent);
|
||
|
fadeout_screen_rect1.Bottom = fadeout_screen_rect1.Top + (fadeout_screen_rect1.Height () * percent);
|
||
|
fadeout_screen_rect2.Bottom = fadeout_screen_rect2.Top + (fadeout_screen_rect2.Height () * percent);
|
||
|
|
||
|
//
|
||
|
// Submit the geometry
|
||
|
//
|
||
|
Backdrop.Add_Quad (fadeout_screen_rect1, fadeout_uvs1);
|
||
|
Backdrop.Add_Quad (fadeout_screen_rect2, fadeout_uvs2);
|
||
|
Backdrop.Add_Quad (textback_screen_rect, textback_uvs);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Tile the endcaps appropriately
|
||
|
//
|
||
|
section_count = screen_rect.Height () / endcap_height;
|
||
|
for (index = 0; index < section_count; index ++) {
|
||
|
|
||
|
//
|
||
|
// Submit the geometry
|
||
|
//
|
||
|
Backdrop.Add_Quad (endcap_screen_rect1, endcap_uvs1);
|
||
|
Backdrop.Add_Quad (endcap_screen_rect2, endcap_uvs2);
|
||
|
|
||
|
endcap_screen_rect1 += Vector2 (0, endcap_height);
|
||
|
endcap_screen_rect2 += Vector2 (0, endcap_height);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add a chopped off section of an endcap onto the end (if necessary)
|
||
|
//
|
||
|
percent = (screen_rect.Height () / endcap_height) - section_count;
|
||
|
if (percent > 0) {
|
||
|
|
||
|
endcap_uvs1.Bottom = endcap_uvs1.Top + (endcap_uvs1.Height () * percent);
|
||
|
endcap_uvs2.Bottom = endcap_uvs2.Top + (endcap_uvs2.Height () * percent);
|
||
|
endcap_screen_rect1.Bottom = endcap_screen_rect1.Top + (endcap_screen_rect1.Height () * percent);
|
||
|
endcap_screen_rect2.Bottom = endcap_screen_rect2.Top + (endcap_screen_rect2.Height () * percent);
|
||
|
|
||
|
//
|
||
|
// Submit the geometry
|
||
|
//
|
||
|
Backdrop.Add_Quad (endcap_screen_rect1, endcap_uvs1);
|
||
|
Backdrop.Add_Quad (endcap_screen_rect2, endcap_uvs2);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Release our hold on the texture
|
||
|
//
|
||
|
REF_PTR_RELEASE(texture);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// On_Frame_Update
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::On_Frame_Update (void)
|
||
|
{
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Add_Column
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Add_Column (const WCHAR *column_name, float width, const Vector3 &color)
|
||
|
{
|
||
|
//
|
||
|
// Create a new column and add it to the list
|
||
|
//
|
||
|
TextColumnClass *column = new TextColumnClass;
|
||
|
column->Set_Name (column_name);
|
||
|
column->Set_Width (width);
|
||
|
column->Set_Color (color);
|
||
|
Columns.Add (column);
|
||
|
IsViewDirty = true;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Remove_Column
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
TextWindowClass::Remove_Column (int index)
|
||
|
{
|
||
|
if (index < 0 || index >= Columns.Count ()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Free the column
|
||
|
//
|
||
|
TextColumnClass *column = Columns[index];
|
||
|
delete column;
|
||
|
|
||
|
//
|
||
|
// Remove the column from the list
|
||
|
//
|
||
|
Columns.Delete (index);
|
||
|
IsViewDirty = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Delete_All_Columns
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Delete_All_Columns (void)
|
||
|
{
|
||
|
for (int index = 0; index < Columns.Count (); index ++) {
|
||
|
TextColumnClass *column = Columns[index];
|
||
|
delete column;
|
||
|
}
|
||
|
|
||
|
Columns.Delete_All ();
|
||
|
IsViewDirty = true;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Get_Item_Count
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
int
|
||
|
TextWindowClass::Get_Item_Count (void) const
|
||
|
{
|
||
|
return Columns[0]->Get_Item_Count ();
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Get_Display_Count
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
int
|
||
|
TextWindowClass::Get_Display_Count (void)
|
||
|
{
|
||
|
if (IsViewDirty) {
|
||
|
Update_View ();
|
||
|
}
|
||
|
|
||
|
return CurrentDisplayCount;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Delete_Item
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
TextWindowClass::Delete_Item (int index)
|
||
|
{
|
||
|
bool retval = true;
|
||
|
|
||
|
for (int col_index = 0; col_index < Columns.Count (); col_index ++) {
|
||
|
retval &= Columns[col_index]->Delete_Item (index);
|
||
|
}
|
||
|
|
||
|
IsViewDirty = true;
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Insert_Item
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
int
|
||
|
TextWindowClass::Insert_Item (int index, const WCHAR *text)
|
||
|
{
|
||
|
if (Columns.Count () <= 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Insert a new entry in the first column with the given text
|
||
|
//
|
||
|
index = Columns[0]->Insert_Item (index, text);
|
||
|
|
||
|
//
|
||
|
// Add blank entries to all the other columns
|
||
|
//
|
||
|
for (int col_index = 1; col_index < Columns.Count (); col_index ++) {
|
||
|
TextColumnClass *column = Columns[col_index];
|
||
|
column->Insert_Item (index, L"");
|
||
|
}
|
||
|
|
||
|
IsViewDirty = true;
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Set_Item_Text
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
TextWindowClass::Set_Item_Text (int index, int col_index, const WCHAR *text)
|
||
|
{
|
||
|
if (col_index < 0 || col_index >= Columns.Count ()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Change the text entry in this cell
|
||
|
//
|
||
|
Columns[col_index]->Set_Item_Text (index, text);
|
||
|
IsViewDirty = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Set_Item_Color
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
TextWindowClass::Set_Item_Color (int index, int col_index, const Vector3 &color)
|
||
|
{
|
||
|
if (col_index < 0 || col_index >= Columns.Count ()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Change the color for the item in this cell
|
||
|
//
|
||
|
Columns[col_index]->Set_Item_Color (index, color);
|
||
|
IsViewDirty = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Set_Item_Data
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
TextWindowClass::Set_Item_Data (int index, uint32 user_data)
|
||
|
{
|
||
|
//
|
||
|
// Store the user data in the first column
|
||
|
//
|
||
|
Columns[0]->Set_Item_Data (index, user_data);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Get_Item_Data
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
uint32
|
||
|
TextWindowClass::Get_Item_Data (int index)
|
||
|
{
|
||
|
//
|
||
|
// Lookup the user data (its stored in the first column)
|
||
|
//
|
||
|
return Columns[0]->Get_Item_Data (index);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Delete_All_Items
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Delete_All_Items (void)
|
||
|
{
|
||
|
for (int index = 0; index < Columns.Count (); index ++) {
|
||
|
Columns[index]->Delete_All_Items ();
|
||
|
}
|
||
|
|
||
|
IsViewDirty = true;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Build_View
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Build_View (void)
|
||
|
{
|
||
|
//
|
||
|
// Start fresh
|
||
|
//
|
||
|
Free_Renderers ();
|
||
|
|
||
|
//const RectClass &screen_rect = Render2DClass::Get_Screen_Resolution ();
|
||
|
|
||
|
//
|
||
|
// Create the fonts
|
||
|
//
|
||
|
FontCharsClass *header_font = StyleMgrClass::Peek_Font( StyleMgrClass::FONT_INGAME_HEADER_TXT );
|
||
|
FontCharsClass *font = StyleMgrClass::Peek_Font( StyleMgrClass::FONT_INGAME_TXT );
|
||
|
|
||
|
//
|
||
|
// Load the font we'll use for the column headers
|
||
|
//
|
||
|
if (header_font != NULL) {
|
||
|
ColumnHeight = (header_font->Get_Char_Height () * 1.5F);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create the header and body text renderers
|
||
|
//
|
||
|
TextRenderers[0] = new Render2DSentenceClass;
|
||
|
TextRenderers[1] = new Render2DSentenceClass;
|
||
|
|
||
|
TextRenderers[0]->Set_Font (header_font);
|
||
|
TextRenderers[1]->Set_Font (font);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Update_View
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Update_View (float *total_height, bool info_only)
|
||
|
{
|
||
|
//
|
||
|
// Ensure the view has been created before we try to update it
|
||
|
//
|
||
|
if (TextRenderers[0] == NULL || TextRenderers[1] == NULL) {
|
||
|
Build_View ();
|
||
|
}
|
||
|
|
||
|
TextRenderers[0]->Reset ();
|
||
|
TextRenderers[1]->Reset ();
|
||
|
|
||
|
//
|
||
|
// Update the column headers
|
||
|
//
|
||
|
if (AreColumnsDisplayed) {
|
||
|
|
||
|
float x_pos = TextRect.Left;
|
||
|
for (int col_index = 0; col_index < Columns.Count (); col_index ++) {
|
||
|
|
||
|
const Vector3 &color = Columns[col_index]->Get_Color ();
|
||
|
TextRenderers[0]->Build_Sentence (Columns[col_index]->Get_Name ());
|
||
|
TextRenderers[0]->Set_Location (Vector2 (x_pos, TextRect.Top));
|
||
|
TextRenderers[0]->Draw_Sentence (VRGB_TO_INT32(color));
|
||
|
|
||
|
x_pos += Columns[col_index]->Get_Width () * (TextRect.Right - TextRect.Left);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Move past the column headers
|
||
|
//
|
||
|
float y_pos = TextRect.Top;
|
||
|
if (AreColumnsDisplayed) {
|
||
|
y_pos += ColumnHeight;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Update the contents
|
||
|
//
|
||
|
CurrentDisplayCount = 0;
|
||
|
int item_count = Columns[0]->Get_Item_Count ();
|
||
|
for (int item_index = FirstLineIndex; item_index < item_count; item_index ++) {
|
||
|
|
||
|
//
|
||
|
// Update this row of information
|
||
|
//
|
||
|
float row_height = 0;
|
||
|
Update_Row (item_index, y_pos, &row_height);
|
||
|
CurrentDisplayCount ++;
|
||
|
|
||
|
//
|
||
|
// Check to see if we've gone outside the client area of the text window
|
||
|
//
|
||
|
if ((y_pos + row_height) > TextRect.Right && info_only == false) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Move down one row
|
||
|
//
|
||
|
y_pos += int(row_height + LineSpacing);
|
||
|
}
|
||
|
|
||
|
if (info_only == false) {
|
||
|
IsViewDirty = false;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the height to the caller (if necessary)
|
||
|
//
|
||
|
if (total_height != NULL) {
|
||
|
(*total_height) = (y_pos - TextRect.Top);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Get_Total_Display_Height
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
float
|
||
|
TextWindowClass::Get_Total_Display_Height (void)
|
||
|
{
|
||
|
float total_height = 0;
|
||
|
|
||
|
Update_View (&total_height, true);
|
||
|
|
||
|
return total_height;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Update_Row
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Update_Row
|
||
|
(
|
||
|
int item_index,
|
||
|
float y_pos,
|
||
|
float * row_height
|
||
|
)
|
||
|
{
|
||
|
float x_pos = int (TextRect.Left);
|
||
|
|
||
|
//
|
||
|
// Loop over all the columns
|
||
|
//
|
||
|
for (int col_index = 0; col_index < Columns.Count (); col_index ++) {
|
||
|
|
||
|
//
|
||
|
// Alias some variables for readability
|
||
|
//
|
||
|
TextColumnClass *column = Columns[col_index];
|
||
|
|
||
|
//
|
||
|
// Determine what text we should display
|
||
|
//
|
||
|
const WCHAR *text = L"";
|
||
|
Vector3 color (0 ,0, 0);
|
||
|
text = column->Get_Item_Text (item_index);
|
||
|
color = column->Get_Item_Color (item_index);
|
||
|
|
||
|
//
|
||
|
// Determine how wide the column should be
|
||
|
//
|
||
|
float col_width = column->Get_Width () * (TextRect.Right - TextRect.Left);
|
||
|
if (col_index + 1 >= Columns.Count ()) {
|
||
|
col_width = TextRect.Right - x_pos;
|
||
|
}
|
||
|
TextRenderers[1]->Set_Wrapping_Width (col_width - 5);
|
||
|
|
||
|
//
|
||
|
// Update the text and color of this renderer
|
||
|
//
|
||
|
TextRenderers[1]->Build_Sentence (text);
|
||
|
TextRenderers[1]->Set_Location (Vector2 (int(x_pos), int(y_pos)));
|
||
|
TextRenderers[1]->Draw_Sentence (VRGB_TO_INT32(color));
|
||
|
|
||
|
//
|
||
|
// See if this is the 'tallest' column so far
|
||
|
//
|
||
|
RectClass extents = TextRenderers[1]->Get_Draw_Extents ();
|
||
|
(*row_height) = max ((*row_height), extents.Height ());
|
||
|
|
||
|
//
|
||
|
// Move to the next column
|
||
|
//
|
||
|
x_pos += int (column->Get_Width () * (TextRect.Right - TextRect.Left));
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Display
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Display (bool onoff)
|
||
|
{
|
||
|
if (onoff != IsDisplayed) {
|
||
|
FirstLineIndex = 0;
|
||
|
CurrentDisplayCount = 0;
|
||
|
IsDisplayed = onoff;
|
||
|
IsViewDirty = onoff;
|
||
|
|
||
|
Backdrop.Set_Hidden (!onoff);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Page_Down
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Page_Down (void)
|
||
|
{
|
||
|
FirstLineIndex += CurrentDisplayCount;
|
||
|
Update_View ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Page_Up
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Page_Up (void)
|
||
|
{
|
||
|
FirstLineIndex -= CurrentDisplayCount;
|
||
|
FirstLineIndex = max (0, FirstLineIndex);
|
||
|
Update_View ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Scroll_To_Top
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Scroll_To_Top (void)
|
||
|
{
|
||
|
FirstLineIndex = 0;
|
||
|
Update_View ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Render
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextWindowClass::Render (void)
|
||
|
{
|
||
|
if (IsDisplayed == false) {
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
if (IsViewDirty || TextRenderers[0] == NULL) {
|
||
|
Update_View ();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Render the backdrop
|
||
|
//
|
||
|
Backdrop.Render ();
|
||
|
|
||
|
//
|
||
|
// Render each piece of text
|
||
|
//
|
||
|
TextRenderers[0]->Render();
|
||
|
TextRenderers[1]->Render();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
//********************************************************************************//
|
||
|
//
|
||
|
// Start of TextColumnClass
|
||
|
//
|
||
|
//********************************************************************************//
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Free_Data
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextColumnClass::Free_Data (void)
|
||
|
{
|
||
|
Delete_All_Items ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Reset_Contents
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextColumnClass::Reset_Contents (void)
|
||
|
{
|
||
|
//
|
||
|
// Remove all the entries
|
||
|
//
|
||
|
Free_Data ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Insert_Item
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
int
|
||
|
TextColumnClass::Insert_Item (int index, const WCHAR *item_name)
|
||
|
{
|
||
|
TextItemClass *item = new TextItemClass (item_name);
|
||
|
|
||
|
//
|
||
|
// Should we insert this item in the list or add it to the end?
|
||
|
//
|
||
|
if (index < Items.Count ()) {
|
||
|
Items.Insert (index + 1, item);
|
||
|
} else {
|
||
|
Items.Add (item);
|
||
|
index = (Items.Count () - 1);
|
||
|
}
|
||
|
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Delete_Item
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
TextColumnClass::Delete_Item (int index)
|
||
|
{
|
||
|
bool retval = false;
|
||
|
|
||
|
//
|
||
|
// Delete the item if we can find it in our list
|
||
|
//
|
||
|
if (index >= 0 && index < Items.Count ()) {
|
||
|
delete Items[index];
|
||
|
Items.Delete (index);
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Delete_All_Items
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
TextColumnClass::Delete_All_Items (void)
|
||
|
{
|
||
|
//
|
||
|
// Free each of the items in the list
|
||
|
//
|
||
|
for (int index = 0; index < Items.Count (); index ++) {
|
||
|
delete Items[index];
|
||
|
}
|
||
|
|
||
|
Items.Reset_Active();
|
||
|
return ;
|
||
|
}
|