26#include "iconwidget_p.h"
29#include <QApplication>
30#include <QGraphicsSceneMouseEvent>
31#include <QGraphicsView>
34#include <QStyleOptionGraphicsItem>
38#include <kcolorscheme.h>
40#include <kglobalsettings.h>
42#include <kiconeffect.h>
43#include <kiconloader.h>
50#include "private/themedwidgetinterface_p.h"
65IconHoverAnimation::IconHoverAnimation(
QObject *parent)
66 :
QObject(parent), m_value(0), m_fadeIn(false)
70qreal IconHoverAnimation::value()
const
75bool IconHoverAnimation::fadeIn()
const
80QPropertyAnimation *IconHoverAnimation::animation()
const
82 return m_animation.data();
85void IconHoverAnimation::setValue(qreal value)
92void IconHoverAnimation::setFadeIn(
bool fadeIn)
97void IconHoverAnimation::setAnimation(QPropertyAnimation *animation)
102IconWidgetPrivate::IconWidgetPrivate(
IconWidget *i)
105 hoverAnimation(new IconHoverAnimation(q)),
107 preferredIconSize(-1, -1),
108 minimumIconSize(-1, -1),
109 maximumIconSize(-1, -1),
110 states(IconWidgetPrivate::NoState),
114 iconSvgElementChanged(false),
117 textBgCustomized(false)
121IconWidgetPrivate::~IconWidgetPrivate()
123 qDeleteAll(cornerActions);
124 delete hoverAnimation;
127void IconWidgetPrivate::readColors()
131 if (qGray(textColor.rgb()) > 192) {
132 shadowColor = Qt::black;
134 shadowColor = Qt::white;
137 if (!textBgCustomized) {
138 textBgColor = QColor();
142void IconWidgetPrivate::colorConfigChanged()
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);
154void IconWidgetPrivate::iconConfigChanged()
156 if (!icon.isNull()) {
161IconAction::IconAction(
IconWidget *icon, QAction *action)
171void IconAction::show()
173 Animation *
animation = m_animation.data();
178 }
else if (
animation->state() == QAbstractAnimation::Running) {
185 animation->setProperty(
"targetPixmap", m_pixmap);
186 animation->setDirection(QAbstractAnimation::Forward);
190void IconAction::hide()
196 Animation *
animation = m_animation.data();
197 if (
animation->state() == QAbstractAnimation::Running) {
203 animation->setDirection(QAbstractAnimation::Backward);
204 animation->start(QAbstractAnimation::DeleteWhenStopped);
207bool IconAction::isVisible()
const
212bool IconAction::isAnimating()
const
214 return !m_animation.isNull();
217bool IconAction::isPressed()
const
222bool IconAction::isHovered()
const
227void IconAction::setSelected(
bool selected)
229 m_selected = selected;
232bool IconAction::isSelected()
const
237void IconAction::setRect(
const QRectF &rect)
242QRectF IconAction::rect()
const
247void IconAction::rebuildPixmap()
250 QIcon::Mode mode = m_selected ? QIcon::Selected : QIcon::Normal;
253 m_pixmap = QPixmap(26, 26);
254 m_pixmap.fill(Qt::transparent);
256 int element = IconWidgetPrivate::Minibutton;
258 element = IconWidgetPrivate::MinibuttonPressed;
259 }
else if (m_hovered) {
260 element = IconWidgetPrivate::MinibuttonHover;
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);
268bool IconAction::event(QEvent::Type type,
const QPointF &pos)
270 if (!m_action->isVisible() || !m_action->isEnabled()) {
274 if (m_icon->size().width() < m_rect.width() * 2.0 ||
275 m_icon->size().height() < m_rect.height() * 2.0) {
280 case QEvent::GraphicsSceneMousePress:
282 setSelected(m_rect.contains(pos));
287 case QEvent::GraphicsSceneMouseMove:
289 bool wasSelected = isSelected();
290 bool active = m_rect.contains(pos);
291 setSelected(wasSelected && active);
292 return (wasSelected != isSelected()) || active;
296 case QEvent::GraphicsSceneMouseRelease:
299 bool wasSelected = isSelected();
309 case QEvent::GraphicsSceneHoverEnter:
314 case QEvent::GraphicsSceneHoverLeave:
326QAction *IconAction::action()
const
331void IconAction::paint(QPainter *painter)
const
333 if (!m_action->isVisible() || !m_action->isEnabled()) {
337 if (m_icon->size().width() < m_rect.width() * 2.0 ||
338 m_icon->size().height() < m_rect.height() * 2.0) {
342 Animation *
animation = m_animation.data();
343 if (m_visible && !animation) {
344 painter->drawPixmap(m_rect.toRect(), m_pixmap);
346 painter->drawPixmap(m_rect.toRect(),
347 animation->property(
"currentPixmap").value<QPixmap>());
351IconWidget::IconWidget(QGraphicsItem *parent)
353 d(new IconWidgetPrivate(this))
358IconWidget::IconWidget(
const QString &text, QGraphicsItem *parent)
360 d(new IconWidgetPrivate(this))
366IconWidget::IconWidget(
const QIcon &icon,
const QString &text, QGraphicsItem *parent)
368 d(new IconWidgetPrivate(this))
375IconWidget::~IconWidget()
380void IconWidgetPrivate::init()
384 iconChangeTimer =
new QTimer(q);
385 iconChangeTimer->setSingleShot(
true);
388 QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorConfigChanged()));
389 QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(
int)), q, SLOT(iconConfigChanged()));
392 q->setAcceptsHoverEvents(
true);
393 q->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
396 background->setImagePath(
"widgets/viewitem");
397 background->setCacheAllRenderedFrames(
true);
398 background->setElementPrefix(
"hover");
401 setHorizontalMargin(IconWidgetPrivate::TextMargin, 1, 1);
402 setHorizontalMargin(IconWidgetPrivate::IconMargin, 1, 1);
403 setHorizontalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
406 setVerticalMargin(IconWidgetPrivate::TextMargin, 6, 2);
407 setVerticalMargin(IconWidgetPrivate::IconMargin, 1, 1);
408 setVerticalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
411 currentSize = QSizeF(-1, -1);
415void IconWidget::addIconAction(QAction *action)
417 int count = d->cornerActions.count();
418 if (count >= IconWidgetPrivate::LastIconPosition) {
419 kDebug() <<
"no more room for more actions!";
423 IconAction *iconAction =
new IconAction(
this,
action);
424 d->cornerActions.append(iconAction);
427 iconAction->setRect(d->actionRect(qMin((IconWidgetPrivate::ActionPosition)count, IconWidgetPrivate::LastIconPosition)));
430void IconWidget::removeIconAction(QAction *action)
436 foreach (IconAction *iconAction, d->cornerActions) {
438 iconAction->setRect(d->actionRect((IconWidgetPrivate::ActionPosition)count));
441 d->cornerActions.removeAll(iconAction);
444 if (count < IconWidgetPrivate::LastIconPosition) {
453void IconWidgetPrivate::actionDestroyed(
QObject *action)
455 q->removeIconAction(
static_cast<QAction*
>(action));
458void IconWidget::setAction(QAction *action)
463QAction *IconWidget::action()
const
468int IconWidget::numDisplayLines()
470 return d->numDisplayLines;
473void IconWidget::setNumDisplayLines(
int numLines)
475 if (numLines > d->maxDisplayLines) {
476 d->numDisplayLines = d->maxDisplayLines;
478 d->numDisplayLines = numLines;
482void IconWidget::setDrawBackground(
bool draw)
484 if (d->drawBg != draw) {
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);
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);
501 d->setHorizontalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
502 d->setVerticalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
510bool IconWidget::drawBackground()
const
515QPainterPath IconWidget::shape()
const
517 if (!d->drawBg || d->currentSize.width() < 1) {
518 return QGraphicsItem::shape();
522 QRectF(QPointF(0.0, 0.0), d->currentSize).adjusted(-2, -2, 2, 2), 10.0);
527 if (text.isEmpty() && infoText.isEmpty()) {
528 return QSizeF(.0, .0);
531 QString label = text;
536 qreal textWidth = width -
537 horizontalMargin[IconWidgetPrivate::TextMargin].left -
538 horizontalMargin[IconWidgetPrivate::TextMargin].right;
541 const qreal maxHeight =
542 numDisplayLines * QFontMetrics(q->font()).lineSpacing();
546 if (!infoText.isEmpty()) {
547 label += QString(QChar::LineSeparator) + infoText;
551 setLayoutOptions(layout, option, q->orientation());
552 layout.setFont(q->font());
553 QSizeF size = layoutText(layout, label, QSizeF(textWidth, maxHeight));
555 return addMargin(size, TextMargin);
560 if (option->rect.size() == currentSize) {
564 currentSize = option->rect.size();
565 iconSize = iconSizeForWidgetSize(option, currentSize);
568 foreach (IconAction *iconAction, cornerActions) {
569 iconAction->setRect(actionRect((IconWidgetPrivate::ActionPosition)count));
581 if (orientation == Qt::Vertical) {
584 if (text.isEmpty() && infoText.isEmpty()) {
585 heightAvail = rect.height();
587 heightAvail = rect.height() -
588 displaySizeHint(option, rect.width()).height() -
589 verticalMargin[IconWidgetPrivate::TextMargin].top -
590 verticalMargin[IconWidgetPrivate::TextMargin].bottom;
592 heightAvail = qMax(heightAvail, rect.height() / 2);
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;
602 iconWidth = heightAvail -
603 verticalMargin[IconWidgetPrivate::IconMargin].top -
604 verticalMargin[IconWidgetPrivate::IconMargin].bottom;
607 iconWidth = qMin(heightAvail, rect.width());
610 iconWidth -= verticalMargin[IconWidgetPrivate::ItemMargin].left + verticalMargin[IconWidgetPrivate::ItemMargin].right;
614 if (text.isEmpty() && infoText.isEmpty()) {
616 iconWidth = qMin(rect.height(), rect.width());
618 iconWidth = rect.height() -
619 horizontalMargin[IconWidgetPrivate::IconMargin].top -
620 horizontalMargin[IconWidgetPrivate::IconMargin].bottom;
622 iconWidth -= horizontalMargin[IconWidgetPrivate::ItemMargin].top + horizontalMargin[IconWidgetPrivate::ItemMargin].bottom;
625 QSizeF iconRect(iconWidth, iconWidth);
627 if (maximumIconSize.isValid()) {
628 iconRect = iconRect.boundedTo(maximumIconSize);
634void IconWidget::setSvg(
const QString &svgFilePath,
const QString &elementId)
636 if (svgFilePath.isEmpty()) {
638 d->iconSvg->deleteLater();
646 connect(d->iconSvg, SIGNAL(repaintNeeded()),
this, SLOT(svgChanged()));
647 d->oldIcon = d->icon;
649 d->oldIcon = d->iconSvg->pixmap(d->iconSvgElement);
652 d->iconSvg->setImagePath(svgFilePath);
653 d->iconSvg->setContainsMultipleImages(!elementId.isNull());
654 d->iconSvgElement = elementId;
655 d->iconSvgElementChanged =
true;
658 if (!(d->states & IconWidgetPrivate::HoverState) && !d->iconChangeTimer->isActive() && !d->oldIcon.isNull()) {
659 d->animateMainIcon(
true, d->states);
661 d->oldIcon = QIcon();
664 d->iconChangeTimer->start(300);
668QString IconWidget::svg()
const
671 if (d->iconSvg->isValid() && (d->iconSvgElement.isEmpty() || d->iconSvg->hasElement(d->iconSvgElement))) {
672 return d->iconSvg->imagePath();
681QSizeF IconWidget::sizeHint(Qt::SizeHint which,
const QSizeF & constraint)
const
683 if (which == Qt::PreferredSize) {
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());
694 iconSize = qMax(d->iconSvg->elementSize(d->iconSvgElement).width(), d->iconSvg->elementSize(d->iconSvgElement).height());
696 d->iconSvg->resize(oldSize);
701 if (constraint.width() > 0 || constraint.height() > 0) {
702 QSizeF constrainedWidgetSize(constraint);
703 QSizeF maximumWidgetSize;
705 if (d->maximumIconSize.isValid()) {
707 sizeFromIconSize(qMax(d->maximumIconSize.height(), d->maximumIconSize.width()));
710 QGraphicsWidget::sizeHint(Qt::MaximumSize);
713 if (constrainedWidgetSize.width() <= 0) {
714 constrainedWidgetSize.setWidth(maximumWidgetSize.width());
716 if (constrainedWidgetSize.height() <= 0) {
717 constrainedWidgetSize.setHeight(maximumWidgetSize.height());
722 d->iconSizeForWidgetSize(&option, constrainedWidgetSize);
724 qMin(
iconSize, qMax<int>(iconRect.width(), iconRect.height()));
728 }
else if (which == Qt::MinimumSize) {
729 if (d->minimumIconSize.isValid()) {
730 return sizeFromIconSize(qMax(d->minimumIconSize.height(), d->minimumIconSize.width()));
735 if (d->maximumIconSize.isValid()) {
736 return sizeFromIconSize(qMax(d->maximumIconSize.height(), d->maximumIconSize.width()));
739 return QGraphicsWidget::sizeHint(which, constraint);
743void IconWidgetPrivate::animateMainIcon(
bool show,
const IconWidgetStates state)
749 hoverAnimation->setFadeIn(show);
751 QPropertyAnimation *animation = hoverAnimation->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) {
764 animation->setDirection(show ? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
765 animation->start(show ? QAbstractAnimation::KeepWhenStopped : QAbstractAnimation::DeleteWhenStopped);
769void IconWidgetPrivate::hoverAnimationFinished()
771 if (!hoverAnimation->fadeIn()) {
772 states &= ~IconWidgetPrivate::HoverState;
776void IconWidgetPrivate::drawBackground(QPainter *painter, IconWidgetState state)
782 if (!(states & IconWidgetPrivate::HoverState) && !(states & IconWidgetPrivate::PressedState)) {
786 if (state == IconWidgetPrivate::PressedState) {
787 background->setElementPrefix(
"selected");
789 background->setElementPrefix(
"hover");
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()));
802 painter->drawPixmap(QPoint(0,0), frame);
806QPixmap IconWidgetPrivate::decoration(
const QStyleOptionGraphicsItem *option,
bool useHoverEffect,
bool usePressedEffect)
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;
813 QSize finalSize(iconSize.toSize());
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);
824 if (iconSvgElementChanged || iconSvgPixmap.size() != iconSize.toSize()) {
828 iconSvg->resize(finalSize);
829 iconSvgPixmap = iconSvg->pixmap(iconSvgElement);
830 iconSvgElementChanged =
false;
832 result = iconSvgPixmap;
834 QSize size(iconSize.toSize());
836 if (!icon.availableSizes().isEmpty()) {
837 finalSize = icon.actualSize(iconSize.toSize(), mode, state);
840 result = icon.pixmap(finalSize, mode, state);
843 if (usePressedEffect) {
844 result = result.scaled(result.size() * 0.9, Qt::KeepAspectRatio, Qt::SmoothTransformation);
847 if (!result.isNull() && useHoverEffect) {
848 KIconEffect *effect = KIconLoader::global()->iconEffect();
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);
856 result = PaintUtils::transition(
858 effect->apply(result, KIconLoader::Desktop,
859 KIconLoader::ActiveState), hoverAnimation->value());
862 }
else if (!result.isNull() && !oldIcon.isNull()) {
863 if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) {
866 result = PaintUtils::transition(
867 oldIcon.pixmap(result.size(), mode, state),
868 result, hoverAnimation->value());
876 const QPixmap &pixmap)
const
878 const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
881 const QSizeF size = addMargin(iconSize, IconWidgetPrivate::IconMargin);
883 Qt::LayoutDirection direction = iconDirection(option);
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);
893 alignment = QStyle::visualAlignment(
894 direction, Qt::Alignment(Qt::AlignLeft | Qt::AlignVCenter));
897 const QRect iconRect =
898 QStyle::alignedRect(direction, alignment, size.toSize(), itemRect.toRect());
901 QRect pixmapRect = pixmap.rect();
902 pixmapRect.moveCenter(iconRect.center());
907 return QPointF(pixmapRect.topLeft());
912 const QString &
string)
const
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());
924 if (orientation == Qt::Vertical) {
925 textArea.setTop(decoSize.height() + 1);
928 textArea.setLeft(decoSize.width() + 1);
931 textArea.translate(itemRect.topLeft());
932 return QRectF(QStyle::visualRect(iconDirection(option), option->rect, textArea.toRect()));
936QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout,
938 const QSizeF &constraints)
const
940 const QSizeF size = layoutText(layout, text, constraints.width());
942 if (size.width() > constraints.width() || size.height() > constraints.height()) {
944 q->setToolTip(action->toolTip());
946 const QString elided = elidedText(layout, constraints);
947 return layoutText(layout, elided, constraints.width());
949 q->setToolTip(QString());
955QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout,
const QString &text, qreal maxWidth)
const
957 QFontMetricsF metrics(layout.font());
958 qreal leading = metrics.leading();
960 qreal widthUsed = 0.0;
963 layout.setText(text);
965 layout.beginLayout();
967 while ((line = layout.createLine()).isValid()) {
968 line.setLineWidth(maxWidth);
970 line.setPosition(QPointF(0.0, height));
971 height += line.height();
972 widthUsed = qMax(widthUsed, line.naturalTextWidth());
976 return QSizeF(widthUsed, height);
983QString IconWidgetPrivate::elidedText(QTextLayout &layout,
const QSizeF &size)
const
985 QFontMetricsF metrics(layout.font());
986 const QString text = layout.text();
987 qreal maxWidth = size.width();
988 qreal maxHeight = size.height();
993 elided.reserve(text.length());
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();
1000 height += metrics.leading();
1001 if (height + line.height() + metrics.lineSpacing() > maxHeight) {
1005 if (line.naturalTextWidth() < maxWidth &&
1006 start + length > 0 &&
1007 text[start + length - 1] == QChar::LineSeparator) {
1008 elided += text.mid(start, length - 1);
1010 elided += metrics.elidedText(text.mid(start), Qt::ElideRight, maxWidth);
1013 }
else if (line.naturalTextWidth() > maxWidth) {
1014 elided += metrics.elidedText(text.mid(start, length), Qt::ElideRight, maxWidth);
1016 elided += text.mid(start, length);
1019 height += line.height();
1026 const QPixmap &icon, QTextLayout *labelLayout,
1027 QTextLayout *infoLayout, QRectF *textBoundingRect)
const
1029 bool showInformation =
false;
1031 setLayoutOptions(*labelLayout, option, q->orientation());
1033 QFontMetricsF fm(labelLayout->font());
1034 const QRectF textArea = labelRectangle(option, icon, text);
1035 QRectF textRect = subtractMargin(textArea, IconWidgetPrivate::TextMargin);
1039 QSizeF maxLabelSize = textRect.size();
1040 QSizeF maxInfoSize = textRect.size();
1046 if (!infoText.isEmpty() && textRect.height() >= fm.lineSpacing() * 2) {
1047 infoLayout->setFont(labelLayout->font());
1048 infoLayout->setTextOption(labelLayout->textOption());
1050 maxLabelSize.rheight() -= fm.lineSpacing();
1051 showInformation =
true;
1055 labelSize = layoutText(*labelLayout, text, maxLabelSize);
1056 maxInfoSize.rheight() -= labelSize.height();
1059 if (showInformation) {
1060 infoSize = layoutText(*infoLayout, infoText, maxInfoSize);
1062 infoSize = QSizeF(0, 0);
1065 const Qt::Alignment alignment = labelLayout->textOption().alignment();
1066 const QSizeF size(qMax(labelSize.width(), infoSize.width()),
1067 labelSize.height() + infoSize.height());
1069 QStyle::alignedRect(iconDirection(option), alignment, size.toSize(), textRect.toRect());
1073 labelLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y()));
1075 for (
int i = 0; i < labelLayout->lineCount(); ++i) {
1076 line = labelLayout->lineAt(i);
1077 haloRects.append(line.naturalTextRect().translated(labelLayout->position().toPoint()).toRect());
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());
1089 const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
1090 QPalette::Normal : QPalette::Disabled;
1093 if (option->state & QStyle::State_Selected) {
1094 return option->palette.brush(group, QPalette::HighlightedText);
1096 return option->palette.brush(group, QPalette::Text);
1101 const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
1102 QPalette::Normal : QPalette::Disabled;
1104 QBrush background(Qt::NoBrush);
1107 if (option->state & QStyle::State_Selected) {
1108 background = option->palette.brush(group, QPalette::Highlight);
1113void IconWidgetPrivate::drawTextItems(QPainter *painter,
1115 const QTextLayout &labelLayout,
1116 const QTextLayout &infoLayout)
const
1121 painter->setPen(textColor);
1125 painter->translate(0.5, 0.5);
1127 labelLayout.draw(painter, QPointF());
1129 if (!infoLayout.text().isEmpty()) {
1130 painter->setPen(textColor);
1131 infoLayout.draw(painter, QPointF());
1141 d->layoutIcons(option);
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;
1152 }
else if (d->states & IconWidgetPrivate::HoverState) {
1153 state = IconWidgetPrivate::HoverState;
1156 QPixmap
icon = d->decoration(option, state != IconWidgetPrivate::NoState, state & IconWidgetPrivate::PressedState);
1157 const QPointF iconPos = d->iconPosition(option,
icon);
1159 d->drawBackground(painter, state);
1162 if (!
icon.isNull()) {
1163 painter->drawPixmap(iconPos,
icon);
1167 foreach (
const IconAction *
action, d->cornerActions) {
1168 if (
action->isAnimating()) {
1174 QTextLayout labelLayout, infoLayout;
1175 QRectF textBoundingRect;
1177 d->layoutTextItems(option,
icon, &labelLayout, &infoLayout, &textBoundingRect);
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);
1201 if (d->shadowColor.value() < 128) {
1202 shadowPos = QPoint(1, 2);
1204 shadowPos = QPoint(0, 0);
1207 QImage shadow(textBoundingRect.size().toSize() + QSize(4, 4),
1208 QImage::Format_ARGB32_Premultiplied);
1209 shadow.fill(Qt::transparent);
1211 QPainter buffPainter(&shadow);
1212 buffPainter.translate(-textBoundingRect.x(), -textBoundingRect.y());
1213 d->drawTextItems(&buffPainter, option, labelLayout, infoLayout);
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();
1222 foreach (
const QRect &rect, d->haloRects) {
1227 d->drawTextItems(painter, option, labelLayout, infoLayout);
1230void IconWidget::setTextBackgroundColor(
const QColor &color)
1232 d->textBgCustomized =
true;
1233 d->textBgColor = color;
1237QColor IconWidget::textBackgroundColor()
const
1239 return d->textBgColor;
1242void IconWidget::drawActionButtonBase(QPainter *painter,
const QSize &size,
int element)
1244 qreal radius = size.width() / 2;
1245 QRadialGradient gradient(radius, radius, radius, radius, radius);
1248 if (element == IconWidgetPrivate::MinibuttonPressed) {
1250 }
else if (element == IconWidgetPrivate::MinibuttonHover) {
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));
1262 painter->setBrush(gradient);
1263 painter->setPen(Qt::NoPen);
1264 painter->drawEllipse(QRectF(QPointF(.0, .0), size));
1267void IconWidget::setText(
const QString &text)
1269 d->text = KGlobal::locale()->removeAcceleratorMarker(
text);
1271 d->currentSize = QSizeF(-1, -1);
1275 d->layoutIcons(&styleoption);
1278 if (!parentWidget() || !parentWidget()->layout()) {
1279 resize(preferredSize());
1283QString IconWidget::text()
const
1288void IconWidget::setInfoText(
const QString &text)
1292 d->currentSize = QSizeF(-1, -1);
1296 d->layoutIcons(&styleoption);
1299 if (!parentWidget() || !parentWidget()->layout()) {
1300 resize(preferredSize());
1304QString IconWidget::infoText()
const
1309QIcon IconWidget::icon()
const
1314void IconWidget::setIcon(
const QString &icon)
1316 if (
icon.isEmpty()) {
1324void IconWidget::setIcon(
const QIcon &icon)
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);
1336 d->oldIcon = QIcon();
1338 d->iconChangeTimer->start(300);
1343QSizeF IconWidget::iconSize()
const
1348void IconWidget::setPreferredIconSize(
const QSizeF &size)
1350 d->preferredIconSize = size;
1354QSizeF IconWidget::preferredIconSize()
const
1356 return d->preferredIconSize;
1359void IconWidget::setMinimumIconSize(
const QSizeF &size)
1361 d->minimumIconSize = size;
1365QSizeF IconWidget::minimumIconSize()
const
1367 return d->minimumIconSize;
1370void IconWidget::setMaximumIconSize(
const QSizeF &size)
1372 d->maximumIconSize = size;
1376QSizeF IconWidget::maximumIconSize()
const
1378 return d->maximumIconSize;
1381bool IconWidget::isDown()
1383 return d->states & IconWidgetPrivate::PressedState;
1386void IconWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
1388 if (event->button() != Qt::LeftButton) {
1389 QGraphicsWidget::mousePressEvent(event);
1393 if (KGlobalSettings::singleClick() || (receivers(SIGNAL(
clicked()))) > 0) {
1394 d->states |= IconWidgetPrivate::PressedState;
1396 d->clickStartPos = scenePos();
1398 bool handled =
false;
1399 foreach (IconAction *
action, d->cornerActions) {
1400 handled =
action->event(event->type(), event->pos());
1406 if (!handled && boundingRect().contains(event->pos())) {
1413void IconWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1415 if (~d->states & IconWidgetPrivate::PressedState) {
1416 QGraphicsWidget::mouseMoveEvent(event);
1420 if (boundingRect().contains(event->pos())) {
1421 if (~d->states & IconWidgetPrivate::HoverState) {
1422 d->states |= IconWidgetPrivate::HoverState;
1426 if (d->states & IconWidgetPrivate::HoverState) {
1427 d->states &= ~IconWidgetPrivate::HoverState;
1433void IconWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1435 if (~d->states & IconWidgetPrivate::PressedState) {
1436 QGraphicsWidget::mouseMoveEvent(event);
1440 d->states &= ~IconWidgetPrivate::PressedState;
1443 bool handled = d->clickStartPos != scenePos();
1445 foreach (IconAction *
action, d->cornerActions) {
1446 if (
action->event(event->type(), event->pos())) {
1454 if (boundingRect().contains(event->pos())) {
1456 if (KGlobalSettings::singleClick()) {
1460 if (d->action && d->action->menu()) {
1461 d->action->menu()->popup(event->screenPos());
1470void IconWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1474 d->states |= IconWidgetPrivate::PressedState;
1477 if (!KGlobalSettings::singleClick()) {
1484void IconWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
1487 foreach (IconAction *
action, d->cornerActions) {
1489 action->event(event->type(), event->pos());
1492 d->oldIcon = QIcon();
1493 d->animateMainIcon(
true, d->states|IconWidgetPrivate::HoverState);
1495 QGraphicsWidget::hoverEnterEvent(event);
1498void IconWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
1501 foreach (IconAction *
action, d->cornerActions) {
1503 action->event(event->type(), event->pos());
1507 d->states &= ~IconWidgetPrivate::PressedState;
1509 d->animateMainIcon(
false, d->states|IconWidgetPrivate::HoverState);
1511 QGraphicsWidget::hoverLeaveEvent(event);
1514bool IconWidget::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
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);
1527void IconWidget::setPressed(
bool pressed)
1530 d->states |= IconWidgetPrivate::ManualPressedState;
1531 d->states |= IconWidgetPrivate::PressedState;
1533 d->states &= ~IconWidgetPrivate::ManualPressedState;
1534 d->states &= ~IconWidgetPrivate::PressedState;
1539void IconWidget::setUnpressed()
1544void IconWidgetPrivate::svgChanged()
1546 iconSvgElementChanged =
true;
1550void IconWidget::setOrientation(Qt::Orientation orientation)
1556Qt::Orientation IconWidget::orientation()
const
1558 return d->orientation;
1561void IconWidget::invertLayout(
bool invert)
1563 d->invertLayout = invert;
1566bool IconWidget::invertedLayout()
const
1568 return d->invertLayout;
1571QSizeF IconWidget::sizeFromIconSize(
const qreal iconWidth)
const
1573 d->setActiveMargins();
1574 if (d->text.isEmpty() && d->infoText.isEmpty()) {
1576 return d->addMargin(QSizeF(iconWidth, iconWidth), IconWidgetPrivate::ItemMargin);
1579 QFontMetricsF fm(font());
1582 if (d->orientation == Qt::Vertical) {
1583 width = qMax(d->maxWordWidth(d->text),
1584 d->maxWordWidth(d->infoText)) +
1586 d->verticalMargin[IconWidgetPrivate::TextMargin].left +
1587 d->verticalMargin[IconWidgetPrivate::TextMargin].right;
1591 d->verticalMargin[IconWidgetPrivate::IconMargin].left +
1592 d->verticalMargin[IconWidgetPrivate::IconMargin].right);
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;
1606 option.state = QStyle::State_None;
1607 option.rect = QRect(0, 0, width, QWIDGETSIZE_MAX);
1608 textHeight = d->displaySizeHint(&option, width).height();
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;
1618 height = qMax(iconWidth +
1619 d->verticalMargin[IconWidgetPrivate::IconMargin].top +
1620 d->verticalMargin[IconWidgetPrivate::IconMargin].bottom,
1622 d->verticalMargin[IconWidgetPrivate::TextMargin].top +
1623 d->verticalMargin[IconWidgetPrivate::TextMargin].bottom);
1626 return d->addMargin(QSizeF(width, height), IconWidgetPrivate::ItemMargin);
1629void IconWidget::changeEvent(QEvent *event)
1631 d->changeEvent(event);
1632 QGraphicsWidget::changeEvent(event);
1637#include "iconwidget.moc"
1638#include "iconwidget_p.moc"
static Plasma::Animation * create(Animator::Animation type, QObject *parent=0)
Factory to build new animation objects.
@ PixmapTransitionAnimation
Provides an SVG with borders.
A theme aware image-centric SVG class.
Q_INVOKABLE QColor color(ColorRole role) const
Returns the text color to be used by items resting on the background.
static Theme * defaultTheme()
Singleton pattern accessor.
QScriptValue animation(const QString &anim)
QPainterPath roundedRectangle(const QRectF &rect, qreal radius)
Returns a nicely rounded rectanglular path for painting.
void shadowBlur(QImage &image, int radius, const QColor &color)
Creates a blurred shadow of the supplied image.
void drawHalo(QPainter *painter, const QRectF &rect)
Namespace for everything in libplasma.
@ Vertical
The applet is constrained horizontally, but can expand vertically.