mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 06:53:58 +00:00
- made the menu's text input handler Unicode capable.
Also make sure that the savegame description remains readable. Unlike in-game text this can be done without double-encoding existing UTF-8.
This commit is contained in:
parent
54cb16ad8e
commit
deb233677e
13 changed files with 111 additions and 30 deletions
|
@ -412,14 +412,13 @@ public:
|
||||||
|
|
||||||
void AddChar(int character)
|
void AddChar(int character)
|
||||||
{
|
{
|
||||||
uint8_t encoded[5];
|
|
||||||
int size;
|
int size;
|
||||||
if (utf8_encode(character, encoded, &size) == 0)
|
auto encoded = MakeUTF8(character, &size);
|
||||||
|
if (*encoded != 0)
|
||||||
{
|
{
|
||||||
encoded[size] = 0;
|
|
||||||
if (Text.IsEmpty())
|
if (Text.IsEmpty())
|
||||||
{
|
{
|
||||||
Text = (char*)encoded;
|
Text = encoded;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -292,9 +292,8 @@ static void CT_AddChar (int c)
|
||||||
if (CharLen < QUEUESIZE-2)
|
if (CharLen < QUEUESIZE-2)
|
||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
uint8_t encode[4];
|
auto encode = MakeUTF8(c, &size);
|
||||||
ChatQueue.Pop();
|
if (*encode)
|
||||||
if (utf8_encode(c, encode, &size) == 0)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < size; i++)
|
for (int i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "d_net.h"
|
#include "d_net.h"
|
||||||
#include "g_game.h"
|
#include "g_game.h"
|
||||||
#include "info.h"
|
#include "info.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
|
||||||
EventManager staticEventManager;
|
EventManager staticEventManager;
|
||||||
EventManager eventManager;
|
EventManager eventManager;
|
||||||
|
@ -1026,7 +1027,7 @@ FUiEvent::FUiEvent(const event_t *ev)
|
||||||
break;
|
break;
|
||||||
case EV_GUI_Char:
|
case EV_GUI_Char:
|
||||||
KeyChar = ev->data1;
|
KeyChar = ev->data1;
|
||||||
KeyString = FString(char(ev->data1));
|
KeyString = MakeUTF8(ev->data1);
|
||||||
IsAlt = !!ev->data2; // only true for Win32, not sure about SDL
|
IsAlt = !!ev->data2; // only true for Win32, not sure about SDL
|
||||||
break;
|
break;
|
||||||
default: // mouse event
|
default: // mouse event
|
||||||
|
|
|
@ -185,14 +185,11 @@ void FSavegameManager::ReadSaveStrings()
|
||||||
if (arc.OpenReader((const char *)data, info->LumpSize))
|
if (arc.OpenReader((const char *)data, info->LumpSize))
|
||||||
{
|
{
|
||||||
int savever = 0;
|
int savever = 0;
|
||||||
FString engine;
|
|
||||||
FString iwad;
|
|
||||||
FString title;
|
|
||||||
|
|
||||||
arc("Save Version", savever);
|
arc("Save Version", savever);
|
||||||
arc("Engine", engine);
|
FString engine = arc.GetString("Engine");
|
||||||
arc("Game WAD", iwad);
|
FString iwad = arc.GetString("Game WAD");
|
||||||
arc("Title", title);
|
FString title = arc.GetString("Title");
|
||||||
|
|
||||||
|
|
||||||
if (engine.Compare(GAMESIG) != 0 || savever > SAVEVER)
|
if (engine.Compare(GAMESIG) != 0 || savever > SAVEVER)
|
||||||
{
|
{
|
||||||
|
@ -473,10 +470,10 @@ unsigned FSavegameManager::ExtractSaveData(int index)
|
||||||
FSerializer arc(nullptr);
|
FSerializer arc(nullptr);
|
||||||
if (arc.OpenReader((const char *)data, info->LumpSize))
|
if (arc.OpenReader((const char *)data, info->LumpSize))
|
||||||
{
|
{
|
||||||
FString time, pcomment, comment;
|
FString comment;
|
||||||
|
|
||||||
arc("Creation Time", time);
|
FString time = arc.GetString("Creation Time");
|
||||||
arc("Comment", pcomment);
|
FString pcomment = arc.GetString("Comment");
|
||||||
|
|
||||||
comment = time;
|
comment = time;
|
||||||
if (time.Len() > 0) comment += "\n";
|
if (time.Len() > 0) comment += "\n";
|
||||||
|
|
|
@ -1158,3 +1158,17 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FStringStruct, AppendCharacter)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||||
|
PARAM_INT(c);
|
||||||
|
self->AppendCharacter(c);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FStringStruct, DeleteLastCharacter)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||||
|
self->DeleteLastCharacter();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -221,6 +221,13 @@ struct FWriter
|
||||||
else if (mWriter2) mWriter2->Null();
|
else if (mWriter2) mWriter2->Null();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StringU(const char *k, bool encode)
|
||||||
|
{
|
||||||
|
if (encode) k = StringToUnicode(k);
|
||||||
|
if (mWriter1) mWriter1->String(k);
|
||||||
|
else if (mWriter2) mWriter2->String(k);
|
||||||
|
}
|
||||||
|
|
||||||
void String(const char *k)
|
void String(const char *k)
|
||||||
{
|
{
|
||||||
k = StringToUnicode(k);
|
k = StringToUnicode(k);
|
||||||
|
@ -813,7 +820,7 @@ FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr)
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
// Adds a string literal. This won't get double encoded, like a serialized string.
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
|
@ -822,11 +829,33 @@ FSerializer &FSerializer::AddString(const char *key, const char *charptr)
|
||||||
if (isWriting())
|
if (isWriting())
|
||||||
{
|
{
|
||||||
WriteKey(key);
|
WriteKey(key);
|
||||||
w->String(charptr);
|
w->StringU(MakeUTF8(charptr), false);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Reads back a string without any processing.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
const char *FSerializer::GetString(const char *key)
|
||||||
|
{
|
||||||
|
auto val = r->FindKey(key);
|
||||||
|
if (val != nullptr)
|
||||||
|
{
|
||||||
|
if (val->IsString())
|
||||||
|
{
|
||||||
|
return val->GetString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
|
@ -100,6 +100,7 @@ public:
|
||||||
FSerializer &Sprite(const char *key, int32_t &spritenum, int32_t *def);
|
FSerializer &Sprite(const char *key, int32_t &spritenum, int32_t *def);
|
||||||
FSerializer &StringPtr(const char *key, const char *&charptr); // This only retrieves the address but creates no permanent copy of the string unlike the regular char* serializer.
|
FSerializer &StringPtr(const char *key, const char *&charptr); // This only retrieves the address but creates no permanent copy of the string unlike the regular char* serializer.
|
||||||
FSerializer &AddString(const char *key, const char *charptr);
|
FSerializer &AddString(const char *key, const char *charptr);
|
||||||
|
const char *GetString(const char *key);
|
||||||
FSerializer &ScriptNum(const char *key, int &num);
|
FSerializer &ScriptNum(const char *key, int &num);
|
||||||
bool isReading() const
|
bool isReading() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -247,3 +247,13 @@ const char *MakeUTF8(const char *outline, int *numchars = nullptr)
|
||||||
UTF8String.Push(0);
|
UTF8String.Push(0);
|
||||||
return UTF8String.Data();
|
return UTF8String.Data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *MakeUTF8(int codepoint, int *psize)
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
UTF8String.Resize(5);
|
||||||
|
utf8_encode(codepoint, (uint8_t*)UTF8String.Data(), &size);
|
||||||
|
UTF8String[size] = 0;
|
||||||
|
if (psize) *psize = size;
|
||||||
|
return UTF8String.Data();
|
||||||
|
}
|
||||||
|
|
|
@ -4,5 +4,6 @@ int utf8_encode(int32_t codepoint, uint8_t *buffer, int *size);
|
||||||
int utf8_decode(const uint8_t *src, int *size);
|
int utf8_decode(const uint8_t *src, int *size);
|
||||||
int GetCharFromString(const uint8_t *&string);
|
int GetCharFromString(const uint8_t *&string);
|
||||||
const char *MakeUTF8(const char *outline, int *numchars = nullptr); // returns a pointer to a static buffer, assuming that its caller will immediately process the result.
|
const char *MakeUTF8(const char *outline, int *numchars = nullptr); // returns a pointer to a static buffer, assuming that its caller will immediately process the result.
|
||||||
|
const char *MakeUTF8(int codepoint, int *psize = nullptr);
|
||||||
|
|
||||||
extern uint16_t win1252map[];
|
extern uint16_t win1252map[];
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
#include "zstring.h"
|
#include "zstring.h"
|
||||||
#include "v_text.h"
|
#include "v_text.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
|
||||||
FNullStringData FString::NullString =
|
FNullStringData FString::NullString =
|
||||||
{
|
{
|
||||||
|
@ -475,6 +476,28 @@ FString FString::Mid (size_t pos, size_t numChars) const
|
||||||
return FString (Chars + pos, numChars);
|
return FString (Chars + pos, numChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FString::AppendCharacter(int codepoint)
|
||||||
|
{
|
||||||
|
(*this) << MakeUTF8(codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FString::DeleteLastCharacter()
|
||||||
|
{
|
||||||
|
if (Len() == 0) return;
|
||||||
|
auto pos = Len() - 1;
|
||||||
|
while (pos > 0 && Chars[pos] >= 0x80 && Chars[pos] < 0xc0) pos--;
|
||||||
|
if (pos <= 0)
|
||||||
|
{
|
||||||
|
Data()->Release();
|
||||||
|
ResetToNull();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Truncate(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
long FString::IndexOf (const FString &substr, long startIndex) const
|
long FString::IndexOf (const FString &substr, long startIndex) const
|
||||||
{
|
{
|
||||||
return IndexOf (substr.Chars, startIndex);
|
return IndexOf (substr.Chars, startIndex);
|
||||||
|
|
|
@ -208,6 +208,9 @@ public:
|
||||||
FString Right (size_t numChars) const;
|
FString Right (size_t numChars) const;
|
||||||
FString Mid (size_t pos, size_t numChars = ~(size_t)0) const;
|
FString Mid (size_t pos, size_t numChars = ~(size_t)0) const;
|
||||||
|
|
||||||
|
void AppendCharacter(int codepoint);
|
||||||
|
void DeleteLastCharacter();
|
||||||
|
|
||||||
long IndexOf (const FString &substr, long startIndex=0) const;
|
long IndexOf (const FString &substr, long startIndex=0) const;
|
||||||
long IndexOf (const char *substr, long startIndex=0) const;
|
long IndexOf (const char *substr, long startIndex=0) const;
|
||||||
long IndexOf (char subchar, long startIndex=0) const;
|
long IndexOf (char subchar, long startIndex=0) const;
|
||||||
|
|
|
@ -894,6 +894,8 @@ struct StringStruct native
|
||||||
native int ToInt(int base = 0) const;
|
native int ToInt(int base = 0) const;
|
||||||
native double ToDouble() const;
|
native double ToDouble() const;
|
||||||
native void Split(out Array<String> tokens, String delimiter, EmptyTokenType keepEmpty = TOK_KEEPEMPTY) const;
|
native void Split(out Array<String> tokens, String delimiter, EmptyTokenType keepEmpty = TOK_KEEPEMPTY) const;
|
||||||
|
native void AppendCharacter(int c);
|
||||||
|
native void DeleteLastCharacter();
|
||||||
}
|
}
|
||||||
|
|
||||||
class SectorEffect : Thinker native
|
class SectorEffect : Thinker native
|
||||||
|
|
|
@ -49,6 +49,7 @@ class TextEnterMenu : Menu
|
||||||
int InputGridX;
|
int InputGridX;
|
||||||
int InputGridY;
|
int InputGridY;
|
||||||
bool AllowColors;
|
bool AllowColors;
|
||||||
|
Font displayFont;
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
|
@ -76,6 +77,7 @@ class TextEnterMenu : Menu
|
||||||
InputGridY = 0;
|
InputGridY = 0;
|
||||||
}
|
}
|
||||||
AllowColors = allowcolors; // [TP]
|
AllowColors = allowcolors; // [TP]
|
||||||
|
displayFont = SmallFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TextEnterMenu Open(Menu parent, String textbuffer, int maxlen, int sizemode, bool showgrid = false, bool allowcolors = false)
|
static TextEnterMenu Open(Menu parent, String textbuffer, int maxlen, int sizemode, bool showgrid = false, bool allowcolors = false)
|
||||||
|
@ -115,9 +117,9 @@ class TextEnterMenu : Menu
|
||||||
{
|
{
|
||||||
mInputGridOkay = false;
|
mInputGridOkay = false;
|
||||||
if (mEnterString.Length() < mEnterSize &&
|
if (mEnterString.Length() < mEnterSize &&
|
||||||
(mSizeMode == 2/*entering player name*/ || SmallFont.StringWidth(mEnterString) < (mEnterSize-1)*8))
|
(mSizeMode == 2/*entering player name*/ || displayFont.StringWidth(mEnterString) < (mEnterSize-1)*8))
|
||||||
{
|
{
|
||||||
mEnterString.AppendFormat("%c", ev.KeyChar);
|
mEnterString.AppendCharacter(ev.KeyChar);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +128,7 @@ class TextEnterMenu : Menu
|
||||||
{
|
{
|
||||||
if (mEnterString.Length() > 0)
|
if (mEnterString.Length() > 0)
|
||||||
{
|
{
|
||||||
mEnterString.Truncate(mEnterString.Length() - 1);
|
mEnterString.DeleteLastCharacter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ev.Type == UIEvent.Type_KeyDown)
|
else if (ev.Type == UIEvent.Type_KeyDown)
|
||||||
|
@ -269,7 +271,7 @@ class TextEnterMenu : Menu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mEnterString.Length() < mEnterSize &&
|
else if (mEnterString.Length() < mEnterSize &&
|
||||||
(mSizeMode == 2/*entering player name*/ || SmallFont.StringWidth(mEnterString) < (mEnterSize-1)*8))
|
(mSizeMode == 2/*entering player name*/ || displayFont.StringWidth(mEnterString) < (mEnterSize-1)*8))
|
||||||
{
|
{
|
||||||
mEnterString = mEnterString .. c;
|
mEnterString = mEnterString .. c;
|
||||||
}
|
}
|
||||||
|
@ -298,7 +300,7 @@ class TextEnterMenu : Menu
|
||||||
String InputGridChars = Chars;
|
String InputGridChars = Chars;
|
||||||
int cell_width = 18 * CleanXfac;
|
int cell_width = 18 * CleanXfac;
|
||||||
int cell_height = 12 * CleanYfac;
|
int cell_height = 12 * CleanYfac;
|
||||||
int top_padding = cell_height / 2 - SmallFont.GetHeight() * CleanYfac / 2;
|
int top_padding = cell_height / 2 - displayFont.GetHeight() * CleanYfac / 2;
|
||||||
|
|
||||||
// Darken the background behind the character grid.
|
// Darken the background behind the character grid.
|
||||||
screen.Dim(0, 0.8, 0, screen.GetHeight() - INPUTGRID_HEIGHT * cell_height, screen.GetWidth(), INPUTGRID_HEIGHT * cell_height);
|
screen.Dim(0, 0.8, 0, screen.GetHeight() - INPUTGRID_HEIGHT * cell_height, screen.GetWidth(), INPUTGRID_HEIGHT * cell_height);
|
||||||
|
@ -319,7 +321,7 @@ class TextEnterMenu : Menu
|
||||||
{
|
{
|
||||||
int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen.GetWidth() / 2;
|
int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen.GetWidth() / 2;
|
||||||
int ch = InputGridChars.CharCodeAt(y * INPUTGRID_WIDTH + x);
|
int ch = InputGridChars.CharCodeAt(y * INPUTGRID_WIDTH + x);
|
||||||
int width = SmallFont.GetCharWidth(ch);
|
int width = displayFont.GetCharWidth(ch);
|
||||||
|
|
||||||
// The highlighted character is yellow; the rest are dark gray.
|
// The highlighted character is yellow; the rest are dark gray.
|
||||||
int colr = (x == InputGridX && y == InputGridY) ? Font.CR_YELLOW : Font.CR_DARKGRAY;
|
int colr = (x == InputGridX && y == InputGridY) ? Font.CR_YELLOW : Font.CR_DARKGRAY;
|
||||||
|
@ -328,7 +330,7 @@ class TextEnterMenu : Menu
|
||||||
if (ch > 32)
|
if (ch > 32)
|
||||||
{
|
{
|
||||||
// Draw a normal character.
|
// Draw a normal character.
|
||||||
screen.DrawChar(SmallFont, colr, xx + cell_width/2 - width*CleanXfac/2, yy + top_padding, ch, DTA_CleanNoMove, true);
|
screen.DrawChar(displayFont, colr, xx + cell_width/2 - width*CleanXfac/2, yy + top_padding, ch, DTA_CleanNoMove, true);
|
||||||
}
|
}
|
||||||
else if (ch == 32)
|
else if (ch == 32)
|
||||||
{
|
{
|
||||||
|
@ -336,7 +338,7 @@ class TextEnterMenu : Menu
|
||||||
int x1 = xx + cell_width/2 - width * CleanXfac * 3 / 4;
|
int x1 = xx + cell_width/2 - width * CleanXfac * 3 / 4;
|
||||||
int x2 = x1 + width * 3 * CleanXfac / 2;
|
int x2 = x1 + width * 3 * CleanXfac / 2;
|
||||||
int y1 = yy + top_padding;
|
int y1 = yy + top_padding;
|
||||||
int y2 = y1 + SmallFont.GetHeight() * CleanYfac;
|
int y2 = y1 + displayFont.GetHeight() * CleanYfac;
|
||||||
screen.Clear(x1, y1, x2, y1+CleanYfac, palcolor); // top
|
screen.Clear(x1, y1, x2, y1+CleanYfac, palcolor); // top
|
||||||
screen.Clear(x1, y2, x2, y2+CleanYfac, palcolor); // bottom
|
screen.Clear(x1, y2, x2, y2+CleanYfac, palcolor); // bottom
|
||||||
screen.Clear(x1, y1+CleanYfac, x1+CleanXfac, y2, palcolor); // left
|
screen.Clear(x1, y1+CleanYfac, x1+CleanXfac, y2, palcolor); // left
|
||||||
|
@ -346,8 +348,8 @@ class TextEnterMenu : Menu
|
||||||
{
|
{
|
||||||
// Draw the backspace and end "characters".
|
// Draw the backspace and end "characters".
|
||||||
String str = ch == 8 ? "BS" : "ED";
|
String str = ch == 8 ? "BS" : "ED";
|
||||||
screen.DrawText(SmallFont, colr,
|
screen.DrawText(displayFont, colr,
|
||||||
xx + cell_width/2 - SmallFont.StringWidth(str)*CleanXfac/2,
|
xx + cell_width/2 - displayFont.StringWidth(str)*CleanXfac/2,
|
||||||
yy + top_padding, str, DTA_CleanNoMove, true);
|
yy + top_padding, str, DTA_CleanNoMove, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue