-QString UiStyle::_timestampFormatString;
-
-UiStyle::UiStyle(QObject *parent)
-: QObject(parent),
- _channelJoinedIcon(SmallIcon("irc-channel-active")),
- _channelPartedIcon(SmallIcon("irc-channel-inactive")),
- _userOfflineIcon(SmallIcon("im-user-offline")),
- _userOnlineIcon(SmallIcon("im-user")),
- _userAwayIcon(SmallIcon("im-user-away")),
- _categoryOpIcon(SmallIcon("irc-operator")),
- _categoryVoiceIcon(SmallIcon("irc-voice")),
- _opIconLimit(UserCategoryItem::categoryFromModes("o")),
- _voiceIconLimit(UserCategoryItem::categoryFromModes("v"))
-{
- // register FormatList if that hasn't happened yet
- // FIXME I don't think this actually avoids double registration... then again... does it hurt?
- if(QVariant::nameToType("UiStyle::FormatList") == QVariant::Invalid) {
- qRegisterMetaType<FormatList>("UiStyle::FormatList");
- qRegisterMetaTypeStreamOperators<FormatList>("UiStyle::FormatList");
- Q_ASSERT(QVariant::nameToType("UiStyle::FormatList") != QVariant::Invalid);
- }
-
- _uiStylePalette = QVector<QBrush>(NumRoles, QBrush());
-
- // Now initialize the mapping between FormatCodes and FormatTypes...
- _formatCodes["%O"] = Base;
- _formatCodes["%B"] = Bold;
- _formatCodes["%S"] = Italic;
- _formatCodes["%U"] = Underline;
- _formatCodes["%R"] = Reverse;
-
- _formatCodes["%DN"] = Nick;
- _formatCodes["%DH"] = Hostmask;
- _formatCodes["%DC"] = ChannelName;
- _formatCodes["%DM"] = ModeFlags;
- _formatCodes["%DU"] = Url;
-
- setTimestampFormatString("[hh:mm:ss]");
-
- // BufferView / NickView settings
- UiStyleSettings s;
- _showBufferViewIcons = _showNickViewIcons = s.value("ShowItemViewIcons", true).toBool();
- s.notify("ShowItemViewIcons", this, SLOT(showItemViewIconsChanged()));
-
- loadStyleSheet();
-}
-
-UiStyle::~UiStyle() {
- qDeleteAll(_metricsCache);
-}
-
-void UiStyle::reload() {
- loadStyleSheet();
-}
-
-void UiStyle::loadStyleSheet() {
- qDeleteAll(_metricsCache);
- _metricsCache.clear();
- _formatCache.clear();
- _formats.clear();
-
- UiStyleSettings s;
-
- QString styleSheet;
- styleSheet += loadStyleSheet("file:///" + Quassel::findDataFilePath("default.qss"));
- styleSheet += loadStyleSheet("file:///" + Quassel::configDirPath() + "settings.qss");
- if(s.value("UseCustomStyleSheet", false).toBool())
- styleSheet += loadStyleSheet("file:///" + s.value("CustomStyleSheetPath").toString(), true);
- styleSheet += loadStyleSheet("file:///" + Quassel::optionValue("qss"), true);
-
- if(!styleSheet.isEmpty()) {
- QssParser parser;
- parser.processStyleSheet(styleSheet);
- QApplication::setPalette(parser.palette());
- _uiStylePalette = parser.uiStylePalette();
-
- QTextCharFormat baseFmt = parser.formats().value(Base);
- foreach(quint64 fmtType, parser.formats().keys()) {
- QTextCharFormat fmt = baseFmt;
- fmt.merge(parser.formats().value(fmtType));
- _formats[fmtType] = fmt;
- }
- _listItemFormats = parser.listItemFormats();
-
- styleSheet = styleSheet.trimmed();
- if(!styleSheet.isEmpty())
- qApp->setStyleSheet(styleSheet); // pass the remaining sections to the application
- }
-
- emit changed();
-}
-
-QString UiStyle::loadStyleSheet(const QString &styleSheet, bool shouldExist) {
- QString ss = styleSheet;
- if(ss.startsWith("file:///")) {
- ss.remove(0, 8);
- if(ss.isEmpty())
- return QString();
-
- QFile file(ss);
- if(file.open(QFile::ReadOnly)) {
- QTextStream stream(&file);
- ss = stream.readAll();
- file.close();
- } else {
- if(shouldExist)
- qWarning() << "Could not open stylesheet file:" << file.fileName();
- return QString();
+bool UiStyle::_useCustomTimestampFormat; /// If true, use the custom timestamp format
+QString UiStyle::_timestampFormatString; /// Timestamp format
+QString UiStyle::_systemTimestampFormatString; /// Cached copy of system locale timestamp format
+UiStyle::SenderPrefixMode UiStyle::_senderPrefixDisplay; /// Display of prefix modes before sender
+bool UiStyle::_showSenderBrackets; /// If true, show brackets around sender names
+
+namespace {
+
+// Extended mIRC colors as defined in https://modern.ircdocs.horse/formatting.html#colors-16-98
+QColor extendedMircColor(int number)
+{
+ static const std::vector<QColor> colorMap = {"#470000", "#472100", "#474700", "#324700", "#004700", "#00472c", "#004747", "#002747",
+ "#000047", "#2e0047", "#470047", "#47002a", "#740000", "#743a00", "#747400", "#517400",
+ "#007400", "#007449", "#007474", "#004074", "#000074", "#4b0074", "#740074", "#740045",
+ "#b50000", "#b56300", "#b5b500", "#7db500", "#00b500", "#00b571", "#00b5b5", "#0063b5",
+ "#0000b5", "#7500b5", "#b500b5", "#b5006b", "#ff0000", "#ff8c00", "#ffff00", "#b2ff00",
+ "#00ff00", "#00ffa0", "#00ffff", "#008cff", "#0000ff", "#a500ff", "#ff00ff", "#ff0098",
+ "#ff5959", "#ffb459", "#ffff71", "#cfff60", "#6fff6f", "#65ffc9", "#6dffff", "#59b4ff",
+ "#5959ff", "#c459ff", "#ff66ff", "#ff59bc", "#ff9c9c", "#ffd39c", "#ffff9c", "#e2ff9c",
+ "#9cff9c", "#9cffdb", "#9cffff", "#9cd3ff", "#9c9cff", "#dc9cff", "#ff9cff", "#ff94d3",
+ "#000000", "#131313", "#282828", "#363636", "#4d4d4d", "#656565", "#818181", "#9f9f9f",
+ "#bcbcbc", "#e2e2e2", "#ffffff"};
+ if (number < 16)
+ return {};
+ size_t index = number - 16;
+ return (index < colorMap.size() ? colorMap[index] : QColor{});
+}
+
+} // namespace
+
+UiStyle::UiStyle(QObject* parent)
+ : QObject(parent)
+ , _channelJoinedIcon{icon::get("irc-channel-active")}
+ , _channelPartedIcon{icon::get("irc-channel-inactive")}
+ , _userOfflineIcon{icon::get({"im-user-offline", "user-offline"})}
+ , _userOnlineIcon{icon::get({"im-user-online", "im-user", "user-available"})}
+ , _userAwayIcon{icon::get({"im-user-away", "user-away"})}
+ , _categoryOpIcon{icon::get("irc-operator")}
+ , _categoryVoiceIcon{icon::get("irc-voice")}
+ , _opIconLimit{UserCategoryItem::categoryFromModes("o")}
+ , _voiceIconLimit{UserCategoryItem::categoryFromModes("v")}
+{
+ static bool registered = []() {
+ qRegisterMetaType<FormatList>();
+ qRegisterMetaTypeStreamOperators<FormatList>();
+ return true;
+ }();
+ Q_UNUSED(registered)
+
+ _uiStylePalette = QVector<QBrush>(static_cast<int>(ColorRole::NumRoles), QBrush());
+
+ // Now initialize the mapping between FormatCodes and FormatTypes...
+ _formatCodes["%O"] = FormatType::Base;
+ _formatCodes["%B"] = FormatType::Bold;
+ _formatCodes["%I"] = FormatType::Italic;
+ _formatCodes["%U"] = FormatType::Underline;
+ _formatCodes["%S"] = FormatType::Strikethrough;
+
+ _formatCodes["%DN"] = FormatType::Nick;
+ _formatCodes["%DH"] = FormatType::Hostmask;
+ _formatCodes["%DC"] = FormatType::ChannelName;
+ _formatCodes["%DM"] = FormatType::ModeFlags;
+ _formatCodes["%DU"] = FormatType::Url;
+
+ // Initialize fallback defaults
+ // NOTE: If you change this, update qtui/chatviewsettings.h, too. More explanations available
+ // in there.
+ setUseCustomTimestampFormat(false);
+ setTimestampFormatString(" hh:mm:ss");
+ setSenderPrefixDisplay(UiStyle::SenderPrefixMode::HighestMode);
+ enableSenderBrackets(false);
+
+ // BufferView / NickView settings
+ UiStyleSettings s;
+ s.initAndNotify("ShowItemViewIcons", this, &UiStyle::showItemViewIconsChanged, true);
+ s.initAndNotify("AllowMircColors", this, &UiStyle::allowMircColorsChanged, true);
+
+ loadStyleSheet();
+}
+
+UiStyle::~UiStyle()
+{
+ qDeleteAll(_metricsCache);
+}
+
+void UiStyle::reload()
+{
+ loadStyleSheet();
+}
+
+void UiStyle::loadStyleSheet()
+{
+ qDeleteAll(_metricsCache);
+ _metricsCache.clear();
+ _formatCache.clear();
+ _formats.clear();
+
+ UiStyleSettings s;
+
+ QString styleSheet;
+ styleSheet += loadStyleSheet("file:///" + Quassel::findDataFilePath("stylesheets/default.qss"));
+ styleSheet += loadStyleSheet("file:///" + Quassel::configDirPath() + "settings.qss");
+ if (s.value("UseCustomStyleSheet", false).toBool()) {
+ QString customSheetPath(s.value("CustomStyleSheetPath").toString());
+ QString customSheet = loadStyleSheet("file:///" + customSheetPath, true);
+ if (customSheet.isEmpty()) {
+ // MIGRATION: changed default install path for data from /usr/share/apps to /usr/share
+ if (customSheetPath.startsWith("/usr/share/apps/quassel")) {
+ customSheetPath.replace(QRegExp("^/usr/share/apps"), "/usr/share");
+ customSheet = loadStyleSheet("file:///" + customSheetPath, true);
+ if (!customSheet.isEmpty()) {
+ s.setValue("CustomStyleSheetPath", customSheetPath);
+ qDebug() << "Custom stylesheet path migrated to" << customSheetPath;
+ }
+ }
+ }
+ styleSheet += customSheet;