summaryrefslogtreecommitdiff
path: root/indra/newview/llgroupcolormap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llgroupcolormap.cpp')
-rw-r--r--indra/newview/llgroupcolormap.cpp150
1 files changed, 150 insertions, 0 deletions
diff --git a/indra/newview/llgroupcolormap.cpp b/indra/newview/llgroupcolormap.cpp
new file mode 100644
index 0000000000..36fde1ce38
--- /dev/null
+++ b/indra/newview/llgroupcolormap.cpp
@@ -0,0 +1,150 @@
+/**
+ * @file llgroupcolormap.cpp
+ * @brief Per-group nameplate tint registry.
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llgroupcolormap.h"
+
+#include "lldir.h"
+#include "llsdserialize.h"
+#include "llsdutil_math.h" // ll_sd_from_color4 / ll_color4_from_sd
+#include "llvoavatar.h" // LLVOAvatar::invalidateNameTags()
+
+static constexpr char GROUP_COLOR_FILE[] = "settings_group_colors.xml";
+
+// ---------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------
+
+LLGroupColorMap::LLGroupColorMap()
+{
+}
+
+// ---------------------------------------------------------------------------
+// Public API
+// ---------------------------------------------------------------------------
+
+void LLGroupColorMap::setGroupColor(const LLUUID& group_id, const LLColor4& color)
+{
+ if (group_id.isNull())
+ return;
+
+ // Treat fully-transparent as "no color" (remove entry)
+ if (color.mV[VW] < 0.01f)
+ {
+ clearGroupColor(group_id);
+ return;
+ }
+
+ mColors[group_id] = color;
+ saveToDisk();
+ invalidateAllNameTags();
+}
+
+LLColor4 LLGroupColorMap::getGroupColor(const LLUUID& group_id) const
+{
+ if (group_id.isNull())
+ return LLColor4::transparent;
+
+ auto it = mColors.find(group_id);
+ if (it != mColors.end())
+ return it->second;
+
+ return LLColor4::transparent;
+}
+
+bool LLGroupColorMap::hasGroupColor(const LLUUID& group_id) const
+{
+ if (group_id.isNull())
+ return false;
+ return mColors.find(group_id) != mColors.end();
+}
+
+void LLGroupColorMap::clearGroupColor(const LLUUID& group_id)
+{
+ if (mColors.erase(group_id) > 0)
+ {
+ saveToDisk();
+ invalidateAllNameTags();
+ }
+}
+
+// ---------------------------------------------------------------------------
+// Persistence
+// ---------------------------------------------------------------------------
+
+// static
+std::string LLGroupColorMap::getFilePath()
+{
+ std::string path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "");
+ if (!path.empty())
+ return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, GROUP_COLOR_FILE);
+ // Fall back to app_settings (before first login, path not yet set)
+ return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, GROUP_COLOR_FILE);
+}
+
+void LLGroupColorMap::loadFromDisk()
+{
+ mColors.clear();
+
+ const std::string filepath = getFilePath();
+ if (!gDirUtilp->fileExists(filepath))
+ return;
+
+ llifstream stream(filepath.c_str());
+ if (!stream.is_open())
+ {
+ LL_WARNS("GroupColor") << "Cannot open " << filepath << LL_ENDL;
+ return;
+ }
+
+ LLSD data;
+ if (LLSDSerialize::fromXMLDocument(data, stream) < 0)
+ {
+ LL_WARNS("GroupColor") << "Failed to parse " << filepath << LL_ENDL;
+ return;
+ }
+
+ // Format: map of { group_uuid_string : [r, g, b, a] }
+ for (LLSD::map_const_iterator it = data.beginMap(); it != data.endMap(); ++it)
+ {
+ LLUUID group_id(it->first);
+ if (group_id.isNull()) continue;
+ LLColor4 color = ll_color4_from_sd(it->second);
+ if (color.mV[VW] >= 0.01f)
+ mColors[group_id] = color;
+ }
+
+ LL_INFOS("GroupColor") << "Loaded " << mColors.size()
+ << " group color(s) from " << filepath << LL_ENDL;
+}
+
+void LLGroupColorMap::saveToDisk() const
+{
+ const std::string filepath = getFilePath();
+
+ LLSD data = LLSD::emptyMap();
+ for (const auto& [group_id, color] : mColors)
+ data[group_id.asString()] = ll_sd_from_color4(color);
+
+ llofstream stream(filepath.c_str());
+ if (!stream.is_open())
+ {
+ LL_WARNS("GroupColor") << "Cannot write " << filepath << LL_ENDL;
+ return;
+ }
+ LLSDSerialize::toPrettyXML(data, stream);
+}
+
+// ---------------------------------------------------------------------------
+// Invalidation
+// ---------------------------------------------------------------------------
+
+// static
+void LLGroupColorMap::invalidateAllNameTags()
+{
+ LLVOAvatar::invalidateNameTags();
+}