Compare commits

...

4 Commits

10 changed files with 379 additions and 23 deletions

View File

@ -1,4 +1,5 @@
#include "ui/CSimpleFontScript.hpp" #include "ui/CSimpleFontScript.hpp"
#include "ui/CSimpleFontString.hpp"
#include "util/Unimplemented.hpp" #include "util/Unimplemented.hpp"
#include <cstdint> #include <cstdint>

View File

@ -15,10 +15,12 @@
#include "util/StringTo.hpp" #include "util/StringTo.hpp"
#include <common/XML.hpp> #include <common/XML.hpp>
#include <storm/String.hpp> #include <storm/String.hpp>
#include <tempest/Math.hpp>
int32_t CSimpleFontString::s_count; int32_t CSimpleFontString::s_count;
int32_t CSimpleFontString::s_metatable; int32_t CSimpleFontString::s_metatable;
int32_t CSimpleFontString::s_objectType; int32_t CSimpleFontString::s_objectType;
const char* CSimpleFontString::s_objectTypeName = "FontString";
void CSimpleFontString::CreateScriptMetaTable() { void CSimpleFontString::CreateScriptMetaTable() {
lua_State* L = FrameScript_GetContext(); lua_State* L = FrameScript_GetContext();
@ -127,6 +129,16 @@ bool CSimpleFontString::IsA(int32_t type) {
|| type == CScriptObject::s_objectType; || type == CScriptObject::s_objectType;
} }
bool CSimpleFontString::IsA(const char* typeName) {
return !SStrCmpI(typeName, CSimpleFontString::s_objectTypeName, STORM_MAX_STR)
|| !SStrCmpI(typeName, CScriptRegion::s_objectTypeName, STORM_MAX_STR)
|| !SStrCmpI(typeName, CScriptObject::s_objectTypeName, STORM_MAX_STR);
}
const char* CSimpleFontString::GetObjectTypeName() {
return CSimpleFontString::s_objectTypeName;
}
void CSimpleFontString::FontObjectUpdated(CSimpleFontStringAttributes& attributes) { void CSimpleFontString::FontObjectUpdated(CSimpleFontStringAttributes& attributes) {
attributes.Update(this, this->m_fontableFlags); attributes.Update(this, this->m_fontableFlags);
} }
@ -936,3 +948,39 @@ void CSimpleFontString::UpdateString() {
this->OnRegionChanged(); this->OnRegionChanged();
} }
bool CSimpleFontString::SetAlphaGradient(int32_t startChar, int32_t length) {
this->m_alphaGradientStart = startChar;
this->m_alphaGradientLength = length;
if (this->m_string) {
// TODO: return TextBlockSetGradient()
}
return false;
}
void CSimpleFontString::SetShadowColor(const CImVector& color) {
if (this->m_shadowColor != color) {
this->m_shadowColor = color;
this->UpdateString();
}
}
void CSimpleFontString::SetShadowOffset(const C2Vector& offset) {
}
void CSimpleFontString::SetTextHeight(float height) {
if (CMath::fequal(height, this->m_fontHeight)) {
return;
}
this->m_styleFlags &= ~0x200u;
this->m_fontHeight = height;
this->m_cachedWidth = 0.0;
this->m_cachedHeight = 0.0;
if (this->m_string) {
HandleClose(this->m_string);
this->m_string = nullptr;
}
// TODO: Unset some flag
this->Resize(0);
}

View File

