2016-03-27 11:49:47 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
Copyright (C) 2015 the OpenMoHAA team
|
|
|
|
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
|
|
|
|
OpenMoHAA source code 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 2 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ui_local.h"
|
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
qboolean UI_FontDBCSIsLeadByte(fontheader_t* font, unsigned short uch);
|
|
|
|
int UI_FontCodeSearch(const fontheader_t* font, unsigned short uch);
|
|
|
|
|
2016-03-27 11:49:47 +02:00
|
|
|
UIFont::UIFont()
|
|
|
|
{
|
|
|
|
m_font = uii.Rend_LoadFont( "verdana-14" );
|
|
|
|
if( !m_font ) {
|
|
|
|
uii.Sys_Error( ERR_DROP, "Couldn't load font Verdana\n" );
|
|
|
|
}
|
|
|
|
|
|
|
|
color = UBlack;
|
|
|
|
setColor( color );
|
|
|
|
}
|
|
|
|
|
|
|
|
UIFont::UIFont
|
|
|
|
(
|
|
|
|
const char *fn
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
setFont( fn );
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIFont::Print
|
|
|
|
(
|
|
|
|
float x,
|
|
|
|
float y,
|
|
|
|
const char *text,
|
2023-05-18 00:54:37 +02:00
|
|
|
size_t maxlen,
|
2016-03-27 11:49:47 +02:00
|
|
|
qboolean bVirtualScreen
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
uii.Rend_SetColor( color );
|
|
|
|
uii.Rend_DrawString( m_font, text, x, y, maxlen, bVirtualScreen );
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIFont::PrintJustified
|
|
|
|
(
|
|
|
|
const UIRect2D& rect,
|
|
|
|
fonthorzjustify_t horz,
|
|
|
|
fontvertjustify_t vert,
|
|
|
|
const char *text,
|
|
|
|
float *vVirtualScale
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
float newx, newy;
|
|
|
|
int textwidth, textheight;
|
|
|
|
UIRect2D sizedRect;
|
2023-05-15 21:25:51 +02:00
|
|
|
const char* source;
|
|
|
|
char* dest;
|
|
|
|
char string[2048];
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-05-15 21:25:51 +02:00
|
|
|
if (vVirtualScale)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-05-15 21:25:51 +02:00
|
|
|
sizedRect.pos.x = rect.pos.x / vVirtualScale[0];
|
|
|
|
sizedRect.pos.y = rect.pos.y / vVirtualScale[1];
|
2023-05-16 16:22:42 +02:00
|
|
|
sizedRect.size.width = rect.size.width / vVirtualScale[0];
|
|
|
|
sizedRect.size.height = rect.size.height / vVirtualScale[1];
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sizedRect = rect;
|
|
|
|
}
|
|
|
|
|
2023-05-15 21:25:51 +02:00
|
|
|
if (horz == FONT_JUSTHORZ_LEFT && vert == FONT_JUSTVERT_TOP)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
|
|
|
// no need to justify
|
2023-05-15 21:25:51 +02:00
|
|
|
Print(sizedRect.pos.x, sizedRect.pos.y, text, -1, vVirtualScale != NULL);
|
2016-03-27 11:49:47 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-15 21:25:51 +02:00
|
|
|
textheight = getHeight(text, -1, qfalse);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-05-15 21:25:51 +02:00
|
|
|
switch (vert)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
|
|
|
case FONT_JUSTVERT_TOP:
|
|
|
|
newy = sizedRect.pos.y;
|
|
|
|
break;
|
|
|
|
case FONT_JUSTVERT_CENTER:
|
2023-05-15 21:25:51 +02:00
|
|
|
newy = sizedRect.pos.y + (sizedRect.size.height - textheight) * 0.5;
|
2016-03-27 11:49:47 +02:00
|
|
|
break;
|
|
|
|
case FONT_JUSTVERT_BOTTOM:
|
2023-05-15 21:25:51 +02:00
|
|
|
newy = sizedRect.pos.y + sizedRect.size.height - textheight;
|
2016-03-27 11:49:47 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
newy = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
source = text;
|
2023-05-15 21:25:51 +02:00
|
|
|
while (*source)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-05-15 21:25:51 +02:00
|
|
|
// skip new lines
|
|
|
|
while (*source == '\n') {
|
2016-03-27 11:49:47 +02:00
|
|
|
source++;
|
2023-05-15 21:25:51 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-05-15 21:25:51 +02:00
|
|
|
if (!*source) {
|
|
|
|
// don't print an empty string
|
2016-03-27 11:49:47 +02:00
|
|
|
return;
|
2023-05-15 21:25:51 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
dest = string;
|
|
|
|
|
|
|
|
do
|
|
|
|
*dest++ = *source++;
|
2023-05-15 21:25:51 +02:00
|
|
|
while (*source && *source != '\n');
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
*dest = 0;
|
|
|
|
|
2023-05-15 21:25:51 +02:00
|
|
|
textwidth = getWidth(string, -1);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-05-15 21:25:51 +02:00
|
|
|
switch (horz)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
|
|
|
case FONT_JUSTHORZ_CENTER:
|
2023-05-15 21:25:51 +02:00
|
|
|
newx = sizedRect.pos.x + (sizedRect.size.width - textwidth) * 0.5;
|
2016-03-27 11:49:47 +02:00
|
|
|
break;
|
|
|
|
case FONT_JUSTHORZ_LEFT:
|
|
|
|
newx = sizedRect.pos.x;
|
|
|
|
break;
|
|
|
|
case FONT_JUSTHORZ_RIGHT:
|
|
|
|
newx = sizedRect.pos.x + sizedRect.size.width - textwidth;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
newx = 0.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-05-15 21:25:51 +02:00
|
|
|
Print(newx, newy, string, -1, vVirtualScale != NULL);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
// expand for newline
|
2023-05-15 21:25:51 +02:00
|
|
|
newy += getHeight(" ", -1, qfalse);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIFont::setColor
|
|
|
|
(
|
|
|
|
UColor col
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
color = col;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIFont::setAlpha
|
|
|
|
(
|
|
|
|
float alpha
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
color.a = alpha;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIFont::setFont
|
|
|
|
(
|
|
|
|
const char *fontname
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
m_font = uii.Rend_LoadFont( fontname );
|
|
|
|
if( !m_font ) {
|
|
|
|
uii.Sys_Error( ERR_DROP, "Couldn't load font %s\n", fontname );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int UIFont::getWidth
|
|
|
|
(
|
|
|
|
const char *text,
|
|
|
|
int maxlen
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
return UI_FontStringWidth( m_font, text, maxlen );
|
|
|
|
}
|
|
|
|
|
|
|
|
int UIFont::getCharWidth
|
|
|
|
(
|
2023-07-17 00:24:04 +02:00
|
|
|
unsigned short ch
|
2016-03-27 11:49:47 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
{
|
2023-07-17 00:24:04 +02:00
|
|
|
int index;
|
|
|
|
int indirected;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
if (!m_font) {
|
|
|
|
return 0;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
if (ch == '\t') {
|
|
|
|
ch = ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_font->numPages)
|
|
|
|
{
|
|
|
|
int code = CodeSearch(ch);
|
|
|
|
if (code < 0) {
|
2016-03-27 11:49:47 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
index = m_font->charTable[code].index;
|
|
|
|
indirected = m_font->charTable[code].loc;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-07-17 00:24:04 +02:00
|
|
|
indirected = m_font->sgl[0]->indirection[ch];
|
|
|
|
if (indirected < 0 || indirected > 255) {
|
2016-03-27 11:49:47 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ch == '\t') {
|
|
|
|
return m_font->sgl[index]->locations[indirected].size[0] * 256.0 * 3.0;
|
|
|
|
} else {
|
|
|
|
return m_font->sgl[index]->locations[indirected].size[0] * 256.0;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int UIFont::getHeight
|
|
|
|
(
|
|
|
|
const char *text,
|
|
|
|
int maxlen,
|
|
|
|
qboolean bVirtual
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
float height;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if( !m_font ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
height = getHeight( bVirtual );
|
|
|
|
|
2023-05-09 20:08:35 +02:00
|
|
|
for(i = 0; text[i]; i++)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
|
|
|
if( maxlen != -1 && i > maxlen ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( text[ i ] == '\n' )
|
|
|
|
{
|
|
|
|
height += getHeight( bVirtual );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
|
|
|
int UIFont::getHeight
|
|
|
|
(
|
|
|
|
qboolean bVirtual
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if( bVirtual )
|
|
|
|
{
|
|
|
|
if( m_font )
|
|
|
|
{
|
2023-07-17 00:24:04 +02:00
|
|
|
return ( m_font->sgl[0]->height * uid.vidHeight / 480.0 );
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return ( 16.0 * uid.vidHeight / 480.0 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( m_font )
|
|
|
|
{
|
2023-07-17 00:24:04 +02:00
|
|
|
return m_font->sgl[0]->height;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
int UIFont::CodeSearch(unsigned short uch)
|
|
|
|
{
|
|
|
|
return UI_FontCodeSearch(m_font, uch);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
qboolean UI_FontDBCSIsLeadByte(fontheader_t* font, unsigned short uch)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-17 00:24:04 +02:00
|
|
|
// Byte ranges found in Wikipedia articles with relevant search strings in each case
|
|
|
|
switch (font->codePage) {
|
|
|
|
case 932:
|
|
|
|
// Shift_jis
|
|
|
|
return ((uch >= 0x81) && (uch <= 0x9F)) ||
|
|
|
|
((uch >= 0xE0) && (uch <= 0xFC));
|
|
|
|
// Lead bytes F0 to FC may be a Microsoft addition.
|
|
|
|
case 936:
|
|
|
|
// GBK
|
|
|
|
return (uch >= 0x81) && (uch <= 0xFE);
|
|
|
|
case 949:
|
|
|
|
// Korean Wansung KS C-5601-1987
|
|
|
|
return (uch >= 0x81) && (uch <= 0xFE);
|
|
|
|
case 950:
|
|
|
|
// Big5
|
|
|
|
return (uch >= 0x81) && (uch <= 0xFE);
|
|
|
|
case 1361:
|
|
|
|
// Korean Johab KS C-5601-1992
|
|
|
|
return
|
|
|
|
((uch >= 0x84) && (uch <= 0xD3)) ||
|
|
|
|
((uch >= 0xD8) && (uch <= 0xDE)) ||
|
|
|
|
((uch >= 0xE0) && (uch <= 0xF9));
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int UI_FontCodeSearch(const fontheader_t* font, unsigned short uch) {
|
|
|
|
int mid;
|
|
|
|
int l, r;
|
|
|
|
|
|
|
|
r = font->charTableLength;
|
|
|
|
l = 0;
|
|
|
|
while (l < r) {
|
|
|
|
mid = (l + r) / 2;
|
|
|
|
|
|
|
|
if (font->charTable[mid].cp > uch) {
|
|
|
|
r = (l + r) / 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uch == font->charTable[mid].cp) {
|
|
|
|
return (l + r) / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
l = mid + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uch != font->charTable[l].cp) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
float UI_FontgetCharWidthf(fontheader_t* font, unsigned short uch)
|
|
|
|
{
|
|
|
|
int index;
|
2016-03-27 11:49:47 +02:00
|
|
|
int indirected;
|
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
if (!font) {
|
|
|
|
return 0.f;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
if (uch == '\t') {
|
|
|
|
uch = ' ';
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
if (font->numPages)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-17 00:24:04 +02:00
|
|
|
int code = UI_FontCodeSearch(font, uch);
|
|
|
|
if (code < 0) {
|
|
|
|
return 0.f;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
index = font->charTable[code].index;
|
|
|
|
indirected = font->charTable[code].loc;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
indirected = font->sgl[0]->indirection[uch];
|
|
|
|
if (indirected < 0 || indirected > 255) {
|
|
|
|
return 0.f;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
2023-07-17 00:24:04 +02:00
|
|
|
|
|
|
|
index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uch == '\t') {
|
|
|
|
return font->sgl[index]->locations[indirected].size[0] * 3.0;
|
|
|
|
} else {
|
|
|
|
return font->sgl[index]->locations[indirected].size[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int UI_FontStringMaxWidth
|
|
|
|
(
|
|
|
|
fontheader_t *pFont,
|
|
|
|
const char *pszString,
|
|
|
|
int iMaxLen
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
float widths = 0.0;
|
|
|
|
float maxwidths = iMaxLen / 256.0f;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!pFont) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
unsigned short uch = pszString[i++];
|
|
|
|
|
|
|
|
if (uch == 0 || (iMaxLen != -1 && i > iMaxLen))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UI_FontDBCSIsLeadByte(pFont, uch))
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-17 00:24:04 +02:00
|
|
|
uch = (uch << 8) | pszString[i];
|
|
|
|
if (!pszString[i]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
if (uch == '\n')
|
|
|
|
{
|
|
|
|
widths = 0.0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
widths += UI_FontgetCharWidthf(pFont, uch);
|
|
|
|
|
|
|
|
if (maxwidths < widths) {
|
|
|
|
return i - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int UI_FontStringWidth
|
|
|
|
(
|
|
|
|
fontheader_t *pFont,
|
|
|
|
const char *pszString,
|
|
|
|
int iMaxLen
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
float widths = 0.0;
|
|
|
|
float maxwidths = 0.0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!pFont) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
unsigned short uch = pszString[i++];
|
|
|
|
|
|
|
|
if (uch == 0 || (iMaxLen != -1 && i > iMaxLen))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UI_FontDBCSIsLeadByte(pFont, uch))
|
|
|
|
{
|
|
|
|
uch = (uch << 8) | pszString[i];
|
|
|
|
if (!pszString[i]) {
|
|
|
|
break;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
i++;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-17 00:24:04 +02:00
|
|
|
if (uch == '\n')
|
|
|
|
{
|
|
|
|
widths = 0.0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
widths += UI_FontgetCharWidthf(pFont, uch);
|
|
|
|
|
|
|
|
if (maxwidths < widths) {
|
|
|
|
maxwidths = widths;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return maxwidths * 256.0;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|