Developer Documentation
text.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 
43 
44 //== INCLUDES =================================================================
45 
46 #include <QPolygonF>
47 #include <QGraphicsItem>
48 #include <QFontMetrics>
49 #include <QPen>
50 #include <QPainter>
51 
52 #include "text.hh"
53 
54 #define BACK_OFFSET 2
55 
56 //== NAMESPACES ===============================================================
57 namespace VSI {
58 
59 //=============================================================================
60 //
61 // CLASS VSI::Text - IMPLEMENTATION
62 //
63 //=============================================================================
64 
66 Text::Text (QGraphicsItem *_parent) :
67  QGraphicsSimpleTextItem (_parent),
68  backgroundSet_ (false),
69  leftOut_(true),
70  rightOut_(true),
71  alignment_ (Qt::AlignLeft),
72  hStretch_ (true)
73 {
74  setBrush (Qt::white);
75 }
76 
77 //------------------------------------------------------------------------------
78 
80 Text::Text (const QString &_text, QGraphicsItem *_parent) :
81  QGraphicsSimpleTextItem (_text, _parent),
82  text_ (_text),
83  backgroundSet_ (false),
84  leftOut_(true),
85  rightOut_(true),
86  alignment_ (Qt::AlignLeft),
87  hStretch_ (true)
88 {
89  setBrush (Qt::white);
90 }
91 
92 //------------------------------------------------------------------------------
93 
96 {
97 }
98 
99 //------------------------------------------------------------------------------
100 
102 void Text::setGeometry (const QRectF &_rect)
103 {
104  QFontMetrics fn (font ());
105 
106  int width = _rect.width ();
107 
108  if (backgroundSet_)
109  {
110  if (rightOut_)
111  width -= _rect.height () / 2;
112  else
113  width -= BACK_OFFSET * 2;
114 
115  if (leftOut_)
116  width -= _rect.height () / 2;
117  else
118  width -= BACK_OFFSET * 2;
119  }
120 
121  if (fn.boundingRect (text_).width () > width)
122  {
123  QString nt = text_ + "...";
124  while (fn.boundingRect (nt).width () > width && nt.length () > 3)
125  nt.remove (nt.length () - 4, 1);
126  QGraphicsSimpleTextItem::setText (nt);
127  }
128  else
129  QGraphicsSimpleTextItem::setText (text_);
130 
131  QGraphicsSimpleTextItem::setPos (_rect.topLeft ());
132  QGraphicsLayoutItem::setGeometry (_rect);
133 }
134 
135 //------------------------------------------------------------------------------
136 
137 // size information for layouting
138 QSizeF Text::sizeHint (Qt::SizeHint _which, const QSizeF &/*_constraint*/) const
139 {
140  QFontMetrics fn (font ());
141  QSizeF sh;
142 
143  int w = 0;
144  if (rightOut_)
145  w += (fn.height () / 2) + (BACK_OFFSET * 2);
146  else
147  w += BACK_OFFSET * 2;
148  if (leftOut_)
149  w += (fn.height () / 2) + (BACK_OFFSET * 2);
150  else
151  w += BACK_OFFSET * 2;
152 
153  QSizeF bOff = QSizeF (w, BACK_OFFSET * 2);
154 
155  switch (_which) {
156  case Qt::MinimumSize:
157  sh = QSizeF(fn.boundingRect ("...").width (), fn.height ());
158  if (backgroundSet_)
159  sh += bOff;
160  break;
161  case Qt::PreferredSize:
162  sh = QSizeF(fn.boundingRect (text_).width (), fn.height ());
163  if (backgroundSet_)
164  sh += bOff;
165  break;
166  case Qt::MaximumSize:
167  sh = QSizeF(fn.boundingRect (text_).width (), fn.height ());
168  if (backgroundSet_)
169  sh += bOff;
170  if (hStretch_)
171  sh += QSizeF (65535, 0);
172  break;
173  case Qt::MinimumDescent:
174  sh = QSizeF(0, fn.descent ());
175  default:
176  break;
177  }
178 
179  return sh;
180 }
181 
182 //------------------------------------------------------------------------------
183 
185 void Text::paint (QPainter *_painter, const QStyleOptionGraphicsItem *_option, QWidget *_widget)
186 {
187  qreal h = geometry ().size ().height () / 2.0;
188 
189  if (backgroundSet_)
190  {
191  QPainterPath path;
192 
193  path.moveTo (geometry ().size ().width () / 2, 0);
194  if (leftOut_)
195  {
196  path.lineTo (h, 0);
197  path.arcTo (0, 0, h * 2.0, h * 2.0, 90, 180);
198  }
199  else
200  {
201  path.lineTo (-h, 0);
202  path.arcTo (-h * 2, 0, h * 2.0, h * 2.0, 90, -180);
203  }
204 
205  if (rightOut_)
206  {
207  path.lineTo (geometry ().size ().width () - h, geometry ().size ().height ());
208  path.arcTo (geometry ().size ().width () - (h * 2), 0, h * 2.0, h * 2.0, -90, 180);
209  }
210  else
211  {
212  path.lineTo (geometry ().size ().width () + h, geometry ().size ().height ());
213  path.arcTo (geometry ().size ().width (), 0, h * 2.0, h * 2.0, -90, -180);
214  }
215  path.lineTo (geometry ().size ().width () / 2, 0);
216 
217  _painter->setBrush (backgroundBrush_);
218  _painter->setPen (backgroundPen_);
219  _painter->drawPath (path);
220 
221 
222  QLinearGradient lG;
223 
224  lG.setStart (0, h);
225  lG.setFinalStop(0, h * 2);
226  lG.setColorAt(0, Qt::transparent);
227  lG.setColorAt(1, QColor (0, 0, 0, 192));
228 
229  _painter->setBrush (lG);
230  _painter->setPen (Qt::NoPen);
231  _painter->drawPath(path);
232 
233  lG.setStart (0, h);
234  lG.setFinalStop(0, 0);
235  lG.setColorAt(0, Qt::transparent);
236  lG.setColorAt(1, QColor (255, 255, 255, 192));
237 
238  QPen pen;
239  pen.setColor (Qt::transparent);
240  pen.setWidthF (4);
241  _painter->setBrush (lG);
242  _painter->setPen (pen);
243  _painter->drawPath(path);
244 
245  if (leftOut_)
246  _painter->translate (h, BACK_OFFSET);
247  else
248  _painter->translate (BACK_OFFSET * 2, BACK_OFFSET);
249  }
250 
251  QFontMetrics fn (font ());
252  int trans;
253  if (alignment_ == Qt::AlignHCenter)
254  {
255  trans = geometry ().size ().width ();
256 
257  if (backgroundSet_)
258  {
259  if (rightOut_)
260  trans -= h;
261  else
262  trans -= BACK_OFFSET * 2;
263  if (leftOut_)
264  trans -= h;
265  else
266  trans -= BACK_OFFSET * 2;
267  }
268 
269  _painter->translate ((trans - fn.boundingRect (QGraphicsSimpleTextItem::text ()).width ()) / 2, 0);
270  }
271  else if (alignment_ == Qt::AlignRight)
272  {
273  trans = geometry ().size ().width ();
274 
275  if (backgroundSet_)
276  {
277  if (rightOut_)
278  trans -= h;
279  else
280  trans -= BACK_OFFSET * 2;
281  if (leftOut_)
282  trans -= h;
283  else
284  trans -= BACK_OFFSET * 2;
285  }
286 
287  _painter->translate (trans - fn.boundingRect (QGraphicsSimpleTextItem::text ()).width (), 0);
288  }
289  else
290  {
291 
292  }
293 
294  QGraphicsSimpleTextItem::paint (_painter, _option, _widget);
295 }
296 
297 //------------------------------------------------------------------------------
298 
300 void Text::setBackground(bool _leftOut, bool _rightOut)
301 {
302  backgroundSet_ = true;
303  leftOut_ = _leftOut;
304  rightOut_ = _rightOut;
305  updateGeometry ();
306 }
307 
308 //------------------------------------------------------------------------------
309 
311 void Text::setAlignment(Qt::Alignment _alignment)
312 {
313  if (_alignment & Qt::AlignLeft)
314  alignment_ = Qt::AlignLeft;
315  else if (_alignment & Qt::AlignHCenter)
316  alignment_ = Qt::AlignHCenter;
317  else if (_alignment & Qt::AlignRight)
318  alignment_ = Qt::AlignRight;
319 }
320 
321 //------------------------------------------------------------------------------
322 
324 void Text::setHorizontalStretch(bool _stretch)
325 {
326  hStretch_ = _stretch;
327  updateGeometry ();
328 }
329 
330 //------------------------------------------------------------------------------
331 
334 {
335  backgroundSet_ = false;
336  updateGeometry ();
337 }
338 
339 //------------------------------------------------------------------------------
340 
342 QRectF Text::boundingRect() const
343 {
344  QFontMetrics fn (font ());
345  int x, w;
346 
347  if (!backgroundSet_)
348  {
349  QRectF rect = QGraphicsSimpleTextItem::boundingRect ();
350 
351  if (alignment_ == Qt::AlignHCenter)
352  rect.translate ((geometry ().size ().width () - fn.boundingRect (QGraphicsSimpleTextItem::text ()).width ()) / 2, 0);
353  else if (alignment_ == Qt::AlignRight)
354  rect.translate (geometry ().size ().width () - fn.boundingRect (QGraphicsSimpleTextItem::text ()).width (), 0);
355 
356  return rect;
357  }
358 
359  w = geometry ().size ().width ();
360  x = 0;
361 
362  if (!leftOut_)
363  {
364  w += (fn.height () / 2) + (BACK_OFFSET * 2);
365  x -= (fn.height () / 2) + (BACK_OFFSET * 2);
366  }
367 
368  if (!rightOut_)
369  {
370  w += (fn.height () / 2) + (BACK_OFFSET * 2);
371  }
372 
373  return QRectF (QPointF (x, 0), QSizeF(w, geometry ().size ().height ()));
374 }
375 
376 //------------------------------------------------------------------------------
377 
379 void Text::setBackgroundBrush(QBrush _brush)
380 {
381  backgroundBrush_ = _brush;
382  update ();
383 }
384 
385 //------------------------------------------------------------------------------
386 
388 void Text::setBackgroundPen(QPen _pen)
389 {
390  backgroundPen_ = _pen;
391  update ();
392 }
393 
394 //------------------------------------------------------------------------------
395 
397 QPainterPath Text::shape() const
398 {
399  if (!backgroundSet_)
400  {
401  QPainterPath shape = QGraphicsSimpleTextItem::shape ();
402 
403  QFontMetrics fn (font ());
404 
405  if (alignment_ == Qt::AlignHCenter || alignment_ == Qt::AlignRight)
406  {
407  QTransform trans;
408  if (alignment_ == Qt::AlignHCenter)
409  trans = QTransform::fromTranslate ((geometry ().size ().width () - fn.boundingRect (QGraphicsSimpleTextItem::text ()).width ()) / 2, 0);
410  else if (alignment_ == Qt::AlignRight)
411  trans = QTransform::fromTranslate (geometry ().size ().width () - fn.boundingRect (QGraphicsSimpleTextItem::text ()).width (), 0);
412 
413  QList<QPolygonF> poly = shape.toSubpathPolygons (trans);
414 
415  shape = QPainterPath ();
416 
417  foreach (const QPolygonF &p, poly)
418  shape.addPolygon(p);
419  }
420 
421  return shape;
422  }
423 
424  qreal h = geometry ().size ().height () / 2.0;
425 
426  QPainterPath path;
427 
428  path.moveTo (geometry ().size ().width () / 2, 0);
429  if (leftOut_)
430  {
431  path.lineTo (h, 0);
432  path.arcTo (0, 0, h * 2.0, h * 2.0, 90, 180);
433  }
434  else
435  {
436  path.lineTo (-h, 0);
437  path.arcTo (-h * 2, 0, h * 2.0, h * 2.0, 90, -180);
438  }
439 
440  if (rightOut_)
441  {
442  path.lineTo (geometry ().size ().width () - h, geometry ().size ().height ());
443  path.arcTo (geometry ().size ().width () - (h * 2), 0, h * 2.0, h * 2.0, -90, 180);
444  }
445  else
446  {
447  path.lineTo (geometry ().size ().width () + h, geometry ().size ().height ());
448  path.arcTo (geometry ().size ().width (), 0, h * 2.0, h * 2.0, -90, -180);
449  }
450  path.lineTo (geometry ().size ().width () / 2, 0);
451 
452  return path;
453 }
454 
455 //------------------------------------------------------------------------------
456 }
457 
void setAlignment(Qt::Alignment _alignment)
Placement of the text in a stretched widget.
Definition: text.cc:311
QPainterPath shape() const
Returns the shape for proper repainting/event handling.
Definition: text.cc:397
virtual void setGeometry(const QRectF &_rect)
Sets the geometry.
Definition: text.cc:102
void clearBackground()
Disables backgorund painting.
Definition: text.cc:333
virtual void setBackgroundPen(QPen _pen)
Sets the background pen.
Definition: text.cc:388
~Text()
Destrucotr.
Definition: text.cc:95
virtual void paint(QPainter *_painter, const QStyleOptionGraphicsItem *_option, QWidget *_widget=0)
Background painting.
Definition: text.cc:185
Text(QGraphicsItem *_parent=0)
Constructor.
Definition: text.cc:66
virtual void setBackgroundBrush(QBrush _brush)
Sets the background brush.
Definition: text.cc:379
virtual QRectF boundingRect() const
Bounding rectangle.
Definition: text.cc:342
void setBackground(bool _leftOut, bool _rightOut)
Enables background painting.
Definition: text.cc:300
void setHorizontalStretch(bool _stretch)
Should this widget be stretchable in horizontal direction.
Definition: text.cc:324