|
34 | 34 |
|
35 | 35 | #include "llfloaterpreference.h" |
36 | 36 |
|
| 37 | +#include "alavatargroups.h" |
37 | 38 | #include "llaudioengine.h" |
| 39 | +#include "llchat.h" |
| 40 | +#include "llstyle.h" |
| 41 | +#include "lluicolortable.h" |
| 42 | +#include "llviewerchat.h" |
38 | 43 | #include "message.h" |
39 | 44 | #include "llfloaterautoreplacesettings.h" |
40 | 45 | #include "llagent.h" |
|
74 | 79 | #include "llscrolllistitem.h" |
75 | 80 | #include "llsliderctrl.h" |
76 | 81 | #include "lltabcontainer.h" |
| 82 | +#include "lltextbox.h" |
77 | 83 | #include "lltrans.h" |
78 | 84 | #include "lluri.h" |
79 | 85 | #include "llviewercontrol.h" |
@@ -3066,6 +3072,162 @@ class LLPanelPreferencePrivacy : public LLPanelPreference |
3066 | 3072 | static LLPanelInjector<LLPanelPreferenceGraphics> t_pref_graph("panel_preference_graphics"); |
3067 | 3073 | static LLPanelInjector<LLPanelPreferencePrivacy> t_pref_privacy("panel_preference_privacy"); |
3068 | 3074 | static LLPanelInjector<LLPanelPreferenceSound> t_pref_sound("panel_preference_sound"); |
| 3075 | +static LLPanelInjector<LLPanelPreferenceColors> t_pref_colors("panel_preference_colors"); |
| 3076 | + |
| 3077 | +bool LLPanelPreferenceColors::postBuild() |
| 3078 | +{ |
| 3079 | + mPreviewBox = getChild<LLTextBox>("irc_chat_preview"); |
| 3080 | + updatePreview(); |
| 3081 | + return LLPanelPreference::postBuild(); |
| 3082 | +} |
| 3083 | + |
| 3084 | +void LLPanelPreferenceColors::draw() |
| 3085 | +{ |
| 3086 | + // The chat-color swatches commit straight into LLUIColorTable (no settings |
| 3087 | + // signal to listen to), so poll a cheap signature of everything the preview |
| 3088 | + // depends on and re-render only when it actually changes. |
| 3089 | + static const char* const color_names[] = { |
| 3090 | + "UserChatColor", "AgentChatColor", "FriendChatColor", "SystemChatColor", |
| 3091 | + "ObjectChatColor", "llOwnerSayChatColor", "LindenChatColor", "HTMLLinkColor", |
| 3092 | + }; |
| 3093 | + std::string signature; |
| 3094 | + for (const char* name : color_names) |
| 3095 | + { |
| 3096 | + const LLColor4& c = LLUIColorTable::instance().getColor(name).get(); |
| 3097 | + signature += llformat("%.3f,%.3f,%.3f;", c.mV[VRED], c.mV[VGREEN], c.mV[VBLUE]); |
| 3098 | + } |
| 3099 | + signature += llformat("%d;%.3f;%.3f;%.3f;%d", |
| 3100 | + gSavedSettings.getBOOL("AlchemyChatIRCColorsEnabled") ? 1 : 0, |
| 3101 | + gSavedSettings.getF32("AlchemyChatIRCAgentSaturation"), |
| 3102 | + gSavedSettings.getF32("AlchemyChatIRCAgentLightness"), |
| 3103 | + gSavedSettings.getF32("AlchemyChatIRCNameLightness"), |
| 3104 | + gSavedSettings.getBOOL("Use24HourClock") ? 1 : 0); |
| 3105 | + |
| 3106 | + if (signature != mPreviewSignature) |
| 3107 | + { |
| 3108 | + mPreviewSignature = signature; |
| 3109 | + updatePreview(); |
| 3110 | + } |
| 3111 | + |
| 3112 | + LLPanelPreference::draw(); |
| 3113 | +} |
| 3114 | + |
| 3115 | +void LLPanelPreferenceColors::updatePreview() |
| 3116 | +{ |
| 3117 | + if (!mPreviewBox) |
| 3118 | + return; |
| 3119 | + |
| 3120 | + // One line per chat category the panel above exposes. Each carries the base |
| 3121 | + // color the real getChatColor() switch would pick (friend/Linden can't be |
| 3122 | + // detected from a fake id, so we set it explicitly), plus a stable id so the |
| 3123 | + // per-avatar IRC color stays constant between refreshes. The IRC override and |
| 3124 | + // name dimming are then applied through the real ALAvatarGroups calls, so the |
| 3125 | + // preview tracks the live colors and settings exactly like in-world local chat. |
| 3126 | + enum EKind { K_SYSTEM, K_SELF, K_RESIDENT, K_FRIEND, K_LINDEN, K_OBJECT, K_OWNER }; |
| 3127 | + static const struct |
| 3128 | + { |
| 3129 | + EKind kind; |
| 3130 | + const char* color; // base text color name |
| 3131 | + const char* id; // stable per-avatar id (empty for system/self) |
| 3132 | + S32 hour; // mock 24h timestamp, formatted per Use24HourClock |
| 3133 | + S32 minute; |
| 3134 | + const char* name; // speaker name ("" hides the name prefix) |
| 3135 | + const char* text; |
| 3136 | + } samples[] = { |
| 3137 | + { K_SYSTEM, "SystemChatColor", "", 13, 42, "", "Welcome to Quirk Island. Mind the dancing llamas." }, |
| 3138 | + { K_SELF, "UserChatColor", "", 13, 43, "You", "ok who moved my virtual cheese" }, |
| 3139 | + { K_RESIDENT, "AgentChatColor", "a1a1a1a1-0000-0000-0000-000000000001", 13, 44, "Bartholomew Bumblecrash", "anyone else seeing the sky do the wobble thing?" }, |
| 3140 | + { K_RESIDENT, "AgentChatColor", "f6f6f6f6-0000-0000-0000-000000000006", 13, 45, "Wandering Pixel", "https://marketplace.secondlife.com/" }, |
| 3141 | + { K_FRIEND, "FriendChatColor", "b2b2b2b2-0000-0000-0000-000000000002", 13, 46, "Glittertoes McSparkle", "omg hi!! brb taming a baby dragon" }, |
| 3142 | + { K_LINDEN, "LindenChatColor", "c3c3c3c3-0000-0000-0000-000000000003", 13, 47, "Governor Linden", "Rolling restart in 5, hold onto your hats." }, |
| 3143 | + { K_OBJECT, "ObjectChatColor", "d4d4d4d4-0000-0000-0000-000000000004", 13, 48, "Object", "Welcome to Help Island!" }, |
| 3144 | + { K_OWNER, "llOwnerSayChatColor", "e5e5e5e5-0000-0000-0000-000000000005", 13, 49, "Animation HUD", "2,167 bytes free :)" }, |
| 3145 | + }; |
| 3146 | + |
| 3147 | + static const LLUIColor time_color = LLUIColorTable::instance().getColor("ChatHeaderTimestampColor"); |
| 3148 | + const bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); |
| 3149 | + |
| 3150 | + mPreviewBox->setText(LLStringUtil::null); // clear before re-appending |
| 3151 | + |
| 3152 | + bool prepend_newline = false; // newline before every line except the first |
| 3153 | + for (const auto& s : samples) |
| 3154 | + { |
| 3155 | + LLChat chat; |
| 3156 | + chat.mFromName = s.name; |
| 3157 | + chat.mText = s.text; |
| 3158 | + switch (s.kind) |
| 3159 | + { |
| 3160 | + case K_SYSTEM: |
| 3161 | + chat.mSourceType = CHAT_SOURCE_SYSTEM; |
| 3162 | + break; |
| 3163 | + case K_SELF: |
| 3164 | + chat.mSourceType = CHAT_SOURCE_AGENT; |
| 3165 | + chat.mFromID = gAgentID; |
| 3166 | + break; |
| 3167 | + case K_OBJECT: |
| 3168 | + chat.mSourceType = CHAT_SOURCE_OBJECT; |
| 3169 | + chat.mFromID = LLUUID(s.id); |
| 3170 | + break; |
| 3171 | + case K_OWNER: |
| 3172 | + chat.mSourceType = CHAT_SOURCE_OBJECT; |
| 3173 | + chat.mChatType = CHAT_TYPE_OWNER; |
| 3174 | + chat.mFromID = LLUUID(s.id); |
| 3175 | + break; |
| 3176 | + default: // resident / friend / Linden are all "other agents" |
| 3177 | + chat.mSourceType = CHAT_SOURCE_AGENT; |
| 3178 | + chat.mFromID = LLUUID(s.id); |
| 3179 | + break; |
| 3180 | + } |
| 3181 | + |
| 3182 | + // Base category color, then the live IRC overrides (mirrors getChatColor + |
| 3183 | + // getIRCNameColor in llchathistory.cpp). getIRCChatColor only recolors other |
| 3184 | + // agents, so self/system/object/owner keep their configured color. Names are |
| 3185 | + // clickable SLURLs in chat, so by default they take the link color; when IRC |
| 3186 | + // coloring is on, getIRCNameColor overrides that with the dimmed per-avatar color. |
| 3187 | + LLUIColor txt_color = LLUIColorTable::instance().getColor(s.color); |
| 3188 | + ALAvatarGroups::instance().getIRCChatColor(chat, txt_color); |
| 3189 | + |
| 3190 | + LLUIColor name_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); |
| 3191 | + ALAvatarGroups::instance().getIRCNameColor(chat, txt_color, name_color); |
| 3192 | + |
| 3193 | + // Timestamp prefix, like nearby chat: "[hh:mm] ", honoring the |
| 3194 | + // Use24HourClock pref the way LLFloaterIMSessionTab::appendTime() does. |
| 3195 | + std::string time_str; |
| 3196 | + if (use_24h) |
| 3197 | + { |
| 3198 | + time_str = llformat("%d:%02d", s.hour, s.minute); |
| 3199 | + } |
| 3200 | + else |
| 3201 | + { |
| 3202 | + S32 h12 = s.hour % 12; |
| 3203 | + if (h12 == 0) h12 = 12; |
| 3204 | + time_str = llformat("%d:%02d %s", h12, s.minute, s.hour < 12 ? "AM" : "PM"); |
| 3205 | + } |
| 3206 | + |
| 3207 | + LLStyle::Params time_style; |
| 3208 | + time_style.color(time_color); |
| 3209 | + time_style.readonly_color(time_color); |
| 3210 | + mPreviewBox->appendText("[" + time_str + "] ", prepend_newline, time_style); |
| 3211 | + prepend_newline = false; // keep the rest of the line attached to the timestamp |
| 3212 | + |
| 3213 | + if (!chat.mFromName.empty()) |
| 3214 | + { |
| 3215 | + LLStyle::Params name_style; |
| 3216 | + name_style.color(name_color); |
| 3217 | + name_style.readonly_color(name_color); |
| 3218 | + mPreviewBox->appendText(chat.mFromName + ": ", prepend_newline, name_style); |
| 3219 | + } |
| 3220 | + |
| 3221 | + // parse_urls is set on the widget, so any URL in the text is linkified |
| 3222 | + // (and colored HTMLLinkColor) automatically by appendText. |
| 3223 | + LLStyle::Params text_style; |
| 3224 | + text_style.color(txt_color); |
| 3225 | + text_style.readonly_color(txt_color); |
| 3226 | + mPreviewBox->appendText(chat.mText, prepend_newline, text_style); |
| 3227 | + |
| 3228 | + prepend_newline = true; |
| 3229 | + } |
| 3230 | +} |
3069 | 3231 |
|
3070 | 3232 | bool LLPanelPreferenceSound::postBuild() |
3071 | 3233 | { |
|
0 commit comments