• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

Plasma

  • sources
  • kde-4.12
  • kdelibs
  • plasma
  • widgets
iconwidget.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2007 by Aaron Seigo <aseigo@kde.org>
3  * Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
4  * Copyright 2007 by Matt Broadstone <mbroadst@gmail.com>
5  * Copyright 2006-2007 Fredrik Höglund <fredrik@kde.org>
6  * Copyright 2007 by Marco Martin <notmart@gmail.com>
7  * Copyright 2008 by Alexis Ménard <darktears31@gmail.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU Library General Public License as
11  * published by the Free Software Foundation; either version 2, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this program; if not, write to the
21  * Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 
25 #include "iconwidget.h"
26 #include "iconwidget_p.h"
27 
28 #include <QAction>
29 #include <QApplication>
30 #include <QGraphicsSceneMouseEvent>
31 #include <QGraphicsView>
32 #include <QMenu>
33 #include <QPainter>
34 #include <QStyleOptionGraphicsItem>
35 #include <QTextLayout>
36 #include <QTimer>
37 
38 #include <kcolorscheme.h>
39 #include <kdebug.h>
40 #include <kglobalsettings.h>
41 #include <kicon.h>
42 #include <kiconeffect.h>
43 #include <kiconloader.h>
44 #include <kmimetype.h>
45 #include <kurl.h>
46 
47 #include "animator.h"
48 #include "animations/animation.h"
49 #include "paintutils.h"
50 #include "private/themedwidgetinterface_p.h"
51 #include "theme.h"
52 
53 #include "svg.h"
54 
55 /*
56 TODO:
57  Add these to a UrlIcon class
58  void setUrl(const KUrl& url);
59  KUrl url() const;
60 */
61 
62 namespace Plasma
63 {
64 
65 IconHoverAnimation::IconHoverAnimation(QObject *parent)
66  : QObject(parent), m_value(0), m_fadeIn(false)
67 {
68 }
69 
70 qreal IconHoverAnimation::value() const
71 {
72  return m_value;
73 }
74 
75 bool IconHoverAnimation::fadeIn() const
76 {
77  return m_fadeIn;
78 }
79 
80 QPropertyAnimation *IconHoverAnimation::animation() const
81 {
82  return m_animation.data();
83 }
84 
85 void IconHoverAnimation::setValue(qreal value)
86 {
87  m_value = value;
88  QGraphicsWidget *item = static_cast<QGraphicsWidget*>(parent());
89  item->update();
90 }
91 
92 void IconHoverAnimation::setFadeIn(bool fadeIn)
93 {
94  m_fadeIn = fadeIn;
95 }
96 
97 void IconHoverAnimation::setAnimation(QPropertyAnimation *animation)
98 {
99  m_animation = animation;
100 }
101 
102 IconWidgetPrivate::IconWidgetPrivate(IconWidget *i)
103  : ActionWidgetInterface<IconWidget>(i),
104  iconSvg(0),
105  hoverAnimation(new IconHoverAnimation(q)),
106  iconSize(48, 48),
107  preferredIconSize(-1, -1),
108  minimumIconSize(-1, -1),
109  maximumIconSize(-1, -1),
110  states(IconWidgetPrivate::NoState),
111  orientation(Qt::Vertical),
112  numDisplayLines(2),
113  activeMargins(0),
114  iconSvgElementChanged(false),
115  invertLayout(false),
116  drawBg(false),
117  textBgCustomized(false)
118 {
119 }
120 
121 IconWidgetPrivate::~IconWidgetPrivate()
122 {
123  qDeleteAll(cornerActions);
124  delete hoverAnimation;
125 }
126 
127 void IconWidgetPrivate::readColors()
128 {
129  textColor = Plasma::Theme::defaultTheme()->color(Theme::TextColor);
130 
131  if (qGray(textColor.rgb()) > 192) {
132  shadowColor = Qt::black;
133  } else {
134  shadowColor = Qt::white;
135  }
136 
137  if (!textBgCustomized) {
138  textBgColor = QColor();
139  }
140 }
141 
142 void IconWidgetPrivate::colorConfigChanged()
143 {
144  readColors();
145  if (drawBg) {
146  qreal left, top, right, bottom;
147  background->getMargins(left, top, right, bottom);
148  setVerticalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
149  setHorizontalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
150  }
151  q->update();
152 }
153 
154 void IconWidgetPrivate::iconConfigChanged()
155 {
156  if (!icon.isNull()) {
157  q->update();
158  }
159 }
160 
161 IconAction::IconAction(IconWidget *icon, QAction *action)
162  : m_icon(icon),
163  m_action(action),
164  m_hovered(false),
165  m_pressed(false),
166  m_selected(false),
167  m_visible(false)
168 {
169 }
170 
171 void IconAction::show()
172 {
173  Animation *animation = m_animation.data();
174  if (!animation) {
175  animation = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation, m_icon);
176  animation->setTargetWidget(m_icon);
177  m_animation = animation;
178  } else if (animation->state() == QAbstractAnimation::Running) {
179  animation->pause();
180  }
181 
182  rebuildPixmap();
183  m_visible = true;
184 
185  animation->setProperty("targetPixmap", m_pixmap);
186  animation->setDirection(QAbstractAnimation::Forward);
187  animation->start();
188 }
189 
190 void IconAction::hide()
191 {
192  if (!m_animation) {
193  return;
194  }
195 
196  Animation *animation = m_animation.data();
197  if (animation->state() == QAbstractAnimation::Running) {
198  animation->pause();
199  }
200 
201  m_visible = false;
202 
203  animation->setDirection(QAbstractAnimation::Backward);
204  animation->start(QAbstractAnimation::DeleteWhenStopped);
205 }
206 
207 bool IconAction::isVisible() const
208 {
209  return m_visible;
210 }
211 
212 bool IconAction::isAnimating() const
213 {
214  return !m_animation.isNull();
215 }
216 
217 bool IconAction::isPressed() const
218 {
219  return m_pressed;
220 }
221 
222 bool IconAction::isHovered() const
223 {
224  return m_hovered;
225 }
226 
227 void IconAction::setSelected(bool selected)
228 {
229  m_selected = selected;
230 }
231 
232 bool IconAction::isSelected() const
233 {
234  return m_selected;
235 }
236 
237 void IconAction::setRect(const QRectF &rect)
238 {
239  m_rect = rect;
240 }
241 
242 QRectF IconAction::rect() const
243 {
244  return m_rect;
245 }
246 
247 void IconAction::rebuildPixmap()
248 {
249  // Determine proper QIcon mode based on selection status
250  QIcon::Mode mode = m_selected ? QIcon::Selected : QIcon::Normal;
251 
252  // Draw everything
253  m_pixmap = QPixmap(26, 26);
254  m_pixmap.fill(Qt::transparent);
255 
256  int element = IconWidgetPrivate::Minibutton;
257  if (m_pressed) {
258  element = IconWidgetPrivate::MinibuttonPressed;
259  } else if (m_hovered) {
260  element = IconWidgetPrivate::MinibuttonHover;
261  }
262 
263  QPainter painter(&m_pixmap);
264  m_icon->drawActionButtonBase(&painter, m_pixmap.size(), element);
265  m_action->icon().paint(&painter, 2, 2, 22, 22, Qt::AlignCenter, mode);
266 }
267 
268 bool IconAction::event(QEvent::Type type, const QPointF &pos)
269 {
270  if (!m_action->isVisible() || !m_action->isEnabled()) {
271  return false;
272  }
273 
274  if (m_icon->size().width() < m_rect.width() * 2.0 ||
275  m_icon->size().height() < m_rect.height() * 2.0) {
276  return false;
277  }
278 
279  switch (type) {
280  case QEvent::GraphicsSceneMousePress:
281  {
282  setSelected(m_rect.contains(pos));
283  return isSelected();
284  }
285  break;
286 
287  case QEvent::GraphicsSceneMouseMove:
288  {
289  bool wasSelected = isSelected();
290  bool active = m_rect.contains(pos);
291  setSelected(wasSelected && active);
292  return (wasSelected != isSelected()) || active;
293  }
294  break;
295 
296  case QEvent::GraphicsSceneMouseRelease:
297  {
298  // kDebug() << "IconAction::event got a QEvent::MouseButtonRelease, " << isSelected();
299  bool wasSelected = isSelected();
300  setSelected(false);
301  if (wasSelected) {
302  m_action->trigger();
303  }
304 
305  return wasSelected;
306  }
307  break;
308 
309  case QEvent::GraphicsSceneHoverEnter:
310  m_pressed = false;
311  m_hovered = true;
312  break;
313 
314  case QEvent::GraphicsSceneHoverLeave:
315  m_pressed = false;
316  m_hovered = false;
317  break;
318 
319  default:
320  break;
321  }
322 
323  return false;
324 }
325 
326 QAction *IconAction::action() const
327 {
328  return m_action;
329 }
330 
331 void IconAction::paint(QPainter *painter) const
332 {
333  if (!m_action->isVisible() || !m_action->isEnabled()) {
334  return;
335  }
336 
337  if (m_icon->size().width() < m_rect.width() * 2.0 ||
338  m_icon->size().height() < m_rect.height() * 2.0) {
339  return;
340  }
341 
342  Animation *animation = m_animation.data();
343  if (m_visible && !animation) {
344  painter->drawPixmap(m_rect.toRect(), m_pixmap);
345  } else {
346  painter->drawPixmap(m_rect.toRect(),
347  animation->property("currentPixmap").value<QPixmap>());
348  }
349 }
350 
351 IconWidget::IconWidget(QGraphicsItem *parent)
352  : QGraphicsWidget(parent),
353  d(new IconWidgetPrivate(this))
354 {
355  d->init();
356 }
357 
358 IconWidget::IconWidget(const QString &text, QGraphicsItem *parent)
359  : QGraphicsWidget(parent),
360  d(new IconWidgetPrivate(this))
361 {
362  d->init();
363  setText(text);
364 }
365 
366 IconWidget::IconWidget(const QIcon &icon, const QString &text, QGraphicsItem *parent)
367  : QGraphicsWidget(parent),
368  d(new IconWidgetPrivate(this))
369 {
370  d->init();
371  setText(text);
372  setIcon(icon);
373 }
374 
375 IconWidget::~IconWidget()
376 {
377  delete d;
378 }
379 
380 void IconWidgetPrivate::init()
381 {
382  readColors();
383 
384  iconChangeTimer = new QTimer(q);
385  iconChangeTimer->setSingleShot(true);
386 
387  QObject::connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), q, SLOT(colorConfigChanged()));
388  QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorConfigChanged()));
389  QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), q, SLOT(iconConfigChanged()));
390 
391  // setAcceptedMouseButtons(Qt::LeftButton);
392  q->setAcceptsHoverEvents(true);
393  q->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
394 
395  background = new Plasma::FrameSvg(q);
396  background->setImagePath("widgets/viewitem");
397  background->setCacheAllRenderedFrames(true);
398  background->setElementPrefix("hover");
399 
400  // Margins for horizontal mode (list views, tree views, table views)
401  setHorizontalMargin(IconWidgetPrivate::TextMargin, 1, 1);
402  setHorizontalMargin(IconWidgetPrivate::IconMargin, 1, 1);
403  setHorizontalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
404 
405  // Margins for vertical mode (icon views)
406  setVerticalMargin(IconWidgetPrivate::TextMargin, 6, 2);
407  setVerticalMargin(IconWidgetPrivate::IconMargin, 1, 1);
408  setVerticalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
409 
410  setActiveMargins();
411  currentSize = QSizeF(-1, -1);
412  initTheming();
413 }
414 
415 void IconWidget::addIconAction(QAction *action)
416 {
417  int count = d->cornerActions.count();
418  if (count >= IconWidgetPrivate::LastIconPosition) {
419  kDebug() << "no more room for more actions!";
420  // just overlap it with the last item for now. ugly, but there you go.
421  }
422 
423  IconAction *iconAction = new IconAction(this, action);
424  d->cornerActions.append(iconAction);
425  connect(action, SIGNAL(destroyed(QObject*)), this, SLOT(actionDestroyed(QObject*)));
426 
427  iconAction->setRect(d->actionRect(qMin((IconWidgetPrivate::ActionPosition)count, IconWidgetPrivate::LastIconPosition)));
428 }
429 
430 void IconWidget::removeIconAction(QAction *action)
431 {
432  //WARNING: do NOT access the action pointer passed in, as it may already be
433  //be destroyed. see IconWidgetPrivate::actionDestroyed(QObject*)
434  int count = 0;
435  bool found = false;
436  foreach (IconAction *iconAction, d->cornerActions) {
437  if (found) {
438  iconAction->setRect(d->actionRect((IconWidgetPrivate::ActionPosition)count));
439  } else if (!action || iconAction->action() == action) {
440  delete iconAction;
441  d->cornerActions.removeAll(iconAction);
442  }
443 
444  if (count < IconWidgetPrivate::LastIconPosition) {
445  ++count;
446  }
447  }
448 
449  // redraw since an action has been deleted.
450  update();
451 }
452 
453 void IconWidgetPrivate::actionDestroyed(QObject *action)
454 {
455  q->removeIconAction(static_cast<QAction*>(action));
456 }
457 
458 void IconWidget::setAction(QAction *action)
459 {
460  d->setAction(action);
461 }
462 
463 QAction *IconWidget::action() const
464 {
465  return d->action;
466 }
467 
468 int IconWidget::numDisplayLines()
469 {
470  return d->numDisplayLines;
471 }
472 
473 void IconWidget::setNumDisplayLines(int numLines)
474 {
475  if (numLines > d->maxDisplayLines) {
476  d->numDisplayLines = d->maxDisplayLines;
477  } else {
478  d->numDisplayLines = numLines;
479  }
480 }
481 
482 void IconWidget::setDrawBackground(bool draw)
483 {
484  if (d->drawBg != draw) {
485  d->drawBg = draw;
486 
487  QStyle *style = QApplication::style();
488  int focusHMargin = draw ? style->pixelMetric(QStyle::PM_FocusFrameHMargin) : 1;
489  int focusVMargin = draw ? style->pixelMetric(QStyle::PM_FocusFrameVMargin) : 1;
490  d->setHorizontalMargin(IconWidgetPrivate::TextMargin, focusHMargin, focusVMargin);
491  d->setHorizontalMargin(IconWidgetPrivate::IconMargin, focusHMargin, focusVMargin);
492  d->setVerticalMargin(IconWidgetPrivate::IconMargin, focusHMargin, focusVMargin);
493  d->currentSize = QSizeF(-1, -1);
494 
495  if (draw) {
496  qreal left, top, right, bottom;
497  d->background->getMargins(left, top, right, bottom);
498  d->setHorizontalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
499  d->setVerticalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
500  } else {
501  d->setHorizontalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
502  d->setVerticalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
503  }
504 
505  update();
506  updateGeometry();
507  }
508 }
509 
510 bool IconWidget::drawBackground() const
511 {
512  return d->drawBg;
513 }
514 
515 QPainterPath IconWidget::shape() const
516 {
517  if (!d->drawBg || d->currentSize.width() < 1) {
518  return QGraphicsItem::shape();
519  }
520 
521  return PaintUtils::roundedRectangle(
522  QRectF(QPointF(0.0, 0.0), d->currentSize).adjusted(-2, -2, 2, 2), 10.0);
523 }
524 
525 QSizeF IconWidgetPrivate::displaySizeHint(const QStyleOptionGraphicsItem *option, const qreal width) const
526 {
527  if (text.isEmpty() && infoText.isEmpty()) {
528  return QSizeF(.0, .0);
529  }
530 
531  QString label = text;
532  // const qreal maxWidth = (orientation == Qt::Vertical) ? iconSize.width() + 10 : 32757;
533  // NOTE: find a way to use the other layoutText, it currently returns nominal width, when
534  // we actually need the actual width.
535 
536  qreal textWidth = width -
537  horizontalMargin[IconWidgetPrivate::TextMargin].left -
538  horizontalMargin[IconWidgetPrivate::TextMargin].right;
539 
540  //allow only five lines of text
541  const qreal maxHeight =
542  numDisplayLines * QFontMetrics(q->font()).lineSpacing();
543 
544  // To compute the nominal size for the label + info, we'll just append
545  // the information string to the label
546  if (!infoText.isEmpty()) {
547  label += QString(QChar::LineSeparator) + infoText;
548  }
549 
550  QTextLayout layout;
551  setLayoutOptions(layout, option, q->orientation());
552  layout.setFont(q->font());
553  QSizeF size = layoutText(layout, label, QSizeF(textWidth, maxHeight));
554 
555  return addMargin(size, TextMargin);
556 }
557 
558 void IconWidgetPrivate::layoutIcons(const QStyleOptionGraphicsItem *option)
559 {
560  if (option->rect.size() == currentSize) {
561  return;
562  }
563 
564  currentSize = option->rect.size();
565  iconSize = iconSizeForWidgetSize(option, currentSize);
566 
567  int count = 0;
568  foreach (IconAction *iconAction, cornerActions) {
569  iconAction->setRect(actionRect((IconWidgetPrivate::ActionPosition)count));
570  ++count;
571  }
572 }
573 
574 QSizeF IconWidgetPrivate::iconSizeForWidgetSize(const QStyleOptionGraphicsItem *option, const QSizeF &rect)
575 {
576  setActiveMargins();
577 
578  //calculate icon size based on the available space
579  qreal iconWidth;
580 
581  if (orientation == Qt::Vertical) {
582  qreal heightAvail;
583  //if there is text resize the icon in order to make room for the text
584  if (text.isEmpty() && infoText.isEmpty()) {
585  heightAvail = rect.height();
586  } else {
587  heightAvail = rect.height() -
588  displaySizeHint(option, rect.width()).height() -
589  verticalMargin[IconWidgetPrivate::TextMargin].top -
590  verticalMargin[IconWidgetPrivate::TextMargin].bottom;
591  //never make a label higher than half the total height
592  heightAvail = qMax(heightAvail, rect.height() / 2);
593  }
594 
595  //aspect ratio very "tall"
596  if (!text.isEmpty() || !infoText.isEmpty()) {
597  if (rect.width() < heightAvail) {
598  iconWidth = rect.width() -
599  verticalMargin[IconWidgetPrivate::IconMargin].left -
600  verticalMargin[IconWidgetPrivate::IconMargin].right;
601  } else {
602  iconWidth = heightAvail -
603  verticalMargin[IconWidgetPrivate::IconMargin].top -
604  verticalMargin[IconWidgetPrivate::IconMargin].bottom;
605  }
606  } else {
607  iconWidth = qMin(heightAvail, rect.width());
608  }
609 
610  iconWidth -= verticalMargin[IconWidgetPrivate::ItemMargin].left + verticalMargin[IconWidgetPrivate::ItemMargin].right;
611  } else {
612  //Horizontal layout
613  //if there is text resize the icon in order to make room for the text
614  if (text.isEmpty() && infoText.isEmpty()) {
615  // with no text, we just take up the whole geometry
616  iconWidth = qMin(rect.height(), rect.width());
617  } else {
618  iconWidth = rect.height() -
619  horizontalMargin[IconWidgetPrivate::IconMargin].top -
620  horizontalMargin[IconWidgetPrivate::IconMargin].bottom;
621  }
622  iconWidth -= horizontalMargin[IconWidgetPrivate::ItemMargin].top + horizontalMargin[IconWidgetPrivate::ItemMargin].bottom;
623  }
624 
625  QSizeF iconRect(iconWidth, iconWidth);
626 
627  if (maximumIconSize.isValid()) {
628  iconRect = iconRect.boundedTo(maximumIconSize);
629  }
630 
631  return iconRect;
632 }
633 
634 void IconWidget::setSvg(const QString &svgFilePath, const QString &elementId)
635 {
636  if (svgFilePath.isEmpty()) {
637  if (d->iconSvg) {
638  d->iconSvg->deleteLater();
639  d->iconSvg = 0;
640  }
641  return;
642  }
643 
644  if (!d->iconSvg) {
645  d->iconSvg = new Plasma::Svg(this);
646  connect(d->iconSvg, SIGNAL(repaintNeeded()), this, SLOT(svgChanged()));
647  d->oldIcon = d->icon;
648  } else {
649  d->oldIcon = d->iconSvg->pixmap(d->iconSvgElement);
650  }
651 
652  d->iconSvg->setImagePath(svgFilePath);
653  d->iconSvg->setContainsMultipleImages(!elementId.isNull());
654  d->iconSvgElement = elementId;
655  d->iconSvgElementChanged = true;
656  updateGeometry();
657 
658  if (!(d->states & IconWidgetPrivate::HoverState) && !d->iconChangeTimer->isActive() && !d->oldIcon.isNull()) {
659  d->animateMainIcon(true, d->states);
660  } else {
661  d->oldIcon = QIcon();
662  update();
663  }
664  d->iconChangeTimer->start(300);
665  d->icon = QIcon();
666 }
667 
668 QString IconWidget::svg() const
669 {
670  if (d->iconSvg) {
671  if (d->iconSvg->isValid() && (d->iconSvgElement.isEmpty() || d->iconSvg->hasElement(d->iconSvgElement))) {
672  return d->iconSvg->imagePath();
673  } else {
674  return QString();
675  }
676  }
677 
678  return QString();
679 }
680 
681 QSizeF IconWidget::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
682 {
683  if (which == Qt::PreferredSize) {
684  int iconSize;
685 
686  if (d->preferredIconSize.isValid()) {
687  iconSize = qMax(d->preferredIconSize.height(), d->preferredIconSize.width());
688  } else if (d->iconSvg) {
689  QSizeF oldSize = d->iconSvg->size();
690  d->iconSvg->resize();
691  if (d->iconSvgElement.isNull()) {
692  iconSize = qMax(d->iconSvg->size().width(), d->iconSvg->size().height());
693  } else {
694  iconSize = qMax(d->iconSvg->elementSize(d->iconSvgElement).width(), d->iconSvg->elementSize(d->iconSvgElement).height());
695  }
696  d->iconSvg->resize(oldSize);
697  } else {
698  iconSize = KIconLoader::SizeMedium;
699  }
700 
701  if (constraint.width() > 0 || constraint.height() > 0) {
702  QSizeF constrainedWidgetSize(constraint);
703  QSizeF maximumWidgetSize;
704 
705  if (d->maximumIconSize.isValid()) {
706  maximumWidgetSize =
707  sizeFromIconSize(qMax(d->maximumIconSize.height(), d->maximumIconSize.width()));
708  } else {
709  maximumWidgetSize =
710  QGraphicsWidget::sizeHint(Qt::MaximumSize);
711  }
712 
713  if (constrainedWidgetSize.width() <= 0) {
714  constrainedWidgetSize.setWidth(maximumWidgetSize.width());
715  }
716  if (constrainedWidgetSize.height() <= 0) {
717  constrainedWidgetSize.setHeight(maximumWidgetSize.height());
718  }
719 
720  QStyleOptionGraphicsItem option;
721  QSizeF iconRect =
722  d->iconSizeForWidgetSize(&option, constrainedWidgetSize);
723  iconSize =
724  qMin(iconSize, qMax<int>(iconRect.width(), iconRect.height()));
725  }
726 
727  return sizeFromIconSize(iconSize);
728  } else if (which == Qt::MinimumSize) {
729  if (d->minimumIconSize.isValid()) {
730  return sizeFromIconSize(qMax(d->minimumIconSize.height(), d->minimumIconSize.width()));
731  }
732 
733  return sizeFromIconSize(KIconLoader::SizeSmall);
734  } else {
735  if (d->maximumIconSize.isValid()) {
736  return sizeFromIconSize(qMax(d->maximumIconSize.height(), d->maximumIconSize.width()));
737  }
738 
739  return QGraphicsWidget::sizeHint(which, constraint);
740  }
741 }
742 
743 void IconWidgetPrivate::animateMainIcon(bool show, const IconWidgetStates state)
744 {
745  if (show) {
746  states = state;
747  }
748 
749  hoverAnimation->setFadeIn(show);
750 
751  QPropertyAnimation *animation = hoverAnimation->animation();
752  if (!animation) {
753  animation = new QPropertyAnimation(hoverAnimation, "value");
754  animation->setDuration(150);
755  animation->setEasingCurve(QEasingCurve::OutQuad);
756  animation->setStartValue(0.0);
757  animation->setEndValue(1.0);
758  hoverAnimation->setAnimation(animation);
759  q->connect(animation, SIGNAL(finished()), q, SLOT(hoverAnimationFinished()));
760  } else if (animation->state() == QAbstractAnimation::Running) {
761  animation->pause();
762  }
763 
764  animation->setDirection(show ? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
765  animation->start(show ? QAbstractAnimation::KeepWhenStopped : QAbstractAnimation::DeleteWhenStopped);
766  q->update();
767 }
768 
769 void IconWidgetPrivate::hoverAnimationFinished()
770 {
771  if (!hoverAnimation->fadeIn()) {
772  states &= ~IconWidgetPrivate::HoverState;
773  }
774 }
775 
776 void IconWidgetPrivate::drawBackground(QPainter *painter, IconWidgetState state)
777 {
778  if (!drawBg) {
779  return;
780  }
781 
782  if (!(states & IconWidgetPrivate::HoverState) && !(states & IconWidgetPrivate::PressedState)) {
783  return;
784  }
785 
786  if (state == IconWidgetPrivate::PressedState) {
787  background->setElementPrefix("selected");
788  } else {
789  background->setElementPrefix("hover");
790  }
791 
792  if (qFuzzyCompare(hoverAnimation->value(), 1)) {
793  background->resizeFrame(currentSize);
794  background->paintFrame(painter);
795  } else if (!qFuzzyCompare(hoverAnimation->value()+1, 1)) {
796  background->resizeFrame(currentSize);
797  QPixmap frame = background->framePixmap();
798  QPainter bufferPainter(&frame);
799  bufferPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
800  bufferPainter.fillRect(frame.rect(), QColor(0,0,0, 255*hoverAnimation->value()));
801  bufferPainter.end();
802  painter->drawPixmap(QPoint(0,0), frame);
803  }
804 }
805 
806 QPixmap IconWidgetPrivate::decoration(const QStyleOptionGraphicsItem *option, bool useHoverEffect, bool usePressedEffect)
807 {
808  QPixmap result;
809 
810  QIcon::Mode mode = option->state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled;
811  QIcon::State state = option->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
812 
813  QSize finalSize(iconSize.toSize());
814  //for small sizes, use a standard size
815  if (finalSize.width() < KIconLoader::SizeSmallMedium) {
816  finalSize = QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
817  } else if (finalSize.width() < KIconLoader::SizeMedium) {
818  finalSize = QSize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium);
819  } else if (finalSize.width() < KIconLoader::SizeLarge) {
820  finalSize = QSize(KIconLoader::SizeMedium, KIconLoader::SizeMedium);
821  }
822 
823  if (iconSvg) {
824  if (iconSvgElementChanged || iconSvgPixmap.size() != iconSize.toSize()) {
825  //even the svg is returned at standard sizes because:
826  // * it may have a version optimized for that size
827  // * look aligned with other icons
828  iconSvg->resize(finalSize);
829  iconSvgPixmap = iconSvg->pixmap(iconSvgElement);
830  iconSvgElementChanged = false;
831  }
832  result = iconSvgPixmap;
833  } else {
834  QSize size(iconSize.toSize());
835  //the QIcon isn't filled with available sizes, return a near standard size for small pixmaps
836  if (!icon.availableSizes().isEmpty()) {
837  finalSize = icon.actualSize(iconSize.toSize(), mode, state);
838  }
839 
840  result = icon.pixmap(finalSize, mode, state);
841  }
842 
843  if (usePressedEffect) {
844  result = result.scaled(result.size() * 0.9, Qt::KeepAspectRatio, Qt::SmoothTransformation);
845  }
846 
847  if (!result.isNull() && useHoverEffect) {
848  KIconEffect *effect = KIconLoader::global()->iconEffect();
849  // Note that in KIconLoader terminology, active = hover.
850  // We're assuming that the icon group is desktop/filemanager, since this
851  // is KFileItemDelegate.
852  if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
853  if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) {
854  result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState);
855  } else {
856  result = PaintUtils::transition(
857  result,
858  effect->apply(result, KIconLoader::Desktop,
859  KIconLoader::ActiveState), hoverAnimation->value());
860  }
861  }
862  } else if (!result.isNull() && !oldIcon.isNull()) {
863  if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) {
864  oldIcon = QIcon();
865  } else {
866  result = PaintUtils::transition(
867  oldIcon.pixmap(result.size(), mode, state),
868  result, hoverAnimation->value());
869  }
870  }
871 
872  return result;
873 }
874 
875 QPointF IconWidgetPrivate::iconPosition(const QStyleOptionGraphicsItem *option,
876  const QPixmap &pixmap) const
877 {
878  const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
879 
880  // Compute the nominal decoration rectangle
881  const QSizeF size = addMargin(iconSize, IconWidgetPrivate::IconMargin);
882 
883  Qt::LayoutDirection direction = iconDirection(option);
884 
885  //alignment depends from orientation and option->direction
886  Qt::Alignment alignment;
887  if (text.isEmpty() && infoText.isEmpty()) {
888  alignment = Qt::AlignCenter;
889  } else if (orientation == Qt::Vertical) {
890  alignment = Qt::Alignment(Qt::AlignHCenter | Qt::AlignTop);
891  //Horizontal
892  } else {
893  alignment = QStyle::visualAlignment(
894  direction, Qt::Alignment(Qt::AlignLeft | Qt::AlignVCenter));
895  }
896 
897  const QRect iconRect =
898  QStyle::alignedRect(direction, alignment, size.toSize(), itemRect.toRect());
899 
900  // Position the pixmap in the center of the rectangle
901  QRect pixmapRect = pixmap.rect();
902  pixmapRect.moveCenter(iconRect.center());
903 
904  // add a gimmicky margin of 5px to y, TEMP TEMP TEMP
905  // pixmapRect = pixmapRect.adjusted(0, 5, 0, 0);
906 
907  return QPointF(pixmapRect.topLeft());
908 }
909 
910 QRectF IconWidgetPrivate::labelRectangle(const QStyleOptionGraphicsItem *option,
911  const QPixmap &icon,
912  const QString &string) const
913 {
914  Q_UNUSED(string)
915 
916  if (icon.isNull()) {
917  return option->rect;
918  }
919 
920  const QSizeF decoSize = addMargin(iconSize, IconWidgetPrivate::IconMargin);
921  const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
922  QRectF textArea(QPointF(0, 0), itemRect.size());
923 
924  if (orientation == Qt::Vertical) {
925  textArea.setTop(decoSize.height() + 1);
926  } else {
927  //Horizontal
928  textArea.setLeft(decoSize.width() + 1);
929  }
930 
931  textArea.translate(itemRect.topLeft());
932  return QRectF(QStyle::visualRect(iconDirection(option), option->rect, textArea.toRect()));
933 }
934 
935 // Lays the text out in a rectangle no larger than constraints, eliding it as necessary
936 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout,
937  const QString &text,
938  const QSizeF &constraints) const
939 {
940  const QSizeF size = layoutText(layout, text, constraints.width());
941 
942  if (size.width() > constraints.width() || size.height() > constraints.height()) {
943  if (action) {
944  q->setToolTip(action->toolTip());
945  }
946  const QString elided = elidedText(layout, constraints);
947  return layoutText(layout, elided, constraints.width());
948  }
949  q->setToolTip(QString());
950 
951  return size;
952 }
953 
954 // Lays the text out in a rectangle no wider than maxWidth
955 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout, const QString &text, qreal maxWidth) const
956 {
957  QFontMetricsF metrics(layout.font());
958  qreal leading = metrics.leading();
959  qreal height = 0.0;
960  qreal widthUsed = 0.0;
961  QTextLine line;
962 
963  layout.setText(text);
964 
965  layout.beginLayout();
966 
967  while ((line = layout.createLine()).isValid()) {
968  line.setLineWidth(maxWidth);
969  height += leading;
970  line.setPosition(QPointF(0.0, height));
971  height += line.height();
972  widthUsed = qMax(widthUsed, line.naturalTextWidth());
973  }
974  layout.endLayout();
975 
976  return QSizeF(widthUsed, height);
977 }
978 
979 // Elides the text in the layout, by iterating over each line in the layout, eliding
980 // or word breaking the line if it's wider than the max width, and finally adding an
981 // ellipses at the end of the last line, if there are more lines than will fit within
982 // the vertical size constraints.
983 QString IconWidgetPrivate::elidedText(QTextLayout &layout, const QSizeF &size) const
984 {
985  QFontMetricsF metrics(layout.font());
986  const QString text = layout.text();
987  qreal maxWidth = size.width();
988  qreal maxHeight = size.height();
989  qreal height = 0;
990 
991  // Elide each line that has already been laid out in the layout.
992  QString elided;
993  elided.reserve(text.length());
994 
995  for (int i = 0; i < layout.lineCount(); i++) {
996  QTextLine line = layout.lineAt(i);
997  int start = line.textStart();
998  int length = line.textLength();
999 
1000  height += metrics.leading();
1001  if (height + line.height() + metrics.lineSpacing() > maxHeight) {
1002  // Unfortunately, if the line ends because of a line separator,
1003  // elidedText() will be too clever and keep adding lines until
1004  // it finds one that's too wide.
1005  if (line.naturalTextWidth() < maxWidth &&
1006  start + length > 0 &&
1007  text[start + length - 1] == QChar::LineSeparator) {
1008  elided += text.mid(start, length - 1);
1009  } else {
1010  elided += metrics.elidedText(text.mid(start), Qt::ElideRight, maxWidth);
1011  }
1012  break;
1013  } else if (line.naturalTextWidth() > maxWidth) {
1014  elided += metrics.elidedText(text.mid(start, length), Qt::ElideRight, maxWidth);
1015  } else {
1016  elided += text.mid(start, length);
1017  }
1018 
1019  height += line.height();
1020  }
1021 
1022  return elided;
1023 }
1024 
1025 void IconWidgetPrivate::layoutTextItems(const QStyleOptionGraphicsItem *option,
1026  const QPixmap &icon, QTextLayout *labelLayout,
1027  QTextLayout *infoLayout, QRectF *textBoundingRect) const
1028 {
1029  bool showInformation = false;
1030 
1031  setLayoutOptions(*labelLayout, option, q->orientation());
1032 
1033  QFontMetricsF fm(labelLayout->font());
1034  const QRectF textArea = labelRectangle(option, icon, text);
1035  QRectF textRect = subtractMargin(textArea, IconWidgetPrivate::TextMargin);
1036 
1037  //kDebug() << this << "text area" << textArea << "text rect" << textRect;
1038  // Sizes and constraints for the different text parts
1039  QSizeF maxLabelSize = textRect.size();
1040  QSizeF maxInfoSize = textRect.size();
1041  QSizeF labelSize;
1042  QSizeF infoSize;
1043 
1044  // If we have additional info text, and there's space for at least two lines of text,
1045  // adjust the max label size to make room for at least one line of the info text
1046  if (!infoText.isEmpty() && textRect.height() >= fm.lineSpacing() * 2) {
1047  infoLayout->setFont(labelLayout->font());
1048  infoLayout->setTextOption(labelLayout->textOption());
1049 
1050  maxLabelSize.rheight() -= fm.lineSpacing();
1051  showInformation = true;
1052  }
1053 
1054  // Lay out the label text, and adjust the max info size based on the label size
1055  labelSize = layoutText(*labelLayout, text, maxLabelSize);
1056  maxInfoSize.rheight() -= labelSize.height();
1057 
1058  // Lay out the info text
1059  if (showInformation) {
1060  infoSize = layoutText(*infoLayout, infoText, maxInfoSize);
1061  } else {
1062  infoSize = QSizeF(0, 0);
1063  }
1064  // Compute the bounding rect of the text
1065  const Qt::Alignment alignment = labelLayout->textOption().alignment();
1066  const QSizeF size(qMax(labelSize.width(), infoSize.width()),
1067  labelSize.height() + infoSize.height());
1068  *textBoundingRect =
1069  QStyle::alignedRect(iconDirection(option), alignment, size.toSize(), textRect.toRect());
1070 
1071  // Compute the positions where we should draw the layouts
1072  haloRects.clear();
1073  labelLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y()));
1074  QTextLine line;
1075  for (int i = 0; i < labelLayout->lineCount(); ++i) {
1076  line = labelLayout->lineAt(i);
1077  haloRects.append(line.naturalTextRect().translated(labelLayout->position().toPoint()).toRect());
1078  }
1079  infoLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y() + labelSize.height()));
1080  for (int i = 0; i < infoLayout->lineCount(); ++i) {
1081  line = infoLayout->lineAt(i);
1082  haloRects.append(line.naturalTextRect().translated(infoLayout->position().toPoint()).toRect());
1083  }
1084  //kDebug() << "final position is" << labelLayout->position();
1085 }
1086 
1087 QBrush IconWidgetPrivate::foregroundBrush(const QStyleOptionGraphicsItem *option) const
1088 {
1089  const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
1090  QPalette::Normal : QPalette::Disabled;
1091 
1092  // Always use the highlight color for selected items
1093  if (option->state & QStyle::State_Selected) {
1094  return option->palette.brush(group, QPalette::HighlightedText);
1095  }
1096  return option->palette.brush(group, QPalette::Text);
1097 }
1098 
1099 QBrush IconWidgetPrivate::backgroundBrush(const QStyleOptionGraphicsItem *option) const
1100 {
1101  const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
1102  QPalette::Normal : QPalette::Disabled;
1103 
1104  QBrush background(Qt::NoBrush);
1105 
1106  // Always use the highlight color for selected items
1107  if (option->state & QStyle::State_Selected) {
1108  background = option->palette.brush(group, QPalette::Highlight);
1109  }
1110  return background;
1111 }
1112 
1113 void IconWidgetPrivate::drawTextItems(QPainter *painter,
1114  const QStyleOptionGraphicsItem *option,
1115  const QTextLayout &labelLayout,
1116  const QTextLayout &infoLayout) const
1117 {
1118  Q_UNUSED(option)
1119 
1120  painter->save();
1121  painter->setPen(textColor);
1122 
1123  // the translation prevents odd rounding errors in labelLayout.position()
1124  // when applied to the canvas
1125  painter->translate(0.5, 0.5);
1126 
1127  labelLayout.draw(painter, QPointF());
1128 
1129  if (!infoLayout.text().isEmpty()) {
1130  painter->setPen(textColor);
1131  infoLayout.draw(painter, QPointF());
1132  }
1133  painter->restore();
1134 }
1135 
1136 void IconWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
1137 {
1138  Q_UNUSED(widget);
1139 
1140  //Lay out the main icon and action icons
1141  d->layoutIcons(option);
1142 
1143  // Compute the metrics, and lay out the text items
1144  // ========================================================================
1145  IconWidgetPrivate::IconWidgetState state = IconWidgetPrivate::NoState;
1146  if (d->states & IconWidgetPrivate::ManualPressedState) {
1147  state = IconWidgetPrivate::PressedState;
1148  } else if (d->states & IconWidgetPrivate::PressedState) {
1149  if (d->states & IconWidgetPrivate::HoverState) {
1150  state = IconWidgetPrivate::PressedState;
1151  }
1152  } else if (d->states & IconWidgetPrivate::HoverState) {
1153  state = IconWidgetPrivate::HoverState;
1154  }
1155 
1156  QPixmap icon = d->decoration(option, state != IconWidgetPrivate::NoState, state & IconWidgetPrivate::PressedState);
1157  const QPointF iconPos = d->iconPosition(option, icon);
1158 
1159  d->drawBackground(painter, state);
1160 
1161  // draw icon
1162  if (!icon.isNull()) {
1163  painter->drawPixmap(iconPos, icon);
1164  }
1165 
1166  // Draw corner actions
1167  foreach (const IconAction *action, d->cornerActions) {
1168  if (action->isAnimating()) {
1169  action->paint(painter);
1170  }
1171  }
1172 
1173  // Draw text last because it is overlayed
1174  QTextLayout labelLayout, infoLayout;
1175  QRectF textBoundingRect;
1176 
1177  d->layoutTextItems(option, icon, &labelLayout, &infoLayout, &textBoundingRect);
1178 
1179  if (d->textBgColor != QColor() && d->textBgColor.alpha() > 0 &&
1180  !(d->text.isEmpty() && d->infoText.isEmpty()) &&
1181  !textBoundingRect.isEmpty() &&
1182  !qFuzzyCompare(d->hoverAnimation->value(), (qreal)1.0)) {
1183  QRectF rect = textBoundingRect.adjusted(-2, -2, 4, 4).toAlignedRect();
1184  painter->setPen(Qt::transparent);
1185  QColor color = d->textBgColor;
1186  color.setAlpha(60 * (1.0 - d->hoverAnimation->value()));
1187  QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
1188  gradient.setColorAt(0, color.lighter(120));
1189  gradient.setColorAt(1, color.darker(120));
1190  painter->setBrush(gradient);
1191  gradient.setColorAt(0, color.lighter(130));
1192  gradient.setColorAt(1, color.darker(130));
1193  painter->setPen(QPen(gradient, 0));
1194  painter->setRenderHint(QPainter::Antialiasing);
1195  painter->drawPath(PaintUtils::roundedRectangle(rect.translated(0.5, 0.5), 4));
1196  }
1197 
1198 
1199  if (d->shadowColor.value() < 128 || textBackgroundColor() != QColor()) {
1200  QPoint shadowPos;
1201  if (d->shadowColor.value() < 128) {
1202  shadowPos = QPoint(1, 2);
1203  } else {
1204  shadowPos = QPoint(0, 0);
1205  }
1206 
1207  QImage shadow(textBoundingRect.size().toSize() + QSize(4, 4),
1208  QImage::Format_ARGB32_Premultiplied);
1209  shadow.fill(Qt::transparent);
1210  {
1211  QPainter buffPainter(&shadow);
1212  buffPainter.translate(-textBoundingRect.x(), -textBoundingRect.y());
1213  d->drawTextItems(&buffPainter, option, labelLayout, infoLayout);
1214  }
1215 
1216  PaintUtils::shadowBlur(shadow, 2, d->shadowColor);
1217  painter->drawImage(textBoundingRect.topLeft() + shadowPos, shadow);
1218  } else if (!(d->text.isEmpty() && d->infoText.isEmpty()) &&
1219  !textBoundingRect.isEmpty()) {
1220  QRect labelRect = d->labelRectangle(option, icon, d->text).toRect();
1221 
1222  foreach (const QRect &rect, d->haloRects) {
1223  Plasma::PaintUtils::drawHalo(painter, rect);
1224  }
1225  }
1226 
1227  d->drawTextItems(painter, option, labelLayout, infoLayout);
1228 }
1229 
1230 void IconWidget::setTextBackgroundColor(const QColor &color)
1231 {
1232  d->textBgCustomized = true;
1233  d->textBgColor = color;
1234  update();
1235 }
1236 
1237 QColor IconWidget::textBackgroundColor() const
1238 {
1239  return d->textBgColor;
1240 }
1241 
1242 void IconWidget::drawActionButtonBase(QPainter *painter, const QSize &size, int element)
1243 {
1244  qreal radius = size.width() / 2;
1245  QRadialGradient gradient(radius, radius, radius, radius, radius);
1246  int alpha;
1247 
1248  if (element == IconWidgetPrivate::MinibuttonPressed) {
1249  alpha = 255;
1250  } else if (element == IconWidgetPrivate::MinibuttonHover) {
1251  alpha = 200;
1252  } else {
1253  alpha = 160;
1254  }
1255  gradient.setColorAt(0, QColor::fromRgb(d->textColor.red(),
1256  d->textColor.green(),
1257  d->textColor.blue(), alpha));
1258  gradient.setColorAt(1, QColor::fromRgb(d->textColor.red(),
1259  d->textColor.green(),
1260  d->textColor.blue(), 0));
1261 
1262  painter->setBrush(gradient);
1263  painter->setPen(Qt::NoPen);
1264  painter->drawEllipse(QRectF(QPointF(.0, .0), size));
1265 }
1266 
1267 void IconWidget::setText(const QString &text)
1268 {
1269  d->text = KGlobal::locale()->removeAcceleratorMarker(text);
1270  // cause a relayout
1271  d->currentSize = QSizeF(-1, -1);
1272  //try to relayout, needed if an icon was never shown before
1273  if (!isVisible()) {
1274  QStyleOptionGraphicsItem styleoption;
1275  d->layoutIcons(&styleoption);
1276  }
1277  updateGeometry();
1278  if (!parentWidget() || !parentWidget()->layout()) {
1279  resize(preferredSize());
1280  }
1281 }
1282 
1283 QString IconWidget::text() const
1284 {
1285  return d->text;
1286 }
1287 
1288 void IconWidget::setInfoText(const QString &text)
1289 {
1290  d->infoText = text;
1291  // cause a relayout
1292  d->currentSize = QSizeF(-1, -1);
1293  //try to relayout, needed if an icon was never shown before
1294  if (!isVisible()) {
1295  QStyleOptionGraphicsItem styleoption;
1296  d->layoutIcons(&styleoption);
1297  }
1298  updateGeometry();
1299  if (!parentWidget() || !parentWidget()->layout()) {
1300  resize(preferredSize());
1301  }
1302 }
1303 
1304 QString IconWidget::infoText() const
1305 {
1306  return d->infoText;
1307 }
1308 
1309 QIcon IconWidget::icon() const
1310 {
1311  return d->icon;
1312 }
1313 
1314 void IconWidget::setIcon(const QString &icon)
1315 {
1316  if (icon.isEmpty()) {
1317  setIcon(QIcon());
1318  return;
1319  }
1320 
1321  setIcon(KIcon(icon));
1322 }
1323 
1324 void IconWidget::setIcon(const QIcon &icon)
1325 {
1326  setSvg(QString());
1327 
1328  /*fade to the new icon, but to not bee a too big hog, not do that when:
1329  - the fade animation is already running
1330  - the icon is under mouse
1331  - one betwen the old and new icon is null*/
1332  if (!(d->states & IconWidgetPrivate::HoverState) && !d->iconChangeTimer->isActive() && d->oldIcon.isNull() && !d->icon.isNull() && !icon.isNull()) {
1333  d->oldIcon = d->icon;
1334  d->animateMainIcon(true, d->states);
1335  } else {
1336  d->oldIcon = QIcon();
1337  }
1338  d->iconChangeTimer->start(300);
1339  d->icon = icon;
1340  update();
1341 }
1342 
1343 QSizeF IconWidget::iconSize() const
1344 {
1345  return d->iconSize;
1346 }
1347 
1348 void IconWidget::setPreferredIconSize(const QSizeF &size)
1349 {
1350  d->preferredIconSize = size;
1351  updateGeometry();
1352 }
1353 
1354 QSizeF IconWidget::preferredIconSize() const
1355 {
1356  return d->preferredIconSize;
1357 }
1358 
1359 void IconWidget::setMinimumIconSize(const QSizeF &size)
1360 {
1361  d->minimumIconSize = size;
1362  updateGeometry();
1363 }
1364 
1365 QSizeF IconWidget::minimumIconSize() const
1366 {
1367  return d->minimumIconSize;
1368 }
1369 
1370 void IconWidget::setMaximumIconSize(const QSizeF &size)
1371 {
1372  d->maximumIconSize = size;
1373  updateGeometry();
1374 }
1375 
1376 QSizeF IconWidget::maximumIconSize() const
1377 {
1378  return d->maximumIconSize;
1379 }
1380 
1381 bool IconWidget::isDown()
1382 {
1383  return d->states & IconWidgetPrivate::PressedState;
1384 }
1385 
1386 void IconWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
1387 {
1388  if (event->button() != Qt::LeftButton) {
1389  QGraphicsWidget::mousePressEvent(event);
1390  return;
1391  }
1392 
1393  if (KGlobalSettings::singleClick() || (receivers(SIGNAL(clicked()))) > 0) {
1394  d->states |= IconWidgetPrivate::PressedState;
1395  }
1396  d->clickStartPos = scenePos();
1397 
1398  bool handled = false;
1399  foreach (IconAction *action, d->cornerActions) {
1400  handled = action->event(event->type(), event->pos());
1401  if (handled) {
1402  break;
1403  }
1404  }
1405 
1406  if (!handled && boundingRect().contains(event->pos())) {
1407  emit pressed(true);
1408  }
1409 
1410  update();
1411 }
1412 
1413 void IconWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1414 {
1415  if (~d->states & IconWidgetPrivate::PressedState) {
1416  QGraphicsWidget::mouseMoveEvent(event);
1417  return;
1418  }
1419 
1420  if (boundingRect().contains(event->pos())) {
1421  if (~d->states & IconWidgetPrivate::HoverState) {
1422  d->states |= IconWidgetPrivate::HoverState;
1423  update();
1424  }
1425  } else {
1426  if (d->states & IconWidgetPrivate::HoverState) {
1427  d->states &= ~IconWidgetPrivate::HoverState;
1428  update();
1429  }
1430  }
1431 }
1432 
1433 void IconWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1434 {
1435  if (~d->states & IconWidgetPrivate::PressedState) {
1436  QGraphicsWidget::mouseMoveEvent(event);
1437  return;
1438  }
1439 
1440  d->states &= ~IconWidgetPrivate::PressedState;
1441 
1442  //don't pass click when the mouse was moved
1443  bool handled = d->clickStartPos != scenePos();
1444  if (!handled) {
1445  foreach (IconAction *action, d->cornerActions) {
1446  if (action->event(event->type(), event->pos())) {
1447  handled = true;
1448  break;
1449  }
1450  }
1451  }
1452 
1453  if (!handled) {
1454  if (boundingRect().contains(event->pos())) {
1455  emit clicked();
1456  if (KGlobalSettings::singleClick()) {
1457  emit activated();
1458  }
1459 
1460  if (d->action && d->action->menu()) {
1461  d->action->menu()->popup(event->screenPos());
1462  }
1463  }
1464  emit pressed(false);
1465  }
1466 
1467  update();
1468 }
1469 
1470 void IconWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1471 {
1472  Q_UNUSED(event)
1473 
1474  d->states |= IconWidgetPrivate::PressedState;
1475 
1476  emit doubleClicked();
1477  if (!KGlobalSettings::singleClick()) {
1478  emit activated();
1479  }
1480 
1481  update();
1482 }
1483 
1484 void IconWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
1485 {
1486  //kDebug();
1487  foreach (IconAction *action, d->cornerActions) {
1488  action->show();
1489  action->event(event->type(), event->pos());
1490  }
1491 
1492  d->oldIcon = QIcon();
1493  d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState);
1494 
1495  QGraphicsWidget::hoverEnterEvent(event);
1496 }
1497 
1498 void IconWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
1499 {
1500  //kDebug() << d->cornerActions;
1501  foreach (IconAction *action, d->cornerActions) {
1502  action->hide();
1503  action->event(event->type(), event->pos());
1504  }
1505  // d->states &= ~IconWidgetPrivate::HoverState; // Will be set once progress is zero again ...
1506  //if an eventfilter stolen the mousereleaseevent remove the pressed state here
1507  d->states &= ~IconWidgetPrivate::PressedState;
1508 
1509  d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState);
1510 
1511  QGraphicsWidget::hoverLeaveEvent(event);
1512 }
1513 
1514 bool IconWidget::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
1515 {
1516  Q_UNUSED(watched)
1517 
1518  if (event->type() == QEvent::GraphicsSceneDragEnter) {
1519  d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState);
1520  } else if (event->type() == QEvent::GraphicsSceneDragLeave) {
1521  d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState);
1522  }
1523 
1524  return false;
1525 }
1526 
1527 void IconWidget::setPressed(bool pressed)
1528 {
1529  if (pressed) {
1530  d->states |= IconWidgetPrivate::ManualPressedState;
1531  d->states |= IconWidgetPrivate::PressedState;
1532  } else {
1533  d->states &= ~IconWidgetPrivate::ManualPressedState;
1534  d->states &= ~IconWidgetPrivate::PressedState;
1535  }
1536  update();
1537 }
1538 
1539 void IconWidget::setUnpressed()
1540 {
1541  setPressed(false);
1542 }
1543 
1544 void IconWidgetPrivate::svgChanged()
1545 {
1546  iconSvgElementChanged = true;
1547  q->update();
1548 }
1549 
1550 void IconWidget::setOrientation(Qt::Orientation orientation)
1551 {
1552  d->orientation = orientation;
1553  resize(sizeFromIconSize(d->iconSize.width()));
1554 }
1555 
1556 Qt::Orientation IconWidget::orientation() const
1557 {
1558  return d->orientation;
1559 }
1560 
1561 void IconWidget::invertLayout(bool invert)
1562 {
1563  d->invertLayout = invert;
1564 }
1565 
1566 bool IconWidget::invertedLayout() const
1567 {
1568  return d->invertLayout;
1569 }
1570 
1571 QSizeF IconWidget::sizeFromIconSize(const qreal iconWidth) const
1572 {
1573  d->setActiveMargins();
1574  if (d->text.isEmpty() && d->infoText.isEmpty()) {
1575  //no text, just the icon size
1576  return d->addMargin(QSizeF(iconWidth, iconWidth), IconWidgetPrivate::ItemMargin);
1577  }
1578 
1579  QFontMetricsF fm(font());
1580  qreal width = 0;
1581 
1582  if (d->orientation == Qt::Vertical) {
1583  width = qMax(d->maxWordWidth(d->text),
1584  d->maxWordWidth(d->infoText)) +
1585  fm.width("xxx") +
1586  d->verticalMargin[IconWidgetPrivate::TextMargin].left +
1587  d->verticalMargin[IconWidgetPrivate::TextMargin].right;
1588 
1589  width = qMax(width,
1590  iconWidth +
1591  d->verticalMargin[IconWidgetPrivate::IconMargin].left +
1592  d->verticalMargin[IconWidgetPrivate::IconMargin].right);
1593  } else {
1594  width = iconWidth +
1595  d->horizontalMargin[IconWidgetPrivate::IconMargin].left +
1596  d->horizontalMargin[IconWidgetPrivate::IconMargin].right +
1597  qMax(fm.width(d->text), fm.width(d->infoText)) + fm.width("xxx") +
1598  d->horizontalMargin[IconWidgetPrivate::TextMargin].left +
1599  d->horizontalMargin[IconWidgetPrivate::TextMargin].right;
1600  }
1601 
1602  qreal height;
1603  qreal textHeight;
1604 
1605  QStyleOptionGraphicsItem option;
1606  option.state = QStyle::State_None;
1607  option.rect = QRect(0, 0, width, QWIDGETSIZE_MAX);
1608  textHeight = d->displaySizeHint(&option, width).height();
1609 
1610  if (d->orientation == Qt::Vertical) {
1611  height = iconWidth + textHeight +
1612  d->verticalMargin[IconWidgetPrivate::TextMargin].top +
1613  d->verticalMargin[IconWidgetPrivate::TextMargin].bottom +
1614  d->verticalMargin[IconWidgetPrivate::IconMargin].top +
1615  d->verticalMargin[IconWidgetPrivate::IconMargin].bottom;
1616  } else {
1617  //Horizontal
1618  height = qMax(iconWidth +
1619  d->verticalMargin[IconWidgetPrivate::IconMargin].top +
1620  d->verticalMargin[IconWidgetPrivate::IconMargin].bottom,
1621  textHeight +
1622  d->verticalMargin[IconWidgetPrivate::TextMargin].top +
1623  d->verticalMargin[IconWidgetPrivate::TextMargin].bottom);
1624  }
1625 
1626  return d->addMargin(QSizeF(width, height), IconWidgetPrivate::ItemMargin);
1627 }
1628 
1629 void IconWidget::changeEvent(QEvent *event)
1630 {
1631  d->changeEvent(event);
1632  QGraphicsWidget::changeEvent(event);
1633 }
1634 
1635 } // namespace Plasma
1636 
1637 #include "iconwidget.moc"
1638 #include "iconwidget_p.moc"
Plasma::IconWidget::drawBackground
bool drawBackground() const
Plasma::IconWidget::shape
QPainterPath shape() const
reimplemented from QGraphicsItem
Definition: iconwidget.cpp:515
Plasma::Vertical
The applet is constrained horizontally, but can expand vertically.
Definition: plasma.h:77
Plasma::IconWidget::sizeHint
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint=QSizeF()) const
Definition: iconwidget.cpp:681
Plasma::IconWidget::setAction
void setAction(QAction *action)
Associate an action with this IconWidget this makes the IconWidget follow the state of the action...
Definition: iconwidget.cpp:458
Plasma::IconWidget::invertedLayout
bool invertedLayout() const
Definition: iconwidget.cpp:1566
Plasma::IconWidget::setUnpressed
void setUnpressed()
Shortcut for setPressed(false)
Definition: iconwidget.cpp:1539
Plasma::IconWidget::mouseDoubleClickEvent
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
Definition: iconwidget.cpp:1470
Plasma::IconWidget::mouseMoveEvent
void mouseMoveEvent(QGraphicsSceneMouseEvent *event)
Definition: iconwidget.cpp:1413
animation.h
Plasma::IconWidget::setNumDisplayLines
void setNumDisplayLines(int numLines)
Definition: iconwidget.cpp:473
Plasma::Animator::PixmapTransitionAnimation
Definition: animator.h:68
Plasma::IconWidget::mouseReleaseEvent
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
Definition: iconwidget.cpp:1433
Plasma::IconWidget::drawActionButtonBase
void drawActionButtonBase(QPainter *painter, const QSize &size, int element)
Definition: iconwidget.cpp:1242
QWidget
Plasma::IconWidget::numDisplayLines
int numDisplayLines()
Plasma::IconWidget::sizeFromIconSize
Q_INVOKABLE QSizeF sizeFromIconSize(const qreal iconWidth) const
Definition: iconwidget.cpp:1571
Plasma::IconWidget::IconWidget
IconWidget(QGraphicsItem *parent=0)
Creates a new Plasma::IconWidget.
Definition: iconwidget.cpp:351
Plasma::Desktop
On the planar desktop layer, extending across the full screen from edge to edge.
Definition: plasma.h:111
Plasma::Theme::TextColor
the text color to be used by items resting on the background
Definition: theme.h:63
Plasma::IconWidget::setText
void setText(const QString &text)
Sets the text associated with this icon.
Definition: iconwidget.cpp:1267
Plasma::IconWidget::addIconAction
void addIconAction(QAction *action)
Plasma::IconWidget allows the user to specify a number of actions (currently four) to be displayed ar...
Definition: iconwidget.cpp:415
Plasma::PaintUtils::drawHalo
void drawHalo(QPainter *painter, const QRectF &rect)
Definition: paintutils.cpp:154
theme.h
iconwidget.h
Plasma::IconWidget::sceneEventFilter
bool sceneEventFilter(QGraphicsItem *watched, QEvent *event)
Definition: iconwidget.cpp:1514
Plasma::IconWidget::activated
void activated()
Indicates when the icon has been activated following the single or doubleclick settings.
Plasma::FrameSvg
Provides an SVG with borders.
Definition: framesvg.h:76
QObject
Plasma::IconWidget::removeIconAction
void removeIconAction(QAction *action)
Removes a previously set iconAction.
Definition: iconwidget.cpp:430
Plasma::IconWidget::orientation
Qt::Orientation orientation() const
Plasma::IconWidget::iconSize
QSizeF iconSize() const
Plasma::AnimationScriptEngine::animation
QScriptValue animation(const QString &anim)
Definition: animationscriptengine.cpp:55
Plasma::IconWidget::maximumIconSize
QSizeF maximumIconSize() const
Plasma::IconWidget::IconWidgetPrivate
friend class IconWidgetPrivate
Definition: iconwidget.h:389
Plasma::PaintUtils::roundedRectangle
QPainterPath roundedRectangle(const QRectF &rect, qreal radius)
Returns a nicely rounded rectanglular path for painting.
Definition: paintutils.cpp:159
Plasma::IconWidget::paint
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=0)
Definition: iconwidget.cpp:1136
Plasma::IconWidget::setPreferredIconSize
void setPreferredIconSize(const QSizeF &size)
Set the size you prefer the icon will be when positioned in a layout.
Definition: iconwidget.cpp:1348
Plasma::IconWidget::setSvg
void setSvg(const QString &svgFilePath, const QString &svgIconElement=QString())
Convenience method to set the svg image to use when given the filepath and name of svg...
Definition: iconwidget.cpp:634
paintutils.h
Plasma::IconWidget::invertLayout
void invertLayout(bool invert)
inverts the layout of the icons if the orientation is horizontal, normally we get icon on the left wi...
Definition: iconwidget.cpp:1561
Plasma::IconWidget::setIcon
void setIcon(const QIcon &icon)
Sets the graphical icon for this Plasma::IconWidget.
Definition: iconwidget.cpp:1324
Plasma::KeepAspectRatio
The applet keeps a fixed aspect ratio.
Definition: plasma.h:213
Plasma::IconWidget::changeEvent
void changeEvent(QEvent *event)
Definition: iconwidget.cpp:1629
Plasma::PaintUtils::shadowBlur
void shadowBlur(QImage &image, int radius, const QColor &color)
Creates a blurred shadow of the supplied image.
Definition: paintutils.cpp:38
Plasma::IconWidget::clicked
void clicked()
Indicates when the icon has been clicked.
Plasma::IconWidget::setMaximumIconSize
void setMaximumIconSize(const QSizeF &size)
Set the size that should be the maximum beyond the icon shouldn't scale when the icon will be when po...
Definition: iconwidget.cpp:1370
Plasma::IconWidget::hoverEnterEvent
void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
Definition: iconwidget.cpp:1484
Plasma::IconWidget::isDown
bool isDown()
Definition: iconwidget.cpp:1381
Plasma::IconWidget::setTextBackgroundColor
void setTextBackgroundColor(const QColor &color)
Sets the color to use behind the text of the icon.
Definition: iconwidget.cpp:1230
Plasma::type
static QScriptValue type(QScriptContext *ctx, QScriptEngine *eng)
Definition: easingcurve.cpp:63
Plasma::IconWidget::setPressed
void setPressed(bool pressed=true)
Sets the appearance of the icon to pressed or restores the appearance to normal.
Definition: iconwidget.cpp:1527
Plasma::IconWidget::hoverLeaveEvent
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
Definition: iconwidget.cpp:1498
Plasma::Theme::defaultTheme
static Theme * defaultTheme()
Singleton pattern accessor.
Definition: theme.cpp:544
Plasma::Animator::create
static Plasma::Animation * create(Animator::Animation type, QObject *parent=0)
Factory to build new animation objects.
Definition: animator.cpp:61
IconWidget
Provides a generic icon.
Definition: iconwidget.h:37
Plasma::PaintUtils::transition
QPixmap transition(const QPixmap &from, const QPixmap &to, qreal amount)
Blends a pixmap into another.
Definition: paintutils.cpp:208
Plasma::IconWidget::minimumIconSize
QSizeF minimumIconSize() const
Plasma::IconWidget::infoText
QString infoText() const
Returns the meta text associated with this icon.
Plasma::IconWidget::text
QString text() const
Returns the text associated with this icon.
Plasma::IconWidget::~IconWidget
virtual ~IconWidget()
Destroys this Plasma::IconWidget.
Definition: iconwidget.cpp:375
Plasma::Theme::color
Q_INVOKABLE QColor color(ColorRole role) const
Returns the text color to be used by items resting on the background.
Definition: theme.cpp:918
Plasma::IconWidget::preferredIconSize
QSizeF preferredIconSize() const
animator.h
Plasma::IconWidget::icon
QIcon icon() const
Plasma::IconWidget::action
QAction * action() const
Plasma::IconWidget::textBackgroundColor
QColor textBackgroundColor() const
QStyleOptionGraphicsItem
Plasma::IconWidget::pressed
void pressed(bool down)
Indicates when the icon has been pressed.
Plasma::Svg
A theme aware image-centric SVG class.
Definition: svg.h:56
Plasma::IconWidget::setDrawBackground
void setDrawBackground(bool draw)
Sets whether or not to draw a background area for the icon.
Definition: iconwidget.cpp:482
Plasma::IconWidget::setMinimumIconSize
void setMinimumIconSize(const QSizeF &size)
Set the size that should be the minimum beyond the icon shouldn't scale when the icon will be when po...
Definition: iconwidget.cpp:1359
svg.h
Plasma::IconWidget::mousePressEvent
void mousePressEvent(QGraphicsSceneMouseEvent *event)
Definition: iconwidget.cpp:1386
Plasma::IconWidget::setOrientation
void setOrientation(Qt::Orientation orientation)
let set the orientation of the icon Qt::Vertical: text under the icon Qt::Horizontal text at a side o...
Definition: iconwidget.cpp:1550
QGraphicsWidget
Plasma::IconWidget::setInfoText
void setInfoText(const QString &text)
Sets the additional information to be displayed by this icon.
Definition: iconwidget.cpp:1288
Plasma::IconWidget::svg
QString svg() const
Plasma::IconWidget::doubleClicked
void doubleClicked()
Indicates when the icon has been double-clicked.
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:48:33 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal