halflife-photomode/cl_dll/vgui_SchemeManager.cpp

561 lines
15 KiB
C++

//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. ===========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================
#include "hud.h"
#include "vgui_SchemeManager.h"
#include "cvardef.h"
#include <string.h>
cvar_t* g_CV_BitmapFonts;
void Scheme_Init()
{
g_CV_BitmapFonts = gEngfuncs.pfnRegisterVariable("bitmapfonts", "1", 0);
}
//-----------------------------------------------------------------------------
// Purpose: Scheme managers data container
//-----------------------------------------------------------------------------
class CSchemeManager::CScheme
{
public:
enum
{
SCHEME_NAME_LENGTH = 32,
FONT_NAME_LENGTH = 48,
FONT_FILENAME_LENGTH = 64,
};
// name
char schemeName[SCHEME_NAME_LENGTH];
// font
char fontName[FONT_NAME_LENGTH];
int fontSize;
int fontWeight;
vgui::Font* font;
bool ownFontPointer; // true if the font is ours to delete
// scheme
byte fgColor[4];
byte bgColor[4];
byte armedFgColor[4];
byte armedBgColor[4];
byte mousedownFgColor[4];
byte mousedownBgColor[4];
byte borderColor[4];
// construction/destruction
CScheme();
~CScheme();
};
CSchemeManager::CScheme::CScheme()
{
schemeName[0] = 0;
fontName[0] = 0;
fontSize = 0;
fontWeight = 0;
font = NULL;
ownFontPointer = false;
}
CSchemeManager::CScheme::~CScheme()
{
// only delete our font pointer if we own it
if (ownFontPointer)
{
delete font;
}
}
//-----------------------------------------------------------------------------
// Purpose: resolution information
// !! needs to be shared out
//-----------------------------------------------------------------------------
static int g_ResArray[] =
{
320,
400,
512,
640,
800,
1024,
1152,
1280,
1600};
static int g_NumReses = sizeof(g_ResArray) / sizeof(int);
static byte* LoadFileByResolution(const char* filePrefix, int xRes, const char* filePostfix)
{
// find our resolution in the res array
int resNum = g_NumReses - 1;
while (g_ResArray[resNum] > xRes)
{
resNum--;
if (resNum < 0)
return NULL;
}
// try open the file
byte* pFile = NULL;
while (true)
{
// try load
char fname[256];
sprintf(fname, "%s%d%s", filePrefix, g_ResArray[resNum], filePostfix);
pFile = gEngfuncs.COM_LoadFile(fname, 5, NULL);
if (pFile)
break;
if (resNum == 0)
return NULL;
resNum--;
}
return pFile;
}
static void ParseRGBAFromString(byte colorArray[4], const char* colorVector)
{
int r, g, b, a;
if (4 == sscanf(colorVector, "%d %d %d %d", &r, &g, &b, &a))
{
colorArray[0] = r;
colorArray[1] = g;
colorArray[2] = b;
colorArray[3] = a;
}
else
{
//Pure white for easier debugging
colorArray[0] = 255;
colorArray[1] = 255;
colorArray[2] = 255;
colorArray[3] = 255;
}
}
//-----------------------------------------------------------------------------
// Purpose: initializes the scheme manager
// loading the scheme files for the current resolution
// Input : xRes -
// yRes - dimensions of output window
//-----------------------------------------------------------------------------
CSchemeManager::CSchemeManager(int xRes, int yRes)
{
// basic setup
m_pSchemeList = NULL;
m_iNumSchemes = 0;
// find the closest matching scheme file to our resolution
char token[1024];
char* pFile = (char*)LoadFileByResolution("", xRes, "_textscheme.txt");
m_xRes = xRes;
char* pFileStart = pFile;
byte* pFontData;
int fontFileLength;
char fontFilename[512];
//
// Read the scheme descriptions from the text file, into a temporary array
// format is simply:
// <paramName name> = <paramValue>
//
// a <paramName name> of "SchemeName" signals a new scheme is being described
//
const static int numTmpSchemes = 64;
static CScheme tmpSchemes[numTmpSchemes];
memset(tmpSchemes, 0, sizeof(tmpSchemes));
int currentScheme = -1;
CScheme* pScheme = NULL;
if (!pFile)
{
gEngfuncs.Con_DPrintf("Unable to find *_textscheme.txt\n");
goto buildDefaultFont;
}
// record what has been entered so we can create defaults from the different values
bool hasFgColor, hasBgColor, hasArmedFgColor, hasArmedBgColor, hasMouseDownFgColor, hasMouseDownBgColor;
pFile = gEngfuncs.COM_ParseFile(pFile, token);
while (strlen(token) > 0 && (currentScheme < numTmpSchemes))
{
// get the paramName name
static const int tokenSize = 64;
char paramName[tokenSize], paramValue[tokenSize];
strncpy(paramName, token, tokenSize);
paramName[tokenSize - 1] = 0; // ensure null termination
// get the '=' character
pFile = gEngfuncs.COM_ParseFile(pFile, token);
if (stricmp(token, "="))
{
if (currentScheme < 0)
{
gEngfuncs.Con_Printf("error parsing font scheme text file at file start - expected '=', found '%s''\n", token);
}
else
{
gEngfuncs.Con_Printf("error parsing font scheme text file at scheme '%s' - expected '=', found '%s''\n", tmpSchemes[currentScheme].schemeName, token);
}
break;
}
// get paramValue
pFile = gEngfuncs.COM_ParseFile(pFile, token);
strncpy(paramValue, token, tokenSize);
paramValue[tokenSize - 1] = 0; // ensure null termination
// is this a new scheme?
if (!stricmp(paramName, "SchemeName"))
{
// setup the defaults for the current scheme
if (pScheme)
{
// foreground color defaults (normal -> armed -> mouse down)
if (!hasFgColor)
{
pScheme->fgColor[0] = pScheme->fgColor[1] = pScheme->fgColor[2] = pScheme->fgColor[3] = 255;
}
if (!hasArmedFgColor)
{
memcpy(pScheme->armedFgColor, pScheme->fgColor, sizeof(pScheme->armedFgColor));
}
if (!hasMouseDownFgColor)
{
memcpy(pScheme->mousedownFgColor, pScheme->armedFgColor, sizeof(pScheme->mousedownFgColor));
}
// background color (normal -> armed -> mouse down)
if (!hasBgColor)
{
pScheme->bgColor[0] = pScheme->bgColor[1] = pScheme->bgColor[2] = pScheme->bgColor[3] = 0;
}
if (!hasArmedBgColor)
{
memcpy(pScheme->armedBgColor, pScheme->bgColor, sizeof(pScheme->armedBgColor));
}
if (!hasMouseDownBgColor)
{
memcpy(pScheme->mousedownBgColor, pScheme->armedBgColor, sizeof(pScheme->mousedownBgColor));
}
// font size
if (0 == pScheme->fontSize)
{
pScheme->fontSize = 17;
}
if ('\0' == pScheme->fontName[0])
{
strcpy(pScheme->fontName, "Arial");
}
}
// create the new scheme
currentScheme++;
pScheme = &tmpSchemes[currentScheme];
hasFgColor = hasBgColor = hasArmedFgColor = hasArmedBgColor = hasMouseDownFgColor = hasMouseDownBgColor = false;
strncpy(pScheme->schemeName, paramValue, CScheme::SCHEME_NAME_LENGTH);
pScheme->schemeName[CScheme::SCHEME_NAME_LENGTH - 1] = '\0'; // ensure null termination of string
}
if (!pScheme)
{
gEngfuncs.Con_Printf("font scheme text file MUST start with a 'SchemeName'\n");
break;
}
// pull the data out into the scheme
if (!stricmp(paramName, "FontName"))
{
strncpy(pScheme->fontName, paramValue, CScheme::FONT_NAME_LENGTH);
pScheme->fontName[CScheme::FONT_NAME_LENGTH - 1] = 0;
}
else if (!stricmp(paramName, "FontSize"))
{
pScheme->fontSize = atoi(paramValue);
}
else if (!stricmp(paramName, "FontWeight"))
{
pScheme->fontWeight = atoi(paramValue);
}
else if (!stricmp(paramName, "FgColor"))
{
ParseRGBAFromString(pScheme->fgColor, paramValue);
hasFgColor = true;
}
else if (!stricmp(paramName, "BgColor"))
{
ParseRGBAFromString(pScheme->bgColor, paramValue);
hasBgColor = true;
}
else if (!stricmp(paramName, "FgColorArmed"))
{
ParseRGBAFromString(pScheme->armedFgColor, paramValue);
hasArmedFgColor = true;
}
else if (!stricmp(paramName, "BgColorArmed"))
{
ParseRGBAFromString(pScheme->armedBgColor, paramValue);
hasArmedBgColor = true;
}
else if (!stricmp(paramName, "FgColorMousedown"))
{
ParseRGBAFromString(pScheme->mousedownFgColor, paramValue);
hasMouseDownFgColor = true;
}
else if (!stricmp(paramName, "BgColorMousedown"))
{
ParseRGBAFromString(pScheme->mousedownBgColor, paramValue);
hasMouseDownBgColor = true;
}
else if (!stricmp(paramName, "BorderColor"))
{
ParseRGBAFromString(pScheme->borderColor, paramValue);
hasMouseDownBgColor = true;
}
// get the new token last, so we now if the loop needs to be continued or not
pFile = gEngfuncs.COM_ParseFile(pFile, token);
}
// free the file
gEngfuncs.COM_FreeFile(pFileStart);
buildDefaultFont:
// make sure we have at least 1 valid font
if (currentScheme < 0)
{
currentScheme = 0;
strcpy(tmpSchemes[0].schemeName, "Default Scheme");
strcpy(tmpSchemes[0].fontName, "Arial");
tmpSchemes[0].fontSize = 0;
tmpSchemes[0].fgColor[0] = tmpSchemes[0].fgColor[1] = tmpSchemes[0].fgColor[2] = tmpSchemes[0].fgColor[3] = 255;
tmpSchemes[0].armedFgColor[0] = tmpSchemes[0].armedFgColor[1] = tmpSchemes[0].armedFgColor[2] = tmpSchemes[0].armedFgColor[3] = 255;
tmpSchemes[0].mousedownFgColor[0] = tmpSchemes[0].mousedownFgColor[1] = tmpSchemes[0].mousedownFgColor[2] = tmpSchemes[0].mousedownFgColor[3] = 255;
}
// we have the full list of schemes in the tmpSchemes array
// now allocate the correct sized list
m_iNumSchemes = currentScheme + 1; // 0-based index
m_pSchemeList = new CScheme[m_iNumSchemes];
// copy in the data
memcpy(m_pSchemeList, tmpSchemes, sizeof(CScheme) * m_iNumSchemes);
// create the fonts
for (int i = 0; i < m_iNumSchemes; i++)
{
m_pSchemeList[i].font = NULL;
// see if the current font values exist in a previously loaded font
for (int j = 0; j < i; j++)
{
// check if the font name, size, and weight are the same
if (!stricmp(m_pSchemeList[i].fontName, m_pSchemeList[j].fontName) && m_pSchemeList[i].fontSize == m_pSchemeList[j].fontSize && m_pSchemeList[i].fontWeight == m_pSchemeList[j].fontWeight)
{
// copy the pointer, but mark i as not owning it
m_pSchemeList[i].font = m_pSchemeList[j].font;
m_pSchemeList[i].ownFontPointer = false;
}
}
// if we haven't found the font already, load it ourselves
if (!m_pSchemeList[i].font)
{
fontFileLength = -1;
pFontData = NULL;
if (g_CV_BitmapFonts && 0 != g_CV_BitmapFonts->value)
{
int fontRes = 640;
if (m_xRes >= 1600)
fontRes = 1600;
else if (m_xRes >= 1280)
fontRes = 1280;
else if (m_xRes >= 1152)
fontRes = 1152;
else if (m_xRes >= 1024)
fontRes = 1024;
else if (m_xRes >= 800)
fontRes = 800;
sprintf(fontFilename, "gfx\\vgui\\fonts\\%d_%s.tga", fontRes, m_pSchemeList[i].schemeName);
pFontData = gEngfuncs.COM_LoadFile(fontFilename, 5, &fontFileLength);
if (!pFontData)
gEngfuncs.Con_Printf("Missing bitmap font: %s\n", fontFilename);
}
m_pSchemeList[i].font = new vgui::Font(
m_pSchemeList[i].fontName,
pFontData,
fontFileLength,
m_pSchemeList[i].fontSize,
0,
0,
m_pSchemeList[i].fontWeight,
false,
false,
false,
false);
m_pSchemeList[i].ownFontPointer = true;
}
// fix up alpha values; VGUI uses 1-A (A=0 being solid, A=255 transparent)
m_pSchemeList[i].fgColor[3] = 255 - m_pSchemeList[i].fgColor[3];
m_pSchemeList[i].bgColor[3] = 255 - m_pSchemeList[i].bgColor[3];
m_pSchemeList[i].armedFgColor[3] = 255 - m_pSchemeList[i].armedFgColor[3];
m_pSchemeList[i].armedBgColor[3] = 255 - m_pSchemeList[i].armedBgColor[3];
m_pSchemeList[i].mousedownFgColor[3] = 255 - m_pSchemeList[i].mousedownFgColor[3];
m_pSchemeList[i].mousedownBgColor[3] = 255 - m_pSchemeList[i].mousedownBgColor[3];
}
}
//-----------------------------------------------------------------------------
// Purpose: frees all the memory used by the scheme manager
//-----------------------------------------------------------------------------
CSchemeManager::~CSchemeManager()
{
delete[] m_pSchemeList;
m_iNumSchemes = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Finds a scheme in the list, by name
// Input : char *schemeName - string name of the scheme
// Output : SchemeHandle_t handle to the scheme
//-----------------------------------------------------------------------------
SchemeHandle_t CSchemeManager::getSchemeHandle(const char* schemeName)
{
// iterate through the list
for (int i = 0; i < m_iNumSchemes; i++)
{
if (!stricmp(schemeName, m_pSchemeList[i].schemeName))
return i;
}
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: always returns a valid scheme handle
// Input : schemeHandle -
// Output : CScheme
//-----------------------------------------------------------------------------
CSchemeManager::CScheme* CSchemeManager::getSafeScheme(SchemeHandle_t schemeHandle)
{
if (schemeHandle < m_iNumSchemes)
return m_pSchemeList + schemeHandle;
return m_pSchemeList;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the schemes pointer to a font
// Input : schemeHandle -
// Output : vgui::Font
//-----------------------------------------------------------------------------
vgui::Font* CSchemeManager::getFont(SchemeHandle_t schemeHandle)
{
return getSafeScheme(schemeHandle)->font;
}
void CSchemeManager::getFgColor(SchemeHandle_t schemeHandle, int& r, int& g, int& b, int& a)
{
CScheme* pScheme = getSafeScheme(schemeHandle);
r = pScheme->fgColor[0];
g = pScheme->fgColor[1];
b = pScheme->fgColor[2];
a = pScheme->fgColor[3];
}
void CSchemeManager::getBgColor(SchemeHandle_t schemeHandle, int& r, int& g, int& b, int& a)
{
CScheme* pScheme = getSafeScheme(schemeHandle);
r = pScheme->bgColor[0];
g = pScheme->bgColor[1];
b = pScheme->bgColor[2];
a = pScheme->bgColor[3];
}
void CSchemeManager::getFgArmedColor(SchemeHandle_t schemeHandle, int& r, int& g, int& b, int& a)
{
CScheme* pScheme = getSafeScheme(schemeHandle);
r = pScheme->armedFgColor[0];
g = pScheme->armedFgColor[1];
b = pScheme->armedFgColor[2];
a = pScheme->armedFgColor[3];
}
void CSchemeManager::getBgArmedColor(SchemeHandle_t schemeHandle, int& r, int& g, int& b, int& a)
{
CScheme* pScheme = getSafeScheme(schemeHandle);
r = pScheme->armedBgColor[0];
g = pScheme->armedBgColor[1];
b = pScheme->armedBgColor[2];
a = pScheme->armedBgColor[3];
}
void CSchemeManager::getFgMousedownColor(SchemeHandle_t schemeHandle, int& r, int& g, int& b, int& a)
{
CScheme* pScheme = getSafeScheme(schemeHandle);
r = pScheme->mousedownFgColor[0];
g = pScheme->mousedownFgColor[1];
b = pScheme->mousedownFgColor[2];
a = pScheme->mousedownFgColor[3];
}
void CSchemeManager::getBgMousedownColor(SchemeHandle_t schemeHandle, int& r, int& g, int& b, int& a)
{
CScheme* pScheme = getSafeScheme(schemeHandle);
r = pScheme->mousedownBgColor[0];
g = pScheme->mousedownBgColor[1];
b = pScheme->mousedownBgColor[2];
a = pScheme->mousedownBgColor[3];
}
void CSchemeManager::getBorderColor(SchemeHandle_t schemeHandle, int& r, int& g, int& b, int& a)
{
CScheme* pScheme = getSafeScheme(schemeHandle);
r = pScheme->borderColor[0];
g = pScheme->borderColor[1];
b = pScheme->borderColor[2];
a = pScheme->borderColor[3];
}