Merged changes from branch "sput" r50:55 back into trunk.
[quassel.git] / gui / style.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-07 by The Quassel Team                             *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "style.h"
22
23 void Style::init() {
24    // Colors (mIRC standard)
25   colors["00"] = QColor("white");
26   colors["01"] = QColor("black");
27   colors["02"] = QColor("navy");
28   colors["03"] = QColor("green");
29   colors["04"] = QColor("red");
30   colors["05"] = QColor("maroon");
31   colors["06"] = QColor("purple");
32   colors["07"] = QColor("orange");
33   colors["08"] = QColor("yellow");
34   colors["09"] = QColor("lime");
35   colors["10"] = QColor("teal");
36   colors["11"] = QColor("aqua");
37   colors["12"] = QColor("royalblue");
38   colors["13"] = QColor("fuchsia");
39   colors["14"] = QColor("grey");
40   colors["15"] = QColor("silver");
41
42   QTextCharFormat def;
43   //def.setFont(QFont("Lucida Mono"));
44   formats["default"] = def;
45
46   // %B - 0x02 - bold
47   QTextCharFormat bold;
48   bold.setFontWeight(QFont::Bold);
49   formats["%B"] = bold;
50
51   // %O - 0x0f - plain
52   formats["%O"] = QTextCharFormat();
53
54   // %R - 0x12 - reverse
55   // -- - 0x16 - reverse
56   // (no format)
57
58   // %S - 0x1d - italic
59   QTextCharFormat italic;
60   italic.setFontItalic(true);
61   formats["%S"] = italic;
62
63   // %U - 0x1f - underline
64   QTextCharFormat underline;
65   underline.setFontUnderline(true);
66   formats["%U"] = underline;
67
68   // %C - 0x03 - mIRC colors
69   for(uint i = 0; i < 16; i++) {
70     QString idx = QString("%1").arg(i, (int)2, (int)10, (QChar)'0');
71     QString fg = QString("%C%1").arg(idx);
72     QString bg = QString("%C,%1").arg(idx);
73     QTextCharFormat fgf; fgf.setForeground(QBrush(colors[idx])); formats[fg] = fgf;
74     QTextCharFormat bgf; bgf.setBackground(QBrush(colors[idx])); formats[bg] = bgf;
75   }
76
77   // Internal formats - %D<char>
78   // %D0 - plain msg
79   QTextCharFormat plainMsg;
80   plainMsg.setForeground(QBrush("black"));
81   formats["%D0"] = plainMsg;
82   // %Dn - notice
83   QTextCharFormat notice;
84   notice.setForeground(QBrush("navy"));
85   formats["%Dn"] = notice;
86   // %Ds - server msg
87   QTextCharFormat server;
88   server.setForeground(QBrush("navy"));
89   formats["%Ds"] = server;
90   // %De - error msg
91   QTextCharFormat error;
92   error.setForeground(QBrush("red"));
93   formats["%De"] = error;
94   // %Dj - join
95   QTextCharFormat join;
96   join.setForeground(QBrush("green"));
97   formats["%Dj"] = join;
98   // %Dp - part
99   QTextCharFormat part;
100   part.setForeground(QBrush("firebrick"));
101   formats["%Dp"] = part;
102   // %Dq - quit
103   QTextCharFormat quit;
104   quit.setForeground(QBrush("firebrick"));
105   formats["%Dq"] = quit;
106   // %Dk - kick
107   QTextCharFormat kick;
108   kick.setForeground(QBrush("firebrick"));
109   formats["%Dk"] = kick;
110   // %Dr - nick rename
111   QTextCharFormat nren;
112   nren.setForeground(QBrush("magenta"));
113   formats["%Dr"] = nren;
114   // %Dm - mode change
115   QTextCharFormat mode;
116   mode.setForeground(QBrush("steelblue"));
117   formats["%Dm"] = mode;
118
119   // %DT - timestamp
120   QTextCharFormat ts;
121   ts.setForeground(QBrush("grey"));
122   formats["%DT"] = ts;
123   // %DS - sender
124   QTextCharFormat sender;
125   sender.setAnchor(true);
126   sender.setForeground(QBrush("navy"));
127   formats["%DS"] = sender;
128   // %DN - nickname
129   QTextCharFormat nick;
130   nick.setAnchor(true);
131   nick.setFontWeight(QFont::Bold);
132   formats["%DN"] = nick;
133   // %DH - hostmask
134   QTextCharFormat hostmask;
135   hostmask.setFontItalic(true);
136   formats["%DH"] = hostmask;
137   // %DC - channame
138   QTextCharFormat channel;
139   channel.setAnchor(true);
140   channel.setFontWeight(QFont::Bold);
141   formats["%DC"] = channel;
142   // %DM - modeflags
143   QTextCharFormat flags;
144   flags.setFontWeight(QFont::Bold);
145   formats["%DM"] = flags;
146
147 }
148
149 QString Style::mircToInternal(QString mirc) {
150   mirc.replace('%', "%%");      // escape % just to be sure
151   mirc.replace('\x02', "%B");
152   mirc.replace('\x03', "%C");
153   mirc.replace('\x0f', "%O");
154   mirc.replace('\x12', "%R");
155   mirc.replace('\x16', "%R");
156   mirc.replace('\x1d', "%S");
157   mirc.replace('\x1f', "%U");
158   return mirc;
159 }
160
161 /** Returns a string stripped of format codes, and a list of FormatRange objects
162  *  describing the formats of the string.
163  * \param s string in internal format (% style format codes)
164  */ 
165 Style::StringFormats Style::internalToFormatted(QString s) {
166   QHash<QString, int> toggles;
167   QString p;
168   StringFormats sf;
169   QTextLayout::FormatRange rng;
170   rng.format = formats["default"]; rng.start = 0; rng.length = -1; sf.formats.append(rng);
171   toggles["default"] = sf.formats.count() - 1;
172   int i, j;
173   for(i = 0, j = 0; i < s.length(); i++) {
174     if(s[i] != '%') { p += s[i]; j++; continue; }
175     i++;
176     if(s[i] == '%') { p += '%'; j++; continue; }
177     else if(s[i] == 'C') {
178       if(!s[i+1].isDigit() && s[i+1] != ',') {
179         if(toggles.contains("bg")) {
180           sf.formats[toggles["bg"]].length = j - sf.formats[toggles["bg"]].start;
181           toggles.remove("bg");
182         }
183       }
184       if(s[i+1].isDigit() || s[i+1] != ',') {
185         if(toggles.contains("fg")) {
186           sf.formats[toggles["fg"]].length = j - sf.formats[toggles["fg"]].start;
187           toggles.remove("fg");
188         }
189         if(s[i+1].isDigit()) {
190           QString n(s[++i]);
191           if(s[i+1].isDigit()) n += s[++i];
192           int num = n.toInt() & 0xf;
193           n = QString("%C%1").arg(num, (int)2, (int)10, (QChar)'0');
194           //qDebug() << n << formats[n].foreground();
195           QTextLayout::FormatRange range; 
196           range.format = formats[n]; range.start = j; range.length = -1; sf.formats.append(range);
197           toggles["fg"] = sf.formats.count() - 1;
198         }
199       }
200       if(s[i+1] == ',') {
201         if(toggles.contains("bg")) {
202           sf.formats[toggles["bg"]].length = j - sf.formats[toggles["bg"]].start;
203           toggles.remove("bg");
204         }
205         i++;
206         if(s[i+1].isDigit()) {
207           QString n(s[++i]);
208           if(s[i+1].isDigit()) n += s[++i];
209           int num = n.toInt() & 0xf;
210           n = QString("%C,%1").arg(num, (int)2, (int)10, (QChar)'0');
211           QTextLayout::FormatRange range;
212           range.format = formats[n]; range.start = j; range.length = -1;
213           sf.formats.append(range);
214           toggles["bg"] = sf.formats.count() - 1;
215         }
216       }
217     } else if(s[i] == 'O') {
218       foreach(QString key, toggles.keys()) {
219         sf.formats[toggles[key]].length = j - sf.formats[toggles[key]].start;
220         toggles.remove(key);
221       }
222
223     } else if(s[i] == 'R') {
224       // TODO implement reverse formatting
225
226     } else {
227       // all others are toggles
228       QString key = "%"; key += s[i];
229       if(s[i] == 'D') key += s[i+1];
230       if(formats.contains(key)) {
231         if(s[i] == 'D') i++;
232         if(toggles.contains(key)) {
233           sf.formats[toggles[key]].length = j - sf.formats[toggles[key]].start;
234           toggles.remove(key);
235         } else {
236           QTextLayout::FormatRange range;
237           range.format = formats[key]; range.start = j; range.length = -1;
238           sf.formats.append(range);
239           toggles[key] = sf.formats.count() -1;
240         }
241       } else {
242         // unknown format
243         p += '%'; p += s[i]; j+=2;
244       }
245     }
246   }
247   foreach(int idx, toggles.values()) {
248     sf.formats[idx].length = j - sf.formats[idx].start;
249   }
250   sf.text = p;
251   return sf;
252 }
253
254 QHash<QString, QTextCharFormat> Style::formats;
255 QHash<QString, QColor> Style::colors;
256