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

Plasma

  • 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  if (iconSvg) {
814  if (iconSvgElementChanged || iconSvgPixmap.size() != iconSize.toSize()) {
815  iconSvg->resize(iconSize);
816  iconSvgPixmap = iconSvg->pixmap(iconSvgElement);
817  iconSvgElementChanged = false;
818  }
819  result = iconSvgPixmap;
820  } else {
821  const QSize size = icon.actualSize(iconSize.toSize(), mode, state);
822  result = icon.pixmap(size, mode, state);
823  }
824 
825  if (usePressedEffect) {
826  result = result.scaled(result.size() * 0.9, Qt::KeepAspectRatio, Qt::SmoothTransformation);
827  }
828 
829  if (!result.isNull() && useHoverEffect) {
830  KIconEffect *effect = KIconLoader::global()->iconEffect();
831  // Note that in KIconLoader terminology, active = hover.
832  // We're assuming that the icon group is desktop/filemanager, since this
833  // is KFileItemDelegate.
834  if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
835  if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) {
836  result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState);
837  } else {
838  result = PaintUtils::transition(
839  result,
840  effect->apply(result, KIconLoader::Desktop,
841  KIconLoader::ActiveState), hoverAnimation->value());
842  }
843  }
844  } else if (!result.isNull() && !oldIcon.isNull()) {
845  if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) {
846  oldIcon = QIcon();
847  } else {
848  result = PaintUtils::transition(
849  oldIcon.pixmap(result.size(), mode, state),
850  result, hoverAnimation->value());
851  }
852  }
853 
854  return result;
855 }
856 
857 QPointF IconWidgetPrivate::iconPosition(const QStyleOptionGraphicsItem *option,
858  const QPixmap &pixmap) const
859 {
860  const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
861 
862  // Compute the nominal decoration rectangle
863  const QSizeF size = addMargin(iconSize, IconWidgetPrivate::IconMargin);
864 
865  Qt::LayoutDirection direction = iconDirection(option);
866 
867  //alignment depends from orientation and option->direction
868  Qt::Alignment alignment;
869  if (text.isEmpty() && infoText.isEmpty()) {
870  alignment = Qt::AlignCenter;
871  } else if (orientation == Qt::Vertical) {
872  alignment = Qt::Alignment(Qt::AlignHCenter | Qt::AlignTop);
873  //Horizontal
874  } else {
875  alignment = QStyle::visualAlignment(
876  direction, Qt::Alignment(Qt::AlignLeft | Qt::AlignVCenter));
877  }
878 
879  const QRect iconRect =
880  QStyle::alignedRect(direction, alignment, size.toSize(), itemRect.toRect());
881 
882  // Position the pixmap in the center of the rectangle
883  QRect pixmapRect = pixmap.rect();
884  pixmapRect.moveCenter(iconRect.center());
885 
886  // add a gimmicky margin of 5px to y, TEMP TEMP TEMP
887  // pixmapRect = pixmapRect.adjusted(0, 5, 0, 0);
888 
889  return QPointF(pixmapRect.topLeft());
890 }
891 
892 QRectF IconWidgetPrivate::labelRectangle(const QStyleOptionGraphicsItem *option,
893  const QPixmap &icon,
894  const QString &string) const
895 {
896  Q_UNUSED(string)
897 
898  if (icon.isNull()) {
899  return option->rect;
900  }
901 
902  const QSizeF decoSize = addMargin(iconSize, IconWidgetPrivate::IconMargin);
903  const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
904  QRectF textArea(QPointF(0, 0), itemRect.size());
905 
906  if (orientation == Qt::Vertical) {
907  textArea.setTop(decoSize.height() + 1);
908  } else {
909  //Horizontal
910  textArea.setLeft(decoSize.width() + 1);
911  }
912 
913  textArea.translate(itemRect.topLeft());
914  return QRectF(QStyle::visualRect(iconDirection(option), option->rect, textArea.toRect()));
915 }
916 
917 // Lays the text out in a rectangle no larger than constraints, eliding it as necessary
918 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout,
919  const QString &text,
920  const QSizeF &constraints) const
921 {
922  const QSizeF size = layoutText(layout, text, constraints.width());
923 
924  if (size.width() > constraints.width() || size.height() > constraints.height()) {
925  if (action) {
926  q->setToolTip(action->toolTip());
927  }
928  const QString elided = elidedText(layout, constraints);
929  return layoutText(layout, elided, constraints.width());
930  }
931  q->setToolTip(QString());
932 
933  return size;
934 }
935 
936 // Lays the text out in a rectangle no wider than maxWidth
937 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout, const QString &text, qreal maxWidth) const
938 {
939  QFontMetricsF metrics(layout.font());
940  qreal leading = metrics.leading();
941  qreal height = 0.0;
942  qreal widthUsed = 0.0;
943  QTextLine line;
944 
945  layout.setText(text);
946 
947  layout.beginLayout();
948 
949  while ((line = layout.createLine()).isValid()) {
950  line.setLineWidth(maxWidth);
951  height += leading;
952  line.setPosition(QPointF(0.0, height));
953  height += line.height();
954  widthUsed = qMax(widthUsed, line.naturalTextWidth());
955  }
956  layout.endLayout();
957 
958  return QSizeF(widthUsed, height);
959 }
960 
961 // Elides the text in the layout, by iterating over each line in the layout, eliding
962 // or word breaking the line if it's wider than the max width, and finally adding an
963 // ellipses at the end of the last line, if there are more lines than will fit within
964 // the vertical size constraints.
965 QString IconWidgetPrivate::elidedText(QTextLayout &layout, const QSizeF &size) const
966 {
967  QFontMetricsF metrics(layout.font());
968  const QString text = layout.text();
969  qreal maxWidth = size.width();
970  qreal maxHeight = size.height();
971  qreal height = 0;
972 
973  // Elide each line that has already been laid out in the layout.
974  QString elided;
975  elided.reserve(text.length());
976 
977  for (int i = 0; i < layout.lineCount(); i++) {
978  QTextLine line = layout.lineAt(i);
979  int start = line.textStart();
980  int length = line.textLength();
981 
982  height += metrics.leading();
983  if (height + line.height() + metrics.lineSpacing() > maxHeight) {
984  // Unfortunately, if the line ends because of a line separator,
985  // elidedText() will be too clever and keep adding lines until
986  // it finds one that's too wide.
987  if (line.naturalTextWidth() < maxWidth &&
988  start + length > 0 &&
989  text[start + length - 1] == QChar::LineSeparator) {
990  elided += text.mid(start, length - 1);
991  } else {
992  elided += metrics.elidedText(text.mid(start), Qt::ElideRight, maxWidth);
993  }
994  break;
995  } else if (line.naturalTextWidth() > maxWidth) {
996  elided += metrics.elidedText(text.mid(start, length), Qt::ElideRight, maxWidth);
997  } else {
998  elided += text.mid(start, length);
999  }
1000 
1001  height += line.height();
1002  }
1003 
1004  return elided;
1005 }
1006 
1007 void IconWidgetPrivate::layoutTextItems(const QStyleOptionGraphicsItem *option,
1008  const QPixmap &icon, QTextLayout *labelLayout,
1009  QTextLayout *infoLayout, QRectF *textBoundingRect) const
1010 {
1011  bool showInformation = false;
1012 
1013  setLayoutOptions(*labelLayout, option, q->orientation());
1014 
1015  QFontMetricsF fm(labelLayout->font());
1016  const QRectF textArea = labelRectangle(option, icon, text);
1017  QRectF textRect = subtractMargin(textArea, IconWidgetPrivate::TextMargin);
1018 
1019  //kDebug() << this << "text area" << textArea << "text rect" << textRect;
1020  // Sizes and constraints for the different text parts
1021  QSizeF maxLabelSize = textRect.size();
1022  QSizeF maxInfoSize = textRect.size();
1023  QSizeF labelSize;
1024  QSizeF infoSize;
1025 
1026  // If we have additional info text, and there's space for at least two lines of text,
1027  // adjust the max label size to make room for at least one line of the info text
1028  if (!infoText.isEmpty() && textRect.height() >= fm.lineSpacing() * 2) {
1029  infoLayout->setFont(labelLayout->font());
1030  infoLayout->setTextOption(labelLayout->textOption());
1031 
1032  maxLabelSize.rheight() -= fm.lineSpacing();
1033  showInformation = true;
1034  }
1035 
1036  // Lay out the label text, and adjust the max info size based on the label size
1037  labelSize = layoutText(*labelLayout, text, maxLabelSize);
1038  maxInfoSize.rheight() -= labelSize.height();
1039 
1040  // Lay out the info text
1041  if (showInformation) {
1042  infoSize = layoutText(*infoLayout, infoText, maxInfoSize);
1043  } else {
1044  infoSize = QSizeF(0, 0);
1045  }
1046  // Compute the bounding rect of the text
1047  const Qt::Alignment alignment = labelLayout->textOption().alignment();
1048  const QSizeF size(qMax(labelSize.width(), infoSize.width()),
1049  labelSize.height() + infoSize.height());
1050  *textBoundingRect =
1051  QStyle::alignedRect(iconDirection(option), alignment, size.toSize(), textRect.toRect());
1052 
1053  // Compute the positions where we should draw the layouts
1054  haloRects.clear();
1055  labelLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y()));
1056  QTextLine line;
1057  for (int i = 0; i < labelLayout->lineCount(); ++i) {
1058  line = labelLayout->lineAt(i);
1059  haloRects.append(line.naturalTextRect().translated(labelLayout->position().toPoint()).toRect());
1060  }
1061  infoLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y() + labelSize.height()));
1062  for (int i = 0; i < infoLayout->lineCount(); ++i) {
1063  line = infoLayout->lineAt(i);
1064  haloRects.append(line.naturalTextRect().translated(infoLayout->position().toPoint()).toRect());
1065  }
1066  //kDebug() << "final position is" << labelLayout->position();
1067 }
1068 
1069 QBrush IconWidgetPrivate::foregroundBrush(const QStyleOptionGraphicsItem *option) const
1070 {
1071  const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
1072  QPalette::Normal : QPalette::Disabled;
1073 
1074  // Always use the highlight color for selected items
1075  if (option->state & QStyle::State_Selected) {
1076  return option->palette.brush(group, QPalette::HighlightedText);
1077  }
1078  return option->palette.brush(group, QPalette::Text);
1079 }
1080 
1081 QBrush IconWidgetPrivate::backgroundBrush(const QStyleOptionGraphicsItem *option) const
1082 {
1083  const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
1084  QPalette::Normal : QPalette::Disabled;
1085 
1086  QBrush background(Qt::NoBrush);
1087 
1088  // Always use the highlight color for selected items
1089  if (option->state & QStyle::State_Selected) {
1090  background = option->palette.brush(group, QPalette::Highlight);
1091  }
1092  return background;
1093 }
1094 
1095 void IconWidgetPrivate::drawTextItems(QPainter *painter,
1096  const QStyleOptionGraphicsItem *option,
1097  const QTextLayout &labelLayout,
1098  const QTextLayout &infoLayout) const
1099 {
1100  Q_UNUSED(option)
1101 
1102  painter->save();
1103  painter->setPen(textColor);
1104 
1105  // the translation prevents odd rounding errors in labelLayout.position()
1106  // when applied to the canvas
1107  painter->translate(0.5, 0.5);
1108 
1109  labelLayout.draw(painter, QPointF());
1110 
1111  if (!infoLayout.text().isEmpty()) {
1112  painter->setPen(textColor);
1113  infoLayout.draw(painter, QPointF());
1114  }
1115  painter->restore();
1116 }
1117 
1118 void IconWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
1119 {
1120  Q_UNUSED(widget);
1121 
1122  //Lay out the main icon and action icons
1123  d->layoutIcons(option);
1124 
1125  // Compute the metrics, and lay out the text items
1126  // ========================================================================
1127  IconWidgetPrivate::IconWidgetState state = IconWidgetPrivate::NoState;
1128  if (d->states & IconWidgetPrivate::ManualPressedState) {
1129  state = IconWidgetPrivate::PressedState;
1130  } else if (d->states & IconWidgetPrivate::PressedState) {
1131  if (d->states & IconWidgetPrivate::HoverState) {
1132  state = IconWidgetPrivate::PressedState;
1133  }
1134  } else if (d->states & IconWidgetPrivate::HoverState) {
1135  state = IconWidgetPrivate::HoverState;
1136  }
1137 
1138  QPixmap icon = d->decoration(option, state != IconWidgetPrivate::NoState, state & IconWidgetPrivate::PressedState);
1139  const QPointF iconPos = d->iconPosition(option, icon);
1140 
1141  d->drawBackground(painter, state);
1142 
1143  // draw icon
1144  if (!icon.isNull()) {
1145  painter->drawPixmap(iconPos, icon);
1146  }
1147 
1148  // Draw corner actions
1149  foreach (const IconAction *action, d->cornerActions) {
1150  if (action->isAnimating()) {
1151  action->paint(painter);
1152  }
1153  }
1154 
1155  // Draw text last because it is overlayed
1156  QTextLayout labelLayout, infoLayout;
1157  QRectF textBoundingRect;
1158 
1159  d->layoutTextItems(option, icon, &labelLayout, &infoLayout, &textBoundingRect);
1160 
1161  if (d->textBgColor != QColor() && d->textBgColor.alpha() > 0 &&
1162  !(d->text.isEmpty() && d->infoText.isEmpty()) &&
1163  !textBoundingRect.isEmpty() &&
1164  !qFuzzyCompare(d->hoverAnimation->value(), (qreal)1.0)) {
1165  QRectF rect = textBoundingRect.adjusted(-2, -2, 4, 4).toAlignedRect();
1166  painter->setPen(Qt::transparent);
1167  QColor color = d->textBgColor;
1168  color.setAlpha(60 * (1.0 - d->hoverAnimation->value()));
1169  QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
1170  gradient.setColorAt(0, color.lighter(120));
1171  gradient.setColorAt(1, color.darker(120));
1172  painter->setBrush(gradient);
1173  gradient.setColorAt(0, color.lighter(130));
1174  gradient.setColorAt(1, color.darker(130));
1175  painter->setPen(QPen(gradient, 0));
1176  painter->setRenderHint(QPainter::Antialiasing);
1177  painter->drawPath(PaintUtils::roundedRectangle(rect.translated(0.5, 0.5), 4));
1178  }
1179 
1180 
1181  if (d->shadowColor.value() < 128 || textBackgroundColor() != QColor()) {
1182  QPoint shadowPos;
1183  if (d->shadowColor.value() < 128) {
1184  shadowPos = QPoint(1, 2);
1185  } else {
1186  shadowPos = QPoint(0, 0);
1187  }
1188 
1189  QImage shadow(textBoundingRect.size().toSize() + QSize(4, 4),
1190  QImage::Format_ARGB32_Premultiplied);
1191  shadow.fill(Qt::transparent);
1192  {
1193  QPainter buffPainter(&shadow);
1194  buffPainter.translate(-textBoundingRect.x(), -textBoundingRect.y());
1195  d->drawTextItems(&buffPainter, option, labelLayout, infoLayout);
1196  }
1197 
1198  PaintUtils::shadowBlur(shadow, 2, d->shadowColor);
1199  painter->drawImage(textBoundingRect.topLeft() + shadowPos, shadow);
1200  } else if (!(d->text.isEmpty() && d->infoText.isEmpty()) &&
1201  !textBoundingRect.isEmpty()) {
1202  QRect labelRect = d->labelRectangle(option, icon, d->text).toRect();
1203 
1204  foreach (const QRect &rect, d->haloRects) {
1205  Plasma::PaintUtils::drawHalo(painter, rect);
1206  }
1207  }
1208 
1209  d->drawTextItems(painter, option, labelLayout, infoLayout);
1210 }
1211 
1212 void IconWidget::setTextBackgroundColor(const QColor &color)
1213 {
1214  d->textBgCustomized = true;
1215  d->textBgColor = color;
1216  update();
1217 }
1218 
1219 QColor IconWidget::textBackgroundColor() const
1220 {
1221  return d->textBgColor;
1222 }
1223 
1224 void IconWidget::drawActionButtonBase(QPainter *painter, const QSize &size, int element)
1225 {
1226  qreal radius = size.width() / 2;
1227  QRadialGradient gradient(radius, radius, radius, radius, radius);
1228  int alpha;
1229 
1230  if (element == IconWidgetPrivate::MinibuttonPressed) {
1231  alpha = 255;
1232  } else if (element == IconWidgetPrivate::MinibuttonHover) {
1233  alpha = 200;
1234  } else {
1235  alpha = 160;
1236  }
1237  gradient.setColorAt(0, QColor::fromRgb(d->textColor.red(),
1238  d->textColor.green(),
1239  d->textColor.blue(), alpha));
1240  gradient.setColorAt(1, QColor::fromRgb(d->textColor.red(),
1241  d->textColor.green(),
1242  d->textColor.blue(), 0));
1243 
1244  painter->setBrush(gradient);
1245  painter->setPen(Qt::NoPen);
1246  painter->drawEllipse(QRectF(QPointF(.0, .0), size));
1247 }
1248 
1249 void IconWidget::setText(const QString &text)
1250 {
1251  d->text = KGlobal::locale()->removeAcceleratorMarker(text);
1252  // cause a relayout
1253  d->currentSize = QSizeF(-1, -1);
1254  //try to relayout, needed if an icon was never shown before
1255  if (!isVisible()) {
1256  QStyleOptionGraphicsItem styleoption;
1257  d->layoutIcons(&styleoption);
1258  }
1259  updateGeometry();
1260  if (!parentWidget() || !parentWidget()->layout()) {
1261  resize(preferredSize());
1262  }
1263 }
1264 
1265 QString IconWidget::text() const
1266 {
1267  return d->text;
1268 }
1269 
1270 void IconWidget::setInfoText(const QString &text)
1271 {
1272  d->infoText = text;
1273  // cause a relayout
1274  d->currentSize = QSizeF(-1, -1);
1275  //try to relayout, needed if an icon was never shown before
1276  if (!isVisible()) {
1277  QStyleOptionGraphicsItem styleoption;
1278  d->layoutIcons(&styleoption);
1279  }
1280  updateGeometry();
1281  if (!parentWidget() || !parentWidget()->layout()) {
1282  resize(preferredSize());
1283  }
1284 }
1285 
1286 QString IconWidget::infoText() const
1287 {
1288  return d->infoText;
1289 }
1290 
1291 QIcon IconWidget::icon() const
1292 {
1293  return d->icon;
1294 }
1295 
1296 void IconWidget::setIcon(const QString &icon)
1297 {
1298  if (icon.isEmpty()) {
1299  setIcon(QIcon());
1300  return;
1301  }
1302 
1303  setIcon(KIcon(icon));
1304 }
1305 
1306 void IconWidget::setIcon(const QIcon &icon)
1307 {
1308  setSvg(QString());
1309 
1310  /*fade to the new icon, but to not bee a too big hog, not do that when:
1311  - the fade animation is already running
1312  - the icon is under mouse
1313  - one betwen the old and new icon is null*/
1314  if (!(d->states & IconWidgetPrivate::HoverState) && !d->iconChangeTimer->isActive() && d->oldIcon.isNull() && !d->icon.isNull() && !icon.isNull()) {
1315  d->oldIcon = d->icon;
1316  d->animateMainIcon(true, d->states);
1317  } else {
1318  d->oldIcon = QIcon();
1319  }
1320  d->iconChangeTimer->start(300);
1321  d->icon = icon;
1322  update();
1323 }
1324 
1325 QSizeF IconWidget::iconSize() const
1326 {
1327  return d->iconSize;
1328 }
1329 
1330 void IconWidget::setPreferredIconSize(const QSizeF &size)
1331 {
1332  d->preferredIconSize = size;
1333  updateGeometry();
1334 }
1335 
1336 QSizeF IconWidget::preferredIconSize() const
1337 {
1338  return d->preferredIconSize;
1339 }
1340 
1341 void IconWidget::setMinimumIconSize(const QSizeF &size)
1342 {
1343  d->minimumIconSize = size;
1344  updateGeometry();
1345 }
1346 
1347 QSizeF IconWidget::minimumIconSize() const
1348 {
1349  return d->minimumIconSize;
1350 }
1351 
1352 void IconWidget::setMaximumIconSize(const QSizeF &size)
1353 {
1354  d->maximumIconSize = size;
1355  updateGeometry();
1356 }
1357 
1358 QSizeF IconWidget::maximumIconSize() const
1359 {
1360  return d->maximumIconSize;
1361 }
1362 
1363 bool IconWidget::isDown()
1364 {
1365  return d->states & IconWidgetPrivate::PressedState;
1366 }
1367 
1368 void IconWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
1369 {
1370  if (event->button() != Qt::LeftButton) {
1371  QGraphicsWidget::mousePressEvent(event);
1372  return;
1373  }
1374 
1375  if (KGlobalSettings::singleClick() || (receivers(SIGNAL(clicked()))) > 0) {
1376  d->states |= IconWidgetPrivate::PressedState;
1377  }
1378  d->clickStartPos = scenePos();
1379 
1380  bool handled = false;
1381  foreach (IconAction *action, d->cornerActions) {
1382  handled = action->event(event->type(), event->pos());
1383  if (handled) {
1384  break;
1385  }
1386  }
1387 
1388  if (!handled && boundingRect().contains(event->pos())) {
1389  emit pressed(true);
1390  }
1391 
1392  update();
1393 }
1394 
1395 void IconWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1396 {
1397  if (~d->states & IconWidgetPrivate::PressedState) {
1398  QGraphicsWidget::mouseMoveEvent(event);
1399  return;
1400  }
1401 
1402  if (boundingRect().contains(event->pos())) {
1403  if (~d->states & IconWidgetPrivate::HoverState) {
1404  d->states |= IconWidgetPrivate::HoverState;
1405  update();
1406  }
1407  } else {
1408  if (d->states & IconWidgetPrivate::HoverState) {
1409  d->states &= ~IconWidgetPrivate::HoverState;
1410  update();
1411  }
1412  }
1413 }
1414 
1415 void IconWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1416 {
1417  if (~d->states & IconWidgetPrivate::PressedState) {
1418  QGraphicsWidget::mouseMoveEvent(event);
1419  return;
1420  }
1421 
1422  d->states &= ~IconWidgetPrivate::PressedState;
1423 
1424  //don't pass click when the mouse was moved
1425  bool handled = d->clickStartPos != scenePos();
1426  if (!handled) {
1427  foreach (IconAction *action, d->cornerActions) {
1428  if (action->event(event->type(), event->pos())) {
1429  handled = true;
1430  break;
1431  }
1432  }
1433  }
1434 
1435  if (!handled) {
1436  if (boundingRect().contains(event->pos())) {
1437  emit clicked();
1438  if (KGlobalSettings::singleClick()) {
1439  emit activated();
1440  }
1441 
1442  if (d->action && d->action->menu()) {
1443  d->action->menu()->popup(event->screenPos());
1444  }
1445  }
1446  emit pressed(false);
1447  }
1448 
1449  update();
1450 }
1451 
1452 void IconWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1453 {
1454  Q_UNUSED(event)
1455 
1456  d->states |= IconWidgetPrivate::PressedState;
1457 
1458  emit doubleClicked();
1459  if (!KGlobalSettings::singleClick()) {
1460  emit activated();
1461  }
1462 
1463  update();
1464 }
1465 
1466 void IconWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
1467 {
1468  //kDebug();
1469  foreach (IconAction *action, d->cornerActions) {
1470  action->show();
1471  action->event(event->type(), event->pos());
1472  }
1473 
1474  d->oldIcon = QIcon();
1475  d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState);
1476 
1477  QGraphicsWidget::hoverEnterEvent(event);
1478 }
1479 
1480 void IconWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
1481 {
1482  //kDebug() << d->cornerActions;
1483  foreach (IconAction *action, d->cornerActions) {
1484  action->hide();
1485  action->event(event->type(), event->pos());
1486  }
1487  // d->states &= ~IconWidgetPrivate::HoverState; // Will be set once progress is zero again ...
1488  //if an eventfilter stolen the mousereleaseevent remove the pressed state here
1489  d->states &= ~IconWidgetPrivate::PressedState;
1490 
1491  d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState);
1492 
1493  QGraphicsWidget::hoverLeaveEvent(event);
1494 }
1495 
1496 bool IconWidget::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
1497 {
1498  Q_UNUSED(watched)
1499 
1500  if (event->type() == QEvent::GraphicsSceneDragEnter) {
1501  d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState);
1502  } else if (event->type() == QEvent::GraphicsSceneDragLeave) {
1503  d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState);
1504  }
1505 
1506  return false;
1507 }
1508 
1509 void IconWidget::setPressed(bool pressed)
1510 {
1511  if (pressed) {
1512  d->states |= IconWidgetPrivate::ManualPressedState;
1513  d->states |= IconWidgetPrivate::PressedState;
1514  } else {
1515  d->states &= ~IconWidgetPrivate::ManualPressedState;
1516  d->states &= ~IconWidgetPrivate::PressedState;
1517  }
1518  update();
1519 }
1520 
1521 void IconWidget::setUnpressed()
1522 {
1523  setPressed(false);
1524 }
1525 
1526 void IconWidgetPrivate::svgChanged()
1527 {
1528  iconSvgElementChanged = true;
1529  q->update();
1530 }
1531 
1532 void IconWidget::setOrientation(Qt::Orientation orientation)
1533 {
1534  d->orientation = orientation;
1535  resize(sizeFromIconSize(d->iconSize.width()));
1536 }
1537 
1538 Qt::Orientation IconWidget::orientation() const
1539 {
1540  return d->orientation;
1541 }
1542 
1543 void IconWidget::invertLayout(bool invert)
1544 {
1545  d->invertLayout = invert;
1546 }
1547 
1548 bool IconWidget::invertedLayout() const
1549 {
1550  return d->invertLayout;
1551 }
1552 
1553 QSizeF IconWidget::sizeFromIconSize(const qreal iconWidth) const
1554 {
1555  d->setActiveMargins();
1556  if (d->text.isEmpty() && d->infoText.isEmpty()) {
1557  //no text, just the icon size
1558  return d->addMargin(QSizeF(iconWidth, iconWidth), IconWidgetPrivate::ItemMargin);
1559  }
1560 
1561  QFontMetricsF fm(font());
1562  qreal width = 0;
1563 
1564  if (d->orientation == Qt::Vertical) {
1565  width = qMax(d->maxWordWidth(d->text),
1566  d->maxWordWidth(d->infoText)) +
1567  fm.width("xxx") +
1568  d->verticalMargin[IconWidgetPrivate::TextMargin].left +
1569  d->verticalMargin[IconWidgetPrivate::TextMargin].right;
1570 
1571  width = qMax(width,
1572  iconWidth +
1573  d->verticalMargin[IconWidgetPrivate::IconMargin].left +
1574  d->verticalMargin[IconWidgetPrivate::IconMargin].right);
1575  } else {
1576  width = iconWidth +
1577  d->horizontalMargin[IconWidgetPrivate::IconMargin].left +
1578  d->horizontalMargin[IconWidgetPrivate::IconMargin].right +
1579  qMax(fm.width(d->text), fm.width(d->infoText)) + fm.width("xxx") +
1580  d->horizontalMargin[IconWidgetPrivate::TextMargin].left +
1581  d->horizontalMargin[IconWidgetPrivate::TextMargin].right;
1582  }
1583 
1584  qreal height;
1585  qreal textHeight;
1586 
1587  QStyleOptionGraphicsItem option;
1588  option.state = QStyle::State_None;
1589  option.rect = QRect(0, 0, width, QWIDGETSIZE_MAX);
1590  textHeight = d->displaySizeHint(&option, width).height();
1591 
1592  if (d->orientation == Qt::Vertical) {
1593  height = iconWidth + textHeight +
1594  d->verticalMargin[IconWidgetPrivate::TextMargin].top +
1595  d->verticalMargin[IconWidgetPrivate::TextMargin].bottom +
1596  d->verticalMargin[IconWidgetPrivate::IconMargin].top +
1597  d->verticalMargin[IconWidgetPrivate::IconMargin].bottom;
1598  } else {
1599  //Horizontal
1600  height = qMax(iconWidth +
1601  d->verticalMargin[IconWidgetPrivate::IconMargin].top +
1602  d->verticalMargin[IconWidgetPrivate::IconMargin].bottom,
1603  textHeight +
1604  d->verticalMargin[IconWidgetPrivate::TextMargin].top +
1605  d->verticalMargin[IconWidgetPrivate::TextMargin].bottom);
1606  }
1607 
1608  return d->addMargin(QSizeF(width, height), IconWidgetPrivate::ItemMargin);
1609 }
1610 
1611 void IconWidget::changeEvent(QEvent *event)
1612 {
1613  d->changeEvent(event);
1614  QGraphicsWidget::changeEvent(event);
1615 }
1616 
1617 } // namespace Plasma
1618 
1619 #include "iconwidget.moc"
1620 #include "iconwidget_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Fri Nov 16 2012 14:55:55 by doxygen 1.8.1 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-4.8.5 API Reference

Skip menu "kdelibs-4.8.5 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
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
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