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

Plasma

iconwidget.cpp
Go to the documentation of this file.
00001 /*
00002  *   Copyright 2007 by Aaron Seigo <aseigo@kde.org>
00003  *   Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
00004  *   Copyright 2007 by Matt Broadstone <mbroadst@gmail.com>
00005  *   Copyright 2006-2007 Fredrik Höglund <fredrik@kde.org>
00006  *   Copyright 2007 by Marco Martin <notmart@gmail.com>
00007  *   Copyright 2008 by Alexis Ménard <darktears31@gmail.com>
00008  *
00009  *   This program is free software; you can redistribute it and/or modify
00010  *   it under the terms of the GNU Library General Public License as
00011  *   published by the Free Software Foundation; either version 2, or
00012  *   (at your option) any later version.
00013  *
00014  *   This program is distributed in the hope that it will be useful,
00015  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *   GNU General Public License for more details
00018  *
00019  *   You should have received a copy of the GNU Library General Public
00020  *   License along with this program; if not, write to the
00021  *   Free Software Foundation, Inc.,
00022  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023  */
00024 
00025 #include "iconwidget.h"
00026 #include "iconwidget_p.h"
00027 
00028 #include <QAction>
00029 #include <QApplication>
00030 #include <QGraphicsSceneMouseEvent>
00031 #include <QGraphicsView>
00032 #include <QMenu>
00033 #include <QPainter>
00034 #include <QStyleOptionGraphicsItem>
00035 #include <QTextLayout>
00036 #include <QTimer>
00037 
00038 #include <kcolorscheme.h>
00039 #include <kdebug.h>
00040 #include <kglobalsettings.h>
00041 #include <kicon.h>
00042 #include <kiconeffect.h>
00043 #include <kiconloader.h>
00044 #include <kmimetype.h>
00045 #include <kurl.h>
00046 
00047 #include "animator.h"
00048 #include "animations/animation.h"
00049 #include "paintutils.h"
00050 #include "private/themedwidgetinterface_p.h"
00051 #include "theme.h"
00052 
00053 #include "svg.h"
00054 
00055 /*
00056 TODO:
00057     Add these to a UrlIcon class
00058     void setUrl(const KUrl& url);
00059     KUrl url() const;
00060 */
00061 
00062 namespace Plasma
00063 {
00064 
00065 IconHoverAnimation::IconHoverAnimation(QObject *parent)
00066     : QObject(parent), m_value(0), m_fadeIn(false)
00067 {
00068 }
00069 
00070 qreal IconHoverAnimation::value() const
00071 {
00072     return m_value;
00073 }
00074 
00075 bool IconHoverAnimation::fadeIn() const
00076 {
00077     return m_fadeIn;
00078 }
00079 
00080 QPropertyAnimation *IconHoverAnimation::animation() const
00081 {
00082     return m_animation.data();
00083 }
00084 
00085 void IconHoverAnimation::setValue(qreal value)
00086 {
00087     m_value = value;
00088     QGraphicsWidget *item = static_cast<QGraphicsWidget*>(parent());
00089     item->update();
00090 }
00091 
00092 void IconHoverAnimation::setFadeIn(bool fadeIn)
00093 {
00094     m_fadeIn = fadeIn;
00095 }
00096 
00097 void IconHoverAnimation::setAnimation(QPropertyAnimation *animation)
00098 {
00099     m_animation = animation;
00100 }
00101 
00102 IconWidgetPrivate::IconWidgetPrivate(IconWidget *i)
00103     : ActionWidgetInterface<IconWidget>(i),
00104       iconSvg(0),
00105       hoverAnimation(new IconHoverAnimation(q)),
00106       iconSize(48, 48),
00107       preferredIconSize(-1, -1),
00108       minimumIconSize(-1, -1),
00109       maximumIconSize(-1, -1),
00110       states(IconWidgetPrivate::NoState),
00111       orientation(Qt::Vertical),
00112       numDisplayLines(2),
00113       activeMargins(0),
00114       iconSvgElementChanged(false),
00115       invertLayout(false),
00116       drawBg(false),
00117       textBgCustomized(false)
00118 {
00119 }
00120 
00121 IconWidgetPrivate::~IconWidgetPrivate()
00122 {
00123     qDeleteAll(cornerActions);
00124     delete hoverAnimation;
00125 }
00126 
00127 void IconWidgetPrivate::readColors()
00128 {
00129     textColor = Plasma::Theme::defaultTheme()->color(Theme::TextColor);
00130 
00131     if (qGray(textColor.rgb()) > 192) {
00132         shadowColor = Qt::black;
00133     } else {
00134         shadowColor = Qt::white;
00135     }
00136 
00137     if (!textBgCustomized) {
00138         textBgColor = QColor();
00139     }
00140 }
00141 
00142 void IconWidgetPrivate::colorConfigChanged()
00143 {
00144     readColors();
00145     if (drawBg) {
00146         qreal left, top, right, bottom;
00147         background->getMargins(left, top, right, bottom);
00148         setVerticalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
00149         setHorizontalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
00150     }
00151     q->update();
00152 }
00153 
00154 void IconWidgetPrivate::iconConfigChanged()
00155 {
00156     if (!icon.isNull()) {
00157         q->update();
00158     }
00159 }
00160 
00161 IconAction::IconAction(IconWidget *icon, QAction *action)
00162     : m_icon(icon),
00163       m_action(action),
00164       m_hovered(false),
00165       m_pressed(false),
00166       m_selected(false),
00167       m_visible(false)
00168 {
00169 }
00170 
00171 void IconAction::show()
00172 {
00173     Animation *animation = m_animation.data();
00174     if (!animation) {
00175         animation = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation, m_icon);
00176         animation->setTargetWidget(m_icon);
00177         m_animation = animation;
00178     } else if (animation->state() == QAbstractAnimation::Running) {
00179         animation->pause();
00180     }
00181 
00182     rebuildPixmap();
00183     m_visible = true;
00184 
00185     animation->setProperty("targetPixmap", m_pixmap);
00186     animation->setDirection(QAbstractAnimation::Forward);
00187     animation->start();
00188 }
00189 
00190 void IconAction::hide()
00191 {
00192     if (!m_animation) {
00193         return;
00194     }
00195 
00196     Animation *animation = m_animation.data();
00197     if (animation->state() == QAbstractAnimation::Running) {
00198         animation->pause();
00199     }
00200 
00201     m_visible = false;
00202 
00203     animation->setDirection(QAbstractAnimation::Backward);
00204     animation->start(QAbstractAnimation::DeleteWhenStopped);
00205 }
00206 
00207 bool IconAction::isVisible() const
00208 {
00209     return m_visible;
00210 }
00211 
00212 bool IconAction::isAnimating() const
00213 {
00214     return !m_animation.isNull();
00215 }
00216 
00217 bool IconAction::isPressed() const
00218 {
00219     return m_pressed;
00220 }
00221 
00222 bool IconAction::isHovered() const
00223 {
00224     return m_hovered;
00225 }
00226 
00227 void IconAction::setSelected(bool selected)
00228 {
00229     m_selected = selected;
00230 }
00231 
00232 bool IconAction::isSelected() const
00233 {
00234     return m_selected;
00235 }
00236 
00237 void IconAction::setRect(const QRectF &rect)
00238 {
00239     m_rect = rect;
00240 }
00241 
00242 QRectF IconAction::rect() const
00243 {
00244     return m_rect;
00245 }
00246 
00247 void IconAction::rebuildPixmap()
00248 {
00249     // Determine proper QIcon mode based on selection status
00250     QIcon::Mode mode = m_selected ? QIcon::Selected : QIcon::Normal;
00251 
00252     // Draw everything
00253     m_pixmap = QPixmap(26, 26);
00254     m_pixmap.fill(Qt::transparent);
00255 
00256     int element = IconWidgetPrivate::Minibutton;
00257     if (m_pressed) {
00258         element = IconWidgetPrivate::MinibuttonPressed;
00259     } else if (m_hovered) {
00260         element = IconWidgetPrivate::MinibuttonHover;
00261     }
00262 
00263     QPainter painter(&m_pixmap);
00264     m_icon->drawActionButtonBase(&painter, m_pixmap.size(), element);
00265     m_action->icon().paint(&painter, 2, 2, 22, 22, Qt::AlignCenter, mode);
00266 }
00267 
00268 bool IconAction::event(QEvent::Type type, const QPointF &pos)
00269 {
00270     if (!m_action->isVisible() || !m_action->isEnabled()) {
00271         return false;
00272     }
00273 
00274     if (m_icon->size().width() < m_rect.width() * 2.0 ||
00275         m_icon->size().height() < m_rect.height() * 2.0) {
00276         return false;
00277     }
00278 
00279     switch (type) {
00280     case QEvent::GraphicsSceneMousePress:
00281     {
00282         setSelected(m_rect.contains(pos));
00283         return isSelected();
00284     }
00285     break;
00286 
00287     case QEvent::GraphicsSceneMouseMove:
00288     {
00289         bool wasSelected = isSelected();
00290         bool active = m_rect.contains(pos);
00291         setSelected(wasSelected && active);
00292         return (wasSelected != isSelected()) || active;
00293     }
00294     break;
00295 
00296     case QEvent::GraphicsSceneMouseRelease:
00297     {
00298         // kDebug() << "IconAction::event got a QEvent::MouseButtonRelease, " << isSelected();
00299         bool wasSelected = isSelected();
00300         setSelected(false);
00301         if (wasSelected) {
00302             m_action->trigger();
00303         }
00304 
00305         return wasSelected;
00306     }
00307     break;
00308 
00309     case QEvent::GraphicsSceneHoverEnter:
00310         m_pressed = false;
00311         m_hovered = true;
00312         break;
00313 
00314     case QEvent::GraphicsSceneHoverLeave:
00315         m_pressed = false;
00316         m_hovered = false;
00317         break;
00318 
00319     default:
00320         break;
00321     }
00322 
00323     return false;
00324 }
00325 
00326 QAction *IconAction::action() const
00327 {
00328     return m_action;
00329 }
00330 
00331 void IconAction::paint(QPainter *painter) const
00332 {
00333     if (!m_action->isVisible() || !m_action->isEnabled()) {
00334         return;
00335     }
00336 
00337     if (m_icon->size().width() < m_rect.width() * 2.0 ||
00338         m_icon->size().height() < m_rect.height() * 2.0) {
00339         return;
00340     }
00341 
00342     Animation *animation = m_animation.data();
00343     if (m_visible && !animation) {
00344         painter->drawPixmap(m_rect.toRect(), m_pixmap);
00345     } else {
00346         painter->drawPixmap(m_rect.toRect(),
00347                 animation->property("currentPixmap").value<QPixmap>());
00348     }
00349 }
00350 
00351 IconWidget::IconWidget(QGraphicsItem *parent)
00352     : QGraphicsWidget(parent),
00353       d(new IconWidgetPrivate(this))
00354 {
00355     d->init();
00356 }
00357 
00358 IconWidget::IconWidget(const QString &text, QGraphicsItem *parent)
00359     : QGraphicsWidget(parent),
00360       d(new IconWidgetPrivate(this))
00361 {
00362     d->init();
00363     setText(text);
00364 }
00365 
00366 IconWidget::IconWidget(const QIcon &icon, const QString &text, QGraphicsItem *parent)
00367     : QGraphicsWidget(parent),
00368       d(new IconWidgetPrivate(this))
00369 {
00370     d->init();
00371     setText(text);
00372     setIcon(icon);
00373 }
00374 
00375 IconWidget::~IconWidget()
00376 {
00377     delete d;
00378 }
00379 
00380 void IconWidgetPrivate::init()
00381 {
00382     readColors();
00383 
00384     iconChangeTimer = new QTimer(q);
00385     iconChangeTimer->setSingleShot(true);
00386 
00387     QObject::connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), q, SLOT(colorConfigChanged()));
00388     QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorConfigChanged()));
00389     QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), q, SLOT(iconConfigChanged()));
00390 
00391     // setAcceptedMouseButtons(Qt::LeftButton);
00392     q->setAcceptsHoverEvents(true);
00393     q->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
00394 
00395     background = new Plasma::FrameSvg(q);
00396     background->setImagePath("widgets/viewitem");
00397     background->setCacheAllRenderedFrames(true);
00398     background->setElementPrefix("hover");
00399 
00400     // Margins for horizontal mode (list views, tree views, table views)
00401     setHorizontalMargin(IconWidgetPrivate::TextMargin, 1, 1);
00402     setHorizontalMargin(IconWidgetPrivate::IconMargin, 1, 1);
00403     setHorizontalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
00404 
00405     // Margins for vertical mode (icon views)
00406     setVerticalMargin(IconWidgetPrivate::TextMargin, 6, 2);
00407     setVerticalMargin(IconWidgetPrivate::IconMargin, 1, 1);
00408     setVerticalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
00409 
00410     setActiveMargins();
00411     currentSize = QSizeF(-1, -1);
00412     initTheming();
00413 }
00414 
00415 void IconWidget::addIconAction(QAction *action)
00416 {
00417     int count = d->cornerActions.count();
00418     if (count >= IconWidgetPrivate::LastIconPosition) {
00419         kDebug() << "no more room for more actions!";
00420         // just overlap it with the last item for now. ugly, but there you go.
00421     }
00422 
00423     IconAction *iconAction = new IconAction(this, action);
00424     d->cornerActions.append(iconAction);
00425     connect(action, SIGNAL(destroyed(QObject*)), this, SLOT(actionDestroyed(QObject*)));
00426 
00427     iconAction->setRect(d->actionRect(qMin((IconWidgetPrivate::ActionPosition)count, IconWidgetPrivate::LastIconPosition)));
00428 }
00429 
00430 void IconWidget::removeIconAction(QAction *action)
00431 {
00432     //WARNING: do NOT access the action pointer passed in, as it may already be
00433     //be destroyed. see IconWidgetPrivate::actionDestroyed(QObject*)
00434     int count = 0;
00435     bool found = false;
00436     foreach (IconAction *iconAction, d->cornerActions) {
00437         if (found) {
00438             iconAction->setRect(d->actionRect((IconWidgetPrivate::ActionPosition)count));
00439         } else if (!action || iconAction->action() == action) {
00440             delete iconAction;
00441             d->cornerActions.removeAll(iconAction);
00442         }
00443 
00444         if (count < IconWidgetPrivate::LastIconPosition) {
00445             ++count;
00446         }
00447     }
00448 
00449     // redraw since an action has been deleted.
00450     update();
00451 }
00452 
00453 void IconWidgetPrivate::actionDestroyed(QObject *action)
00454 {
00455     q->removeIconAction(static_cast<QAction*>(action));
00456 }
00457 
00458 void IconWidget::setAction(QAction *action)
00459 {
00460     d->setAction(action);
00461 }
00462 
00463 QAction *IconWidget::action() const
00464 {
00465     return d->action;
00466 }
00467 
00468 int IconWidget::numDisplayLines()
00469 {
00470     return d->numDisplayLines;
00471 }
00472 
00473 void IconWidget::setNumDisplayLines(int numLines)
00474 {
00475     if (numLines > d->maxDisplayLines) {
00476         d->numDisplayLines = d->maxDisplayLines;
00477     } else {
00478         d->numDisplayLines = numLines;
00479     }
00480 }
00481 
00482 void IconWidget::setDrawBackground(bool draw)
00483 {
00484     if (d->drawBg != draw) {
00485         d->drawBg = draw;
00486 
00487         QStyle *style = QApplication::style();
00488         int focusHMargin = draw ? style->pixelMetric(QStyle::PM_FocusFrameHMargin) : 1;
00489         int focusVMargin = draw ? style->pixelMetric(QStyle::PM_FocusFrameVMargin) : 1;
00490         d->setHorizontalMargin(IconWidgetPrivate::TextMargin, focusHMargin, focusVMargin);
00491         d->setHorizontalMargin(IconWidgetPrivate::IconMargin, focusHMargin, focusVMargin);
00492         d->setVerticalMargin(IconWidgetPrivate::IconMargin, focusHMargin, focusVMargin);
00493         d->currentSize = QSizeF(-1, -1);
00494 
00495         if (draw) {
00496             qreal left, top, right, bottom;
00497             d->background->getMargins(left, top, right, bottom);
00498             d->setHorizontalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
00499             d->setVerticalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
00500         } else {
00501             d->setHorizontalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
00502             d->setVerticalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
00503         }
00504 
00505         update();
00506         updateGeometry();
00507     }
00508 }
00509 
00510 bool IconWidget::drawBackground() const
00511 {
00512     return d->drawBg;
00513 }
00514 
00515 QPainterPath IconWidget::shape() const
00516 {
00517     if (!d->drawBg || d->currentSize.width() < 1) {
00518         return QGraphicsItem::shape();
00519     }
00520 
00521     return PaintUtils::roundedRectangle(
00522         QRectF(QPointF(0.0, 0.0), d->currentSize).adjusted(-2, -2, 2, 2), 10.0);
00523 }
00524 
00525 QSizeF IconWidgetPrivate::displaySizeHint(const QStyleOptionGraphicsItem *option, const qreal width) const
00526 {
00527     if (text.isEmpty() && infoText.isEmpty()) {
00528       return QSizeF(.0, .0);
00529     }
00530 
00531     QString label = text;
00532     // const qreal maxWidth = (orientation == Qt::Vertical) ? iconSize.width() + 10 : 32757;
00533     // NOTE: find a way to use the other layoutText, it currently returns nominal width, when
00534     //       we actually need the actual width.
00535 
00536     qreal textWidth = width -
00537                       horizontalMargin[IconWidgetPrivate::TextMargin].left -
00538                       horizontalMargin[IconWidgetPrivate::TextMargin].right;
00539 
00540     //allow only five lines of text
00541     const qreal maxHeight =
00542         numDisplayLines * QFontMetrics(q->font()).lineSpacing();
00543 
00544     // To compute the nominal size for the label + info, we'll just append
00545     // the information string to the label
00546     if (!infoText.isEmpty()) {
00547         label += QString(QChar::LineSeparator) + infoText;
00548     }
00549 
00550     QTextLayout layout;
00551     setLayoutOptions(layout, option, q->orientation());
00552     layout.setFont(q->font());
00553     QSizeF size = layoutText(layout, label, QSizeF(textWidth, maxHeight));
00554 
00555     return addMargin(size, TextMargin);
00556 }
00557 
00558 void IconWidgetPrivate::layoutIcons(const QStyleOptionGraphicsItem *option)
00559 {
00560     if (option->rect.size() == currentSize) {
00561         return;
00562     }
00563 
00564     currentSize = option->rect.size();
00565     iconSize = iconSizeForWidgetSize(option, currentSize);
00566 
00567     int count = 0;
00568     foreach (IconAction *iconAction, cornerActions) {
00569         iconAction->setRect(actionRect((IconWidgetPrivate::ActionPosition)count));
00570         ++count;
00571     }
00572 }
00573 
00574 QSizeF IconWidgetPrivate::iconSizeForWidgetSize(const QStyleOptionGraphicsItem *option, const QSizeF &rect)
00575 {
00576     setActiveMargins();
00577 
00578     //calculate icon size based on the available space
00579     qreal iconWidth;
00580 
00581     if (orientation == Qt::Vertical) {
00582         qreal heightAvail;
00583         //if there is text resize the icon in order to make room for the text
00584         if (text.isEmpty() && infoText.isEmpty()) {
00585             heightAvail = rect.height();
00586         } else {
00587             heightAvail = rect.height() -
00588                           displaySizeHint(option, rect.width()).height() -
00589                           verticalMargin[IconWidgetPrivate::TextMargin].top -
00590                           verticalMargin[IconWidgetPrivate::TextMargin].bottom;
00591             //never make a label higher than half the total height
00592             heightAvail = qMax(heightAvail, rect.height() / 2);
00593         }
00594 
00595         //aspect ratio very "tall"
00596         if (!text.isEmpty() || !infoText.isEmpty()) {
00597             if (rect.width() < heightAvail) {
00598                 iconWidth = rect.width() -
00599                             verticalMargin[IconWidgetPrivate::IconMargin].left -
00600                             verticalMargin[IconWidgetPrivate::IconMargin].right;
00601             } else {
00602                 iconWidth = heightAvail -
00603                             verticalMargin[IconWidgetPrivate::IconMargin].top -
00604                             verticalMargin[IconWidgetPrivate::IconMargin].bottom;
00605             }
00606         } else {
00607             iconWidth = qMin(heightAvail, rect.width());
00608         }
00609 
00610         iconWidth -= verticalMargin[IconWidgetPrivate::ItemMargin].left + verticalMargin[IconWidgetPrivate::ItemMargin].right;
00611     } else {
00612         //Horizontal layout
00613         //if there is text resize the icon in order to make room for the text
00614         if (text.isEmpty() && infoText.isEmpty()) {
00615             // with no text, we just take up the whole geometry
00616             iconWidth = qMin(rect.height(), rect.width());
00617         } else {
00618             iconWidth = rect.height() -
00619                         horizontalMargin[IconWidgetPrivate::IconMargin].top -
00620                         horizontalMargin[IconWidgetPrivate::IconMargin].bottom;
00621         }
00622         iconWidth -= horizontalMargin[IconWidgetPrivate::ItemMargin].top + horizontalMargin[IconWidgetPrivate::ItemMargin].bottom;
00623     }
00624 
00625     QSizeF iconRect(iconWidth, iconWidth);
00626 
00627     if (maximumIconSize.isValid()) {
00628         iconRect = iconRect.boundedTo(maximumIconSize);
00629     }
00630 
00631     return iconRect;
00632 }
00633 
00634 void IconWidget::setSvg(const QString &svgFilePath, const QString &elementId)
00635 {
00636     if (svgFilePath.isEmpty()) {
00637         if (d->iconSvg) {
00638             d->iconSvg->deleteLater();
00639             d->iconSvg = 0;
00640         }
00641         return;
00642     }
00643 
00644     if (!d->iconSvg) {
00645         d->iconSvg = new Plasma::Svg(this);
00646         connect(d->iconSvg, SIGNAL(repaintNeeded()), this, SLOT(svgChanged()));
00647         d->oldIcon = d->icon;
00648     } else {
00649         d->oldIcon = d->iconSvg->pixmap(d->iconSvgElement);
00650     }
00651 
00652     d->iconSvg->setImagePath(svgFilePath);
00653     d->iconSvg->setContainsMultipleImages(!elementId.isNull());
00654     d->iconSvgElement = elementId;
00655     d->iconSvgElementChanged = true;
00656     updateGeometry();
00657 
00658     if (!(d->states & IconWidgetPrivate::HoverState) && !d->iconChangeTimer->isActive() && !d->oldIcon.isNull()) {
00659         d->animateMainIcon(true, d->states);
00660     } else {
00661         d->oldIcon = QIcon();
00662         update();
00663     }
00664     d->iconChangeTimer->start(300);
00665     d->icon = QIcon();
00666 }
00667 
00668 QString IconWidget::svg() const
00669 {
00670     if (d->iconSvg) {
00671         if (d->iconSvg->isValid() && (d->iconSvgElement.isEmpty() || d->iconSvg->hasElement(d->iconSvgElement))) {
00672             return d->iconSvg->imagePath();
00673         } else {
00674             return QString();
00675         }
00676     }
00677 
00678     return QString();
00679 }
00680 
00681 QSizeF IconWidget::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
00682 {
00683     if (which == Qt::PreferredSize) {
00684         int iconSize;
00685 
00686         if (d->preferredIconSize.isValid()) {
00687             iconSize = qMax(d->preferredIconSize.height(), d->preferredIconSize.width());
00688         } else if (d->iconSvg) {
00689             QSizeF oldSize = d->iconSvg->size();
00690             d->iconSvg->resize();
00691             if (d->iconSvgElement.isNull()) {
00692                 iconSize = qMax(d->iconSvg->size().width(), d->iconSvg->size().height());
00693             } else {
00694                 iconSize = qMax(d->iconSvg->elementSize(d->iconSvgElement).width(), d->iconSvg->elementSize(d->iconSvgElement).height());
00695             }
00696             d->iconSvg->resize(oldSize);
00697         } else {
00698             iconSize = KIconLoader::SizeMedium;
00699         }
00700 
00701         if (constraint.width() > 0 || constraint.height() > 0) {
00702             QSizeF constrainedWidgetSize(constraint);
00703             QSizeF maximumWidgetSize;
00704 
00705             if (d->maximumIconSize.isValid()) {
00706                 maximumWidgetSize =
00707                     sizeFromIconSize(qMax(d->maximumIconSize.height(), d->maximumIconSize.width()));
00708             } else {
00709                 maximumWidgetSize =
00710                     QGraphicsWidget::sizeHint(Qt::MaximumSize);
00711             }
00712 
00713             if (constrainedWidgetSize.width() <= 0) {
00714                 constrainedWidgetSize.setWidth(maximumWidgetSize.width());
00715             }
00716             if (constrainedWidgetSize.height() <= 0) {
00717                 constrainedWidgetSize.setHeight(maximumWidgetSize.height());
00718             }
00719 
00720             QStyleOptionGraphicsItem option;
00721             QSizeF iconRect =
00722                 d->iconSizeForWidgetSize(&option, constrainedWidgetSize);
00723             iconSize =
00724                 qMin(iconSize, qMax<int>(iconRect.width(), iconRect.height()));
00725         }
00726 
00727         return sizeFromIconSize(iconSize);
00728     } else if (which == Qt::MinimumSize) {
00729         if (d->minimumIconSize.isValid()) {
00730             return sizeFromIconSize(qMax(d->minimumIconSize.height(), d->minimumIconSize.width()));
00731         }
00732 
00733         return sizeFromIconSize(KIconLoader::SizeSmall);
00734     } else {
00735         if (d->maximumIconSize.isValid()) {
00736             return sizeFromIconSize(qMax(d->maximumIconSize.height(), d->maximumIconSize.width()));
00737         }
00738 
00739         return QGraphicsWidget::sizeHint(which, constraint);
00740     }
00741 }
00742 
00743 void IconWidgetPrivate::animateMainIcon(bool show, const IconWidgetStates state)
00744 {
00745     if (show) {
00746         states = state;
00747     }
00748 
00749     hoverAnimation->setFadeIn(show);
00750 
00751     QPropertyAnimation *animation = hoverAnimation->animation();
00752     if (!animation) {
00753         animation = new QPropertyAnimation(hoverAnimation, "value");
00754         animation->setDuration(150);
00755         animation->setEasingCurve(QEasingCurve::OutQuad);
00756         animation->setStartValue(0.0);
00757         animation->setEndValue(1.0);
00758         hoverAnimation->setAnimation(animation);
00759         q->connect(animation, SIGNAL(finished()), q, SLOT(hoverAnimationFinished()));
00760     } else if (animation->state() == QAbstractAnimation::Running) {
00761         animation->pause();
00762     }
00763 
00764     animation->setDirection(show ? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
00765     animation->start(show ? QAbstractAnimation::KeepWhenStopped : QAbstractAnimation::DeleteWhenStopped);
00766     q->update();
00767 }
00768 
00769 void IconWidgetPrivate::hoverAnimationFinished()
00770 {
00771     if (!hoverAnimation->fadeIn()) {
00772         states &= ~IconWidgetPrivate::HoverState;
00773     }
00774 }
00775 
00776 void IconWidgetPrivate::drawBackground(QPainter *painter, IconWidgetState state)
00777 {
00778     if (!drawBg) {
00779         return;
00780     }
00781 
00782     if (!(states & IconWidgetPrivate::HoverState) && !(states & IconWidgetPrivate::PressedState)) {
00783         return;
00784     }
00785 
00786     if (state == IconWidgetPrivate::PressedState) {
00787         background->setElementPrefix("selected");
00788     } else {
00789         background->setElementPrefix("hover");
00790     }
00791 
00792     if (qFuzzyCompare(hoverAnimation->value(), 1)) {
00793         background->resizeFrame(currentSize);
00794         background->paintFrame(painter);
00795     } else if (!qFuzzyCompare(hoverAnimation->value()+1, 1)) {
00796         background->resizeFrame(currentSize);
00797         QPixmap frame = background->framePixmap();
00798         QPainter bufferPainter(&frame);
00799         bufferPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00800         bufferPainter.fillRect(frame.rect(), QColor(0,0,0, 255*hoverAnimation->value()));
00801         bufferPainter.end();
00802         painter->drawPixmap(QPoint(0,0), frame);
00803     }
00804 }
00805 
00806 QPixmap IconWidgetPrivate::decoration(const QStyleOptionGraphicsItem *option, bool useHoverEffect, bool usePressedEffect)
00807 {
00808     QPixmap result;
00809 
00810     QIcon::Mode mode   = option->state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled;
00811     QIcon::State state = option->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
00812 
00813     QSize finalSize(iconSize.toSize());
00814     //for small sizes, use a standard size
00815     if (finalSize.width() < KIconLoader::SizeSmallMedium) {
00816         finalSize = QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
00817     } else if (finalSize.width() < KIconLoader::SizeMedium) {
00818         finalSize = QSize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium);
00819     } else if (finalSize.width() < KIconLoader::SizeLarge) {
00820         finalSize = QSize(KIconLoader::SizeMedium, KIconLoader::SizeMedium);
00821     }
00822 
00823     if (iconSvg) {
00824         if (iconSvgElementChanged || iconSvgPixmap.size() != iconSize.toSize()) {
00825             //even the svg is returned at standard sizes because:
00826             // * it may have a version optimized for that size
00827             // * look aligned with other icons
00828             iconSvg->resize(finalSize);
00829             iconSvgPixmap = iconSvg->pixmap(iconSvgElement);
00830             iconSvgElementChanged = false;
00831         }
00832         result = iconSvgPixmap;
00833     } else {
00834         QSize size(iconSize.toSize());
00835         //the QIcon isn't filled with available sizes, return a near standard size for small pixmaps
00836         if (!icon.availableSizes().isEmpty()) {
00837             finalSize = icon.actualSize(iconSize.toSize(), mode, state);
00838         }
00839 
00840         result = icon.pixmap(finalSize, mode, state);
00841     }
00842 
00843     if (usePressedEffect) {
00844         result = result.scaled(result.size() * 0.9, Qt::KeepAspectRatio, Qt::SmoothTransformation);
00845     }
00846 
00847     if (!result.isNull() && useHoverEffect) {
00848         KIconEffect *effect = KIconLoader::global()->iconEffect();
00849         // Note that in KIconLoader terminology, active = hover.
00850         // We're assuming that the icon group is desktop/filemanager, since this
00851         // is KFileItemDelegate.
00852         if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
00853             if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) {
00854                 result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState);
00855             } else {
00856                 result = PaintUtils::transition(
00857                     result,
00858                     effect->apply(result, KIconLoader::Desktop,
00859                                   KIconLoader::ActiveState), hoverAnimation->value());
00860             }
00861         }
00862     } else if (!result.isNull() && !oldIcon.isNull()) {
00863         if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) {
00864             oldIcon = QIcon();
00865         } else {
00866             result = PaintUtils::transition(
00867                 oldIcon.pixmap(result.size(), mode, state),
00868                 result, hoverAnimation->value());
00869         }
00870     }
00871 
00872     return result;
00873 }
00874 
00875 QPointF IconWidgetPrivate::iconPosition(const QStyleOptionGraphicsItem *option,
00876                                         const QPixmap &pixmap) const
00877 {
00878     const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
00879 
00880     // Compute the nominal decoration rectangle
00881     const QSizeF size = addMargin(iconSize, IconWidgetPrivate::IconMargin);
00882 
00883     Qt::LayoutDirection direction = iconDirection(option);
00884 
00885     //alignment depends from orientation and option->direction
00886     Qt::Alignment alignment;
00887     if (text.isEmpty() && infoText.isEmpty()) {
00888         alignment = Qt::AlignCenter;
00889     } else if (orientation == Qt::Vertical) {
00890         alignment = Qt::Alignment(Qt::AlignHCenter | Qt::AlignTop);
00891     //Horizontal
00892     } else {
00893         alignment = QStyle::visualAlignment(
00894             direction, Qt::Alignment(Qt::AlignLeft | Qt::AlignVCenter));
00895     }
00896 
00897     const QRect iconRect =
00898         QStyle::alignedRect(direction, alignment, size.toSize(), itemRect.toRect());
00899 
00900     // Position the pixmap in the center of the rectangle
00901     QRect pixmapRect = pixmap.rect();
00902     pixmapRect.moveCenter(iconRect.center());
00903 
00904     // add a gimmicky margin of 5px to y, TEMP TEMP TEMP
00905     // pixmapRect = pixmapRect.adjusted(0, 5, 0, 0);
00906 
00907     return QPointF(pixmapRect.topLeft());
00908 }
00909 
00910 QRectF IconWidgetPrivate::labelRectangle(const QStyleOptionGraphicsItem *option,
00911                                          const QPixmap &icon,
00912                                          const QString &string) const
00913 {
00914     Q_UNUSED(string)
00915 
00916     if (icon.isNull()) {
00917         return option->rect;
00918     }
00919 
00920     const QSizeF decoSize = addMargin(iconSize, IconWidgetPrivate::IconMargin);
00921     const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
00922     QRectF textArea(QPointF(0, 0), itemRect.size());
00923 
00924     if (orientation == Qt::Vertical) {
00925         textArea.setTop(decoSize.height() + 1);
00926     } else {
00927         //Horizontal
00928        textArea.setLeft(decoSize.width() + 1);
00929     }
00930 
00931     textArea.translate(itemRect.topLeft());
00932     return QRectF(QStyle::visualRect(iconDirection(option), option->rect, textArea.toRect()));
00933 }
00934 
00935 // Lays the text out in a rectangle no larger than constraints, eliding it as necessary
00936 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout,
00937                                      const QString &text,
00938                                      const QSizeF &constraints) const
00939 {
00940     const QSizeF size = layoutText(layout, text, constraints.width());
00941 
00942     if (size.width() > constraints.width() || size.height() > constraints.height()) {
00943         if (action) {
00944             q->setToolTip(action->toolTip());
00945         }
00946         const QString elided = elidedText(layout, constraints);
00947         return layoutText(layout, elided, constraints.width());
00948     }
00949     q->setToolTip(QString());
00950 
00951     return size;
00952 }
00953 
00954 // Lays the text out in a rectangle no wider than maxWidth
00955 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout, const QString &text, qreal maxWidth) const
00956 {
00957     QFontMetricsF metrics(layout.font());
00958     qreal leading     = metrics.leading();
00959     qreal height      = 0.0;
00960     qreal widthUsed   = 0.0;
00961     QTextLine line;
00962 
00963     layout.setText(text);
00964 
00965     layout.beginLayout();
00966 
00967     while ((line = layout.createLine()).isValid()) {
00968         line.setLineWidth(maxWidth);
00969         height += leading;
00970         line.setPosition(QPointF(0.0, height));
00971         height += line.height();
00972         widthUsed = qMax(widthUsed, line.naturalTextWidth());
00973     }
00974     layout.endLayout();
00975 
00976     return QSizeF(widthUsed, height);
00977 }
00978 
00979 // Elides the text in the layout, by iterating over each line in the layout, eliding
00980 // or word breaking the line if it's wider than the max width, and finally adding an
00981 // ellipses at the end of the last line, if there are more lines than will fit within
00982 // the vertical size constraints.
00983 QString IconWidgetPrivate::elidedText(QTextLayout &layout, const QSizeF &size) const
00984 {
00985     QFontMetricsF metrics(layout.font());
00986     const QString text = layout.text();
00987     qreal maxWidth       = size.width();
00988     qreal maxHeight      = size.height();
00989     qreal height         = 0;
00990 
00991     // Elide each line that has already been laid out in the layout.
00992     QString elided;
00993     elided.reserve(text.length());
00994 
00995     for (int i = 0; i < layout.lineCount(); i++) {
00996         QTextLine line = layout.lineAt(i);
00997         int start  = line.textStart();
00998         int length = line.textLength();
00999 
01000         height += metrics.leading();
01001         if (height + line.height() + metrics.lineSpacing() > maxHeight) {
01002             // Unfortunately, if the line ends because of a line separator,
01003             // elidedText() will be too clever and keep adding lines until
01004             // it finds one that's too wide.
01005             if (line.naturalTextWidth() < maxWidth &&
01006                 start + length > 0 &&
01007                 text[start + length - 1] == QChar::LineSeparator) {
01008                 elided += text.mid(start, length - 1);
01009             } else {
01010                 elided += metrics.elidedText(text.mid(start), Qt::ElideRight, maxWidth);
01011             }
01012             break;
01013         } else if (line.naturalTextWidth() > maxWidth) {
01014             elided += metrics.elidedText(text.mid(start, length), Qt::ElideRight, maxWidth);
01015         } else {
01016             elided += text.mid(start, length);
01017         }
01018 
01019         height += line.height();
01020     }
01021 
01022     return elided;
01023 }
01024 
01025 void IconWidgetPrivate::layoutTextItems(const QStyleOptionGraphicsItem *option,
01026                                         const QPixmap &icon, QTextLayout *labelLayout,
01027                                         QTextLayout *infoLayout, QRectF *textBoundingRect) const
01028 {
01029     bool showInformation = false;
01030 
01031     setLayoutOptions(*labelLayout, option, q->orientation());
01032 
01033     QFontMetricsF fm(labelLayout->font());
01034     const QRectF textArea = labelRectangle(option, icon, text);
01035     QRectF textRect = subtractMargin(textArea, IconWidgetPrivate::TextMargin);
01036 
01037     //kDebug() << this << "text area" << textArea << "text rect" << textRect;
01038     // Sizes and constraints for the different text parts
01039     QSizeF maxLabelSize = textRect.size();
01040     QSizeF maxInfoSize  = textRect.size();
01041     QSizeF labelSize;
01042     QSizeF infoSize;
01043 
01044     // If we have additional info text, and there's space for at least two lines of text,
01045     // adjust the max label size to make room for at least one line of the info text
01046     if (!infoText.isEmpty() && textRect.height() >= fm.lineSpacing() * 2) {
01047         infoLayout->setFont(labelLayout->font());
01048         infoLayout->setTextOption(labelLayout->textOption());
01049 
01050         maxLabelSize.rheight() -= fm.lineSpacing();
01051         showInformation = true;
01052     }
01053 
01054     // Lay out the label text, and adjust the max info size based on the label size
01055     labelSize = layoutText(*labelLayout, text, maxLabelSize);
01056     maxInfoSize.rheight() -= labelSize.height();
01057 
01058     // Lay out the info text
01059     if (showInformation) {
01060         infoSize = layoutText(*infoLayout, infoText, maxInfoSize);
01061     } else {
01062         infoSize = QSizeF(0, 0);
01063     }
01064     // Compute the bounding rect of the text
01065     const Qt::Alignment alignment = labelLayout->textOption().alignment();
01066     const QSizeF size(qMax(labelSize.width(), infoSize.width()),
01067                       labelSize.height() + infoSize.height());
01068     *textBoundingRect =
01069         QStyle::alignedRect(iconDirection(option), alignment, size.toSize(), textRect.toRect());
01070 
01071     // Compute the positions where we should draw the layouts
01072     haloRects.clear();
01073     labelLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y()));
01074     QTextLine line;
01075     for (int i = 0; i < labelLayout->lineCount(); ++i) {
01076         line = labelLayout->lineAt(i);
01077         haloRects.append(line.naturalTextRect().translated(labelLayout->position().toPoint()).toRect());
01078     }
01079     infoLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y() + labelSize.height()));
01080     for (int i = 0; i < infoLayout->lineCount(); ++i) {
01081         line = infoLayout->lineAt(i);
01082         haloRects.append(line.naturalTextRect().translated(infoLayout->position().toPoint()).toRect());
01083     }
01084     //kDebug() << "final position is" << labelLayout->position();
01085 }
01086 
01087 QBrush IconWidgetPrivate::foregroundBrush(const QStyleOptionGraphicsItem *option) const
01088 {
01089     const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
01090             QPalette::Normal : QPalette::Disabled;
01091 
01092     // Always use the highlight color for selected items
01093     if (option->state & QStyle::State_Selected) {
01094         return option->palette.brush(group, QPalette::HighlightedText);
01095     }
01096     return option->palette.brush(group, QPalette::Text);
01097 }
01098 
01099 QBrush IconWidgetPrivate::backgroundBrush(const QStyleOptionGraphicsItem *option) const
01100 {
01101     const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
01102             QPalette::Normal : QPalette::Disabled;
01103 
01104     QBrush background(Qt::NoBrush);
01105 
01106     // Always use the highlight color for selected items
01107     if (option->state & QStyle::State_Selected) {
01108         background = option->palette.brush(group, QPalette::Highlight);
01109     }
01110     return background;
01111 }
01112 
01113 void IconWidgetPrivate::drawTextItems(QPainter *painter,
01114                                       const QStyleOptionGraphicsItem *option,
01115                                       const QTextLayout &labelLayout,
01116                                       const QTextLayout &infoLayout) const
01117 {
01118     Q_UNUSED(option)
01119 
01120     painter->save();
01121     painter->setPen(textColor);
01122 
01123     // the translation prevents odd rounding errors in labelLayout.position()
01124     // when applied to the canvas
01125     painter->translate(0.5, 0.5);
01126 
01127     labelLayout.draw(painter, QPointF());
01128 
01129     if (!infoLayout.text().isEmpty()) {
01130         painter->setPen(textColor);
01131         infoLayout.draw(painter, QPointF());
01132     }
01133     painter->restore();
01134 }
01135 
01136 void IconWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
01137 {
01138     Q_UNUSED(widget);
01139 
01140     //Lay out the main icon and action icons
01141     d->layoutIcons(option);
01142 
01143     // Compute the metrics, and lay out the text items
01144     // ========================================================================
01145     IconWidgetPrivate::IconWidgetState state = IconWidgetPrivate::NoState;
01146     if (d->states & IconWidgetPrivate::ManualPressedState) {
01147         state = IconWidgetPrivate::PressedState;
01148     } else if (d->states & IconWidgetPrivate::PressedState) {
01149         if (d->states & IconWidgetPrivate::HoverState) {
01150             state = IconWidgetPrivate::PressedState;
01151         }
01152     } else if (d->states & IconWidgetPrivate::HoverState) {
01153         state = IconWidgetPrivate::HoverState;
01154     }
01155 
01156     QPixmap icon = d->decoration(option, state != IconWidgetPrivate::NoState, state & IconWidgetPrivate::PressedState);
01157     const QPointF iconPos = d->iconPosition(option, icon);
01158 
01159     d->drawBackground(painter, state);
01160 
01161     // draw icon
01162     if (!icon.isNull()) {
01163         painter->drawPixmap(iconPos, icon);
01164     }
01165 
01166     // Draw corner actions
01167     foreach (const IconAction *action, d->cornerActions) {
01168         if (action->isAnimating()) {
01169             action->paint(painter);
01170         }
01171     }
01172 
01173     // Draw text last because it is overlayed
01174     QTextLayout labelLayout, infoLayout;
01175     QRectF textBoundingRect;
01176 
01177     d->layoutTextItems(option, icon, &labelLayout, &infoLayout, &textBoundingRect);
01178 
01179     if (d->textBgColor != QColor() && d->textBgColor.alpha() > 0 &&
01180         !(d->text.isEmpty() && d->infoText.isEmpty()) &&
01181         !textBoundingRect.isEmpty() &&
01182         !qFuzzyCompare(d->hoverAnimation->value(), (qreal)1.0)) {
01183         QRectF rect = textBoundingRect.adjusted(-2, -2, 4, 4).toAlignedRect();
01184         painter->setPen(Qt::transparent);
01185         QColor color = d->textBgColor;
01186         color.setAlpha(60 * (1.0 - d->hoverAnimation->value()));
01187         QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
01188         gradient.setColorAt(0, color.lighter(120));
01189         gradient.setColorAt(1, color.darker(120));
01190         painter->setBrush(gradient);
01191         gradient.setColorAt(0, color.lighter(130));
01192         gradient.setColorAt(1, color.darker(130));
01193         painter->setPen(QPen(gradient, 0));
01194         painter->setRenderHint(QPainter::Antialiasing);
01195         painter->drawPath(PaintUtils::roundedRectangle(rect.translated(0.5, 0.5), 4));
01196     }
01197 
01198 
01199     if (d->shadowColor.value() < 128 || textBackgroundColor() != QColor()) {
01200         QPoint shadowPos;
01201         if (d->shadowColor.value() < 128) {
01202             shadowPos = QPoint(1, 2);
01203         } else {
01204             shadowPos = QPoint(0, 0);
01205         }
01206 
01207         QImage shadow(textBoundingRect.size().toSize() + QSize(4, 4),
01208                     QImage::Format_ARGB32_Premultiplied);
01209         shadow.fill(Qt::transparent);
01210         {
01211             QPainter buffPainter(&shadow);
01212             buffPainter.translate(-textBoundingRect.x(), -textBoundingRect.y());
01213             d->drawTextItems(&buffPainter, option, labelLayout, infoLayout);
01214         }
01215 
01216         PaintUtils::shadowBlur(shadow, 2, d->shadowColor);
01217         painter->drawImage(textBoundingRect.topLeft() + shadowPos, shadow);
01218     } else if (!(d->text.isEmpty() && d->infoText.isEmpty()) &&
01219                !textBoundingRect.isEmpty()) {
01220         QRect labelRect = d->labelRectangle(option, icon, d->text).toRect();
01221 
01222         foreach (const QRect &rect, d->haloRects) {
01223             Plasma::PaintUtils::drawHalo(painter, rect);
01224         }
01225     }
01226 
01227     d->drawTextItems(painter, option, labelLayout, infoLayout);
01228 }
01229 
01230 void IconWidget::setTextBackgroundColor(const QColor &color)
01231 {
01232     d->textBgCustomized = true;
01233     d->textBgColor = color;
01234     update();
01235 }
01236 
01237 QColor IconWidget::textBackgroundColor() const
01238 {
01239     return d->textBgColor;
01240 }
01241 
01242 void IconWidget::drawActionButtonBase(QPainter *painter, const QSize &size, int element)
01243 {
01244     qreal radius = size.width() / 2;
01245     QRadialGradient gradient(radius, radius, radius, radius, radius);
01246     int alpha;
01247 
01248     if (element == IconWidgetPrivate::MinibuttonPressed) {
01249         alpha = 255;
01250     } else if (element == IconWidgetPrivate::MinibuttonHover) {
01251         alpha = 200;
01252     } else {
01253         alpha = 160;
01254     }
01255     gradient.setColorAt(0, QColor::fromRgb(d->textColor.red(),
01256                                            d->textColor.green(),
01257                                            d->textColor.blue(), alpha));
01258     gradient.setColorAt(1, QColor::fromRgb(d->textColor.red(),
01259                                            d->textColor.green(),
01260                                            d->textColor.blue(), 0));
01261 
01262     painter->setBrush(gradient);
01263     painter->setPen(Qt::NoPen);
01264     painter->drawEllipse(QRectF(QPointF(.0, .0), size));
01265 }
01266 
01267 void IconWidget::setText(const QString &text)
01268 {
01269     d->text = KGlobal::locale()->removeAcceleratorMarker(text);
01270     // cause a relayout
01271     d->currentSize = QSizeF(-1, -1);
01272     //try to relayout, needed if an icon was never shown before
01273     if (!isVisible()) {
01274         QStyleOptionGraphicsItem styleoption;
01275         d->layoutIcons(&styleoption);
01276     }
01277     updateGeometry();
01278     if (!parentWidget() || !parentWidget()->layout()) {
01279         resize(preferredSize());
01280     }
01281 }
01282 
01283 QString IconWidget::text() const
01284 {
01285     return d->text;
01286 }
01287 
01288 void IconWidget::setInfoText(const QString &text)
01289 {
01290     d->infoText = text;
01291     // cause a relayout
01292     d->currentSize = QSizeF(-1, -1);
01293     //try to relayout, needed if an icon was never shown before
01294     if (!isVisible()) {
01295         QStyleOptionGraphicsItem styleoption;
01296         d->layoutIcons(&styleoption);
01297     }
01298     updateGeometry();
01299     if (!parentWidget() || !parentWidget()->layout()) {
01300         resize(preferredSize());
01301     }
01302 }
01303 
01304 QString IconWidget::infoText() const
01305 {
01306     return d->infoText;
01307 }
01308 
01309 QIcon IconWidget::icon() const
01310 {
01311     return d->icon;
01312 }
01313 
01314 void IconWidget::setIcon(const QString &icon)
01315 {
01316     if (icon.isEmpty()) {
01317         setIcon(QIcon());
01318         return;
01319     }
01320 
01321     setIcon(KIcon(icon));
01322 }
01323 
01324 void IconWidget::setIcon(const QIcon &icon)
01325 {
01326     setSvg(QString());
01327 
01328     /*fade to the new icon, but to not bee a too big hog, not do that when:
01329       - the fade animation is already running
01330       - the icon is under mouse
01331       - one betwen the old and new icon is null*/
01332     if (!(d->states & IconWidgetPrivate::HoverState) && !d->iconChangeTimer->isActive() && d->oldIcon.isNull() && !d->icon.isNull() && !icon.isNull()) {
01333         d->oldIcon = d->icon;
01334         d->animateMainIcon(true, d->states);
01335     } else {
01336         d->oldIcon = QIcon();
01337     }
01338     d->iconChangeTimer->start(300);
01339     d->icon = icon;
01340     update();
01341 }
01342 
01343 QSizeF IconWidget::iconSize() const
01344 {
01345     return d->iconSize;
01346 }
01347 
01348 void IconWidget::setPreferredIconSize(const QSizeF &size)
01349 {
01350     d->preferredIconSize = size;
01351     updateGeometry();
01352 }
01353 
01354 QSizeF IconWidget::preferredIconSize() const
01355 {
01356     return d->preferredIconSize;
01357 }
01358 
01359 void IconWidget::setMinimumIconSize(const QSizeF &size)
01360 {
01361     d->minimumIconSize = size;
01362     updateGeometry();
01363 }
01364 
01365 QSizeF IconWidget::minimumIconSize() const
01366 {
01367     return d->minimumIconSize;
01368 }
01369 
01370 void IconWidget::setMaximumIconSize(const QSizeF &size)
01371 {
01372     d->maximumIconSize = size;
01373     updateGeometry();
01374 }
01375 
01376 QSizeF IconWidget::maximumIconSize() const
01377 {
01378     return d->maximumIconSize;
01379 }
01380 
01381 bool IconWidget::isDown()
01382 {
01383     return d->states & IconWidgetPrivate::PressedState;
01384 }
01385 
01386 void IconWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
01387 {
01388     if (event->button() != Qt::LeftButton) {
01389         QGraphicsWidget::mousePressEvent(event);
01390         return;
01391     }
01392 
01393     if (KGlobalSettings::singleClick() || (receivers(SIGNAL(clicked()))) > 0) {
01394         d->states |= IconWidgetPrivate::PressedState;
01395     }
01396     d->clickStartPos = scenePos();
01397 
01398     bool handled = false;
01399     foreach (IconAction *action, d->cornerActions) {
01400         handled = action->event(event->type(), event->pos());
01401         if (handled) {
01402             break;
01403         }
01404     }
01405 
01406     if (!handled && boundingRect().contains(event->pos())) {
01407         emit pressed(true);
01408     }
01409 
01410     update();
01411 }
01412 
01413 void IconWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
01414 {
01415     if (~d->states & IconWidgetPrivate::PressedState) {
01416         QGraphicsWidget::mouseMoveEvent(event);
01417         return;
01418     }
01419 
01420     if (boundingRect().contains(event->pos())) {
01421         if (~d->states & IconWidgetPrivate::HoverState) {
01422             d->states |= IconWidgetPrivate::HoverState;
01423             update();
01424         }
01425     } else {
01426         if (d->states & IconWidgetPrivate::HoverState) {
01427             d->states &= ~IconWidgetPrivate::HoverState;
01428             update();
01429         }
01430     }
01431 }
01432 
01433 void IconWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
01434 {
01435     if (~d->states & IconWidgetPrivate::PressedState) {
01436         QGraphicsWidget::mouseMoveEvent(event);
01437         return;
01438     }
01439 
01440     d->states &= ~IconWidgetPrivate::PressedState;
01441 
01442     //don't pass click when the mouse was moved
01443     bool handled = d->clickStartPos != scenePos();
01444     if (!handled) {
01445         foreach (IconAction *action, d->cornerActions) {
01446             if (action->event(event->type(), event->pos())) {
01447                 handled = true;
01448                 break;
01449             }
01450         }
01451     }
01452 
01453     if (!handled) {
01454         if (boundingRect().contains(event->pos())) {
01455             emit clicked();
01456             if (KGlobalSettings::singleClick()) {
01457                emit activated();
01458             }
01459 
01460             if (d->action && d->action->menu()) {
01461                 d->action->menu()->popup(event->screenPos());
01462             }
01463         }
01464         emit pressed(false);
01465     }
01466 
01467     update();
01468 }
01469 
01470 void IconWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
01471 {
01472     Q_UNUSED(event)
01473 
01474     d->states |= IconWidgetPrivate::PressedState;
01475 
01476     emit doubleClicked();
01477     if (!KGlobalSettings::singleClick()) {
01478         emit activated();
01479     }
01480 
01481     update();
01482 }
01483 
01484 void IconWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
01485 {
01486     //kDebug();
01487     foreach (IconAction *action, d->cornerActions) {
01488         action->show();
01489         action->event(event->type(), event->pos());
01490     }
01491 
01492     d->oldIcon = QIcon();
01493     d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState);
01494 
01495     QGraphicsWidget::hoverEnterEvent(event);
01496 }
01497 
01498 void IconWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
01499 {
01500     //kDebug() << d->cornerActions;
01501     foreach (IconAction *action, d->cornerActions) {
01502         action->hide();
01503         action->event(event->type(), event->pos());
01504     }
01505     // d->states &= ~IconWidgetPrivate::HoverState; // Will be set once progress is zero again ...
01506     //if an eventfilter stolen the mousereleaseevent remove the pressed state here
01507     d->states &= ~IconWidgetPrivate::PressedState;
01508 
01509     d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState);
01510 
01511     QGraphicsWidget::hoverLeaveEvent(event);
01512 }
01513 
01514 bool IconWidget::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
01515 {
01516     Q_UNUSED(watched)
01517 
01518     if (event->type() == QEvent::GraphicsSceneDragEnter) {
01519         d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState);
01520     } else if (event->type() == QEvent::GraphicsSceneDragLeave) {
01521         d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState);
01522     }
01523 
01524     return false;
01525 }
01526 
01527 void IconWidget::setPressed(bool pressed)
01528 {
01529     if (pressed) {
01530         d->states |= IconWidgetPrivate::ManualPressedState;
01531         d->states |= IconWidgetPrivate::PressedState;
01532     } else {
01533         d->states &= ~IconWidgetPrivate::ManualPressedState;
01534         d->states &= ~IconWidgetPrivate::PressedState;
01535     }
01536     update();
01537 }
01538 
01539 void IconWidget::setUnpressed()
01540 {
01541     setPressed(false);
01542 }
01543 
01544 void IconWidgetPrivate::svgChanged()
01545 {
01546     iconSvgElementChanged = true;
01547     q->update();
01548 }
01549 
01550 void IconWidget::setOrientation(Qt::Orientation orientation)
01551 {
01552     d->orientation = orientation;
01553     resize(sizeFromIconSize(d->iconSize.width()));
01554 }
01555 
01556 Qt::Orientation IconWidget::orientation() const
01557 {
01558     return d->orientation;
01559 }
01560 
01561 void IconWidget::invertLayout(bool invert)
01562 {
01563     d->invertLayout = invert;
01564 }
01565 
01566 bool IconWidget::invertedLayout() const
01567 {
01568     return d->invertLayout;
01569 }
01570 
01571 QSizeF IconWidget::sizeFromIconSize(const qreal iconWidth) const
01572 {
01573     d->setActiveMargins();
01574     if (d->text.isEmpty() && d->infoText.isEmpty()) {
01575         //no text, just the icon size
01576         return d->addMargin(QSizeF(iconWidth, iconWidth), IconWidgetPrivate::ItemMargin);
01577     }
01578 
01579     QFontMetricsF fm(font());
01580     qreal width = 0;
01581 
01582     if (d->orientation == Qt::Vertical) {
01583         width = qMax(d->maxWordWidth(d->text),
01584                      d->maxWordWidth(d->infoText)) +
01585                      fm.width("xxx") +
01586                      d->verticalMargin[IconWidgetPrivate::TextMargin].left +
01587                      d->verticalMargin[IconWidgetPrivate::TextMargin].right;
01588 
01589         width = qMax(width,
01590                      iconWidth +
01591                      d->verticalMargin[IconWidgetPrivate::IconMargin].left +
01592                      d->verticalMargin[IconWidgetPrivate::IconMargin].right);
01593     } else {
01594         width = iconWidth +
01595                 d->horizontalMargin[IconWidgetPrivate::IconMargin].left +
01596                 d->horizontalMargin[IconWidgetPrivate::IconMargin].right +
01597                 qMax(fm.width(d->text), fm.width(d->infoText)) + fm.width("xxx") +
01598                 d->horizontalMargin[IconWidgetPrivate::TextMargin].left +
01599                 d->horizontalMargin[IconWidgetPrivate::TextMargin].right;
01600     }
01601 
01602     qreal height;
01603     qreal textHeight;
01604 
01605     QStyleOptionGraphicsItem option;
01606     option.state = QStyle::State_None;
01607     option.rect = QRect(0, 0, width, QWIDGETSIZE_MAX);
01608     textHeight = d->displaySizeHint(&option, width).height();
01609 
01610     if (d->orientation == Qt::Vertical) {
01611         height = iconWidth + textHeight +
01612                  d->verticalMargin[IconWidgetPrivate::TextMargin].top +
01613                  d->verticalMargin[IconWidgetPrivate::TextMargin].bottom +
01614                  d->verticalMargin[IconWidgetPrivate::IconMargin].top +
01615                  d->verticalMargin[IconWidgetPrivate::IconMargin].bottom;
01616     } else {
01617         //Horizontal
01618         height = qMax(iconWidth +
01619                       d->verticalMargin[IconWidgetPrivate::IconMargin].top +
01620                       d->verticalMargin[IconWidgetPrivate::IconMargin].bottom,
01621                       textHeight +
01622                       d->verticalMargin[IconWidgetPrivate::TextMargin].top +
01623                       d->verticalMargin[IconWidgetPrivate::TextMargin].bottom);
01624     }
01625 
01626     return d->addMargin(QSizeF(width, height), IconWidgetPrivate::ItemMargin);
01627 }
01628 
01629 void IconWidget::changeEvent(QEvent *event)
01630 {
01631     d->changeEvent(event);
01632     QGraphicsWidget::changeEvent(event);
01633 }
01634 
01635 } // namespace Plasma
01636 
01637 #include "iconwidget.moc"
01638 #include "iconwidget_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:30:44 by doxygen 1.7.5.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.9.5 API Reference

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