Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2024-04-22 06:07:59 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2024-04-22 06:07:59 +1000
commitca1426eabc873f781eb0dd389d45634b7d183250 (patch)
tree15ea83658ca3824232f14fe4b32ec714e0aa05c6
parentd5f5fb5ddf0d4a9f0b0e6ac012121926d2fcd949 (diff)
Lua chat callbacks + better font styling
golly gee whiz!! i hope i didn't fuck something up
-rw-r--r--assets/opensb/interface.config.patch37
-rw-r--r--assets/opensb/interface/chat/chat.config.patch6
-rw-r--r--assets/opensb/interface/windowconfig/chatbubbles.config.patch7
-rw-r--r--source/base/StarAssets.cpp7
-rw-r--r--source/client/StarClientApplication.cpp1
-rw-r--r--source/core/StarAssetPath.cpp2
-rw-r--r--source/core/StarDirectives.cpp83
-rw-r--r--source/core/StarDirectives.hpp16
-rw-r--r--source/core/StarFormattedJson.cpp4
-rw-r--r--source/core/StarJson.cpp8
-rw-r--r--source/core/StarJson.hpp3
-rw-r--r--source/core/StarJsonBuilder.hpp8
-rw-r--r--source/core/StarJsonParser.hpp66
-rw-r--r--source/core/StarLua.cpp4
-rw-r--r--source/core/StarLua.hpp2
-rw-r--r--source/core/StarText.cpp28
-rw-r--r--source/core/StarText.hpp22
-rw-r--r--source/core/scripting/StarUtilityLuaBindings.cpp4
-rw-r--r--source/frontend/StarActionBar.cpp2
-rw-r--r--source/frontend/StarChat.cpp74
-rw-r--r--source/frontend/StarChat.hpp7
-rw-r--r--source/frontend/StarChatBubbleManager.cpp43
-rw-r--r--source/frontend/StarChatBubbleManager.hpp5
-rw-r--r--source/frontend/StarCinematic.cpp10
-rw-r--r--source/frontend/StarCinematic.hpp3
-rw-r--r--source/frontend/StarClientCommandProcessor.cpp2
-rw-r--r--source/frontend/StarInterfaceLuaBindings.cpp48
-rw-r--r--source/frontend/StarInterfaceLuaBindings.hpp2
-rw-r--r--source/frontend/StarMainInterface.cpp62
-rw-r--r--source/frontend/StarMainInterface.hpp2
-rw-r--r--source/frontend/StarMainInterfaceTypes.cpp10
-rw-r--r--source/frontend/StarMainInterfaceTypes.hpp11
-rw-r--r--source/frontend/StarNameplatePainter.cpp41
-rw-r--r--source/frontend/StarNameplatePainter.hpp9
-rw-r--r--source/frontend/StarTeamBar.cpp3
-rw-r--r--source/frontend/StarTeamBar.hpp2
-rw-r--r--source/game/StarClientContext.cpp8
-rw-r--r--source/game/StarClientContext.hpp4
-rw-r--r--source/game/StarHumanoid.cpp6
-rw-r--r--source/game/StarImageMetadataDatabase.cpp2
-rw-r--r--source/game/StarParallax.cpp2
-rw-r--r--source/game/StarUniverseClient.cpp4
-rw-r--r--source/game/StarUniverseClient.hpp2
-rw-r--r--source/game/StarWorldClient.cpp1
-rw-r--r--source/rendering/StarFontTextureGroup.cpp5
-rw-r--r--source/rendering/StarTextPainter.cpp208
-rw-r--r--source/rendering/StarTextPainter.hpp43
-rw-r--r--source/windowing/StarButtonWidget.cpp27
-rw-r--r--source/windowing/StarButtonWidget.hpp4
-rw-r--r--source/windowing/StarCanvasWidget.cpp29
-rw-r--r--source/windowing/StarCanvasWidget.hpp5
-rw-r--r--source/windowing/StarFuelWidget.cpp7
-rw-r--r--source/windowing/StarFuelWidget.hpp3
-rw-r--r--source/windowing/StarGuiContext.cpp14
-rw-r--r--source/windowing/StarGuiContext.hpp3
-rw-r--r--source/windowing/StarItemSlotWidget.cpp12
-rw-r--r--source/windowing/StarItemSlotWidget.hpp4
-rw-r--r--source/windowing/StarLabelWidget.cpp62
-rw-r--r--source/windowing/StarLabelWidget.hpp7
-rw-r--r--source/windowing/StarPane.cpp9
-rw-r--r--source/windowing/StarPane.hpp3
-rw-r--r--source/windowing/StarTextBoxWidget.cpp52
-rw-r--r--source/windowing/StarTextBoxWidget.hpp7
63 files changed, 661 insertions, 516 deletions
diff --git a/assets/opensb/interface.config.patch b/assets/opensb/interface.config.patch
index 5e71a20..d798609 100644
--- a/assets/opensb/interface.config.patch
+++ b/assets/opensb/interface.config.patch
@@ -1,29 +1,44 @@
{
"nametag" : {
"showMasterNames" : true,
- "fontDirectives" : "?border=1;222;2224",
+ // border is double here as it otherwise fades out near the end
+ // (could just the end to opaque too, but then diagonals are more jaggy)
+ "textStyle" : { "backDirectives" : "?border=1;222;2224?border=1;222;2224" },
"inspectOpacityRate" : 0.15,
"movementThreshold" : 0.5,
"offset" : [0, 13]
},
- "font" : {
- "defaultDirectives" : "",
- "defaultFont" : ""
+ "specialDamageBar" : {
+ "nameStyle" : {}
},
- "cursorTooltip" : {
- "font" : ""
+ "textStyle" : {},
+ "buttonTextStyle" : {
+ "shadow" : "black"
},
+ "labelTextStyle" : {},
+ "paneTextStyle" : {},
+ "textBoxTextStyle" : {},
+ "itemSlotTextStyle" : {
+ "backDirectives" : "?border=1;444;4444"
+ },
+ "teamBarNameStyle" : {},
+ "cursorTooltip" : { "textStyle" : {} },
- "debugFont" : "iosevka-semibold",
- "debugFontSize" : 7,
- "debugFontDirectives" : "?border=1;111a;1114",
+ "debugTextStyle" : {
+ "font" : "iosevka-semibold",
+ "fontSize" : 7,
+ "backDirectives" : "?border=2;111a;1114"
+ },
"debugSpatialClearTime" : 0.0,
"debugOffset" : [80, 130],
// Change planet name to support the new internal string formatting.
"planetNameFormatString" : "- {} -",
- "planetNameDirectives" : "?border=4;000;000",
-
+ "planetTextStyle" : {
+ "backDirectives" : "?border=6;000;000",
+ "fontSize" : 24
+ },
+
"buttonClickSound" : [ "/sfx/interface/button/click.wav" ],
"buttonReleaseSound" : [ "/sfx/interface/button/release.wav" ],
"buttonHoverSound" : [ "/sfx/interface/button/hover.wav" ],
diff --git a/assets/opensb/interface/chat/chat.config.patch b/assets/opensb/interface/chat/chat.config.patch
index 52dc90d..d71b88d 100644
--- a/assets/opensb/interface/chat/chat.config.patch
+++ b/assets/opensb/interface/chat/chat.config.patch
@@ -1,10 +1,8 @@
{
"config" : {
"lineHeight" : 1,
- "font" : {
- "directives" : "?border=1;111a;1114",
- "padding" : [1, 1] // Padding to prevent border clipping at the edges of the log canvas while keeping compat with mods that patch the canvas size
- },
+ "padding" : [1, 1],
+ "textStyle" : { "backDirectives" : "?border=1;111a;1114" },
"colors" : {
"local" : "^white;",
"party" : "^blue;",
diff --git a/assets/opensb/interface/windowconfig/chatbubbles.config.patch b/assets/opensb/interface/windowconfig/chatbubbles.config.patch
index c3da49d..3c0fda8 100644
--- a/assets/opensb/interface/windowconfig/chatbubbles.config.patch
+++ b/assets/opensb/interface/windowconfig/chatbubbles.config.patch
@@ -1,4 +1,7 @@
{
- "movementThreshold" : 0.5,
- "bubbleOffset" : [0, 1.875]
+ "movementThreshold" : 0.5,
+ "bubbleOffset" : [0, 1.875],
+ "textStyle" : {
+ "backDirectives" : "?border=1;000a;0000?border=1;000a;0004"
+ }
} \ No newline at end of file
diff --git a/source/base/StarAssets.cpp b/source/base/StarAssets.cpp
index 357fca0..f2582b1 100644
--- a/source/base/StarAssets.cpp
+++ b/source/base/StarAssets.cpp
@@ -427,8 +427,6 @@ void Assets::queueJsons(StringSet const& paths) const {
}
ImageConstPtr Assets::image(AssetPath const& path) const {
- validatePath(path, true, true);
-
return as<ImageData>(getAsset(AssetId{AssetType::Image, path}))->image;
}
@@ -956,7 +954,7 @@ Json Assets::checkPatchArray(String const& path, AssetSourcePtr const& source, J
Json Assets::readJson(String const& path) const {
ByteArray streamData = read(path);
try {
- Json result = inputUtf8Json(streamData.begin(), streamData.end(), false);
+ Json result = inputUtf8Json(streamData.begin(), streamData.end(), JsonParseType::Top);
for (auto const& pair : m_files.get(path).patchSources) {
auto& patchPath = pair.first;
auto& patchSource = pair.second;
@@ -973,7 +971,7 @@ Json Assets::readJson(String const& path) const {
if (newResult)
result = std::move(newResult);
} else {
- auto patchJson = inputUtf8Json(patchStream.begin(), patchStream.end(), false);
+ auto patchJson = inputUtf8Json(patchStream.begin(), patchStream.end(), JsonParseType::Top);
if (patchJson.isType(Json::Type::Array)) {
auto patchData = patchJson.toArray();
try {
@@ -1131,6 +1129,7 @@ shared_ptr<Assets::AssetData> Assets::loadJson(AssetPath const& path) const {
}
shared_ptr<Assets::AssetData> Assets::loadImage(AssetPath const& path) const {
+ validatePath(path, true, true);
if (!path.directives.empty()) {
shared_ptr<ImageData> source =
as<ImageData>(loadAsset(AssetId{AssetType::Image, {path.basePath, path.subPath, {}}}));
diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp
index 82d18cf..1a74132 100644
--- a/source/client/StarClientApplication.cpp
+++ b/source/client/StarClientApplication.cpp
@@ -667,6 +667,7 @@ void ClientApplication::changeState(MainAppState newState) {
m_mainInterface = make_shared<MainInterface>(m_universeClient, m_worldPainter, m_cinematicOverlay);
m_universeClient->setLuaCallbacks("interface", LuaBindings::makeInterfaceCallbacks(m_mainInterface.get()));
+ m_universeClient->setLuaCallbacks("chat", LuaBindings::makeChatCallbacks(m_mainInterface.get(), m_universeClient.get()));
m_universeClient->startLua();
m_mainMixer->setWorldPainter(m_worldPainter);
diff --git a/source/core/StarAssetPath.cpp b/source/core/StarAssetPath.cpp
index e54a139..23743d9 100644
--- a/source/core/StarAssetPath.cpp
+++ b/source/core/StarAssetPath.cpp
@@ -162,7 +162,7 @@ std::ostream& operator<<(std::ostream& os, AssetPath const& rhs) {
rhs.directives.forEach([&](auto const& entry, Directives const& directives) {
os << "?";
- os << entry.string(*directives.shared);
+ os << entry.string(*directives);
});
return os;
diff --git a/source/core/StarDirectives.cpp b/source/core/StarDirectives.cpp
index 4770200..89985a0 100644
--- a/source/core/StarDirectives.cpp
+++ b/source/core/StarDirectives.cpp
@@ -42,6 +42,8 @@ bool Directives::Shared::empty() const {
return entries.empty();
}
+Directives::Shared::Shared() {}
+
Directives::Shared::Shared(List<Entry>&& givenEntries, String&& givenString, StringView givenPrefix) {
entries = std::move(givenEntries);
string = std::move(givenString);
@@ -74,7 +76,7 @@ Directives::Directives(Directives const& directives) {
Directives::~Directives() {}
Directives& Directives::operator=(String const& s) {
- if (shared && shared->string == s)
+ if (m_shared && m_shared->string == s)
return *this;
parse(String(s));
@@ -82,7 +84,7 @@ Directives& Directives::operator=(String const& s) {
}
Directives& Directives::operator=(String&& s) {
- if (shared && shared->string == s) {
+ if (m_shared && m_shared->string == s) {
s.clear();
return *this;
}
@@ -92,7 +94,7 @@ Directives& Directives::operator=(String&& s) {
}
Directives& Directives::operator=(const char* s) {
- if (shared && shared->string.utf8().compare(s) == 0)
+ if (m_shared && m_shared->string.utf8().compare(s) == 0)
return *this;
parse(s);
@@ -100,27 +102,29 @@ Directives& Directives::operator=(const char* s) {
}
Directives& Directives::operator=(Directives&& other) noexcept {
- shared = std::move(other.shared);
+ m_shared = std::move(other.m_shared);
return *this;
}
Directives& Directives::operator=(Directives const& other) {
- shared = other.shared;
+ m_shared = other.m_shared;
return *this;
}
void Directives::loadOperations() const {
- if (!shared)
+ if (!m_shared)
return;
- MutexLocker lock(shared->mutex, true);
- for (auto& entry : shared->entries)
- entry.loadOperation(*shared);
+ MutexLocker locker(m_shared->mutex, false);
+ if (!m_shared.unique())
+ locker.lock();
+ for (auto& entry : m_shared->entries)
+ entry.loadOperation(*m_shared);
}
void Directives::parse(String&& directives) {
if (directives.empty()) {
- shared.reset();
+ m_shared.reset();
return;
}
@@ -147,46 +151,46 @@ void Directives::parse(String&& directives) {
});
if (entries.empty() && !prefix.empty()) {
- shared.reset();
+ m_shared.reset();
return;
}
- shared = std::make_shared<Shared const>(std::move(entries), std::move(directives), prefix);
+ m_shared = std::make_shared<Shared const>(std::move(entries), std::move(directives), prefix);
if (view.utf8().size() < 1000) { // Pre-load short enough directives
- for (auto& entry : shared->entries)
- entry.loadOperation(*shared);
+ for (auto& entry : m_shared->entries)
+ entry.loadOperation(*m_shared);
}
}
String Directives::string() const {
- if (!shared)
+ if (!m_shared)
return "";
else
- return shared->string;
+ return m_shared->string;
}
StringView Directives::prefix() const {
- if (!shared)
+ if (!m_shared)
return "";
else
- return shared->prefix;
+ return m_shared->prefix;
}
String const* Directives::stringPtr() const {
- if (!shared)
+ if (!m_shared)
return nullptr;
else
- return &shared->string;
+ return &m_shared->string;
}
String Directives::buildString() const {
- if (shared) {
- String built = shared->prefix;
+ if (m_shared) {
+ String built = m_shared->prefix;
- for (auto& entry : shared->entries) {
+ for (auto& entry : m_shared->entries) {
built += "?";
- built += entry.string(*shared);
+ built += entry.string(*m_shared);
}
return built;
@@ -197,23 +201,25 @@ String Directives::buildString() const {
String& Directives::addToString(String& out) const {
if (!empty())
- out += shared->string;
+ out += m_shared->string;
return out;
}
size_t Directives::hash() const {
- return shared ? shared->hash : 0;
+ return m_shared ? m_shared->hash : 0;
}
size_t Directives::size() const {
- return shared ? shared->entries.size() : 0;
+ return m_shared ? m_shared->entries.size() : 0;
}
bool Directives::empty() const {
- return !shared || shared->empty();
+ return !m_shared || m_shared->empty();
}
-Directives::operator bool() const { return !empty(); }
+Directives::operator bool() const {
+ return !empty();
+}
bool Directives::equals(Directives const& other) const {
return hash() == other.hash();
@@ -243,7 +249,7 @@ DataStream& operator>>(DataStream& ds, Directives& directives) {
DataStream& operator<<(DataStream & ds, Directives const& directives) {
if (directives)
- ds.write(directives.shared->string);
+ ds.write(directives->string);
else
ds.write(String());
@@ -326,21 +332,22 @@ String DirectivesGroup::toString() const {
}
void DirectivesGroup::addToString(String& string) const {
- for (auto& directives : m_directives)
- if (directives.shared) {
- auto& dirString = directives.shared->string;
+ for (auto& directives : m_directives) {
+ if (directives) {
+ auto& dirString = directives->string;
if (!dirString.empty()) {
if (dirString.utf8().front() != '?')
string += "?";
string += dirString;
}
}
+ }
}
void DirectivesGroup::forEach(DirectivesCallback callback) const {
for (auto& directives : m_directives) {
- if (directives.shared) {
- for (auto& entry : directives.shared->entries)
+ if (directives) {
+ for (auto& entry : directives->entries)
callback(entry, directives);
}
}
@@ -348,8 +355,8 @@ void DirectivesGroup::forEach(DirectivesCallback callback) const {
bool DirectivesGroup::forEachAbortable(AbortableDirectivesCallback callback) const {
for (auto& directives : m_directives) {
- if (directives.shared) {
- for (auto& entry : directives.shared->entries) {
+ if (directives) {
+ for (auto& entry : directives->entries) {
if (!callback(entry, directives))
return false;
}
@@ -367,7 +374,7 @@ Image DirectivesGroup::applyNewImage(Image const& image) const {
void DirectivesGroup::applyExistingImage(Image& image) const {
forEach([&](auto const& entry, Directives const& directives) {
- ImageOperation const& operation = entry.loadOperation(*directives.shared);
+ ImageOperation const& operation = entry.loadOperation(*directives);
if (auto error = operation.ptr<ErrorImageOperation>())
std::rethrow_exception(error->exception);
else
diff --git a/source/core/StarDirectives.hpp b/source/core/StarDirectives.hpp
index e272915..fa10a33 100644
--- a/source/core/StarDirectives.hpp
+++ b/source/core/StarDirectives.hpp
@@ -36,6 +36,7 @@ public:
mutable Mutex mutex;
bool empty() const;
+ Shared();
Shared(List<Entry>&& givenEntries, String&& givenString, StringView givenPrefix);
};
@@ -65,6 +66,9 @@ public:
bool empty() const;
operator bool() const;
+ Shared const& operator*() const;
+ Shared const* operator->() const;
+
bool equals(Directives const& other) const;
bool equals(String const& string) const;
@@ -78,7 +82,7 @@ public:
//friend bool operator==(Directives const& directives, String const& string);
//friend bool operator==(String const& string, Directives const& directives);
- std::shared_ptr<Shared const> shared;
+ std::shared_ptr<Shared const> m_shared;
};
class DirectivesGroup {
@@ -122,7 +126,6 @@ private:
size_t m_count;
};
-
template <>
struct hash<DirectivesGroup> {
size_t operator()(DirectivesGroup const& s) const;
@@ -130,4 +133,13 @@ struct hash<DirectivesGroup> {
typedef DirectivesGroup ImageDirectives;
+inline Directives::Shared const& Directives::operator*() const {
+ return *m_shared;
+}
+inline Directives::Shared const* Directives::operator->() const {
+ if (!m_shared)
+ throw DirectivesException("Directives::operator-> nullptr");
+ return m_shared.get();
+}
+
}
diff --git a/source/core/StarFormattedJson.cpp b/source/core/StarFormattedJson.cpp
index d7bd8c7..a770ac6 100644
--- a/source/core/StarFormattedJson.cpp
+++ b/source/core/StarFormattedJson.cpp
@@ -65,12 +65,12 @@ bool CommaElement::operator==(CommaElement const&) const {
FormattedJson FormattedJson::parse(String const& string) {
return inputUtf32Json<String::const_iterator, FormattedJsonBuilderStream, FormattedJson>(
- string.begin(), string.end(), true);
+ string.begin(), string.end(), JsonParseType::Value);
}
FormattedJson FormattedJson::parseJson(String const& string) {
return inputUtf32Json<String::const_iterator, FormattedJsonBuilderStream, FormattedJson>(
- string.begin(), string.end(), false);
+ string.begin(), string.end(), JsonParseType::Top);
}
FormattedJson FormattedJson::ofType(Json::Type type) {
diff --git a/source/core/StarJson.cpp b/source/core/StarJson.cpp
index 04ac544..7cf1cda 100644
--- a/source/core/StarJson.cpp
+++ b/source/core/StarJson.cpp
@@ -105,11 +105,15 @@ Json Json::ofType(Type t) {
}
Json Json::parse(String const& string) {
- return inputUtf32Json<String::const_iterator>(string.begin(), string.end(), true);
+ return inputUtf32Json<String::const_iterator>(string.begin(), string.end(), JsonParseType::Value);
+}
+
+Json Json::parseSequence(String const& sequence) {
+ return inputUtf32Json<String::const_iterator>(sequence.begin(), sequence.end(), JsonParseType::Sequence);
}
Json Json::parseJson(String const& json) {
- return inputUtf32Json<String::const_iterator>(json.begin(), json.end(), false);
+ return inputUtf32Json<String::const_iterator>(json.begin(), json.end(), JsonParseType::Top);
}
Json::Json() {}
diff --git a/source/core/StarJson.hpp b/source/core/StarJson.hpp
index a533e47..b58b9a0 100644
--- a/source/core/StarJson.hpp
+++ b/source/core/StarJson.hpp
@@ -51,6 +51,9 @@ public:
// Parses JSON or JSON sub-type
static Json parse(String const& string);
+ // Parses JSON sequence
+ static Json parseSequence(String const& sequence);
+
// Parses JSON object or array only (the only top level types allowed by
// JSON)
static Json parseJson(String const& json);
diff --git a/source/core/StarJsonBuilder.hpp b/source/core/StarJsonBuilder.hpp
index ea0df46..46f192c 100644
--- a/source/core/StarJsonBuilder.hpp
+++ b/source/core/StarJsonBuilder.hpp
@@ -50,7 +50,7 @@ public:
};
template <typename InputIterator>
-Json inputUtf8Json(InputIterator begin, InputIterator end, bool fragment) {
+Json inputUtf8Json(InputIterator begin, InputIterator end, JsonParseType parseType) {
typedef U8ToU32Iterator<InputIterator> Utf32Input;
typedef JsonParser<Utf32Input> Parser;
@@ -58,7 +58,7 @@ Json inputUtf8Json(InputIterator begin, InputIterator end, bool fragment) {
Parser parser(stream);
Utf32Input wbegin(begin);
Utf32Input wend(end);
- Utf32Input pend = parser.parse(wbegin, wend, fragment);
+ Utf32Input pend = parser.parse(wbegin, wend, parseType);
if (parser.error())
throw JsonParsingException(strf("Error parsing json: {} at {}:{}", parser.error(), parser.line(), parser.column()));
@@ -77,11 +77,11 @@ void outputUtf8Json(Json const& val, OutputIterator out, int pretty, bool sort)
}
template <typename InputIterator, typename Stream = JsonBuilderStream, typename Jsonlike = Json>
-Jsonlike inputUtf32Json(InputIterator begin, InputIterator end, bool fragment) {
+Jsonlike inputUtf32Json(InputIterator begin, InputIterator end, JsonParseType parseType) {
Stream stream;
JsonParser<InputIterator> parser(stream);
- InputIterator pend = parser.parse(begin, end, fragment);
+ InputIterator pend = parser.parse(begin, end, parseType);
if (parser.error()) {
throw JsonParsingException(strf("Error parsing json: {} at {}:{}", parser.error(), parser.line(), parser.column()));
diff --git a/source/core/StarJsonParser.hpp b/source/core/StarJsonParser.hpp
index d814edb..0bf7443 100644
--- a/source/core/StarJsonParser.hpp
+++ b/source/core/StarJsonParser.hpp
@@ -27,6 +27,12 @@ struct JsonStream {
virtual void putComma() = 0;
};
+enum class JsonParseType : uint8_t {
+ Top, // Top-level Object or Array
+ Value, // Any singular Json value
+ Sequence // Like an array, but without needing the [] or commas.
+};
+
// Will parse JSON and output to a given JsonStream. Parses an *extension* to
// the JSON format that includes comments.
template <typename InputIterator>
@@ -39,15 +45,17 @@ public:
// Does not throw. On error, returned iterator will not be equal to end, and
// error() will be non-null. Set fragment to true to parse any JSON type
// rather than just object or array.
- InputIterator parse(InputIterator begin, InputIterator end, bool fragment = false) {
+ InputIterator parse(InputIterator begin, InputIterator end, JsonParseType parseType = JsonParseType::Top) {
init(begin, end);
try {
white();
- if (fragment)
- value();
- else
+ if (parseType == JsonParseType::Top)
top();
+ else if (parseType == JsonParseType::Value)
+ value();
+ else if (parseType == JsonParseType::Sequence)
+ sequence();
white();
} catch (ParsingException const&) {
}
@@ -190,6 +198,56 @@ private:
}
}
+ void sequence() {
+ m_stream.beginArray();
+ while (true) {
+ if (isSpace(m_char)) {
+ next();
+ continue;
+ } else if (m_char == '{')
+ object();
+ else if (m_char == '[')
+ array();
+ else if (m_char == '"')
+ string();
+ else if (m_char == '-')
+ number();
+ else if (m_char == 0)
+ break;
+ else {
+ auto begin = m_current;
+ if (m_char >= '0' && m_char <= '9') {
+ number();
+ if (m_error.empty()) {
+ next();
+ continue;
+ }
+ }
+ m_error.clear();
+ m_current = begin;
+ if (m_char == 't' || m_char == 'f' || m_char == 'n') {
+ word();
+ if (m_error.empty()) {
+ next();
+ continue;
+ }
+ }
+ m_error.clear();
+ m_current = begin;
+ // well, shit. do a simple string parse until we hit whitespace
+ // no fancy things like \n, do a proper string if you want that
+ CharArray str;
+ do {
+ str += m_char;
+ next();
+ } while (m_char && !isSpace(m_char));
+ m_stream.putString(str.c_str(), str.length());
+ }
+ next();
+ }
+ m_stream.endArray();
+ }
+
void string() {
CharArray s = parseString();
m_stream.putString(s.c_str(), s.length());
diff --git a/source/core/StarLua.cpp b/source/core/StarLua.cpp
index 73955f2..5a2effa 100644
--- a/source/core/StarLua.cpp
+++ b/source/core/StarLua.cpp
@@ -60,6 +60,10 @@ LuaInt LuaTable::rawLength() const {
return engine().tableLength(true, handleIndex());
}
+void LuaCallbacks::copyCallback(String srcName, String dstName) {
+ m_callbacks.set(dstName, m_callbacks.get(srcName));
+}
+
LuaCallbacks& LuaCallbacks::merge(LuaCallbacks const& callbacks) {
try {
for (auto const& pair : callbacks.m_callbacks)
diff --git a/source/core/StarLua.hpp b/source/core/StarLua.hpp
index 09e81e6..57afb98 100644
--- a/source/core/StarLua.hpp
+++ b/source/core/StarLua.hpp
@@ -267,6 +267,8 @@ LuaValue const LuaNil = LuaValue();
class LuaCallbacks {
public:
+ void copyCallback(String srcName, String dstName);
+
template <typename Function>
void registerCallback(String name, Function&& func);
diff --git a/source/core/StarText.cpp b/source/core/StarText.cpp
index 11fca27..86c9f25 100644
--- a/source/core/StarText.cpp
+++ b/source/core/StarText.cpp
@@ -1,9 +1,35 @@
#include "StarText.hpp"
-
+#include "StarJsonExtra.hpp"
#include <regex>
namespace Star {
+TextStyle::TextStyle(Json const& config) : TextStyle() {
+ if (config.isType(Json::Type::String))
+ font = config.toString();
+ else
+ loadJson(config);
+}
+TextStyle& TextStyle::loadJson(Json const& config) {
+ if (!config)
+ return *this;
+
+ lineSpacing = config.getFloat("lineSpacing", lineSpacing);
+ if (auto jColor = config.opt("color"))
+ color = jsonToColor(*jColor).toRgba();
+ if (auto jShadow = config.opt("shadow"))
+ shadow = jsonToColor(*jShadow).toRgba();
+ fontSize = config.getUInt("fontSize", fontSize);
+ if (auto jFont = config.optString("font"))
+ font = *jFont;
+ if (auto jDirectives = config.optString("directives"))
+ directives = *jDirectives;
+ if (auto jBackDirectives = config.optString("backDirectives"))
+ backDirectives = *jBackDirectives;
+
+ return *this;
+}
+
namespace Text {
static auto stripEscapeRegex = std::regex(strf("\\{:c}[^;]*{:c}", CmdEsc, EndEsc));
String stripEscapeCodes(String const& s) {
diff --git a/source/core/StarText.hpp b/source/core/StarText.hpp
index 4f6a97a..ff6880c 100644
--- a/source/core/StarText.hpp
+++ b/source/core/StarText.hpp
@@ -2,9 +2,29 @@
#include "StarString.hpp"
#include "StarStringView.hpp"
+#include "StarVector.hpp"
+#include "StarDirectives.hpp"
+#include "StarJson.hpp"
namespace Star {
-
+
+unsigned const DefaultFontSize = 8;
+float const DefaultLineSpacing = 1.3f;
+
+struct TextStyle {
+ float lineSpacing = DefaultLineSpacing;
+ Vec4B color = Vec4B::filled(255);
+ Vec4B shadow = Vec4B::filled(0);
+ unsigned fontSize = DefaultFontSize;
+ String font = "";
+ Directives directives;
+ Directives backDirectives;
+
+ TextStyle() = default;
+ TextStyle(Json const& config);
+ TextStyle& loadJson(Json const& config);
+};
+
namespace Text {
unsigned char const StartEsc = '\x1b';
unsigned char const EndEsc = ';';
diff --git a/source/core/scripting/StarUtilityLuaBindings.cpp b/source/core/scripting/StarUtilityLuaBindings.cpp
index 5ab6e19..98ad239 100644
--- a/source/core/scripting/StarUtilityLuaBindings.cpp
+++ b/source/core/scripting/StarUtilityLuaBindings.cpp
@@ -118,12 +118,14 @@ LuaCallbacks LuaBindings::makeUtilityCallbacks() {
callbacks.registerCallback("print", UtilityCallbacks::print);
callbacks.registerCallback("interpolateSinEase", UtilityCallbacks::interpolateSinEase);
callbacks.registerCallback("replaceTags", UtilityCallbacks::replaceTags);
- callbacks.registerCallback("jsonParse", [](String const& json) { return Json::parse(json); });
+ callbacks.registerCallback("parseJsonSequence", [](String const& json) { return Json::parseSequence(json); });
callbacks.registerCallback("jsonMerge", [](Json const& a, Json const& b) { return jsonMerge(a, b); });
callbacks.registerCallback("jsonQuery", [](Json const& json, String const& path, Json const& def) { return json.query(path, def); });
callbacks.registerCallback("makeRandomSource", [](Maybe<uint64_t> seed) { return seed ? RandomSource(*seed) : RandomSource(); });
callbacks.registerCallback("makePerlinSource", [](Json const& config) { return PerlinF(config); });
+ callbacks.copyCallback("parseJson", "jsonFromString"); // SE compat
+
auto hash64LuaValues = [](LuaVariadic<LuaValue> const& values) -> uint64_t {
XXHash64 hash;
diff --git a/source/frontend/StarActionBar.cpp b/source/frontend/StarActionBar.cpp
index fb08e3b..9f78626 100644
--- a/source/frontend/StarActionBar.cpp
+++ b/source/frontend/StarActionBar.cpp
@@ -83,9 +83,7 @@ ActionBar::ActionBar(MainInterfacePaneManager* paneManager, PlayerPtr player) {
TextPositioning countPosition = {jsonToVec2F(m_config.get("countMidAnchor")), HorizontalAnchor::HMidAnchor};
customBarLeft->setCountPosition(countPosition);
- customBarLeft->setCountFontMode(FontMode::Shadow);
customBarRight->setCountPosition(countPosition);
- customBarRight->setCountFontMode(FontMode::Shadow);
m_customBarWidgets.append({customBarLeft, customBarRight, customBarLeftOverlay, customBarRightOverlay});
}
diff --git a/source/frontend/StarChat.cpp b/source/frontend/StarChat.cpp
index 688bf4a..d780d23 100644
--- a/source/frontend/StarChat.cpp
+++ b/source/frontend/StarChat.cpp
@@ -20,32 +20,30 @@ Chat::Chat(UniverseClientPtr client) : m_client(client) {
m_historyOffset = 0;
auto assets = Root::singleton().assets();
+ auto config = assets->json("/interface/chat/chat.config:config");
m_timeChatLastActive = Time::monotonicMilliseconds();
- auto fontConfig = assets->json("/interface/chat/chat.config:config.font");
- m_fontSize = fontConfig.getInt("baseSize");
- m_fontDirectives = fontConfig.queryString("directives", "");
- m_font = fontConfig.queryString("type", "");
- m_chatLineHeight = assets->json("/interface/chat/chat.config:config.lineHeight").toFloat();
- m_chatVisTime = assets->json("/interface/chat/chat.config:config.visTime").toFloat();
- m_fadeRate = assets->json("/interface/chat/chat.config:config.fadeRate").toDouble();
- m_chatHistoryLimit = assets->json("/interface/chat/chat.config:config.chatHistoryLimit").toInt();
-
- m_portraitTextOffset = jsonToVec2I(assets->json("/interface/chat/chat.config:config.portraitTextOffset"));
- m_portraitImageOffset = jsonToVec2I(assets->json("/interface/chat/chat.config:config.portraitImageOffset"));
- m_portraitScale = assets->json("/interface/chat/chat.config:config.portraitScale").toFloat();
- m_portraitVerticalMargin = assets->json("/interface/chat/chat.config:config.portraitVerticalMargin").toFloat();
- m_portraitBackground = assets->json("/interface/chat/chat.config:config.portraitBackground").toString();
-
- m_bodyHeight = assets->json("/interface/chat/chat.config:config.bodyHeight").toInt();
- m_expandedBodyHeight = assets->json("/interface/chat/chat.config:config.expandedBodyHeight").toInt();
-
- m_colorCodes[MessageContext::Local] = assets->json("/interface/chat/chat.config:config.colors.local").toString();
- m_colorCodes[MessageContext::Party] = assets->json("/interface/chat/chat.config:config.colors.party").toString();
- m_colorCodes[MessageContext::Broadcast] = assets->json("/interface/chat/chat.config:config.colors.broadcast").toString();
- m_colorCodes[MessageContext::Whisper] = assets->json("/interface/chat/chat.config:config.colors.whisper").toString();
- m_colorCodes[MessageContext::CommandResult] = assets->json("/interface/chat/chat.config:config.colors.commandResult").toString();
- m_colorCodes[MessageContext::RadioMessage] = assets->json("/interface/chat/chat.config:config.colors.radioMessage").toString();
- m_colorCodes[MessageContext::World] = assets->json("/interface/chat/chat.config:config.colors.world").toString();
+ m_chatTextStyle = config.get("textStyle");
+ m_chatTextStyle.lineSpacing = config.get("lineHeight").toFloat();
+ m_chatVisTime = config.get("visTime").toFloat();
+ m_fadeRate = config.get("fadeRate").toDouble();
+ m_chatHistoryLimit = config.get("chatHistoryLimit").toInt();
+
+ m_portraitTextOffset = jsonToVec2I(config.get("portraitTextOffset"));
+ m_portraitImageOffset = jsonToVec2I(config.get("portraitImageOffset"));
+ m_portraitScale = config.get("portraitScale").toFloat();
+ m_portraitVerticalMargin = config.get("portraitVerticalMargin").toFloat();
+ m_portraitBackground = config.get("portraitBackground").toString();
+
+ m_bodyHeight = config.get("bodyHeight").toInt();
+ m_expandedBodyHeight = config.get("expandedBodyHeight").toInt();
+
+ m_colorCodes[MessageContext::Local] = config.query("colors.local").toString();
+ m_colorCodes[MessageContext::Party] = config.query("colors.party").toString();
+ m_colorCodes[MessageContext::Broadcast] = config.query("colors.broadcast").toString();
+ m_colorCodes[MessageContext::Whisper] = config.query("colors.whisper").toString();
+ m_colorCodes[MessageContext::CommandResult] = config.query("colors.commandResult").toString();
+ m_colorCodes[MessageContext::RadioMessage] = config.query("colors.radioMessage").toString();
+ m_colorCodes[MessageContext::World] = config.query("colors.world").toString();
GuiReader reader;
@@ -72,7 +70,7 @@ Chat::Chat(UniverseClientPtr client) : m_client(client) {
m_say = fetchChild<LabelWidget>("say");
m_chatLog = fetchChild<CanvasWidget>("chatLog");
- if (auto logPadding = fontConfig.optQuery("padding")) {
+ if (auto logPadding = config.optQuery("padding")) {
m_chatLogPadding = jsonToVec2I(logPadding.get());
m_chatLog->setSize(m_chatLog->size() + m_chatLogPadding * 2);
m_chatLog->setPosition(m_chatLog->position() - m_chatLogPadding);
@@ -133,8 +131,8 @@ String Chat::currentChat() const {
return m_textBox->getText();
}
-void Chat::setCurrentChat(String const& chat) {
- m_textBox->setText(chat);
+bool Chat::setCurrentChat(String const& chat, bool moveCursor) {
+ return m_textBox->setText(chat, true, moveCursor);
}
void Chat::clearCurrentChat() {
@@ -179,8 +177,7 @@ void Chat::addMessages(List<ChatReceivedMessage> const& messages, bool showPane)
if (message.portrait.empty())
wrapWidth = m_chatLog->size()[0] - m_chatLogPadding[0] * 2;
- guiContext.setFont(m_font);
- guiContext.setFontSize(m_fontSize);
+ guiContext.setTextStyle(m_chatTextStyle);
StringList lines;
if (message.fromNick != "" && message.portrait == "")
lines = guiContext.wrapInterfaceText(strf("<{}> {}", message.fromNick, message.text), wrapWidth);
@@ -239,10 +236,10 @@ void Chat::renderImpl() {
int messageIndex = -m_historyOffset;
GuiContext& guiContext = GuiContext::singleton();
- guiContext.setFont(m_font);
- guiContext.setFontSize(m_fontSize);
- guiContext.setLineSpacing(m_chatLineHeight);
- for (auto message : m_receivedMessages) {
+ float lineHeight = m_chatTextStyle.lineSpacing;
+ float fontSize = m_chatTextStyle.fontSize;
+ guiContext.setTextStyle(m_chatTextStyle);
+ for (auto& message : m_receivedMessages) {
if (!m_modeFilter.empty() && !m_modeFilter.contains(message.mode))
continue;
@@ -260,7 +257,7 @@ void Chat::renderImpl() {
String messageString = channelColorCode + message.text;
float messageHeight = 0;
- float lineHeightMargin = + ((m_chatLineHeight * m_fontSize) - m_fontSize);
+ float lineHeightMargin = ((lineHeight * fontSize) - fontSize);
unsigned wrapWidth = m_chatLog->size()[0] - m_chatLogPadding[0] * 2;
if (message.portrait != "") {
@@ -274,13 +271,14 @@ void Chat::renderImpl() {
m_chatLog->drawImage(m_portraitBackground, Vec2F(imagePosition), 1.0f, fade);
m_chatLog->drawImage(message.portrait, Vec2F(imagePosition + m_portraitImageOffset), m_portraitScale, fade);
tp.pos += Vec2F(0, floor(messageHeight / 2));
- m_chatLog->drawText(messageString, tp, m_fontSize, fade, FontMode::Normal, m_chatLineHeight, m_font, m_fontDirectives);
+ m_chatTextStyle.color = fade;
+ m_chatLog->drawText(messageString, tp, m_chatTextStyle);
} else {
TextPositioning tp = {Vec2F(chatMin), HorizontalAnchor::LeftAnchor, VerticalAnchor::BottomAnchor, wrapWidth};
messageHeight = guiContext.determineInterfaceTextSize(messageString, tp).size()[1] + lineHeightMargin;
-
- m_chatLog->drawText(messageString, tp, m_fontSize, fade, FontMode::Normal, m_chatLineHeight, m_font, m_fontDirectives);
+ m_chatTextStyle.color = fade;
+ m_chatLog->drawText(messageString, tp, m_chatTextStyle);
}
chatMin[1] += ceil(messageHeight);
diff --git a/source/frontend/StarChat.hpp b/source/frontend/StarChat.hpp
index 28117ff..80cf683 100644
--- a/source/frontend/StarChat.hpp
+++ b/source/frontend/StarChat.hpp
@@ -32,7 +32,7 @@ public:
void addHistory(String const& chat);
String currentChat() const;
- void setCurrentChat(String const& chat);
+ bool setCurrentChat(String const& chat, bool moveCursor = false);
void clearCurrentChat();
ChatSendMode sendMode() const;
@@ -66,10 +66,7 @@ private:
int64_t m_timeChatLastActive;
float m_chatVisTime;
float m_fadeRate;
- unsigned m_fontSize;
- String m_fontDirectives;
- String m_font;
- float m_chatLineHeight;
+ TextStyle m_chatTextStyle;
unsigned m_chatHistoryLimit;
int m_historyOffset;
diff --git a/source/frontend/StarChatBubbleManager.cpp b/source/frontend/StarChatBubbleManager.cpp
index b08e292..d837de7 100644
--- a/source/frontend/StarChatBubbleManager.cpp
+++ b/source/frontend/StarChatBubbleManager.cpp
@@ -20,9 +20,8 @@ ChatBubbleManager::ChatBubbleManager()
auto jsonData = assets->json("/interface/windowconfig/chatbubbles.config");
- m_color = jsonToColor(jsonData.get("textColor"));
-
- m_fontSize = jsonData.getInt("fontSize");
+ m_textStyle.color = jsonToColor(jsonData.get("textColor")).toRgba();
+ m_textStyle.loadJson(jsonData.get("textStyle"));
m_textPadding = jsonToVec2F(jsonData.get("textPadding"));
m_zoom = jsonData.getInt("textZoom");
@@ -196,9 +195,7 @@ void ChatBubbleManager::addChatActions(List<ChatAction> chatActions, bool silent
// bother me so bad if it weren't so fucking easy to do right.
// yea I agree
- m_guiContext->setFontSize(m_fontSize, m_zoom);
- m_guiContext->setFontProcessingDirectives("");
- m_guiContext->setDefaultFont();
+ m_guiContext->setTextStyle(m_textStyle);
auto result = m_guiContext->determineTextSize(sayAction.text, m_textTemplate);
float textWidth = result.width() / m_zoom + m_textPadding[0];
float textHeight = result.height() / m_zoom + m_textPadding[1];
@@ -252,14 +249,17 @@ void ChatBubbleManager::addChatActions(List<ChatAction> chatActions, bool silent
float verticalShift = (partSize * innerTiles[1] - textMultiLineShift) * 0.5f + textMultiLineShift;
Vec2F position = Vec2F(horizontalCenter, verticalShift);
List<BubbleText> bubbleTexts;
- auto fontSize = config.getUInt("fontSize", m_fontSize);
- auto color = config.opt("color").apply(jsonToColor).value(m_color);
- bubbleTexts.append(make_tuple(sayAction.text, fontSize, color.toRgba(), true, position));
+ TextStyle textStyle = m_textStyle;
+ textStyle.fontSize = config.getUInt("fontSize", textStyle.fontSize);
+ if (auto jColor = config.opt("color"))
+ textStyle.color = jsonToColor(*jColor).toRgba();
+ textStyle.loadJson(config.get("style", Json()));
+ bubbleTexts.append(make_tuple(sayAction.text, textStyle, true, position));
for (auto& backgroundImage : backgroundImages)
get<1>(backgroundImage) += Vec2F(-horizontalCenter, partSize);
for (auto& bubbleText : bubbleTexts)
- get<4>(bubbleText) += Vec2F(-horizontalCenter, partSize);
+ get<3>(bubbleText) += Vec2F(-horizontalCenter, partSize);
auto pos = m_camera.worldToScreen(sayAction.position + m_bubbleOffset);
RectF boundBox = fold(backgroundImages, RectF::null(), [pos, this](RectF const& boundBox, BubbleImage const& bubbleImage) {
@@ -272,7 +272,7 @@ void ChatBubbleManager::addChatActions(List<ChatAction> chatActions, bool silent
m_bubbles.filter([&sayAction](BubbleState<Bubble> const&, Bubble const& bubble) { return bubble.entity != sayAction.entity; });
m_bubbles.addBubble(pos, boundBox, std::move(bubble), m_interBubbleMargin * m_zoom);
oldBubbles.sort([](BubbleState<Bubble> const& a, BubbleState<Bubble> const& b) { return a.contents.age < b.contents.age; });
- for (auto bubble : oldBubbles.slice(0, m_maxMessagePerEntity - 1))
+ for (auto& bubble : oldBubbles.slice(0, m_maxMessagePerEntity - 1))
m_bubbles.addBubble(bubble.idealDestination, bubble.boundBox, bubble.contents, 0);
} else if (action.is<PortraitChatAction>()) {
@@ -286,12 +286,12 @@ void ChatBubbleManager::addChatActions(List<ChatAction> chatActions, bool silent
backgroundImages.append(make_tuple(m_portraitMoreImage, Vec2F(m_portraitMorePosition)));
backgroundImages.append(make_tuple(portraitAction.portrait, Vec2F(m_portraitPosition)));
List<BubbleText> bubbleTexts;
- bubbleTexts.append(make_tuple(portraitAction.text, m_fontSize, m_color.toRgba(), false, Vec2F(m_portraitTextPosition)));
+ bubbleTexts.append(make_tuple(portraitAction.text, m_textStyle, false, Vec2F(m_portraitTextPosition)));
for (auto& backgroundImage : backgroundImages)
get<1>(backgroundImage) += Vec2F(-m_portraitBackgroundSize[0] / 2, 0);
for (auto& bubbleText : bubbleTexts)
- get<4>(bubbleText) += Vec2F(-m_portraitBackgroundSize[0] / 2, 0);
+ get<3>(bubbleText) += Vec2F(-m_portraitBackgroundSize[0] / 2, 0);
m_portraitBubbles.prepend({
portraitAction.entity,
@@ -321,28 +321,19 @@ void ChatBubbleManager::addChatActions(List<ChatAction> chatActions, bool silent
RectF ChatBubbleManager::bubbleImageRect(Vec2F screenPos, BubbleImage const& bubbleImage, int pixelRatio) {
auto imgMetadata = Root::singleton().imageMetadataDatabase();
- auto image = get<0>(bubbleImage);
+ auto& image = get<0>(bubbleImage);
return RectF::withSize(screenPos + get<1>(bubbleImage) * pixelRatio, Vec2F(imgMetadata->imageSize(image)) * pixelRatio);
}
void ChatBubbleManager::drawBubbleImage(Vec2F screenPos, BubbleImage const& bubbleImage, int pixelRatio, int alpha) {
- auto image = get<0>(bubbleImage);
+ auto& image = get<0>(bubbleImage);
auto offset = get<1>(bubbleImage) * pixelRatio;
m_guiContext->drawQuad(image, screenPos + offset, pixelRatio, {255, 255, 255, alpha});
}
void ChatBubbleManager::drawBubbleText(Vec2F screenPos, BubbleText const& bubbleText, int pixelRatio, int alpha, bool isPortrait) {
- Vec4B const& baseColor = get<2>(bubbleText);
-
- // use the alpha as a blend value for the text colour as pulled from data.
- Vec4B const& displayColor = Vec4B(baseColor[0], baseColor[1], baseColor[2], (baseColor[3] * alpha) / 255);
-
- m_guiContext->setDefaultFont();
- m_guiContext->setFontProcessingDirectives("");
- m_guiContext->setFontColor(displayColor);
- m_guiContext->setFontSize(get<1>(bubbleText), m_zoom);
-
- auto offset = get<4>(bubbleText) * pixelRatio;
+ m_guiContext->setTextStyle(get<1>(bubbleText), m_zoom);
+ auto offset = get<3>(bubbleText) * pixelRatio;
TextPositioning tp = isPortrait ? m_portraitTextTemplate : m_textTemplate;
tp.pos = screenPos + offset;
diff --git a/source/frontend/StarChatBubbleManager.hpp b/source/frontend/StarChatBubbleManager.hpp
index cf46fcc..42b58db 100644
--- a/source/frontend/StarChatBubbleManager.hpp
+++ b/source/frontend/StarChatBubbleManager.hpp
@@ -26,7 +26,7 @@ public:
private:
typedef tuple<String, Vec2F> BubbleImage;
- typedef tuple<String, unsigned, Vec4B, bool, Vec2F> BubbleText;
+ typedef tuple<String, TextStyle, bool, Vec2F> BubbleText;
struct Bubble {
EntityId entity;
@@ -64,8 +64,7 @@ private:
TextPositioning m_textTemplate;
TextPositioning m_portraitTextTemplate;
- Color m_color;
- int m_fontSize;
+ TextStyle m_textStyle;
Vec2F m_textPadding;
BubbleSeparator<Bubble> m_bubbles;
diff --git a/source/frontend/StarCinematic.cpp b/source/frontend/StarCinematic.cpp
index abd638d..c2dbd20 100644
--- a/source/frontend/StarCinematic.cpp
+++ b/source/frontend/StarCinematic.cpp
@@ -45,8 +45,9 @@ void Cinematic::load(Json const& definition) {
panel->animationFrames = panelDefinition.getInt("animationFrames", std::numeric_limits<int>::max());
panel->text = panelDefinition.getString("text", "");
panel->textPosition = TextPositioning(panelDefinition.get("textPosition", JsonObject()));
- panel->fontColor = panelDefinition.opt("fontColor").apply(jsonToVec4B).value(Vec4B(255, 255, 255, 255));
- panel->fontSize = panelDefinition.getUInt("fontSize", 8);
+ panel->textStyle = panelDefinition.get("textStyle", Json());
+ panel->textStyle.color = panelDefinition.opt("fontColor").apply(jsonToVec4B).value(panel->textStyle.color);
+ panel->textStyle.fontSize = panelDefinition.getUInt("fontSize", panel->textStyle.fontSize);
panel->avatar = panelDefinition.getString("avatar", "");
panel->startTime = panelDefinition.getFloat("startTime", 0);
panel->endTime = panelDefinition.getFloat("endTime", 0);
@@ -208,8 +209,9 @@ void Cinematic::render() {
}
}
if (!panel->text.empty()) {
- textPainter->setFontSize(floor(panel->fontSize * drawableScale));
- auto fontColor = panel->fontColor;
+ textPainter->setTextStyle(panel->textStyle);
+ textPainter->setFontSize(floor(panel->textStyle.fontSize * drawableScale));
+ auto fontColor = panel->textStyle.color;
fontColor[3] *= values.alpha;
textPainter->setFontColor(fontColor);
Vec2F position = (m_offset + values.position + Vec2F(panel->textPosition.pos)) * drawableScale + drawableTranslation;
diff --git a/source/frontend/StarCinematic.hpp b/source/frontend/StarCinematic.hpp
index 15ff2cd..b2e3c81 100644
--- a/source/frontend/StarCinematic.hpp
+++ b/source/frontend/StarCinematic.hpp
@@ -62,8 +62,7 @@ private:
int animationFrames;
String text;
TextPositioning textPosition;
- Vec4B fontColor;
- unsigned fontSize;
+ TextStyle textStyle;
List<KeyFrame> keyFrames;
float startTime;
float endTime;
diff --git a/source/frontend/StarClientCommandProcessor.cpp b/source/frontend/StarClientCommandProcessor.cpp
index 52882d9..def1b43 100644
--- a/source/frontend/StarClientCommandProcessor.cpp
+++ b/source/frontend/StarClientCommandProcessor.cpp
@@ -91,7 +91,7 @@ StringList ClientCommandProcessor::handleCommand(String const& commandLine) {
}
} else {
auto player = m_universeClient->mainPlayer();
- if (auto messageResult = player->receiveMessage(connectionForEntity(player->entityId()), strf("/{}", command), { allArguments }))
+ if (auto messageResult = player->receiveMessage(connectionForEntity(player->entityId()), "/" + command, { allArguments }))
result.append(messageResult->isType(Json::Type::String) ? *messageResult->stringPtr() : messageResult->repr(1, true));
else
m_universeClient->sendChat(commandLine, ChatSendMode::Broadcast);
diff --git a/source/frontend/StarInterfaceLuaBindings.cpp b/source/frontend/StarInterfaceLuaBindings.cpp
index a023a71..9e0bb2e 100644
--- a/source/frontend/StarInterfaceLuaBindings.cpp
+++ b/source/frontend/StarInterfaceLuaBindings.cpp
@@ -4,6 +4,9 @@
#include "StarLuaGameConverters.hpp"
#include "StarMainInterface.hpp"
#include "StarGuiContext.hpp"
+#include "StarChat.hpp"
+#include "StarUniverseClient.hpp"
+#include "StarClientCommandProcessor.hpp"
namespace Star {
@@ -42,4 +45,49 @@ LuaCallbacks LuaBindings::makeInterfaceCallbacks(MainInterface* mainInterface) {
return callbacks;
}
+LuaCallbacks LuaBindings::makeChatCallbacks(MainInterface* mainInterface, UniverseClient* client) {
+ LuaCallbacks callbacks;
+
+ auto chat = as<Chat>(mainInterface->paneManager()->registeredPane(MainInterfacePanes::Chat).get());
+
+ callbacks.registerCallback("send", [chat, client](String const& message, Maybe<String> modeName, Maybe<bool> speak) {
+ auto sendMode = modeName ? ChatSendModeNames.getLeft(*modeName) : ChatSendMode::Broadcast;
+ client->sendChat(message, sendMode, speak);
+ });
+
+ // just for SE compat - this shoulda been a utility callback :moyai:
+ callbacks.registerCallback("parseArguments", [](String const& args) {
+ return Json::parseSequence(args);
+ });
+
+ callbacks.registerCallback("command", [mainInterface](String const& command) -> StringList {
+ return mainInterface->commandProcessor()->handleCommand(command);
+ });
+
+ callbacks.registerCallback("addMessage", [client, chat](String const& text, Maybe<Json> config) {
+ ChatReceivedMessage message({MessageContext::Mode::CommandResult, ""}, client->clientContext()->connectionId(), "", text);
+ if (config) {
+ if (auto mode = config->optString("mode"))
+ message.context.mode = MessageContextModeNames.getLeft(*mode);
+ if (auto channelName = config->optString("channelName"))
+ message.context.channelName = std::move(*channelName);
+ if (auto portrait = config->optString("portrait"))
+ message.portrait = std::move(*portrait);
+ if (auto fromNick = config->optString("fromNick"))
+ message.fromNick = std::move(*fromNick);
+ }
+ chat->addMessages({std::move(message)}, config ? config->getBool("showPane", true) : true);
+ });
+
+ callbacks.registerCallback("input", [chat]() -> String {
+ return chat->currentChat();
+ });
+
+ callbacks.registerCallback("setInput", [chat](String const& text, Maybe<bool> moveCursor) -> bool {
+ return chat->setCurrentChat(text, moveCursor.value(false));
+ });
+
+ return callbacks;
+}
+
}
diff --git a/source/frontend/StarInterfaceLuaBindings.hpp b/source/frontend/StarInterfaceLuaBindings.hpp
index 539cceb..2973f18 100644
--- a/source/frontend/StarInterfaceLuaBindings.hpp
+++ b/source/frontend/StarInterfaceLuaBindings.hpp
@@ -5,9 +5,11 @@
namespace Star {
STAR_CLASS(MainInterface);
+STAR_CLASS(UniverseClient);
namespace LuaBindings {
LuaCallbacks makeInterfaceCallbacks(MainInterface* mainInterface);
+ LuaCallbacks makeChatCallbacks(MainInterface* mainInterface, UniverseClient* client);
}
}
diff --git a/source/frontend/StarMainInterface.cpp b/source/frontend/StarMainInterface.cpp
index 4303a28..ece00a5 100644
--- a/source/frontend/StarMainInterface.cpp
+++ b/source/frontend/StarMainInterface.cpp
@@ -160,10 +160,8 @@ MainInterface::MainInterface(UniverseClientPtr client, WorldPainterPtr painter,
auto planetName = make_shared<Pane>();
m_planetText = make_shared<LabelWidget>();
- m_planetText->setFontSize(m_config->planetNameFontSize);
- m_planetText->setFontMode(FontMode::Normal);
+ m_planetText->setTextStyle(m_config->planetNameTextStyle);
m_planetText->setAnchor(HorizontalAnchor::HMidAnchor, VerticalAnchor::VMidAnchor);
- m_planetText->setDirectives(m_config->planetNameDirectives);
planetName->disableScissoring();
planetName->setPosition(m_config->planetNameOffset);
planetName->setAnchor(PaneAnchor::Center);
@@ -810,9 +808,7 @@ void MainInterface::renderInWorldElements() {
if (m_disableHud)
return;
- m_guiContext->setDefaultFont();
- m_guiContext->setFontProcessingDirectives("");
- m_guiContext->setFontColor(Vec4B::filled(255));
+ m_guiContext->clearTextStyle();
m_questIndicatorPainter->render();
m_nameplatePainter->render();
m_chatBubbleManager->render();
@@ -822,9 +818,7 @@ void MainInterface::render() {
if (m_disableHud)
return;
- m_guiContext->setDefaultFont();
- m_guiContext->setFontProcessingDirectives("");
- m_guiContext->setFontColor(Vec4B::filled(255));
+ m_guiContext->clearTextStyle();
renderBreath();
renderMessages();
renderMonsterHealthBar();
@@ -950,6 +944,10 @@ CanvasWidgetPtr MainInterface::fetchCanvas(String const& canvasName, bool ignore
return canvas;
}
+ClientCommandProcessorPtr MainInterface::commandProcessor() const {
+ return m_clientCommandProcessor;
+}
+
// For when the player swaps characters. We need to completely reload ScriptPanes,
// because a lot of ScriptPanes do not expect the character to suddenly change and may break or spill data over.
void MainInterface::takeScriptPanes(List<ScriptPaneInfo>& out) {
@@ -1084,9 +1082,7 @@ void MainInterface::renderMessages() {
m_guiContext->drawQuad(m_config->messageTextContainer,
RectF::withCenter(backgroundTextCenterPos, Vec2F(imgMetadata->imageSize(m_config->messageTextContainer) * interfaceScale())));
- m_guiContext->setFont(m_config->font);
- m_guiContext->setFontSize(m_config->fontSize);
- m_guiContext->setFontColor(Color::White.toRgba());
+ m_guiContext->setTextStyle(m_config->textStyle);
m_guiContext->renderText(message->message, {messageTextOffset, HorizontalAnchor::HMidAnchor, VerticalAnchor::VMidAnchor});
}
}
@@ -1112,9 +1108,7 @@ void MainInterface::renderMonsterHealthBar() {
m_guiContext->drawQuad(container, RectF::withCenter(backgroundCenterPos + offset, Vec2F(imgMetadata->imageSize(container) * interfaceScale())));
auto nameTextOffset = jsonToVec2F(assets->json("/interface.config:monsterHealth.nameTextOffset")) * interfaceScale();
- m_guiContext->setFont(m_config->font);
- m_guiContext->setFontSize(m_config->fontSize);
- m_guiContext->setFontColor(Color::White.toRgba());
+ m_guiContext->setTextStyle(m_config->textStyle);
m_guiContext->renderText(showDamageEntity->name(), backgroundCenterPos + nameTextOffset);
auto empty = assets->json("/interface.config:monsterHealth.progressEmpty").toString();
@@ -1176,11 +1170,11 @@ void MainInterface::renderSpecialDamageBar() {
m_guiContext->drawQuad(fill, RectF::withSize(bottomCenter + fillOffset, size * interfaceScale()));
auto nameOffset = jsonToVec2F(barConfig.get("nameOffset")) * interfaceScale();
- m_guiContext->setFontColor(jsonToColor(barConfig.get("nameColor")).toRgba());
+ m_guiContext->setFontColor(jsonToColor(barConfig.get("nameStyle")).toRgba());
m_guiContext->setFontSize(barConfig.getUInt("nameSize"));
m_guiContext->setFontProcessingDirectives(barConfig.getString("nameDirectives"));
m_guiContext->renderText(target->name(), TextPositioning(bottomCenter + nameOffset, HorizontalAnchor::HMidAnchor, VerticalAnchor::BottomAnchor));
- m_guiContext->setFontProcessingDirectives("");
+ m_guiContext->clearTextStyle();
}
}
@@ -1341,12 +1335,8 @@ void MainInterface::renderDebug() {
if (m_clientCommandProcessor->debugHudEnabled()) {
auto assets = Root::singleton().assets();
- m_guiContext->setFontSize(m_config->debugFontSize);
- m_guiContext->setFont(m_config->debugFont);
+ m_guiContext->setTextStyle(m_config->debugTextStyle);
m_guiContext->setLineSpacing(0.5f);
- m_guiContext->setFontProcessingDirectives(m_config->debugFontDirectives);
- m_guiContext->setFontColor(Color::White.toRgba());
- m_guiContext->setFontMode(FontMode::Normal);
bool clearMap = m_debugMapClearTimer.wrapTick();
auto logMapValues = LogMap::getValues();
@@ -1358,7 +1348,7 @@ void MainInterface::renderDebug() {
int counter = 0;
for (auto const& pair : logMapValues) {
- TextPositioning positioning = { Vec2F(m_config->debugOffset[0], windowHeight() - m_config->debugOffset[1] - m_config->fontSize * interfaceScale() * counter++) };
+ TextPositioning positioning = { Vec2F(m_config->debugOffset[0], windowHeight() - m_config->debugOffset[1] - m_config->textStyle.fontSize * interfaceScale() * counter++) };
String& text = formatted.emplace_back(strf("{}^lightgray;:^green,set; {}", pair.first, pair.second));
m_debugTextRect.combine(m_guiContext->determineTextSize(text, positioning).padded(m_config->debugBackgroundPad));
}
@@ -1373,15 +1363,9 @@ void MainInterface::renderDebug() {
m_debugTextRect = RectF::null();
for (size_t index = 0; index != formatted.size(); ++index) {
- TextPositioning positioning = { Vec2F(m_config->debugOffset[0], windowHeight() - m_config->debugOffset[1] - m_config->fontSize * interfaceScale() * index) };
+ TextPositioning positioning = { Vec2F(m_config->debugOffset[0], windowHeight() - m_config->debugOffset[1] - m_config->textStyle.fontSize * interfaceScale() * index) };
m_guiContext->renderText(formatted[index], positioning);
}
-
- m_guiContext->setFontSize(8);
- m_guiContext->setDefaultFont();
- m_guiContext->setDefaultLineSpacing();
- m_guiContext->setFontColor(Vec4B::filled(255));
- m_guiContext->setFontProcessingDirectives("");
}
auto const& camera = m_worldPainter->camera();
@@ -1413,7 +1397,7 @@ void MainInterface::renderDebug() {
m_guiContext->drawLine(position + Vec2F(2, -2), position + Vec2F(-2, -2), point.color, 1);
}
- m_guiContext->setFontSize(m_config->debugFontSize);
+ m_guiContext->setTextStyle(m_config->debugTextStyle);
for (auto const& logText : SpatialLogger::getText("world", clearSpatial)) {
m_guiContext->setFontColor(logText.color);
@@ -1424,7 +1408,7 @@ void MainInterface::renderDebug() {
m_guiContext->setFontColor(logText.color);
m_guiContext->renderText(logText.text.utf8Ptr(), logText.position);
}
- m_guiContext->setFontColor(Vec4B::filled(255));
+ m_guiContext->clearTextStyle();
}
void MainInterface::updateCursor() {
@@ -1483,24 +1467,26 @@ void MainInterface::renderCursor() {
auto assets = Root::singleton().assets();
auto imgDb = Root::singleton().imageMetadataDatabase();
- auto backgroundImage = assets->json("/interface.config:cursorTooltip.background").toString();
- auto rawCursorOffset = jsonToVec2I(assets->json("/interface.config:cursorTooltip.offset"));
+ auto config = assets->json("/interface.config:cursorTooltip");
+ auto backgroundImage = config.getString("background");
+ auto rawCursorOffset = jsonToVec2I(config.get("offset"));
Vec2I tooltipSize = Vec2I(imgDb->imageSize(backgroundImage)) * interfaceScale();
Vec2I cursorOffset = (Vec2I{0, -m_cursor.size().y()} + rawCursorOffset) * cursorScale;
Vec2I tooltipOffset = m_cursorScreenPos + cursorOffset;
- size_t fontSize = assets->json("/interface.config:cursorTooltip.fontSize").toUInt();
- String font = assets->json("/interface.config:cursorTooltip.font").toString();
- Vec4B fontColor = jsonToColor(assets->json("/interface.config:cursorTooltip.color")).toRgba();
+ TextStyle textStyle = config.get("textStyle");
+ size_t fontSize = config.get("fontSize").toUInt();
+ Vec4B fontColor = jsonToColor(config.get("color")).toRgba();
m_guiContext->drawQuad(backgroundImage, Vec2F(tooltipOffset) + Vec2F(-tooltipSize.x(), 0), interfaceScale());
+ m_guiContext->setTextStyle(textStyle);
m_guiContext->setFontSize(fontSize);
m_guiContext->setFontColor(fontColor);
- m_guiContext->setFont(font);
m_guiContext->renderText(*m_cursorTooltip,
TextPositioning(Vec2F(tooltipOffset) + Vec2F(-tooltipSize.x(), tooltipSize.y()) / 2,
HorizontalAnchor::HMidAnchor,
VerticalAnchor::VMidAnchor));
+ m_guiContext->clearTextStyle();
}
m_cursorItem->setPosition(m_cursorScreenPos / interfaceScale() + m_config->inventoryItemMouseOffset);
diff --git a/source/frontend/StarMainInterface.hpp b/source/frontend/StarMainInterface.hpp
index 0f1487e..ec79f68 100644
--- a/source/frontend/StarMainInterface.hpp
+++ b/source/frontend/StarMainInterface.hpp
@@ -119,6 +119,8 @@ public:
CanvasWidgetPtr fetchCanvas(String const& canvasName, bool ignoreInterfaceScale = false);
+ ClientCommandProcessorPtr commandProcessor() const;
+
struct ScriptPaneInfo {
ScriptPanePtr scriptPane;
Json config;
diff --git a/source/frontend/StarMainInterfaceTypes.cpp b/source/frontend/StarMainInterfaceTypes.cpp
index 1d67292..957b69d 100644
--- a/source/frontend/StarMainInterfaceTypes.cpp
+++ b/source/frontend/StarMainInterfaceTypes.cpp
@@ -39,8 +39,7 @@ MainInterfaceConfigPtr MainInterfaceConfig::loadFromAssets() {
auto config = make_shared<MainInterfaceConfig>();
- config->fontSize = assets->json("/interface.config:font.baseSize").toInt();
- config->font = assets->json("/interface.config:font.defaultFont").toString();
+ config->textStyle = assets->json("/interface.config:textStyle");
config->inventoryImage = assets->json("/interface.config:mainBar.inventory.base").toString();
config->inventoryImageHover = assets->json("/interface.config:mainBar.inventory.hover").toString();
config->inventoryImageGlow = assets->json("/interface.config:mainBar.inventory.glow").toString();
@@ -130,17 +129,14 @@ MainInterfaceConfigPtr MainInterfaceConfig::loadFromAssets() {
config->planetNameTime = assets->json("/interface.config:planetNameTime").toFloat();
config->planetNameFadeTime = assets->json("/interface.config:planetNameFadeTime").toFloat();
config->planetNameFormatString = assets->json("/interface.config:planetNameFormatString").toString();
- config->planetNameFontSize = assets->json("/interface.config:font.planetSize").toInt();
- config->planetNameDirectives = assets->json("/interface.config:planetNameDirectives").toString();
+ config->planetNameTextStyle = assets->json("/interface.config:planetTextStyle");
config->planetNameOffset = jsonToVec2I(assets->json("/interface.config:planetTextOffset"));
config->renderVirtualCursor = assets->json("/interface.config:renderVirtualCursor").toBool();
config->cursorItemSlot = assets->json("/interface.config:cursorItemSlot");
config->debugOffset = jsonToVec2I(assets->json("/interface.config:debugOffset"));
- config->debugFontSize = assets->json("/interface.config:debugFontSize").toUInt();
- config->debugFont = assets->json("/interface.config:debugFont").toString();
- config->debugFontDirectives = assets->json("/interface.config:debugFontDirectives").toString();
+ config->debugTextStyle = assets->json("/interface.config:debugTextStyle");
config->debugSpatialClearTime = assets->json("/interface.config:debugSpatialClearTime").toFloat();
config->debugMapClearTime = assets->json("/interface.config:debugMapClearTime").toFloat();
config->debugBackgroundColor = jsonToColor(assets->json("/interface.config:debugBackgroundColor"));
diff --git a/source/frontend/StarMainInterfaceTypes.hpp b/source/frontend/StarMainInterfaceTypes.hpp
index 6b0bca3..b5f228a 100644
--- a/source/frontend/StarMainInterfaceTypes.hpp
+++ b/source/frontend/StarMainInterfaceTypes.hpp
@@ -5,6 +5,7 @@
#include "StarBiMap.hpp"
#include "StarRegisteredPaneManager.hpp"
#include "StarAnimation.hpp"
+#include "StarText.hpp"
namespace Star {
@@ -43,8 +44,7 @@ typedef RegisteredPaneManager<MainInterfacePanes> MainInterfacePaneManager;
struct MainInterfaceConfig {
static MainInterfaceConfigPtr loadFromAssets();
- unsigned fontSize;
- String font;
+ TextStyle textStyle;
String inventoryImage;
String inventoryImageHover;
@@ -136,17 +136,14 @@ struct MainInterfaceConfig {
float planetNameTime;
float planetNameFadeTime;
String planetNameFormatString;
- unsigned planetNameFontSize;
- String planetNameDirectives;
+ TextStyle planetNameTextStyle;
Vec2I planetNameOffset;
bool renderVirtualCursor;
Json cursorItemSlot;
Vec2I debugOffset;
- unsigned debugFontSize;
- String debugFont;
- String debugFontDirectives;
+ TextStyle debugTextStyle;
float debugSpatialClearTime;
float debugMapClearTime;
Color debugBackgroundColor;
diff --git a/source/frontend/StarNameplatePainter.cpp b/source/frontend/StarNameplatePainter.cpp
index 4637232..0666af0 100644
--- a/source/frontend/StarNameplatePainter.cpp
+++ b/source/frontend/StarNameplatePainter.cpp
@@ -15,14 +15,11 @@ NameplatePainter::NameplatePainter() {
m_opacityRate = nametagConfig.getFloat("opacityRate");
m_inspectOpacityRate = nametagConfig.queryFloat("inspectOpacityRate", m_opacityRate);
m_offset = jsonToVec2F(nametagConfig.get("offset"));
- m_font = nametagConfig.queryString("font", "");
- m_fontDirectives = nametagConfig.queryString("fontDirectives", "");
- m_fontSize = nametagConfig.getFloat("fontSize");
- m_statusFont = nametagConfig.queryString("font", m_font);
- m_statusFontDirectives = nametagConfig.queryString("fontDirectives", m_fontDirectives);
- m_statusFontSize = nametagConfig.queryFloat("statusFontSize", m_fontSize);
+ Json textStyle = nametagConfig.get("textStyle");
+ m_textStyle = textStyle;
+ m_statusTextStyle = nametagConfig.get("statusTextStyle", textStyle);
m_statusOffset = jsonToVec2F(nametagConfig.get("statusOffset"));
- m_statusColor = jsonToColor(nametagConfig.get("statusColor"));
+ m_statusTextStyle.color = jsonToColor(nametagConfig.get("statusColor")).toRgba();
m_opacityBoost = nametagConfig.getFloat("opacityBoost");
m_nametags.setTweenFactor(nametagConfig.getFloat("tweenFactor"));
m_nametags.setMovementThreshold(nametagConfig.getFloat("movementThreshold"));
@@ -80,31 +77,18 @@ void NameplatePainter::render() {
if (nametag.opacity == 0.0f)
return;
- context.setFont(m_font);
- context.setFontProcessingDirectives(m_fontDirectives);
- context.setFontSize(m_fontSize);
-
+ auto& setStyle = context.setTextStyle(m_textStyle);
auto color = Color::rgb(nametag.color);
color.setAlphaF(nametag.opacity);
- context.setFontColor(color.toRgba());
- context.setFontMode(FontMode::Normal);
+ setStyle.color = color.toRgba();
context.renderText(nametag.name, namePosition(bubble.currentPosition));
if (nametag.statusText) {
- auto statusColor = m_statusColor;
- statusColor.setAlphaF(nametag.opacity);
- context.setFontColor(statusColor.toRgba());
-
- context.setFontSize(m_statusFontSize);
- context.setFontProcessingDirectives(m_statusFontDirectives);
- context.setFont(m_statusFont);
-
+ context.setTextStyle(m_statusTextStyle).color[3] *= nametag.opacity;
context.renderText(*nametag.statusText, statusPosition(bubble.currentPosition));
}
-
- context.setDefaultFont();
- context.setFontProcessingDirectives("");
+ context.clearTextStyle();
});
}
@@ -121,16 +105,13 @@ TextPositioning NameplatePainter::statusPosition(Vec2F bubblePosition) const {
RectF NameplatePainter::determineBoundBox(Vec2F bubblePosition, Nametag const& nametag) const {
auto& context = GuiContext::singleton();
- context.setFontSize(m_fontSize);
- context.setFontProcessingDirectives(m_fontDirectives);
- context.setFont(m_font);
+ context.setTextStyle(m_textStyle);
RectF nametagBox = context.determineTextSize(nametag.name, namePosition(bubblePosition));
if (nametag.statusText) {
- context.setFontSize(m_statusFontSize);
- context.setFontProcessingDirectives(m_statusFontDirectives);
- context.setFont(m_statusFont);
+ context.setTextStyle(m_statusTextStyle);
nametagBox.combine(context.determineTextSize(*nametag.statusText, statusPosition(bubblePosition)));
}
+ context.clearTextStyle();
return nametagBox;
}
diff --git a/source/frontend/StarNameplatePainter.hpp b/source/frontend/StarNameplatePainter.hpp
index d895cfb..06aa187 100644
--- a/source/frontend/StarNameplatePainter.hpp
+++ b/source/frontend/StarNameplatePainter.hpp
@@ -34,14 +34,9 @@ private:
float m_opacityRate;
float m_inspectOpacityRate;
Vec2F m_offset;
- String m_font;
- String m_statusFont;
- String m_fontDirectives;
- String m_statusFontDirectives;
- float m_fontSize;
- float m_statusFontSize;
Vec2F m_statusOffset;
- Color m_statusColor;
+ TextStyle m_textStyle;
+ TextStyle m_statusTextStyle;
float m_opacityBoost;
WorldCamera m_camera;
diff --git a/source/frontend/StarTeamBar.cpp b/source/frontend/StarTeamBar.cpp
index 767bb91..8a8f956 100644
--- a/source/frontend/StarTeamBar.cpp
+++ b/source/frontend/StarTeamBar.cpp
@@ -29,7 +29,8 @@ TeamBar::TeamBar(MainInterface* mainInterface, UniverseClientPtr client) {
m_teamInvitation = make_shared<TeamInvitation>(this);
m_teamMemberMenu = make_shared<TeamMemberMenu>(this);
- m_nameFontSize = assets->json("/interface.config:font.nameSize").toInt();
+ m_nameStyle = assets->json("/interface.config:teamBarNameStyle");
+ m_nameStyle.fontSize = assets->json("/interface.config:font.nameSize").toInt();
m_nameOffset = jsonToVec2F(assets->json("/interface.config:nameOffset"));
GuiReader reader;
diff --git a/source/frontend/StarTeamBar.hpp b/source/frontend/StarTeamBar.hpp
index 9ebbb50..ca50452 100644
--- a/source/frontend/StarTeamBar.hpp
+++ b/source/frontend/StarTeamBar.hpp
@@ -93,7 +93,7 @@ private:
GuiContext* m_guiContext;
- int m_nameFontSize;
+ TextStyle m_nameStyle;
Vec2F m_nameOffset;
TeamInvitePtr m_teamInvite;
diff --git a/source/game/StarClientContext.cpp b/source/game/StarClientContext.cpp
index e6fd89a..a91c40e 100644
--- a/source/game/StarClientContext.cpp
+++ b/source/game/StarClientContext.cpp
@@ -96,4 +96,12 @@ ByteArray ClientContext::writeUpdate() {
return m_rpc->send();
}
+void ClientContext::setConnectionId(ConnectionId connectionId) {
+ m_connectionId = connectionId;
+}
+
+ConnectionId ClientContext::connectionId() const {
+ return m_connectionId;
+}
+
}
diff --git a/source/game/StarClientContext.hpp b/source/game/StarClientContext.hpp
index 1bad18d..5cdd727 100644
--- a/source/game/StarClientContext.hpp
+++ b/source/game/StarClientContext.hpp
@@ -43,9 +43,13 @@ public:
void readUpdate(ByteArray data);
ByteArray writeUpdate();
+ void setConnectionId(ConnectionId connectionId);
+ ConnectionId connectionId() const;
+
private:
Uuid m_serverUuid;
Uuid m_playerUuid;
+ ConnectionId m_connectionId = 0;
JsonRpcPtr m_rpc;
diff --git a/source/game/StarHumanoid.cpp b/source/game/StarHumanoid.cpp
index 418e88d..a18dd3f 100644
--- a/source/game/StarHumanoid.cpp
+++ b/source/game/StarHumanoid.cpp
@@ -1382,11 +1382,11 @@ pair<Vec2F, Directives> Humanoid::extractScaleFromDirectives(Directives const& d
size_t totalLength = 0;
Maybe<Vec2F> scale;
- for (auto& entry : directives.shared->entries) {
- auto string = entry.string(*directives.shared);
+ for (auto& entry : directives->entries) {
+ auto string = entry.string(*directives);
const ScaleImageOperation* op = nullptr;
if (string.beginsWith("scalenearest") && string.utf8().find("skip") == NPos)
- op = entry.loadOperation(*directives.shared).ptr<ScaleImageOperation>();
+ op = entry.loadOperation(*directives).ptr<ScaleImageOperation>();
if (op)
scale = scale.value(Vec2F::filled(1.f)).piecewiseMultiply(op->scale);
diff --git a/source/game/StarImageMetadataDatabase.cpp b/source/game/StarImageMetadataDatabase.cpp
index b3a3983..bf84e51 100644
--- a/source/game/StarImageMetadataDatabase.cpp
+++ b/source/game/StarImageMetadataDatabase.cpp
@@ -132,7 +132,7 @@ AssetPath ImageMetadataDatabase::filterProcessing(AssetPath const& path) {
operation.is<ScanLinesImageOperation>() ||
operation.is<SetColorImageOperation>())) {
filtered += "?";
- filtered += entry.string(*directives.shared);
+ filtered += entry.string(*directives);
}
});
diff --git a/source/game/StarParallax.cpp b/source/game/StarParallax.cpp
index 2670699..d537b2c 100644
--- a/source/game/StarParallax.cpp
+++ b/source/game/StarParallax.cpp
@@ -62,7 +62,7 @@ void ParallaxLayer::addImageDirectives(Directives const& newDirectives) {
if (directives) {
String dirString = directives.string();
- auto& newString = newDirectives.shared->string;
+ auto& newString = newDirectives->string;
if (!newString.empty()) {
if (newString.utf8().front() != '?')
dirString += "?";
diff --git a/source/game/StarUniverseClient.cpp b/source/game/StarUniverseClient.cpp
index adc6bef..136fd7b 100644
--- a/source/game/StarUniverseClient.cpp
+++ b/source/game/StarUniverseClient.cpp
@@ -440,8 +440,8 @@ bool UniverseClient::flying() const {
return false;
}
-void UniverseClient::sendChat(String const& text, ChatSendMode sendMode) {
- if (!text.beginsWith("/"))
+void UniverseClient::sendChat(String const& text, ChatSendMode sendMode, Maybe<bool> speak) {
+ if (speak.value(!text.beginsWith("/")))
m_mainPlayer->addChatMessage(text);
m_connection->pushSingle(make_shared<ChatSendPacket>(text, sendMode));
}
diff --git a/source/game/StarUniverseClient.hpp b/source/game/StarUniverseClient.hpp
index 16457c7..985124a 100644
--- a/source/game/StarUniverseClient.hpp
+++ b/source/game/StarUniverseClient.hpp
@@ -80,7 +80,7 @@ public:
SkyConstPtr currentSky() const;
bool flying() const;
- void sendChat(String const& text, ChatSendMode sendMode);
+ void sendChat(String const& text, ChatSendMode sendMode, Maybe<bool> speak = {});
List<ChatReceivedMessage> pullChatMessages();
uint16_t players();
diff --git a/source/game/StarWorldClient.cpp b/source/game/StarWorldClient.cpp
index eaea2b2..5f7e028 100644
--- a/source/game/StarWorldClient.cpp
+++ b/source/game/StarWorldClient.cpp
@@ -1734,6 +1734,7 @@ void WorldClient::initWorld(WorldStartPacket const& startPacket) {
m_entityUpdateTimer = GameTimer(m_interpolationTracker.entityUpdateDelta());
m_clientId = startPacket.clientId;
+ m_mainPlayer->clientContext()->setConnectionId(startPacket.clientId);
auto entitySpace = connectionEntitySpace(startPacket.clientId);
m_worldTemplate = make_shared<WorldTemplate>(startPacket.templateData);
m_entityMap = make_shared<EntityMap>(m_worldTemplate->size(), entitySpace.first, entitySpace.second);
diff --git a/source/rendering/StarFontTextureGroup.cpp b/source/rendering/StarFontTextureGroup.cpp
index e8f701a..fb3a107 100644
--- a/source/rendering/StarFontTextureGroup.cpp
+++ b/source/rendering/StarFontTextureGroup.cpp
@@ -47,11 +47,12 @@ const FontTextureGroup::GlyphTexture& FontTextureGroup::glyphTexture(String::Cha
m_font->setPixelSize(size);
auto pair = m_font->render(c);
Image& image = pair.first;
- if (processingDirectives && *processingDirectives) {
+ if (processingDirectives) {
try {
+ Directives const& directives = *processingDirectives;
Vec2F preSize = Vec2F(image.size());
- for (auto& entry : processingDirectives->shared->entries)
+ for (auto& entry : directives->entries)
processImageOperation(entry.operation, image);
res.first->second.offset = (preSize - Vec2F(image.size())) / 2;
diff --git a/source/rendering/StarTextPainter.cpp b/source/rendering/StarTextPainter.cpp
index 8e21488..8198969 100644
--- a/source/rendering/StarTextPainter.cpp
+++ b/source/rendering/StarTextPainter.cpp
@@ -1,7 +1,5 @@
#include "StarTextPainter.hpp"
#include "StarJsonExtra.hpp"
-#include "StarText.hpp"
-
#include <regex>
namespace Star {
@@ -40,34 +38,42 @@ TextPositioning TextPositioning::translated(Vec2F translation) const {
TextPainter::TextPainter(RendererPtr renderer, TextureGroupPtr textureGroup)
: m_renderer(renderer),
m_fontTextureGroup(textureGroup),
- m_fontSize(8),
- m_lineSpacing(1.30f),
- m_renderSettings({FontMode::Normal, Vec4B::filled(255), "hobo", ""}) {
+ m_defaultRenderSettings(),
+ m_renderSettings(),
+ m_savedRenderSettings() {
reloadFonts();
m_reloadTracker = make_shared<TrackerListener>();
Root::singleton().registerReloadListener(m_reloadTracker);
}
RectF TextPainter::renderText(StringView s, TextPositioning const& position) {
+ RectF rect;
if (position.charLimit) {
unsigned charLimit = *position.charLimit;
- return doRenderText(s, position, true, &charLimit);
+ rect = doRenderText(s, position, true, &charLimit);
} else {
- return doRenderText(s, position, true, nullptr);
+ rect = doRenderText(s, position, true, nullptr);
}
+ renderPrimitives();
+ return rect;
}
RectF TextPainter::renderLine(StringView s, TextPositioning const& position) {
+ RectF rect;
if (position.charLimit) {
unsigned charLimit = *position.charLimit;
- return doRenderLine(s, position, true, &charLimit);
+ rect = doRenderLine(s, position, true, &charLimit);
} else {
- return doRenderLine(s, position, true, nullptr);
+ rect = doRenderLine(s, position, true, nullptr);
}
+ renderPrimitives();
+ return rect;
}
RectF TextPainter::renderGlyph(String::Char c, TextPositioning const& position) {
- return doRenderGlyph(c, position, true);
+ auto rect = doRenderGlyph(c, position, true);
+ renderPrimitives();
+ return rect;
}
RectF TextPainter::determineTextSize(StringView s, TextPositioning const& position) {
@@ -83,34 +89,36 @@ RectF TextPainter::determineGlyphSize(String::Char c, TextPositioning const& pos
}
int TextPainter::glyphWidth(String::Char c) {
- return m_fontTextureGroup.glyphWidth(c, m_fontSize);
+ return m_fontTextureGroup.glyphWidth(c, m_renderSettings.fontSize);
}
-int TextPainter::stringWidth(StringView s) {
+int TextPainter::stringWidth(StringView s, unsigned charLimit) {
if (s.empty())
return 0;
String font = m_renderSettings.font, setFont = font;
m_fontTextureGroup.switchFont(font);
- int width = 0;
-
Text::CommandsCallback commandsCallback = [&](StringView commands) {
commands.forEachSplitView(",", [&](StringView command, size_t, size_t) {
- if (command == "reset")
+ if (command == "reset") {
m_fontTextureGroup.switchFont(font = setFont);
- else if (command == "set")
+ } else if (command == "set") {
setFont = font;
- else if (command.beginsWith("font="))
+ } else if (command.beginsWith("font=")) {
m_fontTextureGroup.switchFont(font = command.substr(5));
+ }
});
return true;
};
+ int width = 0;
Text::TextCallback textCallback = [&](StringView text) {
- for (String::Char c : text)
+ for (String::Char c : text) {
width += glyphWidth(c);
-
+ if (charLimit && --charLimit == 0)
+ return false;
+ }
return true;
};
@@ -122,7 +130,7 @@ int TextPainter::stringWidth(StringView s) {
bool TextPainter::processWrapText(StringView text, unsigned* wrapWidth, WrapTextCallback textFunc) {
String font = m_renderSettings.font, setFont = font;
m_fontTextureGroup.switchFont(font);
- int lines = 0;
+ unsigned lines = 0;
auto it = text.begin();
auto end = text.end();
@@ -149,14 +157,15 @@ bool TextPainter::processWrapText(StringView text, unsigned* wrapWidth, WrapText
if (escIt != end) {
if (character == Text::EndEsc) {
- StringView inner = slice(escIt, it);
+ StringView inner = slice(++escIt, it);
inner.forEachSplitView(",", [&](StringView command, size_t, size_t) {
- if (command == "reset")
+ if (command == "reset") {
m_fontTextureGroup.switchFont(font = setFont);
- else if (command == "set")
+ } else if (command == "set") {
setFont = font;
- else if (command.beginsWith("font="))
+ } else if (command.beginsWith("font=")) {
m_fontTextureGroup.switchFont(font = command.substr(5));
+ }
});
escIt = end;
}
@@ -177,7 +186,6 @@ bool TextPainter::processWrapText(StringView text, unsigned* wrapWidth, WrapText
splitIt = end;
} else {
int charWidth = glyphWidth(character);
-
// is it a place where we might want to split the line ?
if (character == ' ' || character == '\t') {
splitIt = it;
@@ -220,36 +228,20 @@ bool TextPainter::processWrapText(StringView text, unsigned* wrapWidth, WrapText
List<StringView> TextPainter::wrapTextViews(StringView s, Maybe<unsigned> wrapWidth) {
List<StringView> views = {};
-
- bool active = false;
- StringView current;
- int lastLine = 0;
-
- auto addText = [&active, &current](StringView text) {
- // Merge views if they are adjacent
- if (active && current.utf8Ptr() + current.utf8Size() == text.utf8Ptr())
- current = StringView(current.utf8Ptr(), current.utf8Size() + text.utf8Size());
- else
- current = text;
- active = true;
- };
-
- TextPainter::WrapTextCallback textCallback = [&](StringView text, int line) {
- if (lastLine != line) {
- views.push_back(current);
- lastLine = line;
- active = false;
+ auto last = views.end();
+ unsigned curLine = 0;
+ TextPainter::WrapTextCallback textCallback = [&](StringView text, unsigned line) {
+ if (line == curLine && last != views.end() && last->end() == text.begin()) {
+ *last = StringView(last->utf8Ptr(), last->utf8Size() + text.utf8Size());
+ } else {
+ last = views.insert(views.end(), text);
+ curLine = line;
}
-
- addText(text);
return true;
};
processWrapText(s, wrapWidth.ptr(), textCallback);
- if (active)
- views.push_back(current);
-
return views;
}
@@ -258,12 +250,11 @@ StringList TextPainter::wrapText(StringView s, Maybe<unsigned> wrapWidth) {
String current;
int lastLine = 0;
- TextPainter::WrapTextCallback textCallback = [&](StringView text, int line) {
+ TextPainter::WrapTextCallback textCallback = [&](StringView text, unsigned line) {
if (lastLine != line) {
result.append(std::move(current));
lastLine = line;
}
-
current += text;
return true;
};
@@ -277,40 +268,45 @@ StringList TextPainter::wrapText(StringView s, Maybe<unsigned> wrapWidth) {
};
unsigned TextPainter::fontSize() const {
- return m_fontSize;
+ return m_renderSettings.fontSize;
}
void TextPainter::setFontSize(unsigned size) {
- m_fontSize = size;
+ m_renderSettings.fontSize = size;
}
void TextPainter::setLineSpacing(float lineSpacing) {
- m_lineSpacing = lineSpacing;
+ m_renderSettings.lineSpacing = lineSpacing;
}
void TextPainter::setMode(FontMode mode) {
- m_renderSettings.mode = mode;
+ m_renderSettings.shadow = fontModeToColor(mode).toRgba();
}
void TextPainter::setFontColor(Vec4B color) {
m_renderSettings.color = std::move(color);
}
-void TextPainter::setProcessingDirectives(StringView directives) {
- m_renderSettings.directives = String(directives);
- if (m_renderSettings.directives) {
- m_renderSettings.directives.loadOperations();
- for (auto& entry : m_renderSettings.directives.shared->entries) {
- if (auto border = entry.operation.ptr<BorderImageOperation>())
- border->includeTransparent = true;
- }
- }
+void TextPainter::setProcessingDirectives(StringView directives, bool back) {
+ Directives& target = back ? m_renderSettings.backDirectives : m_renderSettings.directives;
+ modifyDirectives(target = String(directives));
}
void TextPainter::setFont(String const& font) {
m_renderSettings.font = font;
}
+TextStyle& TextPainter::setTextStyle(TextStyle const& textStyle) {
+ TextStyle& style = m_renderSettings = textStyle;
+ modifyDirectives(style.directives);
+ modifyDirectives(style.backDirectives);
+ return style;
+}
+
+void TextPainter::clearTextStyle() {
+ m_renderSettings = m_defaultRenderSettings;
+}
+
void TextPainter::addFont(FontPtr const& font, String const& name) {
m_fontTextureGroup.addFont(font, name);
}
@@ -348,16 +344,19 @@ void TextPainter::applyCommands(StringView unsplitCommands) {
m_renderSettings = m_savedRenderSettings;
} else if (command == "set") {
m_savedRenderSettings = m_renderSettings;
- } else if (command == "shadow") {
- m_renderSettings.mode = (FontMode)((int)m_renderSettings.mode | (int)FontMode::Shadow);
+ } else if (command.beginsWith("shadow")) {
+ if (command.utf8Size() == 6)
+ m_renderSettings.shadow = Color::Black.toRgba();
+ else if (command[6] == '=')
+ m_renderSettings.shadow = Color(command.substr(7)).toRgba();
} else if (command == "noshadow") {
- m_renderSettings.mode = (FontMode)((int)m_renderSettings.mode & (-1 ^ (int)FontMode::Shadow));
+ m_renderSettings.shadow = Color::Clear.toRgba();
} else if (command.beginsWith("font=")) {
m_renderSettings.font = command.substr(5);
} else if (command.beginsWith("directives=")) {
- // Honestly this is really stupid but I just couldn't help myself
- // Should probably limit in the future
setProcessingDirectives(command.substr(11));
+ } else if (command.beginsWith("backdirectives=")) {
+ setProcessingDirectives(command.substr(15), true);
} else {
// expects both #... sequences and plain old color names.
Color c = Color(command);
@@ -370,6 +369,16 @@ void TextPainter::applyCommands(StringView unsplitCommands) {
});
}
+void TextPainter::modifyDirectives(Directives& directives) {
+ if (directives) {
+ directives.loadOperations();
+ for (auto& entry : directives->entries) {
+ if (auto border = entry.operation.ptr<BorderImageOperation>())
+ border->includeTransparent = true;
+ }
+ }
+}
+
RectF TextPainter::doRenderText(StringView s, TextPositioning const& position, bool reallyRender, unsigned* charLimit) {
Vec2F pos = position.pos;
if (s.empty())
@@ -377,26 +386,23 @@ RectF TextPainter::doRenderText(StringView s, TextPositioning const& position, b
List<StringView> lines = wrapTextViews(s, position.wrapWidth);
- int height = (lines.size() - 1) * m_lineSpacing * m_fontSize + m_fontSize;
-
- RenderSettings backupRenderSettings = m_renderSettings;
- m_savedRenderSettings = m_renderSettings;
-
+ TextStyle backup = m_savedRenderSettings = m_renderSettings;
+ int height = (lines.size() - 1) * backup.lineSpacing * backup.fontSize + backup.fontSize;
if (position.vAnchor == VerticalAnchor::BottomAnchor)
- pos[1] += (height - m_fontSize);
+ pos[1] += (height - backup.fontSize);
else if (position.vAnchor == VerticalAnchor::VMidAnchor)
- pos[1] += (height - m_fontSize) / 2;
+ pos[1] += (height - backup.fontSize) / 2;
RectF bounds = RectF::withSize(pos, Vec2F());
for (auto& i : lines) {
bounds.combine(doRenderLine(i, { pos, position.hAnchor, position.vAnchor }, reallyRender, charLimit));
- pos[1] -= m_fontSize * m_lineSpacing;
+ pos[1] -= m_renderSettings.fontSize * m_renderSettings.lineSpacing;
if (charLimit && *charLimit == 0)
break;
}
- m_renderSettings = std::move(backupRenderSettings);
+ m_renderSettings = std::move(backup);
return bounds;
}
@@ -425,9 +431,8 @@ RectF TextPainter::doRenderLine(StringView text, TextPositioning const& position
if (*charLimit == 0)
return false;
else
- --* charLimit;
+ --*charLimit;
}
-
RectF glyphBounds = doRenderGlyph(c, pos, reallyRender);
bounds.combine(glyphBounds);
pos.pos[0] += glyphBounds.width();
@@ -461,41 +466,58 @@ RectF TextPainter::doRenderGlyph(String::Char c, TextPositioning const& position
float vOffset = 0;
if (position.vAnchor == VerticalAnchor::VMidAnchor)
- vOffset = -floor((float)m_fontSize / 2);
+ vOffset = -floor((float)m_renderSettings.fontSize / 2);
else if (position.vAnchor == VerticalAnchor::TopAnchor)
- vOffset = -(float)m_fontSize;
+ vOffset = -(float)m_renderSettings.fontSize;
Directives* directives = m_renderSettings.directives ? &m_renderSettings.directives : nullptr;
+ Vec2F pos = position.pos + Vec2F(hOffset, vOffset);
if (reallyRender) {
- if ((int)m_renderSettings.mode & (int)FontMode::Shadow) {
- Color shadow = Color::Black;
- uint8_t alphaU = m_renderSettings.color[3];
+ bool hasShadow = m_renderSettings.shadow[3] > 0;
+ bool hasBackDirectives = m_renderSettings.backDirectives;
+ if (hasShadow) {
+ //Kae: unlike vanilla we draw only one shadow glyph instead of two, so i'm tweaking the alpha here
+ Vec4B shadow = m_renderSettings.shadow;
+ uint8_t alphaU = m_renderSettings.color[3] * byteToFloat(shadow[3]);
if (alphaU != 255) {
float alpha = byteToFloat(alphaU);
- shadow.setAlpha(floatToByte(alpha * (1.5f - 0.5f * alpha)));
+ shadow[3] = floatToByte(alpha * (1.5f - 0.5f * alpha));
}
else
- shadow.setAlpha(alphaU);
+ shadow[3] = alphaU;
- //Kae: Draw only one shadow glyph instead of stacking two, alpha modified to appear perceptually the same as vanilla
- renderGlyph(c, position.pos + Vec2F(hOffset, vOffset - 2), m_fontSize, 1, shadow.toRgba(), directives);
+ Directives const* shadowDirectives = hasBackDirectives ? &m_renderSettings.backDirectives : directives;
+ renderGlyph(c, pos + Vec2F(0, -2), m_shadowPrimitives, m_renderSettings.fontSize, 1, shadow, shadowDirectives);
}
+ if (hasBackDirectives)
+ renderGlyph(c, pos, m_backPrimitives, m_renderSettings.fontSize, 1, m_renderSettings.color, &m_renderSettings.backDirectives);
- renderGlyph(c, position.pos + Vec2F(hOffset, vOffset), m_fontSize, 1, m_renderSettings.color, directives);
+ auto& output = (hasShadow || hasBackDirectives) ? m_frontPrimitives : m_renderer->immediatePrimitives();
+ renderGlyph(c, pos, output, m_renderSettings.fontSize, 1, m_renderSettings.color, directives);
}
- return RectF::withSize(position.pos + Vec2F(hOffset, vOffset), {(float)width, (int)m_fontSize});
+ return RectF::withSize(pos, {(float)width, (int)m_renderSettings.fontSize});
+}
+
+void TextPainter::renderPrimitives() {
+ auto& destination = m_renderer->immediatePrimitives();
+ std::move(std::begin(m_shadowPrimitives), std::end(m_shadowPrimitives), std::back_inserter(destination));
+ m_shadowPrimitives.clear();
+ std::move(std::begin(m_backPrimitives), std::end(m_backPrimitives), std::back_inserter(destination));
+ m_backPrimitives.clear();
+ std::move(std::begin(m_frontPrimitives), std::end(m_frontPrimitives), std::back_inserter(destination));
+ m_frontPrimitives.clear();
}
-void TextPainter::renderGlyph(String::Char c, Vec2F const& screenPos, unsigned fontSize,
+void TextPainter::renderGlyph(String::Char c, Vec2F const& screenPos, List<RenderPrimitive>& out, unsigned fontSize,
float scale, Vec4B const& color, Directives const* processingDirectives) {
if (!fontSize)
return;
const FontTextureGroup::GlyphTexture& glyphTexture = m_fontTextureGroup.glyphTexture(c, fontSize, processingDirectives);
Vec2F offset = glyphTexture.offset * scale;
- m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), glyphTexture.texture, Vec2F::round(screenPos + offset), scale, color, 0.0f);
+ out.emplace_back(std::in_place_type_t<RenderQuad>(), glyphTexture.texture, Vec2F::round(screenPos + offset), scale, color, 0.0f);
}
FontPtr TextPainter::loadFont(String const& fontPath, Maybe<String> fontName) {
diff --git a/source/rendering/StarTextPainter.hpp b/source/rendering/StarTextPainter.hpp
index a0db304..bff3a64 100644
--- a/source/rendering/StarTextPainter.hpp
+++ b/source/rendering/StarTextPainter.hpp
@@ -4,17 +4,21 @@
#include "StarAnchorTypes.hpp"
#include "StarRoot.hpp"
#include "StarStringView.hpp"
+#include "StarText.hpp"
namespace Star {
-STAR_CLASS(TextPainter);
-
-enum class FontMode {
+// deprecated in favor of explicit shadow color
+enum class FontMode : uint8_t {
Normal,
Shadow
};
-float const DefaultLineSpacing = 1.3f;
+inline Color const& fontModeToColor(FontMode mode) {
+ return mode == FontMode::Shadow ? Color::Black : Color::Clear;
+}
+
+STAR_CLASS(TextPainter);
struct TextPositioning {
TextPositioning();
@@ -52,10 +56,10 @@ public:
RectF determineGlyphSize(String::Char c, TextPositioning const& position);
int glyphWidth(String::Char c);
- int stringWidth(StringView s);
+ int stringWidth(StringView s, unsigned charLimit = 0);
- typedef function<bool(StringView, int)> WrapTextCallback;
+ typedef function<bool(StringView, unsigned)> WrapTextCallback;
bool processWrapText(StringView s, unsigned* wrapWidth, WrapTextCallback textFunc);
List<StringView> wrapTextViews(StringView s, Maybe<unsigned> wrapWidth);
@@ -66,39 +70,36 @@ public:
void setLineSpacing(float lineSpacing);
void setMode(FontMode mode);
void setFontColor(Vec4B color);
- void setProcessingDirectives(StringView directives);
+ void setProcessingDirectives(StringView directives, bool back = false);
void setFont(String const& font);
+ TextStyle& setTextStyle(TextStyle const& textStyle);
+ void clearTextStyle();
void addFont(FontPtr const& font, String const& name);
void reloadFonts();
void cleanup(int64_t textureTimeout);
void applyCommands(StringView unsplitCommands);
private:
- struct RenderSettings {
- FontMode mode;
- Vec4B color;
- String font;
- Directives directives;
- };
-
+ void modifyDirectives(Directives& directives);
RectF doRenderText(StringView s, TextPositioning const& position, bool reallyRender, unsigned* charLimit);
RectF doRenderLine(StringView s, TextPositioning const& position, bool reallyRender, unsigned* charLimit);
RectF doRenderGlyph(String::Char c, TextPositioning const& position, bool reallyRender);
- void renderGlyph(String::Char c, Vec2F const& screenPos, unsigned fontSize, float scale, Vec4B const& color, Directives const* processingDirectives = nullptr);
+ void renderPrimitives();
+ void renderGlyph(String::Char c, Vec2F const& screenPos, List<RenderPrimitive>& out, unsigned fontSize, float scale, Vec4B const& color, Directives const* processingDirectives = nullptr);
static FontPtr loadFont(String const& fontPath, Maybe<String> fontName = {});
RendererPtr m_renderer;
+ List<RenderPrimitive> m_shadowPrimitives;
+ List<RenderPrimitive> m_backPrimitives;
+ List<RenderPrimitive> m_frontPrimitives;
FontTextureGroup m_fontTextureGroup;
- unsigned m_fontSize;
- float m_lineSpacing;
-
- RenderSettings m_renderSettings;
- RenderSettings m_savedRenderSettings;
+ TextStyle m_defaultRenderSettings;
+ TextStyle m_renderSettings;
+ TextStyle m_savedRenderSettings;
String m_nonRenderedCharacters;
-
TrackerListenerPtr m_reloadTracker;
};
diff --git a/source/windowing/StarButtonWidget.cpp b/source/windowing/StarButtonWidget.cpp
index a8c8a85..258ac55 100644
--- a/source/windowing/StarButtonWidget.cpp
+++ b/source/windowing/StarButtonWidget.cpp
@@ -24,14 +24,11 @@ ButtonWidget::ButtonWidget() {
auto interfaceConfig = assets->json("/interface.config");
m_pressedOffset = jsonToVec2I(interfaceConfig.get("buttonPressedOffset"));
- m_fontSize = interfaceConfig.query("font.buttonSize").toInt();
- m_fontDirectives = interfaceConfig.queryString("font.defaultDirectives", "");
- m_font = interfaceConfig.query("font.defaultFont").toString();
-
- m_clickSounds = jsonToStringList(assets->json("/interface.config:buttonClickSound"));
- m_releaseSounds = jsonToStringList(assets->json("/interface.config:buttonReleaseSound"));
- m_hoverSounds = jsonToStringList(assets->json("/interface.config:buttonHoverSound"));
- m_hoverOffSounds = jsonToStringList(assets->json("/interface.config:buttonHoverOffSound"));
+ m_textStyle = interfaceConfig.get("buttonTextStyle");
+ m_clickSounds = jsonToStringList(interfaceConfig.get("buttonClickSound"));
+ m_releaseSounds = jsonToStringList(interfaceConfig.get("buttonReleaseSound"));
+ m_hoverSounds = jsonToStringList(interfaceConfig.get("buttonHoverSound"));
+ m_hoverOffSounds = jsonToStringList(interfaceConfig.get("buttonHoverOffSound"));
}
ButtonWidget::ButtonWidget(WidgetCallbackFunc callback,
@@ -95,19 +92,15 @@ void ButtonWidget::renderImpl() {
if (!m_text.empty()) {
auto& guiContext = GuiContext::singleton();
- guiContext.setFontProcessingDirectives(m_fontDirectives);
- guiContext.setFontSize(m_fontSize);
- guiContext.setFont(m_font);
+ guiContext.setTextStyle(m_textStyle);
if (m_disabled)
guiContext.setFontColor(m_fontColorDisabled.toRgba());
else if (m_fontColorChecked && m_checked)
guiContext.setFontColor(m_fontColorChecked.value().toRgba());
else
guiContext.setFontColor(m_fontColor.toRgba());
- guiContext.setFontMode(FontMode::Shadow);
guiContext.renderInterfaceText(m_text, {textPosition, m_hTextAnchor, VerticalAnchor::VMidAnchor});
- guiContext.setFontMode(FontMode::Normal);
- guiContext.setFontProcessingDirectives("");
+ guiContext.clearTextStyle();
}
}
@@ -323,11 +316,11 @@ void ButtonWidget::setText(String const& text) {
}
void ButtonWidget::setFontSize(int size) {
- m_fontSize = size;
+ m_textStyle.fontSize = size;
}
void ButtonWidget::setFontDirectives(String directives) {
- m_fontDirectives = directives;
+ m_textStyle.directives = directives;
}
void ButtonWidget::setTextOffset(Vec2I textOffset) {
@@ -339,7 +332,7 @@ void ButtonWidget::setTextAlign(HorizontalAnchor hAnchor) {
}
void ButtonWidget::setFontColor(Color color) {
- m_fontColor = color;
+ m_textStyle.color = (m_fontColor = color).toRgba();
}
void ButtonWidget::setFontColorDisabled(Color color) {
diff --git a/source/windowing/StarButtonWidget.hpp b/source/windowing/StarButtonWidget.hpp
index 69335d8..bace69b 100644
--- a/source/windowing/StarButtonWidget.hpp
+++ b/source/windowing/StarButtonWidget.hpp
@@ -121,9 +121,7 @@ protected:
Vec2I m_pressedOffset;
Vec2U m_buttonBoundSize;
- int m_fontSize;
- String m_font;
- String m_fontDirectives;
+ TextStyle m_textStyle;
String m_text;
Vec2I m_textOffset;
diff --git a/source/windowing/StarCanvasWidget.cpp b/source/windowing/StarCanvasWidget.cpp
index 16ec994..b4a3cbf 100644
--- a/source/windowing/StarCanvasWidget.cpp
+++ b/source/windowing/StarCanvasWidget.cpp
@@ -68,7 +68,18 @@ void CanvasWidget::drawTriangles(List<tuple<Vec2F, Vec2F, Vec2F>> const& triangl
}
void CanvasWidget::drawText(String s, TextPositioning position, unsigned fontSize, Vec4B const& color, FontMode mode, float lineSpacing, String font, String processingDirectives) {
- m_renderOps.append(make_tuple(std::move(s), std::move(position), fontSize, color, mode, lineSpacing, std::move(font), std::move(processingDirectives)));
+ TextStyle style;
+ style.fontSize = fontSize;
+ style.color = color;
+ style.shadow = fontModeToColor(mode).toRgba();
+ style.lineSpacing = lineSpacing;
+ style.font = font;
+ style.directives = processingDirectives;
+ m_renderOps.append(make_tuple(std::move(s), std::move(position), std::move(style)));
+}
+
+void CanvasWidget::drawText(String s, TextPositioning position, TextStyle style) {
+ m_renderOps.append(make_tuple(std::move(s), std::move(position), std::move(style)));
}
Vec2I CanvasWidget::mousePosition() const {
@@ -145,7 +156,7 @@ void CanvasWidget::renderImpl() {
if (auto args = op.ptr<TrianglesOp>())
tupleUnpackFunction(bind(&CanvasWidget::renderTriangles, this, renderingOffset, _1, _2), *args);
if (auto args = op.ptr<TextOp>())
- tupleUnpackFunction(bind(&CanvasWidget::renderText, this, renderingOffset, _1, _2, _3, _4, _5, _6, _7, _8), *args);
+ tupleUnpackFunction(bind(&CanvasWidget::renderText, this, renderingOffset, _1, _2, _3), *args);
}
}
@@ -256,14 +267,9 @@ void CanvasWidget::renderTriangles(Vec2F const& renderingOffset, List<tuple<Vec2
context.drawInterfaceTriangles(translated, color);
}
-void CanvasWidget::renderText(Vec2F const& renderingOffset, String const& s, TextPositioning const& position, unsigned fontSize, Vec4B const& color, FontMode mode, float lineSpacing, String const& font, String const& directives) {
+void CanvasWidget::renderText(Vec2F const& renderingOffset, String const& s, TextPositioning const& position, TextStyle const& style) {
auto& context = GuiContext::singleton();
- context.setFontProcessingDirectives(directives);
- context.setFontSize(fontSize, m_ignoreInterfaceScale ? 1 : context.interfaceScale());
- context.setFontColor(color);
- context.setFontMode(mode);
- context.setFont(font);
- context.setLineSpacing(lineSpacing);
+ context.setTextStyle(style, m_ignoreInterfaceScale ? 1 : context.interfaceScale());
TextPositioning translatedPosition = position;
translatedPosition.pos += renderingOffset;
@@ -272,10 +278,7 @@ void CanvasWidget::renderText(Vec2F const& renderingOffset, String const& s, Tex
else
context.renderInterfaceText(s, translatedPosition);
- context.setDefaultLineSpacing();
- context.setDefaultFont();
- context.setFontMode(FontMode::Normal);
- context.setFontProcessingDirectives("");
+ context.clearTextStyle();
}
}
diff --git a/source/windowing/StarCanvasWidget.hpp b/source/windowing/StarCanvasWidget.hpp
index e160160..a13cc2c 100644
--- a/source/windowing/StarCanvasWidget.hpp
+++ b/source/windowing/StarCanvasWidget.hpp
@@ -67,6 +67,7 @@ public:
void drawTriangles(List<tuple<Vec2F, Vec2F, Vec2F>> const& poly, Vec4B const& color = Vec4B(255, 255, 255, 255));
void drawText(String s, TextPositioning position, unsigned fontSize, Vec4B const& color = Vec4B(255, 255, 255, 255), FontMode mode = FontMode::Normal, float lineSpacing = Star::DefaultLineSpacing, String font = "", String processingDirectives = "");
+ void drawText(String s, TextPositioning position, TextStyle style);
protected:
void renderImpl() override;
@@ -79,7 +80,7 @@ protected:
void renderRect(Vec2F const& renderingOffset, RectF const& coords, Vec4B const& color);
void renderPoly(Vec2F const& renderingOffset, PolyF poly, Vec4B const& color, float lineWidth);
void renderTriangles(Vec2F const& renderingOffset, List<tuple<Vec2F, Vec2F, Vec2F>> const& triangles, Vec4B const& color);
- void renderText(Vec2F const& renderingOffset, String const& s, TextPositioning const& position, unsigned fontSize, Vec4B const& color, FontMode mode, float lineSpacing, String const& font, String const& directives);
+ void renderText(Vec2F const& renderingOffset, String const& s, TextPositioning const& position, TextStyle const& style);
private:
bool m_ignoreInterfaceScale;
@@ -97,7 +98,7 @@ private:
typedef tuple<Vec2F, Vec2F, Vec4B, float> LineOp;
typedef tuple<PolyF, Vec4B, float> PolyOp;
typedef tuple<List<tuple<Vec2F, Vec2F, Vec2F>>, Vec4B> TrianglesOp;
- typedef tuple<String, TextPositioning, unsigned, Vec4B, FontMode, float, String, String> TextOp;
+ typedef tuple<String, TextPositioning, TextStyle> TextOp;
typedef MVariant<RectOp, ImageOp, ImageRectOp, DrawableOp, TiledImageOp, LineOp, PolyOp, TrianglesOp, TextOp> RenderOp;
List<RenderOp> m_renderOps;
diff --git a/source/windowing/StarFuelWidget.cpp b/source/windowing/StarFuelWidget.cpp
index d7028f8..8f2d93d 100644
--- a/source/windowing/StarFuelWidget.cpp
+++ b/source/windowing/StarFuelWidget.cpp
@@ -9,8 +9,8 @@ namespace Star {
FuelWidget::FuelWidget() {
auto assets = Root::singleton().assets();
- m_fontSize = assets->json("/interface.config:font.buttonSize").toInt();
- m_font = assets->json("/interface.config:font.defaultFont").toString();
+ m_textStyle.fontSize = assets->json("/interface.config:font.buttonSize").toInt();
+ m_textStyle.loadJson(assets->json("/interface.config:textStyle"));
m_fuelLevel = 0;
m_maxLevel = 0;
@@ -72,8 +72,7 @@ void FuelWidget::renderImpl() {
context()->drawInterfaceQuad("/interface/fuel/fuelgaugemarkings.png", shift(0, 1, entireTex), shift(0, 1, entirePosition));
auto& guiContext = GuiContext::singleton();
- guiContext.setFontSize(m_fontSize);
- guiContext.setFont(m_font);
+ guiContext.setTextStyle(m_textStyle);
if (m_potential != 0) {
guiContext.setFontColor(Color::White.toRgba());
} else if (m_fuelLevel == 0) {
diff --git a/source/windowing/StarFuelWidget.hpp b/source/windowing/StarFuelWidget.hpp
index c057b9a..21f0f6c 100644
--- a/source/windowing/StarFuelWidget.hpp
+++ b/source/windowing/StarFuelWidget.hpp
@@ -30,8 +30,7 @@ protected:
float m_pingTimeout;
- unsigned m_fontSize;
- String m_font;
+ TextStyle m_textStyle;
private:
};
diff --git a/source/windowing/StarGuiContext.cpp b/source/windowing/StarGuiContext.cpp
index d1be94a..492f08e 100644
--- a/source/windowing/StarGuiContext.cpp
+++ b/source/windowing/StarGuiContext.cpp
@@ -377,6 +377,20 @@ void GuiContext::setDefaultFont() {
textPainter()->setFont("");
}
+TextStyle& GuiContext::setTextStyle(TextStyle const& textStyle, int pixelRatio) {
+ TextStyle& setStyle = textPainter()->setTextStyle(textStyle);
+ setStyle.fontSize *= pixelRatio;
+ return setStyle;
+}
+
+TextStyle& GuiContext::setTextStyle(TextStyle const& textStyle) {
+ return setTextStyle(textStyle, interfaceScale());
+}
+
+void GuiContext::clearTextStyle() {
+ textPainter()->clearTextStyle();
+}
+
void GuiContext::setLineSpacing(float lineSpacing) {
textPainter()->setLineSpacing(lineSpacing);
}
diff --git a/source/windowing/StarGuiContext.hpp b/source/windowing/StarGuiContext.hpp
index ef14619..cb0051c 100644
--- a/source/windowing/StarGuiContext.hpp
+++ b/source/windowing/StarGuiContext.hpp
@@ -106,6 +106,9 @@ public:
void setFontProcessingDirectives(String const& directives);
void setFont(String const& font);
void setDefaultFont();
+ TextStyle& setTextStyle(TextStyle const& textStyle, int pixelRatio);
+ TextStyle& setTextStyle(TextStyle const& textStyle);
+ void clearTextStyle();
void setLineSpacing(float lineSpacing);
void setDefaultLineSpacing();
diff --git a/source/windowing/StarItemSlotWidget.cpp b/source/windowing/StarItemSlotWidget.cpp
index 93d95d3..4ba3425 100644
--- a/source/windowing/StarItemSlotWidget.cpp
+++ b/source/windowing/StarItemSlotWidget.cpp
@@ -14,16 +14,13 @@ ItemSlotWidget::ItemSlotWidget(ItemPtr const& item, String const& backingImage)
: m_item(item), m_backingImage(backingImage) {
m_drawBackingImageWhenFull = false;
m_drawBackingImageWhenEmpty = true;
- m_fontSize = 0;
m_progress = 1;
auto assets = Root::singleton().assets();
auto interfaceConfig = assets->json("/interface.config");
m_countPosition = TextPositioning(jsonToVec2F(interfaceConfig.get("itemCountRightAnchor")), HorizontalAnchor::RightAnchor);
m_countFontMode = FontMode::Normal;
- m_fontSize = interfaceConfig.query("font.itemSize").toInt();
- m_font = interfaceConfig.query("font.defaultFont").toString();
- m_fontColor = Color::rgb(jsonToVec3B(interfaceConfig.query("font.defaultColor")));
+ m_textStyle = interfaceConfig.get("itemSlotTextStyle");
m_itemDraggableArea = jsonToRectI(interfaceConfig.get("itemDraggableArea"));
m_durabilityOffset = jsonToVec2I(interfaceConfig.get("itemIconDurabilityOffset"));
@@ -192,13 +189,10 @@ void ItemSlotWidget::renderImpl() {
context()->drawInterfaceQuad(String(strf("/interface/cooldown.png:{}", frame)), Vec2F(screenPosition()));
if (m_item->count() > 1 && m_showCount) { // we don't need to tell people that there's only 1 of something
- context()->setFont(m_font);
- context()->setFontSize(m_fontSize);
- context()->setFontColor(m_fontColor.toRgba());
+ context()->setTextStyle(m_textStyle);
context()->setFontMode(m_countFontMode);
context()->renderInterfaceText(toString(m_item->count()), m_countPosition.translated(Vec2F(screenPosition())));
- context()->setFontMode(FontMode::Normal);
- context()->setDefaultFont();
+ context()->clearTextStyle();
}
} else if (m_drawBackingImageWhenEmpty && m_backingImage != "") {
diff --git a/source/windowing/StarItemSlotWidget.hpp b/source/windowing/StarItemSlotWidget.hpp
index aaa4c9c..3827048 100644
--- a/source/windowing/StarItemSlotWidget.hpp
+++ b/source/windowing/StarItemSlotWidget.hpp
@@ -56,9 +56,7 @@ private:
Vec2I m_durabilityOffset;
RectI m_itemDraggableArea;
- int m_fontSize;
- String m_font;
- Color m_fontColor;
+ TextStyle m_textStyle;
WidgetCallbackFunc m_callback;
WidgetCallbackFunc m_rightClickCallback;
diff --git a/source/windowing/StarLabelWidget.cpp b/source/windowing/StarLabelWidget.cpp
index 35f8618..3c1be8e 100644
--- a/source/windowing/StarLabelWidget.cpp
+++ b/source/windowing/StarLabelWidget.cpp
@@ -10,17 +10,14 @@ LabelWidget::LabelWidget(String text,
VerticalAnchor const& vAnchor,
Maybe<unsigned> wrapWidth,
Maybe<float> lineSpacing)
- : m_fontMode(FontMode::Normal),
- m_color(color),
- m_hAnchor(hAnchor),
+ : m_hAnchor(hAnchor),
m_vAnchor(vAnchor),
- m_wrapWidth(std::move(wrapWidth)),
- m_lineSpacing(std::move(lineSpacing)) {
+ m_wrapWidth(std::move(wrapWidth)) {
auto assets = Root::singleton().assets();
- auto fontConfig = assets->json("/interface.config:font");
- m_fontSize = fontConfig.getInt("baseSize");
- m_processingDirectives = fontConfig.getString("defaultDirectives");
- m_font = fontConfig.queryString("defaultFont", "");
+ m_style = assets->json("/interface.config:labelTextStyle");
+ m_style.color = color.toRgba();
+ if (lineSpacing)
+ m_style.lineSpacing = *lineSpacing;
setText(std::move(text));
}
@@ -38,16 +35,16 @@ void LabelWidget::setText(String newText) {
}
void LabelWidget::setFontSize(int fontSize) {
- m_fontSize = fontSize;
+ m_style.fontSize = fontSize;
updateTextRegion();
}
void LabelWidget::setFontMode(FontMode fontMode) {
- m_fontMode = fontMode;
+ m_style.shadow = fontModeToColor(fontMode).toRgba();
}
void LabelWidget::setColor(Color newColor) {
- m_color = std::move(newColor);
+ m_style.color = newColor.toRgba();
}
void LabelWidget::setAnchor(HorizontalAnchor hAnchor, VerticalAnchor vAnchor) {
@@ -62,12 +59,12 @@ void LabelWidget::setWrapWidth(Maybe<unsigned> wrapWidth) {
}
void LabelWidget::setLineSpacing(Maybe<float> lineSpacing) {
- m_lineSpacing = std::move(lineSpacing);
+ m_style.lineSpacing = lineSpacing.value(DefaultLineSpacing);
updateTextRegion();
}
void LabelWidget::setDirectives(String const& directives) {
- m_processingDirectives = directives;
+ m_style.directives = directives;
updateTextRegion();
}
@@ -76,6 +73,12 @@ void LabelWidget::setTextCharLimit(Maybe<unsigned> charLimit) {
updateTextRegion();
}
+void LabelWidget::setTextStyle(TextStyle const& textStyle) {
+ m_style = textStyle;
+ updateTextRegion();
+}
+
+
RectI LabelWidget::relativeBoundRect() const {
return RectI(m_textRegion).translated(relativePosition());
}
@@ -85,41 +88,14 @@ RectI LabelWidget::getScissorRect() const {
}
void LabelWidget::renderImpl() {
- context()->setFont(m_font);
- context()->setFontSize(m_fontSize);
- context()->setFontMode(m_fontMode);
- context()->setFontColor(m_color.toRgba());
- context()->setFontProcessingDirectives(m_processingDirectives);
-
- if (m_lineSpacing)
- context()->setLineSpacing(*m_lineSpacing);
- else
- context()->setDefaultLineSpacing();
-
+ context()->setTextStyle(m_style);
context()->renderInterfaceText(m_text, {Vec2F(screenPosition()), m_hAnchor, m_vAnchor, m_wrapWidth, m_textCharLimit});
-
- context()->setDefaultFont();
- context()->setFontMode(FontMode::Normal);
- context()->setFontProcessingDirectives("");
- context()->setDefaultLineSpacing();
}
void LabelWidget::updateTextRegion() {
- context()->setFontSize(m_fontSize);
- context()->setFontColor(m_color.toRgba());
- context()->setFontProcessingDirectives(m_processingDirectives);
- context()->setFont(m_font);
- if (m_lineSpacing)
- context()->setLineSpacing(*m_lineSpacing);
- else
- context()->setDefaultLineSpacing();
-
+ context()->setTextStyle(m_style);
m_textRegion = RectI(context()->determineInterfaceTextSize(m_text, {Vec2F(), m_hAnchor, m_vAnchor, m_wrapWidth, m_textCharLimit}));
setSize(m_textRegion.size());
-
- context()->setDefaultFont();
- context()->setFontProcessingDirectives("");
- context()->setDefaultLineSpacing();
}
}
diff --git a/source/windowing/StarLabelWidget.hpp b/source/windowing/StarLabelWidget.hpp
index a25e531..da65fb3 100644
--- a/source/windowing/StarLabelWidget.hpp
+++ b/source/windowing/StarLabelWidget.hpp
@@ -25,6 +25,7 @@ public:
void setLineSpacing(Maybe<float> lineSpacing);
void setDirectives(String const& directives);
void setTextCharLimit(Maybe<unsigned> charLimit);
+ void setTextStyle(TextStyle const& style);
RectI relativeBoundRect() const override;
@@ -36,13 +37,9 @@ private:
void updateTextRegion();
String m_text;
- int m_fontSize;
- FontMode m_fontMode;
- Color m_color;
+ TextStyle m_style;
HorizontalAnchor m_hAnchor;
VerticalAnchor m_vAnchor;
- String m_processingDirectives;
- String m_font;
Maybe<unsigned> m_wrapWidth;
Maybe<float> m_lineSpacing;
Maybe<unsigned> m_textCharLimit;
diff --git a/source/windowing/StarPane.cpp b/source/windowing/StarPane.cpp
index 36e8435..9e1cd4f 100644
--- a/source/windowing/StarPane.cpp
+++ b/source/windowing/StarPane.cpp
@@ -32,8 +32,7 @@ Pane::Pane() {
m_hasDisplayed = false;
auto assets = Root::singleton().assets();
- m_fontSize = assets->json("/interface.config:font.baseSize").toInt();
- m_font = assets->json("/interface.config:font.defaultFont").toString();
+ m_textStyle = assets->json("/interface.config:paneTextStyle");
m_iconOffset = jsonToVec2I(assets->json("/interface.config:paneIconOffset"));
m_titleOffset = jsonToVec2I(assets->json("/interface.config:paneTitleOffset"));
m_subTitleOffset = jsonToVec2I(assets->json("/interface.config:paneSubTitleOffset"));
@@ -436,15 +435,13 @@ void Pane::renderImpl() {
m_context->resetInterfaceScissorRect();
}
- m_context->setFont(m_font);
- m_context->setFontSize(m_fontSize);
+ m_context->setTextStyle(m_textStyle);
m_context->setFontColor(m_titleColor.toRgba());
m_context->setFontMode(FontMode::Shadow);
m_context->renderInterfaceText(m_title, {headerPos + Vec2F(m_titleOffset)});
m_context->setFontColor(m_subTitleColor.toRgba());
m_context->renderInterfaceText(m_subTitle, {headerPos + Vec2F(m_subTitleOffset)});
- m_context->setFontMode(FontMode::Normal);
- m_context->setDefaultFont();
+ m_context->clearTextStyle();
}
}
diff --git a/source/windowing/StarPane.hpp b/source/windowing/StarPane.hpp
index 1d1fc2a..c5ed505 100644
--- a/source/windowing/StarPane.hpp
+++ b/source/windowing/StarPane.hpp
@@ -117,8 +117,7 @@ protected:
WidgetPtr m_icon;
String m_title;
String m_subTitle;
- String m_font;
- unsigned m_fontSize;
+ TextStyle m_textStyle;
Vec2I m_iconOffset;
Vec2I m_titleOffset;
Vec2I m_subTitleOffset;
diff --git a/source/windowing/StarTextBoxWidget.cpp b/source/windowing/StarTextBoxWidget.cpp
index 984021d..41b4696 100644
--- a/source/windowing/StarTextBoxWidget.cpp
+++ b/source/windowing/StarTextBoxWidget.cpp
@@ -23,14 +23,11 @@ TextBoxWidget::TextBoxWidget(String const& startingText, String const& hint, Wid
m_overfillMode = true;
m_maxWidth = assets->json("/interface.config:textBoxDefaultWidth").toInt();
- auto fontConfig = assets->json("/interface.config:font");
- m_fontSize = fontConfig.getInt("baseSize");
- m_processingDirectives = fontConfig.getString("defaultDirectives");
- m_font = fontConfig.queryString("defaultFont", "");
- m_color = Color::rgb(jsonToVec3B(fontConfig.getArray("defaultColor")));
+ auto fontConfig = assets->json("/interface.config:textBoxTextStyle");
+ m_textStyle = fontConfig;
// Meh, padding is hard-coded here
- setSize({m_maxWidth + 6, m_fontSize + 2});
+ setSize({m_maxWidth + 6, m_textStyle.fontSize + 2});
m_cursorHoriz = jsonToVec2I(assets->json("/interface.config:textboxCursorHorizontal"));
m_cursorVert = jsonToVec2I(assets->json("/interface.config:textboxCursorVertical"));
}
@@ -48,20 +45,17 @@ void TextBoxWidget::renderImpl() {
else if (m_hAnchor == HorizontalAnchor::RightAnchor)
pos += Vec2F(size()[0], 0);
- context()->setFont(m_font);
+ context()->setTextStyle(m_textStyle);
if ((m_maxWidth != -1) && m_overfillMode) {
- context()->setFontSize(m_fontSize);
int shift = std::max(0, getCursorOffset() - m_maxWidth);
pos += Vec2F(-shift, 0);
}
- context()->setFontSize(m_fontSize);
- context()->setFontProcessingDirectives(m_processingDirectives);
if (m_text.empty()) {
- context()->setFontColor(m_color.mix(Color::rgbf(0.3f, 0.3f, 0.3f), 0.8f).mix(Color::rgbf(0.0f, 0.0f, 1.0f), blueRate).toRgba());
+ context()->setFontColor(Color::rgba(m_textStyle.color).mix(Color::rgbf(0.3f, 0.3f, 0.3f), 0.8f).mix(Color::rgbf(0.0f, 0.0f, 1.0f), blueRate).toRgba());
context()->renderInterfaceText(m_hint, {pos, m_hAnchor, m_vAnchor});
} else {
- context()->setFontColor(m_color.mix(Color::rgbf(0, 0, 1), blueRate).toRgba());
+ context()->setFontColor(Color::rgba(m_textStyle.color).mix(Color::rgbf(0, 0, 1), blueRate).toRgba());
if (m_textHidden) {
String hiddenText('*', m_text.length());
context()->renderInterfaceText(hiddenText, { pos, m_hAnchor, m_vAnchor });
@@ -69,22 +63,21 @@ void TextBoxWidget::renderImpl() {
else
context()->renderInterfaceText(m_text, { pos, m_hAnchor, m_vAnchor });
}
- context()->setDefaultFont();
- context()->setFontProcessingDirectives("");
- context()->setFontColor(Vec4B::filled(255));
+ context()->clearTextStyle();
if (hasFocus()) {
// render cursor
float cc = 0.6f + 0.4f * std::sin((double)Time::monotonicMilliseconds() / 300.0);
Color cursorColor = Color::rgbf(cc, cc, cc);
+ float fontSize = m_textStyle.fontSize;
context()->drawInterfaceLine(
- pos + Vec2F(getCursorOffset(), m_fontSize * m_cursorVert[0]),
- pos + Vec2F(getCursorOffset(), m_fontSize * m_cursorVert[1]),
+ pos + Vec2F(getCursorOffset(), fontSize * m_cursorVert[0]),
+ pos + Vec2F(getCursorOffset(), fontSize * m_cursorVert[1]),
cursorColor.toRgba());
context()->drawInterfaceLine(
- pos + Vec2F(getCursorOffset() + m_fontSize * m_cursorHoriz[0], m_fontSize * m_cursorVert[0]),
- pos + Vec2F(getCursorOffset() + m_fontSize * m_cursorHoriz[1], m_fontSize * m_cursorVert[0]),
+ pos + Vec2F(getCursorOffset() + fontSize * m_cursorHoriz[0], fontSize * m_cursorVert[0]),
+ pos + Vec2F(getCursorOffset() + fontSize * m_cursorHoriz[1], fontSize * m_cursorVert[0]),
cursorColor.toRgba());
}
@@ -94,8 +87,7 @@ void TextBoxWidget::renderImpl() {
int TextBoxWidget::getCursorOffset() { // horizontal only
float scale;
- context()->setFont(m_font);
- context()->setFontSize(m_fontSize);
+ context()->setTextStyle(m_textStyle);
if (m_hAnchor == HorizontalAnchor::LeftAnchor) {
scale = 1.0;
} else if (m_hAnchor == HorizontalAnchor::HMidAnchor) {
@@ -158,7 +150,7 @@ String const& TextBoxWidget::getText() const {
return m_text;
}
-bool TextBoxWidget::setText(String const& text, bool callback) {
+bool TextBoxWidget::setText(String const& text, bool callback, bool moveCursor) {
if (m_text == text)
return true;
@@ -166,7 +158,10 @@ bool TextBoxWidget::setText(String const& text, bool callback) {
return false;
m_text = text;
- m_cursorOffset = m_text.size();
+ size_t size = m_text.size();
+ if (moveCursor || m_cursorOffset > size)
+ m_cursorOffset = size;
+
m_repeatCode = SpecialRepeatKeyCodes::None;
if (callback)
m_callback(this);
@@ -190,20 +185,20 @@ void TextBoxWidget::setRegex(String const& regex) {
}
void TextBoxWidget::setColor(Color const& color) {
- m_color = color;
+ m_textStyle.color = color.toRgba();
}
void TextBoxWidget::setDirectives(String const& directives) {
- m_processingDirectives = directives;
+ m_textStyle.directives = directives;
}
void TextBoxWidget::setFontSize(int fontSize) {
- m_fontSize = fontSize;
+ m_textStyle.fontSize = fontSize;
}
void TextBoxWidget::setMaxWidth(int maxWidth) {
m_maxWidth = maxWidth;
- setSize({m_maxWidth + 6, m_fontSize + 2});
+ setSize({m_maxWidth + 6, m_textStyle.fontSize + 2});
}
void TextBoxWidget::setOverfillMode(bool overtype) {
@@ -426,8 +421,7 @@ bool TextBoxWidget::newTextValid(String const& text) const {
if (!text.regexMatch(m_regex))
return false;
if ((m_maxWidth != -1) && !m_overfillMode) {
- context()->setFont(m_font);
- context()->setFontSize(m_fontSize);
+ context()->setTextStyle(m_textStyle);
return context()->stringInterfaceWidth(text) <= m_maxWidth;
}
return true;
diff --git a/source/windowing/StarTextBoxWidget.hpp b/source/windowing/StarTextBoxWidget.hpp
index 12294d5..5fed88e 100644
--- a/source/windowing/StarTextBoxWidget.hpp
+++ b/source/windowing/StarTextBoxWidget.hpp
@@ -14,7 +14,7 @@ public:
virtual void update(float dt) override;
String const& getText() const;
- bool setText(String const& text, bool callback = true);
+ bool setText(String const& text, bool callback = true, bool moveCursor = true);
bool getHidden() const;
void setHidden(bool hidden);
@@ -64,10 +64,7 @@ private:
String m_regex;
HorizontalAnchor m_hAnchor;
VerticalAnchor m_vAnchor;
- Color m_color;
- String m_processingDirectives;
- String m_font;
- int m_fontSize;
+ TextStyle m_textStyle;
int m_maxWidth;
int m_cursorOffset;
bool m_isHover;