• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 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/*
56TODO:
57 Add these to a UrlIcon class
58 void setUrl(const KUrl& url);
59 KUrl url() const;
60*/
61
62namespace Plasma
63{
64
65IconHoverAnimation::IconHoverAnimation(QObject *parent)
66 : QObject(parent), m_value(0), m_fadeIn(false)
67{
68}
69
70qreal IconHoverAnimation::value() const
71{
72 return m_value;
73}
74
75bool IconHoverAnimation::fadeIn() const
76{
77 return m_fadeIn;
78}
79
80QPropertyAnimation *IconHoverAnimation::animation() const
81{
82 return m_animation.data();
83}
84
85void IconHoverAnimation::setValue(qreal value)
86{
87 m_value = value;
88 QGraphicsWidget *item = static_cast<QGraphicsWidget*>(parent());
89 item->update();
90}
91
92void IconHoverAnimation::setFadeIn(bool fadeIn)
93{
94 m_fadeIn = fadeIn;
95}
96
97void IconHoverAnimation::setAnimation(QPropertyAnimation *animation)
98{
99 m_animation = animation;
100}
101
102IconWidgetPrivate::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
121IconWidgetPrivate::~IconWidgetPrivate()
122{
123 qDeleteAll(cornerActions);
124 delete hoverAnimation;
125}
126
127void 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
142void 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
154void IconWidgetPrivate::iconConfigChanged()
155{
156 if (!icon.isNull()) {
157 q->update();
158 }
159}
160
161IconAction::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
171void 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
190void 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
207bool IconAction::isVisible() const
208{
209 return m_visible;
210}
211
212bool IconAction::isAnimating() const
213{
214 return !m_animation.isNull();
215}
216
217bool IconAction::isPressed() const
218{
219 return m_pressed;
220}
221
222bool IconAction::isHovered() const
223{
224 return m_hovered;
225}
226
227void IconAction::setSelected(bool selected)
228{
229 m_selected = selected;
230}
231
232bool IconAction::isSelected() const
233{
234 return m_selected;
235}
236
237void IconAction::setRect(const QRectF &rect)
238{
239 m_rect = rect;
240}
241
242QRectF IconAction::rect() const
243{
244 return m_rect;
245}
246
247void 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
268bool 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
326QAction *IconAction::action() const
327{
328 return m_action;
329}
330
331void 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
351IconWidget::IconWidget(QGraphicsItem *parent)
352 : QGraphicsWidget(parent),
353 d(new IconWidgetPrivate(this))
354{
355 d->init();
356}
357
358IconWidget::IconWidget(const QString &text, QGraphicsItem *parent)
359 : QGraphicsWidget(parent),
360 d(new IconWidgetPrivate(this))
361{
362 d->init();
363 setText(text);
364}
365
366IconWidget::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
375IconWidget::~IconWidget()
376{
377 delete d;
378}
379
380void 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
415void 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
430void 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
453void IconWidgetPrivate::actionDestroyed(QObject *action)
454{
455 q->removeIconAction(static_cast<QAction*>(action));
456}
457
458void IconWidget::setAction(QAction *action)
459{
460 d->setAction(action);
461}
462
463QAction *IconWidget::action() const
464{
465 return d->action;
466}
467
468int IconWidget::numDisplayLines()
469{
470 return d->numDisplayLines;
471}
472
473void IconWidget::setNumDisplayLines(int numLines)
474{
475 if (numLines > d->maxDisplayLines) {
476 d->numDisplayLines = d->maxDisplayLines;
477 } else {
478 d->numDisplayLines = numLines;
479 }
480}
481
482void 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
510bool IconWidget::drawBackground() const
511{
512 return d->drawBg;
513}
514
515QPainterPath 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
525QSizeF 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
558void 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
574QSizeF 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
634void 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
668QString 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
681QSizeF 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
743void 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
769void IconWidgetPrivate::hoverAnimationFinished()
770{
771 if (!hoverAnimation->fadeIn()) {
772 states &= ~IconWidgetPrivate::HoverState;
773 }
774}
775
776void 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
806QPixmap 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
875QPointF 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
910QRectF 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
936QSizeF 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
955QSizeF 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.
983QString 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
1025void 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
1087QBrush 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
1099QBrush 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
1113void 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
1136void 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
1230void IconWidget::setTextBackgroundColor(const QColor &color)
1231{
1232 d->textBgCustomized = true;
1233 d->textBgColor = color;
1234 update();
1235}
1236
1237QColor IconWidget::textBackgroundColor() const
1238{
1239 return d->textBgColor;
1240}
1241
1242void 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
1267void 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
1283QString IconWidget::text() const
1284{
1285 return d->text;
1286}
1287
1288void 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
1304QString IconWidget::infoText() const
1305{
1306 return d->infoText;
1307}
1308
1309QIcon IconWidget::icon() const
1310{
1311 return d->icon;
1312}
1313
1314void IconWidget::setIcon(const QString &icon)
1315{
1316 if (icon.isEmpty()) {
1317 setIcon(QIcon());
1318 return;
1319 }
1320
1321 setIcon(KIcon(icon));
1322}
1323
1324void 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
1343QSizeF IconWidget::iconSize() const
1344{
1345 return d->iconSize;
1346}
1347
1348void IconWidget::setPreferredIconSize(const QSizeF &size)
1349{
1350 d->preferredIconSize = size;
1351 updateGeometry();
1352}
1353
1354QSizeF IconWidget::preferredIconSize() const
1355{
1356 return d->preferredIconSize;
1357}
1358
1359void IconWidget::setMinimumIconSize(const QSizeF &size)
1360{
1361 d->minimumIconSize = size;
1362 updateGeometry();
1363}
1364
1365QSizeF IconWidget::minimumIconSize() const
1366{
1367 return d->minimumIconSize;
1368}
1369
1370void IconWidget::setMaximumIconSize(const QSizeF &size)
1371{
1372 d->maximumIconSize = size;
1373 updateGeometry();
1374}
1375
1376QSizeF IconWidget::maximumIconSize() const
1377{
1378 return d->maximumIconSize;
1379}
1380
1381bool IconWidget::isDown()
1382{
1383 return d->states & IconWidgetPrivate::PressedState;
1384}
1385
1386void 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
1413void 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
1433void 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
1470void 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
1484void 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
1498void 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
1514bool 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
1527void 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
1539void IconWidget::setUnpressed()
1540{
1541 setPressed(false);
1542}
1543
1544void IconWidgetPrivate::svgChanged()
1545{
1546 iconSvgElementChanged = true;
1547 q->update();
1548}
1549
1550void IconWidget::setOrientation(Qt::Orientation orientation)
1551{
1552 d->orientation = orientation;
1553 resize(sizeFromIconSize(d->iconSize.width()));
1554}
1555
1556Qt::Orientation IconWidget::orientation() const
1557{
1558 return d->orientation;
1559}
1560
1561void IconWidget::invertLayout(bool invert)
1562{
1563 d->invertLayout = invert;
1564}
1565
1566bool IconWidget::invertedLayout() const
1567{
1568 return d->invertLayout;
1569}
1570
1571QSizeF 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
1629void 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"
animation.h
animator.h
IconWidget
Provides a generic icon.
Plasma::Animator::create
static Plasma::Animation * create(Animator::Animation type, QObject *parent=0)
Factory to build new animation objects.
Definition: animator.cpp:61
Plasma::Animator::PixmapTransitionAnimation
@ PixmapTransitionAnimation
Definition: animator.h:68
Plasma::FrameSvg
Provides an SVG with borders.
Definition: framesvg.h:77
Plasma::IconWidget::setText
void setText(const QString &text)
Sets the text associated with this icon.
Definition: iconwidget.cpp:1267
Plasma::IconWidget::orientation
Qt::Orientation orientation
Definition: iconwidget.h:67
Plasma::IconWidget::doubleClicked
void doubleClicked()
Indicates when the icon has been double-clicked.
Plasma::IconWidget::pressed
void pressed(bool down)
Indicates when the icon has been pressed.
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::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
Plasma::IconWidget::clicked
void clicked()
Indicates when the icon has been clicked.
Plasma::IconWidget::icon
QIcon icon
Definition: iconwidget.h:61
Plasma::IconWidget::textBackgroundColor
QColor textBackgroundColor
Definition: iconwidget.h:62
Plasma::IconWidget::text
QString text
Definition: iconwidget.h:59
Plasma::IconWidget::iconSize
QSizeF iconSize
Definition: iconwidget.h:63
Plasma::IconWidget::activated
void activated()
Indicates when the icon has been activated following the single or doubleclick settings.
Plasma::IconWidget::setIcon
void setIcon(const QIcon &icon)
Sets the graphical icon for this Plasma::IconWidget.
Definition: iconwidget.cpp:1324
Plasma::IconWidget::action
QAction * action
Definition: iconwidget.h:66
Plasma::IconWidget::sizeFromIconSize
Q_INVOKABLE QSizeF sizeFromIconSize(const qreal iconWidth) const
Definition: iconwidget.cpp:1571
Plasma::Svg
A theme aware image-centric SVG class.
Definition: svg.h:57
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::Theme::defaultTheme
static Theme * defaultTheme()
Singleton pattern accessor.
Definition: theme.cpp:544
QGraphicsWidget
QObject
QStyleOptionGraphicsItem
QWidget
iconwidget.h
Plasma::AnimationScriptEngine::animation
QScriptValue animation(const QString &anim)
Definition: animationscriptengine.cpp:55
Plasma::PaintUtils::roundedRectangle
QPainterPath roundedRectangle(const QRectF &rect, qreal radius)
Returns a nicely rounded rectanglular path for painting.
Definition: paintutils.cpp:159
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::PaintUtils::drawHalo
void drawHalo(QPainter *painter, const QRectF &rect)
Definition: paintutils.cpp:154
Plasma
Namespace for everything in libplasma.
Definition: abstractdialogmanager.cpp:25
Plasma::Vertical
@ Vertical
The applet is constrained horizontally, but can expand vertically.
Definition: plasma.h:77
paintutils.h
svg.h
theme.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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.14.38 API Reference

Skip menu "kdelibs-4.14.38 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