Quassel IRC  Pre-Release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
styledlabel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2015 by the Quassel Project *
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) version 3. *
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  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19  ***************************************************************************/
20 
21 #include <QPainter>
22 #include <QTextDocument>
23 #include <QTextLayout>
24 
25 #include "graphicalui.h"
26 #include "styledlabel.h"
27 #include "uistyle.h"
28 
29 StyledLabel::StyledLabel(QWidget *parent)
30  : QFrame(parent),
31  _wrapMode(QTextOption::NoWrap),
32  _alignment(Qt::AlignVCenter|Qt::AlignLeft),
33  _toolTipEnabled(true),
34  _resizeMode(NoResize)
35 {
36  setMouseTracking(true);
37 
38  QTextOption opt = _layout.textOption();
39  opt.setWrapMode(_wrapMode);
40  opt.setAlignment(_alignment);
41  _layout.setTextOption(opt);
42 }
43 
44 
45 void StyledLabel::setCustomFont(const QFont &font)
46 {
47  setFont(font);
48  _layout.setFont(font);
49  setText(_layout.text());
50 }
51 
52 
53 void StyledLabel::setWrapMode(QTextOption::WrapMode mode)
54 {
55  if (_wrapMode == mode)
56  return;
57 
58  _wrapMode = mode;
59  QTextOption opt = _layout.textOption();
60  opt.setWrapMode(mode);
61  _layout.setTextOption(opt);
62 
63  layout();
64 }
65 
66 
67 void StyledLabel::setAlignment(Qt::Alignment alignment)
68 {
69  if (_alignment == alignment)
70  return;
71 
73  QTextOption opt = _layout.textOption();
74  opt.setAlignment(alignment);
75  _layout.setTextOption(opt);
76 
77  layout();
78 }
79 
80 
82 {
83  if (_resizeMode == mode)
84  return;
85 
86  _resizeMode = mode;
87  if (mode == DynamicResize)
88  setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
89  else
90  setWrapMode(QTextOption::NoWrap);
91 }
92 
93 
94 void StyledLabel::resizeEvent(QResizeEvent *event)
95 {
96  QFrame::resizeEvent(event);
97 
98  layout();
99 }
100 
101 
103 {
104  return _sizeHint;
105 }
106 
107 
109 {
110  QSize sh;
111  int padding = frameWidth() * 2;
112  sh = _layout.boundingRect().size().toSize() + QSize(padding, padding);
113 
114  if (_sizeHint != sh) {
115  _sizeHint = sh;
116  updateGeometry();
117  }
118 }
119 
120 
121 void StyledLabel::setText(const QString &text)
122 {
123  UiStyle *style = GraphicalUi::uiStyle();
124 
126  QList<QTextLayout::FormatRange> layoutList = style->toTextLayoutList(sstr.formatList, sstr.plainText.length(), 0);
127 
128  // Use default font rather than the style's
129  QTextLayout::FormatRange fmtRange;
130  fmtRange.format.setFont(font());
131  fmtRange.start = 0;
132  fmtRange.length = sstr.plainText.length();
133  layoutList << fmtRange;
134 
135  // Mark URLs
137  foreach(Clickable click, _clickables) {
138  if (click.type() == Clickable::Url) {
139  QTextLayout::FormatRange range;
140  range.start = click.start();
141  range.length = click.length();
142  range.format.setForeground(palette().link());
143  layoutList << range;
144  }
145  }
146 
147  _layout.setText(sstr.plainText);
148  _layout.setAdditionalFormats(layoutList);
149 
150  layout();
151 
152  endHoverMode();
153 }
154 
155 
157 {
158  if (frameRect().width() - 2*frameWidth() < _layout.minimumWidth())
159 #if QT_VERSION < 0x050000
160  setToolTip(QString("<qt>%1</qt>").arg(Qt::escape(_layout.text()))); // only rich text gets wordwrapped!
161 #else
162  setToolTip(QString("<qt>%1</qt>").arg(_layout.text().toHtmlEscaped())); // only rich text gets wordwrapped!
163 #endif
164  else
165  setToolTip(QString());
166 }
167 
168 
170 {
171  qreal h = 0;
172  qreal w = contentsRect().width();
173 
174  _layout.beginLayout();
175  forever {
176  QTextLine line = _layout.createLine();
177  if (!line.isValid())
178  break;
179  line.setLineWidth(w);
180  line.setPosition(QPointF(0, h));
181  h += line.height();
182  }
183  _layout.endLayout();
184 
185  updateSizeHint();
186  updateToolTip();
187  update();
188 }
189 
190 
191 void StyledLabel::paintEvent(QPaintEvent *e)
192 {
194  QPainter painter(this);
195 
196  qreal y = contentsRect().y() + (contentsRect().height() - _layout.boundingRect().height()) / 2;
197  _layout.draw(&painter, QPointF(contentsRect().x(), y), _extraLayoutList);
198 }
199 
200 
201 int StyledLabel::posToCursor(const QPointF &pos)
202 {
203  if (pos.y() < 0 || pos.y() > height())
204  return -1;
205 
206  for (int l = _layout.lineCount() - 1; l >= 0; l--) {
207  QTextLine line = _layout.lineAt(l);
208  if (pos.y() >= line.y()) {
209  return line.xToCursor(pos.x(), QTextLine::CursorOnCharacter);
210  }
211  }
212  return -1;
213 }
214 
215 
216 void StyledLabel::mouseMoveEvent(QMouseEvent *event)
217 {
218  if (event->buttons() == Qt::NoButton) {
219 #if QT_VERSION < 0x050000
220  Clickable click = _clickables.atCursorPos(posToCursor(event->posF()));
221 #else
222  Clickable click = _clickables.atCursorPos(posToCursor(event->localPos()));
223 #endif
224  if (click.isValid())
225  setHoverMode(click.start(), click.length());
226  else
227  endHoverMode();
228  }
229 }
230 
231 
233 {
234  if (resizeMode() == ResizeOnHover)
235  setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
236 }
237 
238 
240 {
241  endHoverMode();
242  if (resizeMode() == ResizeOnHover)
243  setWrapMode(QTextOption::NoWrap);
244 }
245 
246 
247 void StyledLabel::mousePressEvent(QMouseEvent *event)
248 {
249  if (event->button() == Qt::LeftButton) {
250 #if QT_VERSION < 0x050000
251  Clickable click = _clickables.atCursorPos(posToCursor(event->posF()));
252 #else
253  Clickable click = _clickables.atCursorPos(posToCursor(event->localPos()));
254 #endif
255  if (click.isValid())
256  emit clickableActivated(click);
257  }
258 }
259 
260 
261 void StyledLabel::setHoverMode(int start, int length)
262 {
263  if (_extraLayoutList.count() >= 1 && _extraLayoutList.first().start == start && _extraLayoutList.first().length == length)
264  return;
265 
266  QTextLayout::FormatRange range;
267  range.start = start;
268  range.length = length;
269  range.format.setFontUnderline(true);
270  _extraLayoutList.clear();
271  _extraLayoutList << range;
272 
273  setCursor(Qt::PointingHandCursor);
274  update();
275 }
276 
277 
279 {
280  _extraLayoutList.clear();
281  setCursor(Qt::ArrowCursor);
282  update();
283 }