Fix mIRC colors
[quassel.git] / src / uisupport / uistyle.cpp
index a799d33..b0db2ab 100644 (file)
 
 UiStyle::UiStyle(const QString &settingsKey) : _settingsKey(settingsKey) {
   // register FormatList if that hasn't happened yet
-  // FIXME I don't think this actually avoids double registration... :/
+  // 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);
   }
 
+  _defaultFont = QFont("Monospace", QApplication::font().pointSize());
+
   // Default format
   _defaultPlainFormat.setForeground(QBrush("#000000"));
-  _defaultPlainFormat.setFont(QFont("Monospace", QApplication::font().pointSize()));
+  _defaultPlainFormat.setFont(_defaultFont);
   _defaultPlainFormat.font().setFixedPitch(true);
   _defaultPlainFormat.font().setStyleHint(QFont::TypeWriter);
   setFormat(None, _defaultPlainFormat, Settings::Default);
-  
+
   // Load saved custom formats
   UiStyleSettings s(_settingsKey);
   foreach(FormatType type, s.availableFormats()) {
     _customFormats[type] = s.customFormat(type);
   }
 
-  // Initialize color codes according to mIRC "standard"
-  QStringList colors;
-  //colors << "white" << "black" << "navy" << "green" << "red" << "maroon" << "purple" << "orange";
-  //colors << "yellow" << "lime" << "teal" << "aqua" << "royalblue" << "fuchsia" << "grey" << "silver";
-  colors << "#ffffff" << "#000000" << "#000080" << "#008000" << "#ff0000" << "#800000" << "#800080" << "#ffa500";
-  colors << "#ffff00" << "#00ff00" << "#008080" << "#00ffff" << "#4169E1" << "#ff00ff" << "#808080" << "#c0c0c0";
-
   // Now initialize the mapping between FormatCodes and FormatTypes...
   _formatCodes["%O"] = None;
   _formatCodes["%B"] = Bold;