@ -14,6 +14,7 @@ class CSimpleFontString : public CSimpleRegion, public CSimpleFontable {
static int32_t s_count; static int32_t s_count;
static int32_t s_metatable; static int32_t s_metatable;
static int32_t s_objectType; static int32_t s_objectType;
static const char* s_objectTypeName;
// Static functions // Static functions
static void CreateScriptMetaTable(); static void CreateScriptMetaTable();
@ -43,6 +44,8 @@ class CSimpleFontString : public CSimpleRegion, public CSimpleFontable {
// Virtual member functions // Virtual member functions
virtual ~CSimpleFontString(); virtual ~CSimpleFontString();
virtual bool IsA(int32_t type); virtual bool IsA(int32_t type);
virtual bool IsA(const char* typeName);
virtual const char* GetObjectTypeName();
virtual int32_t GetScriptMetaTable(); virtual int32_t GetScriptMetaTable();
virtual void LoadXML(XMLNode* node, CStatus* status); virtual void LoadXML(XMLNode* node, CStatus* status);
virtual void OnColorChanged(bool a2); virtual void OnColorChanged(bool a2);
@ -84,6 +87,10 @@ class CSimpleFontString : public CSimpleRegion, public CSimpleFontable {
void SetTextLength(uint32_t a2); void SetTextLength(uint32_t a2);
int32_t Sub482AC0(); int32_t Sub482AC0();
void UpdateString(); void UpdateString();
bool SetAlphaGradient(int32_t startChar, int32_t length);
void SetShadowColor(const CImVector& color);
void SetShadowOffset(const C2Vector& offset);
void SetTextHeight(float height);
}; };
#endif #endif

View File

@ -1,40 +1,119 @@
#include "ui/CSimpleFontStringScript.hpp" #include "ui/CSimpleFontStringScript.hpp"
#include "ui/CSimpleFont.hpp" #include "ui/CSimpleFont.hpp"
#include "ui/CSimpleFontString.hpp" #include "ui/CSimpleFontString.hpp"
#include "ui/Util.hpp"
#include "util/Lua.hpp" #include "util/Lua.hpp"
#include "util/Unimplemented.hpp" #include "util/Unimplemented.hpp"
#include <cstdint> #include "util/StringTo.hpp"
#include "gx/Coordinate.hpp"
int32_t CSimpleFontString_IsObjectType(lua_State* L) { int32_t CSimpleFontString_IsObjectType(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
if (!lua_isstring(L, 2)) {
return luaL_error(L, "Usage: %s:IsObjectType(\"TYPE\")", string->GetDisplayName());
}
if (string->IsA(lua_tolstring(L, 2, nullptr))) {
lua_pushnumber(L, 1.0);
} else {
lua_pushnil(L);
}
return 1;
} }
int32_t CSimpleFontString_GetObjectType(lua_State* L) { int32_t CSimpleFontString_GetObjectType(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
lua_pushstring(L, string->GetObjectTypeName());
return 1;
} }
int32_t CSimpleFontString_GetDrawLayer(lua_State* L) { int32_t CSimpleFontString_GetDrawLayer(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
auto layer = DrawLayerToString(string->m_drawlayer);
lua_pushstring(L, layer);
return 1;
} }
int32_t CSimpleFontString_SetDrawLayer(lua_State* L) { int32_t CSimpleFontString_SetDrawLayer(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
const char* strlayer = lua_isstring(L, 2) ? lua_tostring(L, 2) : nullptr;
int32_t layer = 0;
if (!strlayer || !StringToDrawLayer(strlayer, layer)) {
return luaL_error(L, "Usage: %s:SetDrawLayer(\"layer\")", string->GetDisplayName());
}
string->SetFrame(string->m_parent, layer, string->m_shown);
return 0;
} }
int32_t CSimpleFontString_SetVertexColor(lua_State* L) { int32_t CSimpleFontString_SetVertexColor(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
CImVector color;
string->GetVertexColor(color);
CImVector newColor;
FrameScript_GetColor(L, 2, newColor);
if (!lua_isnumber(L, 5)) {
newColor.a = color.a;
}
string->SetVertexColor(newColor);
// TODO: Some flag should be set
return 0;
} }
int32_t CSimpleFontString_GetAlpha(lua_State* L) { int32_t CSimpleFontString_GetAlpha(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
CImVector color;
string->GetVertexColor(color);
lua_pushnumber(L, color.a / 255.0);
return 1;
} }
int32_t CSimpleFontString_SetAlpha(lua_State* L) { int32_t CSimpleFontString_SetAlpha(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
if (!lua_isnumber(L, 2)) {
return luaL_error(L, "Usage: %s:SetAlpha(alpha)", string->GetDisplayName());
}
CImVector color;
string->GetVertexColor(color);
color.a = lua_tonumber(L, 2) * 255.0;
string->SetVertexColor(color);
return 0;
} }
int32_t CSimpleFontString_SetAlphaGradient(lua_State* L) { int32_t CSimpleFontString_SetAlphaGradient(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3)) {
return luaL_error(L, "Usage: %s:SetAlphaGradient(start, length)", string->GetDisplayName());
}
auto start = lua_tonumber(L, 2);
auto length = lua_tonumber(L, 3);
if (string->SetAlphaGradient(start, length)) {
lua_pushnumber(L, 1.0);
} else {
lua_pushnil(L);
}
return 1;
} }
int32_t CSimpleFontString_Show(lua_State* L) { int32_t CSimpleFontString_Show(lua_State* L) {
@ -78,7 +157,17 @@ int32_t CSimpleFontString_IsShown(lua_State* L) {
} }
int32_t CSimpleFontString_GetFontObject(lua_State* L) { int32_t CSimpleFontString_GetFontObject(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
if (string->m_fontObject) {
if (!string->m_fontObject->lua_registered) {
string->m_fontObject->RegisterScriptObject(nullptr);
}
lua_rawgeti(L, LUA_REGISTRYINDEX, string->m_fontObject->lua_objectRef);
} else {
lua_pushnil(L);
}
return 1;
} }
int32_t CSimpleFontString_SetFontObject(lua_State* L) { int32_t CSimpleFontString_SetFontObject(lua_State* L) {
@ -116,19 +205,66 @@ int32_t CSimpleFontString_SetFontObject(lua_State* L) {
} }
int32_t CSimpleFontString_GetFont(lua_State* L) { int32_t CSimpleFontString_GetFont(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
lua_pushstring(L, string->GetFontName());
auto height = string->GetFontHeight(false);
height *= CoordinateGetAspectCompensation() * 1024.0f;
height = DDCToNDCWidth(height);
lua_pushnumber(L, height);
auto flags = FontFlagsToString(string->GetFontFlags());
lua_pushstring(L, flags);
return 3;
} }
int32_t CSimpleFontString_SetFont(lua_State* L) { int32_t CSimpleFontString_SetFont(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
if (!lua_isstring(L, 2) || !lua_isnumber(L, 3)) {
return luaL_error(L, "Usage: %s:SetFont(\"font\", fontHeight [, flags])", string->GetDisplayName());
}
auto fontName = lua_tostring(L, 2);
auto fontHeight = lua_tonumber(L, 3);
fontHeight /= CoordinateGetAspectCompensation() * 1024.0;
fontHeight = NDCToDDCWidth(fontHeight);
if (fontHeight <= 0.00000011920929) {
return luaL_error(L, "ERROR: %s:SetFont(): invalid fontHeight: %f, height must be > 0", string->GetDisplayName(), fontHeight);
}
if (!*fontName) {
return 0;
}
uint32_t fontFlags = 0;
if (lua_isstring(L, 4)) {
fontFlags = StringToFontFlags(lua_tostring(L, 4));
}
if (string->SetFont(fontName, fontHeight, fontFlags, false)) {
// TODO: Set some object flag
lua_pushnumber(L, 1.0);
} else {
lua_pushnil(L);
}
return 1;
} }
int32_t CSimpleFontString_GetText(lua_State* L) { int32_t CSimpleFontString_GetText(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
lua_pushstring(L, string->m_text);
return 1;
} }
int32_t CSimpleFontString_GetFieldSize(lua_State* L) { int32_t CSimpleFontString_GetFieldSize(lua_State* L) {
WHOA_UNIMPLEMENTED(0); lua_pushnumber(L, 8191.0);
return 1;
} }
int32_t CSimpleFontString_SetText(lua_State* L) { int32_t CSimpleFontString_SetText(lua_State* L) {
@ -160,39 +296,124 @@ int32_t CSimpleFontString_SetFormattedText(lua_State* L) {
} }
int32_t CSimpleFontString_GetTextColor(lua_State* L) { int32_t CSimpleFontString_GetTextColor(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
CImVector color;
string->GetVertexColor(color);
lua_pushnumber(L, color.r / 255.0);
lua_pushnumber(L, color.g / 255.0);
lua_pushnumber(L, color.b / 255.0);
lua_pushnumber(L, color.a / 255.0);
return 4;
} }
int32_t CSimpleFontString_SetTextColor(lua_State* L) { int32_t CSimpleFontString_SetTextColor(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
CImVector color;
FrameScript_GetColor(L, 2, color);
string->SetVertexColor(color);
// TODO: Some flag should be set
return 0;
} }
int32_t CSimpleFontString_GetShadowColor(lua_State* L) { int32_t CSimpleFontString_GetShadowColor(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
CImVector color = string->m_shadowColor;
lua_pushnumber(L, color.r / 255.0);
lua_pushnumber(L, color.g / 255.0);
lua_pushnumber(L, color.b / 255.0);
lua_pushnumber(L, color.a / 255.0);
return 4;
} }
int32_t CSimpleFontString_SetShadowColor(lua_State* L) { int32_t CSimpleFontString_SetShadowColor(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
CImVector color;
FrameScript_GetColor(L, 2, color);
string->SetShadowColor(color);
// TODO: Some flag should be set
return 0;
} }
int32_t CSimpleFontString_GetShadowOffset(lua_State* L) { int32_t CSimpleFontString_GetShadowOffset(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
auto offset = string->m_shadowOffset;
offset *= CoordinateGetAspectCompensation() * 1024.0f;
lua_pushnumber(L, DDCToNDCWidth(offset.x));
lua_pushnumber(L, DDCToNDCWidth(offset.y));
return 2;
} }
int32_t CSimpleFontString_SetShadowOffset(lua_State* L) { int32_t CSimpleFontString_SetShadowOffset(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3)) {
return luaL_error(L, "Usage: %s:SetShadowOffset(x, y)", string->GetDisplayName());
}
C2Vector offset;
offset.x = lua_tonumber(L, 2);
offset.y = lua_tonumber(L, 3);
offset /= CoordinateGetAspectCompensation() * 1024.0f;
offset.x = NDCToDDCWidth(offset.x);
offset.y = NDCToDDCWidth(offset.y);
string->SetShadowOffset(offset);
// TODO: Some flag should be set
return 0;
} }
int32_t CSimpleFontString_GetSpacing(lua_State* L) { int32_t CSimpleFontString_GetSpacing(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
float value = string->m_spacing;
value *= CoordinateGetAspectCompensation() * 1024.0f;
lua_pushnumber(L, DDCToNDCWidth(value));
return 1;
} }
int32_t CSimpleFontString_SetSpacing(lua_State* L) { int32_t CSimpleFontString_SetSpacing(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
if (!lua_isnumber(L, 2)) {
return luaL_error(L, "Usage: %s:SetSpacing(spacing)", string->GetDisplayName());
}
float value = lua_tonumber(L, 2);
value /= CoordinateGetAspectCompensation() * 1024.0f;
string->SetSpacing(NDCToDDCWidth(value));
// TODO: Some flag should be set
return 0;
} }
int32_t CSimpleFontString_SetTextHeight(lua_State* L) { int32_t CSimpleFontString_SetTextHeight(lua_State* L) {
WHOA_UNIMPLEMENTED(0); auto type = CSimpleFontString::GetObjectType();
auto string = static_cast<CSimpleFontString*>(FrameScript_GetObjectThis(L, type));
if (!lua_isstring(L, 2)) {
return luaL_error(L, "Usage: %s:SetTextHeight(pixelHeight)", string->GetDisplayName());
}
auto height = lua_tonumber(L, 3);
if (height <= 0.00000011920929) {
return luaL_error(L, "%s:SetTextHeight(): invalid texHeight: %f, height must be > 0", string->GetDisplayName(), height);
}
height /= CoordinateGetAspectCompensation() * 1024.0f;
height = NDCToDDCWidth(height);
string->SetTextHeight(height);
return 0;
} }
int32_t CSimpleFontString_GetStringWidth(lua_State* L) { int32_t CSimpleFontString_GetStringWidth(lua_State* L) {

View File

@ -25,6 +25,7 @@
int32_t CSimpleFrame::s_metatable; int32_t CSimpleFrame::s_metatable;
int32_t CSimpleFrame::s_objectType; int32_t CSimpleFrame::s_objectType;
const char* CSimpleFrame::s_objectTypeName = "Frame";
int32_t CSimpleFrame::GetObjectType() { int32_t CSimpleFrame::GetObjectType() {
if (!CSimpleFrame::s_objectType) { if (!CSimpleFrame::s_objectType) {
@ -654,6 +655,16 @@ bool CSimpleFrame::IsA(int32_t type) {
|| type == CScriptObject::s_objectType; || type == CScriptObject::s_objectType;
} }
bool CSimpleFrame::IsA(const char* typeName) {
return !SStrCmpI(typeName, CSimpleFrame::s_objectTypeName, STORM_MAX_STR)
|| !SStrCmpI(typeName, CScriptRegion::s_objectTypeName, STORM_MAX_STR)
|| !SStrCmpI(typeName, CScriptObject::s_objectTypeName, STORM_MAX_STR);
}
const char* CSimpleFrame::GetObjectTypeName() {
return CSimpleFrame::s_objectTypeName;
}
void CSimpleFrame::EnableEvent(CSimpleEventType eventType, int32_t priority) { void CSimpleFrame::EnableEvent(CSimpleEventType eventType, int32_t priority) {
if ((1 << eventType) & this->m_eventmask) { if ((1 << eventType) & this->m_eventmask) {
return; return;

View File

@ -27,6 +27,7 @@ class CSimpleFrame : public CScriptRegion {
// Static members // Static members
static int32_t s_metatable; static int32_t s_metatable;
static int32_t s_objectType; static int32_t s_objectType;
static const char* s_objectTypeName;
// Static functions // Static functions
static void CreateScriptMetaTable(); static void CreateScriptMetaTable();
@ -91,6 +92,8 @@ class CSimpleFrame : public CScriptRegion {
virtual ~CSimpleFrame(); virtual ~CSimpleFrame();
virtual ScriptIx* GetScriptByName(const char* name, ScriptData& data); virtual ScriptIx* GetScriptByName(const char* name, ScriptData& data);
virtual bool IsA(int32_t type); virtual bool IsA(int32_t type);
virtual bool IsA(const char* typeName);
virtual const char* GetObjectTypeName();
virtual int32_t GetScriptMetaTable(); virtual int32_t GetScriptMetaTable();
virtual void LoadXML(XMLNode* node, CStatus* status); virtual void LoadXML(XMLNode* node, CStatus* status);
virtual void PreOnAnimUpdate(); virtual void PreOnAnimUpdate();

View File

@ -126,3 +126,45 @@ const char* AnchorPointToString(int32_t point) {
return "ANCHOR_NONE"; return "ANCHOR_NONE";
} }
} }
const char* DrawLayerToString(int32_t layer) {
switch (layer) {
case 0:
return "BACKGROUND";
case 1:
return "BORDER";
case 2:
return "ARTWORK";
case 3:
return "OVERLAY";
case 4:
return "HIGHLIGHT";
default:
return "UNKNOWN";
}
}
const char* FontFlagsToString(uint32_t flags) {
struct FlagEntry {
uint32_t flag;
const char* string;
};
static FlagEntry table[3] = {
{ 1, "OUTLINE" },
{ 4, "THICKOUTLINE" },
{ 2, "MONOCHROME" },
};
static char result[64] = {};
result[0] = '\0';
for (size_t i = 0; i < 3; ++i) {
if (flags & table[i].flag) {
if (result[0]) {
SStrPack(result, ", ", sizeof(result));
}
SStrPack(result, table[i].string, sizeof(result));
}
}
return result;
}

View File

@ -17,4 +17,8 @@ const char* OrientationToString(uint32_t orientation);
const char* AnchorPointToString(int32_t point); const char* AnchorPointToString(int32_t point);
const char* DrawLayerToString(int32_t layer);
const char* FontFlagsToString(uint32_t flags);
#endif #endif

View File

@ -199,3 +199,20 @@ bool StringToAnchorPoint(const char* string, int32_t& point) {
return false; return false;
} }
uint32_t StringToFontFlags(const char* string) {
static std::pair<uint32_t, const char*> table[3] = {
{ 1, "OUTLINE" },
{ 4, "THICKOUTLINE" },
{ 2, "MONOCHROME" }
};
uint32_t result = 0;
for (size_t i = 0; i < 3; ++i) {
if (!SStrCmpI(string, table[i].second, STORM_MAX_STR)) {
result |= table[i].first;
}
}
return result;
}

View File

@ -21,4 +21,6 @@ bool StringToOrientation(const char* string, uint32_t& orientation);
bool StringToAnchorPoint(const char* string, int32_t& point); bool StringToAnchorPoint(const char* string, int32_t& point);
uint32_t StringToFontFlags(const char* string);
#endif #endif