@@ -79,14 +74,21 @@ UiStyle::UiStyle(const QString &settingsKey) : _settingsKey(settingsKey) {
   _formatCodes["%DM"] = ModeFlags;
   _formatCodes["%DU"] = Url;
 
+  // Initialize color codes according to mIRC "standard"
+  QStringList colors;
+  //colors << "white" << "black" << "navy" << "green" << "red" << "maroon" << "purple" << "orange";
+  //colors << "yellow" << "lime" << "teal" << "aqua" << "royalblue" << "fuchsia" << "grey" << "silver";
+  colors << "#ffffff" << "#000000" << "#000080" << "#008000" << "#ff0000" << "#800000" << "#800080" << "#ffa500";
+  colors << "#ffff00" << "#00ff00" << "#008080" << "#00ffff" << "#4169E1" << "#ff00ff" << "#808080" << "#c0c0c0";
+
   // Set color formats
   for(int i = 0; i < 16; i++) {
     QString idx = QString("%1").arg(i, (int)2, (int)10, (QChar)'0');
-    _formatCodes[QString("%Dcf%1").arg(idx)] = (FormatType)(FgCol00 + i);
-    _formatCodes[QString("%Dcb%1").arg(idx)] = (FormatType)(BgCol00 + i);
+    _formatCodes[QString("%Dcf%1").arg(idx)] = (FormatType)(FgCol00 | i<<24);
+    _formatCodes[QString("%Dcb%1").arg(idx)] = (FormatType)(BgCol00 | i<<28);
     QTextCharFormat fgf, bgf;
-    fgf.setForeground(QBrush(QColor(colors[i]))); setFormat((FormatType)(FgCol00 + i), fgf, Settings::Default);
-    bgf.setBackground(QBrush(QColor(colors[i]))); setFormat((FormatType)(BgCol00 + i), bgf, Settings::Default);
+    fgf.setForeground(QBrush(QColor(colors[i]))); setFormat((FormatType)(FgCol00 | i<<24), fgf, Settings::Default);
+    bgf.setBackground(QBrush(QColor(colors[i]))); setFormat((FormatType)(BgCol00 | i<<28), bgf, Settings::Default);
   }
 
   // Set a few more standard formats
@@ -103,7 +105,7 @@ UiStyle::UiStyle(const QString &settingsKey) : _settingsKey(settingsKey) {
 }
 
 UiStyle::~ UiStyle() {
-  
+  qDeleteAll(_cachedFontMetrics);
 }
 
 void UiStyle::setFormat(FormatType ftype, QTextCharFormat fmt, Settings::Mode mode) {
@@ -131,7 +133,7 @@ QTextCharFormat UiStyle::format(FormatType ftype, Settings::Mode mode) const {
 // NOTE: This function is intimately tied to the values in FormatType. Don't change this
 //       until you _really_ know what you do!
 QTextCharFormat UiStyle::mergedFormat(quint32 ftype) {
-  if(_cachedFormats.contains(ftype)) return _cachedFormats[ftype];
+  if(_cachedFormats.contains(ftype)) return _cachedFormats.value(ftype);
   if(ftype == Invalid) return QTextCharFormat();
   // Now we construct the merged format, starting with the default
   QTextCharFormat fmt = format(None);
@@ -146,8 +148,13 @@ QTextCharFormat UiStyle::mergedFormat(quint32 ftype) {
   if(ftype & 0x00800000) fmt.merge(format((FormatType)(ftype & 0xf0800000))); // background
   // URL
   if(ftype & Url) fmt.merge(format(Url));
-  _cachedFormats[ftype] = fmt;
-  return fmt;
+  return _cachedFormats[ftype] = fmt;
+}
+
+QFontMetricsF *UiStyle::fontMetrics(quint32 ftype) {
+  // QFontMetricsF is not assignable, so we need to store pointers :/
+  if(_cachedFontMetrics.contains(ftype)) return _cachedFontMetrics.value(ftype);
+  return (_cachedFontMetrics[ftype] = new QFontMetricsF(mergedFormat(ftype).font()));
 }
 
 UiStyle::FormatType UiStyle::formatType(const QString & code) const {
@@ -159,14 +166,32 @@ QString UiStyle::formatCode(FormatType ftype) const {
   return _formatCodes.key(ftype);
 }
 
+QList<QTextLayout::FormatRange> UiStyle::toTextLayoutList(const FormatList &formatList, int textLength) {
+  QList<QTextLayout::FormatRange> formatRanges;
+  QTextLayout::FormatRange range;
+  int i = 0;
+  for(i = 0; i < formatList.count(); i++) {
+    range.format = mergedFormat(formatList.at(i).second);
+    range.start = formatList.at(i).first;
+    if(i > 0) formatRanges.last().length = range.start - formatRanges.last().start;
+    formatRanges.append(range);
+  }
+  if(i > 0) formatRanges.last().length = textLength - formatRanges.last().start;
+  return formatRanges;
+}
+
 // This method expects a well-formatted string, there is no error checking!
 // Since we create those ourselves, we should be pretty safe that nobody does something crappy here.
 UiStyle::StyledString UiStyle::styleString(const QString &s_) {
   QString s = s_;
+  if(s.length() > 65535) {
+    qWarning() << QString("String too long to be styled: %1").arg(s);
+    return StyledString();
+  }
   StyledString result;
-  result.formats.append(qMakePair(0, (quint32)None));
+  result.formatList.append(qMakePair((quint16)0, (quint32)None));
   quint32 curfmt = (quint32)None;
-  int pos = 0; int length = 0;
+  int pos = 0; quint16 length = 0;
   for(;;) {
     pos = s.indexOf('%', pos);
     if(pos < 0) break;
@@ -183,7 +208,7 @@ UiStyle::StyledString UiStyle::styleString(const QString &s_) {
         int color = 10 * s[pos+4].digitValue() + s[pos+5].digitValue();
         //TODO: use 99 as transparent color (re mirc color "standard")
         color &= 0x0f;
-        if(pos+3 == 'f')
+        if(s[pos+3] == 'f')
           curfmt |= (color << 24) | 0x00400000;
         else
           curfmt |= (color << 28) | 0x00800000;
@@ -208,16 +233,16 @@ UiStyle::StyledString UiStyle::styleString(const QString &s_) {
       length = code.length();
     }
     s.remove(pos, length);
-    if(pos == result.formats.last().first)
-      result.formats.last().second = curfmt;
+    if(pos == result.formatList.last().first)
+      result.formatList.last().second = curfmt;
     else
-      result.formats.append(qMakePair(pos, curfmt));
+      result.formatList.append(qMakePair((quint16)pos, curfmt));
   }
-  result.text = s;
+  result.plainText = s;
   return result;
 }
 
-QString UiStyle::mircToInternal(const QString &mirc_) {
+QString UiStyle::mircToInternal(const QString &mirc_) const {
   QString mirc = mirc_;
   mirc.replace('%', "%%");      // escape % just to be sure
   mirc.replace('\x02', "%B");
@@ -265,7 +290,7 @@ UiStyle::StyledMessage UiStyle::styleMessage(const Message &msg) {
   QString user = userFromMask(msg.sender());
   QString host = hostFromMask(msg.sender());
   QString nick = nickFromMask(msg.sender());
-  QString txt = mircToInternal(msg.text());
+  QString txt = mircToInternal(msg.contents());
   QString bufferName = msg.bufferInfo().bufferName();
 
   StyledMessage result;
@@ -303,7 +328,7 @@ UiStyle::StyledMessage UiStyle::styleMessage(const Message &msg) {
       break;
     case Message::Nick:
       s = tr("%Dr<->");
-      if(nick == msg.text()) t = tr("%DrYou are now known as %DN%1%DN").arg(txt);
+      if(nick == msg.contents()) t = tr("%DrYou are now known as %DN%1%DN").arg(txt);
       else t = tr("%Dr%DN%1%DN is now known as %DN%2%DN").arg(nick, txt);
       break;
     case Message::Mode:
@@ -320,7 +345,7 @@ UiStyle::StyledMessage UiStyle::styleMessage(const Message &msg) {
       t = tr("%De[%1]").arg(txt);
   }
   result.sender = styleString(s);
-  result.text = styleString(t);
+  result.contents = styleString(t);
   return result;
 }
 
@@ -335,12 +360,12 @@ QDataStream &operator<<(QDataStream &out, const UiStyle::FormatList &formatList)
 }
 
 QDataStream &operator>>(QDataStream &in, UiStyle::FormatList &formatList) {
-  int cnt;
+  quint16 cnt;
   in >> cnt;
-  for(int i = 0; i < cnt; i++) {
-    int pos; quint32 ftype;
+  for(quint16 i = 0; i < cnt; i++) {
+    quint16 pos; quint32 ftype;
     in >> pos >> ftype;
-    formatList.append(qMakePair(pos, ftype));
+    formatList.append(qMakePair((quint16)pos, ftype));
   }
   return in;
 }