• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.3 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     if (iconSvg) {
00814         if (iconSvgElementChanged || iconSvgPixmap.size() != iconSize.toSize()) {
00815             iconSvg->resize(iconSize);
00816             iconSvgPixmap = iconSvg->pixmap(iconSvgElement);
00817             iconSvgElementChanged = false;
00818         }
00819         result = iconSvgPixmap;
00820     } else {
00821         const QSize size = icon.actualSize(iconSize.toSize(), mode, state);
00822         result = icon.pixmap(size, mode, state);
00823     }
00824 
00825     if (usePressedEffect) {
00826         result = result.scaled(result.size() * 0.9, Qt::KeepAspectRatio, Qt::SmoothTransformation);
00827     }
00828 
00829     if (!result.isNull() && useHoverEffect) {
00830         KIconEffect *effect = KIconLoader::global()->iconEffect();
00831         // Note that in KIconLoader terminology, active = hover.
00832         // We're assuming that the icon group is desktop/filemanager, since this
00833         // is KFileItemDelegate.
00834         if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
00835             if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) {
00836                 result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState);
00837             } else {
00838                 result = PaintUtils::transition(
00839                     result,
00840                     effect->apply(result, KIconLoader::Desktop,
00841                                   KIconLoader::ActiveState), hoverAnimation->value());
00842             }
00843         }
00844     } else if (!result.isNull() && !oldIcon.isNull()) {
00845         if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) {
00846             oldIcon = QIcon();
00847         } else {
00848             result = PaintUtils::transition(
00849                 oldIcon.pixmap(result.size(), mode, state),
00850                 result, hoverAnimation->value());
00851         }
00852     }
00853 
00854     return result;
00855 }
00856 
00857 QPointF IconWidgetPrivate::iconPosition(const QStyleOptionGraphicsItem *option,
00858                                         const QPixmap &pixmap) const
00859 {
00860     const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
00861 
00862     // Compute the nominal decoration rectangle
00863     const QSizeF size = addMargin(iconSize, IconWidgetPrivate::IconMargin);
00864 
00865     Qt::LayoutDirection direction = iconDirection(option);
00866 
00867     //alignment depends from orientation and option->direction
00868     Qt::Alignment alignment;
00869     if (text.isEmpty() && infoText.isEmpty()) {
00870         alignment = Qt::AlignCenter;
00871     } else if (orientation == Qt::Vertical) {
00872         alignment = Qt::Alignment(Qt::AlignHCenter | Qt::AlignTop);
00873     //Horizontal
00874     } else {
00875         alignment = QStyle::visualAlignment(
00876             direction, Qt::Alignment(Qt::AlignLeft | Qt::AlignVCenter));
00877     }
00878 
00879     const QRect iconRect =
00880         QStyle::alignedRect(direction, alignment, size.toSize(), itemRect.toRect());
00881 
00882     // Position the pixmap in the center of the rectangle
00883     QRect pixmapRect = pixmap.rect();
00884     pixmapRect.moveCenter(iconRect.center());
00885 
00886     // add a gimmicky margin of 5px to y, TEMP TEMP TEMP
00887     // pixmapRect = pixmapRect.adjusted(0, 5, 0, 0);
00888 
00889     return QPointF(pixmapRect.topLeft());
00890 }
00891 
00892 QRectF IconWidgetPrivate::labelRectangle(const QStyleOptionGraphicsItem *option,
00893                                          const QPixmap &icon,
00894                                          const QString &string) const
00895 {
00896     Q_UNUSED(string)
00897 
00898     if (icon.isNull()) {
00899         return option->rect;
00900     }
00901 
00902     const QSizeF decoSize = addMargin(iconSize, IconWidgetPrivate::IconMargin);
00903     const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
00904     QRectF textArea(QPointF(0, 0), itemRect.size());
00905 
00906     if (orientation == Qt::Vertical) {
00907         textArea.setTop(decoSize.height() + 1);
00908     } else {
00909         //Horizontal
00910        textArea.setLeft(decoSize.width() + 1);
00911     }
00912 
00913     textArea.translate(itemRect.topLeft());
00914     return QRectF(QStyle::visualRect(iconDirection(option), option->rect, textArea.toRect()));
00915 }
00916 
00917 // Lays the text out in a rectangle no larger than constraints, eliding it as necessary
00918 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout,
00919                                      const QString &text,
00920                                      const QSizeF &constraints) const
00921 {
00922     const QSizeF size = layoutText(layout, text, constraints.width());
00923 
00924     if (size.width() > constraints.width() || size.height() > constraints.height()) {
00925         if (action) {
00926             q->setToolTip(action->toolTip());
00927         }
00928         const QString elided = elidedText(layout, constraints);
00929         return layoutText(layout, elided, constraints.width());
00930     }
00931     q->setToolTip(QString());
00932 
00933     return size;
00934 }
00935 
00936 // Lays the text out in a rectangle no wider than maxWidth
00937 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout, const QString &text, qreal maxWidth) const
00938 {
00939     QFontMetricsF metrics(layout.font());
00940     qreal leading     = metrics.leading();
00941     qreal height      = 0.0;
00942     qreal widthUsed   = 0.0;
00943     QTextLine line;
00944 
00945     layout.setText(text);
00946 
00947     layout.beginLayout();
00948 
00949     while ((line = layout.createLine()).isValid()) {
00950         line.setLineWidth(maxWidth);
00951         height += leading;
00952         line.setPosition(QPointF(0.0, height));
00953         height += line.height();
00954         widthUsed = qMax(widthUsed, line.naturalTextWidth());
00955     }
00956     layout.endLayout();
00957 
00958     return QSizeF(widthUsed, height);
00959 }
00960 
00961 // Elides the text in the layout, by iterating over each line in the layout, eliding
00962 // or word breaking the line if it's wider than the max width, and finally adding an
00963 // ellipses at the end of the last line, if there are more lines than will fit within
00964 // the vertical size constraints.
00965 QString IconWidgetPrivate::elidedText(QTextLayout &layout, const QSizeF &size) const
00966 {
00967     QFontMetricsF metrics(layout.font());
00968     const QString text = layout.text();
00969     qreal maxWidth       = size.width();
00970     qreal maxHeight      = size.height();
00971     qreal height         = 0;
00972 
00973     // Elide each line that has already been laid out in the layout.
00974     QString elided;
00975     elided.reserve(text.length());
00976 
00977     for (int i = 0; i < layout.lineCount(); i++) {
00978         QTextLine line = layout.lineAt(i);
00979         int start  = line.textStart();
00980         int length = line.textLength();
00981 
00982         height += metrics.leading();
00983         if (height + line.height() + metrics.lineSpacing() > maxHeight) {
00984             // Unfortunately, if the line ends because of a line separator,
00985             // elidedText() will be too clever and keep adding lines until
00986             // it finds one that's too wide.
00987             if (line.naturalTextWidth() < maxWidth &&
00988                 start + length > 0 &&
00989                 text[start + length - 1] == QChar::LineSeparator) {
00990                 elided += text.mid(start, length - 1);
00991             } else {
00992                 elided += metrics.elidedText(text.mid(start), Qt::ElideRight, maxWidth);
00993             }
00994             break;
00995         } else if (line.naturalTextWidth() > maxWidth) {
00996             elided += metrics.elidedText(text.mid(start, length), Qt::ElideRight, maxWidth);
00997         } else {
00998             elided += text.mid(start, length);
00999         }
01000 
01001         height += line.height();
01002     }
01003 
01004     return elided;
01005 }
01006 
01007 void IconWidgetPrivate::layoutTextItems(const QStyleOptionGraphicsItem *option,
01008                                         const QPixmap &icon, QTextLayout *labelLayout,
01009                                         QTextLayout *infoLayout, QRectF *textBoundingRect) const
01010 {
01011     bool showInformation = false;
01012 
01013     setLayoutOptions(*labelLayout, option, q->orientation());
01014 
01015     QFontMetricsF fm(labelLayout->font());
01016     const QRectF textArea = labelRectangle(option, icon, text);
01017     QRectF textRect = subtractMargin(textArea, IconWidgetPrivate::TextMargin);
01018 
01019     //kDebug() << this << "text area" << textArea << "text rect" << textRect;
01020     // Sizes and constraints for the different text parts
01021     QSizeF maxLabelSize = textRect.size();
01022     QSizeF maxInfoSize  = textRect.size();
01023     QSizeF labelSize;
01024     QSizeF infoSize;
01025 
01026     // If we have additional info text, and there's space for at least two lines of text,
01027     // adjust the max label size to make room for at least one line of the info text
01028     if (!infoText.isEmpty() && textRect.height() >= fm.lineSpacing() * 2) {
01029         infoLayout->setFont(labelLayout->font());
01030         infoLayout->setTextOption(labelLayout->textOption());
01031 
01032         maxLabelSize.rheight() -= fm.lineSpacing();
01033         showInformation = true;
01034     }
01035 
01036     // Lay out the label text, and adjust the max info size based on the label size
01037     labelSize = layoutText(*labelLayout, text, maxLabelSize);
01038     maxInfoSize.rheight() -= labelSize.height();
01039 
01040     // Lay out the info text
01041     if (showInformation) {
01042         infoSize = layoutText(*infoLayout, infoText, maxInfoSize);
01043     } else {
01044         infoSize = QSizeF(0, 0);
01045     }
01046     // Compute the bounding rect of the text
01047     const Qt::Alignment alignment = labelLayout->textOption().alignment();
01048     const QSizeF size(qMax(labelSize.width(), infoSize.width()),
01049                       labelSize.height() + infoSize.height());
01050     *textBoundingRect =
01051         QStyle::alignedRect(iconDirection(option), alignment, size.toSize(), textRect.toRect());
01052 
01053     // Compute the positions where we should draw the layouts
01054     haloRects.clear();
01055     labelLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y()));
01056     QTextLine line;
01057     for (int i = 0; i < labelLayout->lineCount(); ++i) {
01058         line = labelLayout->lineAt(i);
01059         haloRects.append(line.naturalTextRect().translated(labelLayout->position().toPoint()).toRect());
01060     }
01061     infoLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y() + labelSize.height()));
01062     for (int i = 0; i < infoLayout->lineCount(); ++i) {
01063         line = infoLayout->lineAt(i);
01064         haloRects.append(line.naturalTextRect().translated(infoLayout->position().toPoint()).toRect());
01065     }
01066     //kDebug() << "final position is" << labelLayout->position();
01067 }
01068 
01069 QBrush IconWidgetPrivate::foregroundBrush(const QStyleOptionGraphicsItem *option) const
01070 {
01071     const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
01072             QPalette::Normal : QPalette::Disabled;
01073 
01074     // Always use the highlight color for selected items
01075     if (option->state & QStyle::State_Selected) {
01076         return option->palette.brush(group, QPalette::HighlightedText);
01077     }
01078     return option->palette.brush(group, QPalette::Text);
01079 }
01080 
01081 QBrush IconWidgetPrivate::backgroundBrush(const QStyleOptionGraphicsItem *option) const
01082 {
01083     const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
01084             QPalette::Normal : QPalette::Disabled;
01085 
01086     QBrush background(Qt::NoBrush);
01087 
01088     // Always use the highlight color for selected items
01089     if (option->state & QStyle::State_Selected) {
01090         background = option->palette.brush(group, QPalette::Highlight);
01091     }
01092     return background;
01093 }
01094 
01095 void IconWidgetPrivate::drawTextItems(QPainter *painter,
01096                                       const QStyleOptionGraphicsItem *option,
01097                                       const QTextLayout &labelLayout,
01098                                       const QTextLayout &infoLayout) const
01099 {
01100     Q_UNUSED(option)
01101 
01102     painter->save();
01103     painter->setPen(textColor);
01104 
01105     // the translation prevents odd rounding errors in labelLayout.position()
01106     // when applied to the canvas
01107     painter->translate(0.5, 0.5);
01108 
01109     labelLayout.draw(painter, QPointF());
01110 
01111     if (!infoLayout.text().isEmpty()) {
01112         painter->setPen(textColor);
01113         infoLayout.draw(painter, QPointF());
01114     }
01115     painter->restore();
01116 }
01117 
01118 void IconWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
01119 {
01120     Q_UNUSED(widget);
01121 
01122     //Lay out the main icon and action icons
01123     d->layoutIcons(option);
01124 
01125     // Compute the metrics, and lay out the text items
01126     // ========================================================================
01127     IconWidgetPrivate::IconWidgetState state = IconWidgetPrivate::NoState;
01128     if (d->states & IconWidgetPrivate::ManualPressedState) {
01129         state = IconWidgetPrivate::PressedState;
01130     } else if (d->states & IconWidgetPrivate::PressedState) {
01131         if (d->states & IconWidgetPrivate::HoverState) {
01132             state = IconWidgetPrivate::PressedState;
01133         }
01134     } else if (d->states & IconWidgetPrivate::HoverState) {
01135         state = IconWidgetPrivate::HoverState;
01136     }
01137 
01138     QPixmap icon = d->decoration(option, state != IconWidgetPrivate::NoState, state & IconWidgetPrivate::PressedState);
01139     const QPointF iconPos = d->iconPosition(option, icon);
01140 
01141     d->drawBackground(painter, state);
01142 
01143     // draw icon
01144     if (!icon.isNull()) {
01145         painter->drawPixmap(iconPos, icon);
01146     }
01147 
01148     // Draw corner actions
01149     foreach (const IconAction *action, d->cornerActions) {
01150         if (action->isAnimating()) {
01151             action->paint(painter);
01152         }
01153     }
01154 
01155     // Draw text last because it is overlayed
01156     QTextLayout labelLayout, infoLayout;
01157     QRectF textBoundingRect;
01158 
01159     d->layoutTextItems(option, icon, &labelLayout, &infoLayout, &textBoundingRect);
01160 
01161     if (d->textBgColor != QColor() && d->textBgColor.alpha() > 0 &&
01162         !(d->text.isEmpty() && d->infoText.isEmpty()) &&
01163         !textBoundingRect.isEmpty() &&
01164         !qFuzzyCompare(d->hoverAnimation->value(), (qreal)1.0)) {
01165         QRectF rect = textBoundingRect.adjusted(-2, -2, 4, 4).toAlignedRect();
01166         painter->setPen(Qt::transparent);
01167         QColor color = d->textBgColor;
01168         color.setAlpha(60 * (1.0 - d->hoverAnimation->value()));
01169         QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
01170         gradient.setColorAt(0, color.lighter(120));
01171         gradient.setColorAt(1, color.darker(120));
01172         painter->setBrush(gradient);
01173         gradient.setColorAt(0, color.lighter(130));
01174         gradient.setColorAt(1, color.darker(130));
01175         painter->setPen(QPen(gradient, 0));
01176         painter->setRenderHint(QPainter::Antialiasing);
01177         painter->drawPath(PaintUtils::roundedRectangle(rect.translated(0.5, 0.5), 4));
01178     }
01179 
01180 
01181     if (d->shadowColor.value() < 128 || textBackgroundColor() != QColor()) {
01182         QPoint shadowPos;
01183         if (d->shadowColor.value() < 128) {
01184             shadowPos = QPoint(1, 2);
01185         } else {
01186             shadowPos = QPoint(0, 0);
01187         }
01188 
01189         QImage shadow(textBoundingRect.size().toSize() + QSize(4, 4),
01190                     QImage::Format_ARGB32_Premultiplied);
01191         shadow.fill(Qt::transparent);
01192         {
01193             QPainter buffPainter(&shadow);
01194             buffPainter.translate(-textBoundingRect.x(), -textBoundingRect.y());
01195             d->drawTextItems(&buffPainter, option, labelLayout, infoLayout);
01196         }
01197 
01198         PaintUtils::shadowBlur(shadow, 2, d->shadowColor);
01199         painter->drawImage(textBoundingRect.topLeft() + shadowPos, shadow);
01200     } else if (!(d->text.isEmpty() && d->infoText.isEmpty()) &&
01201                !textBoundingRect.isEmpty()) {
01202         QRect labelRect = d->labelRectangle(option, icon, d->text).toRect();
01203 
01204         foreach (const QRect &rect, d->haloRects) {
01205             Plasma::PaintUtils::drawHalo(painter, rect);
01206         }
01207     }
01208 
01209     d->drawTextItems(painter, option, labelLayout, infoLayout);
01210 }
01211 
01212 void IconWidget::setTextBackgroundColor(const QColor &color)
01213 {
01214     d->textBgCustomized = true;
01215     d->textBgColor = color;
01216     update();
01217 }
01218 
01219 QColor IconWidget::textBackgroundColor() const
01220 {
01221     return d->textBgColor;
01222 }
01223 
01224 void IconWidget::drawActionButtonBase(QPainter *painter, const QSize &size, int element)
01225 {
01226     qreal radius = size.width() / 2;
01227     QRadialGradient gradient(radius, radius, radius, radius, radius);
01228     int alpha;
01229 
01230     if (element == IconWidgetPrivate::MinibuttonPressed) {
01231         alpha = 255;
01232     } else if (element == IconWidgetPrivate::MinibuttonHover) {
01233         alpha = 200;
01234     } else {
01235         alpha = 160;
01236     }
01237     gradient.setColorAt(0, QColor::fromRgb(d->textColor.red(),
01238                                            d->textColor.green(),
01239                                            d->textColor.blue(), alpha));
01240     gradient.setColorAt(1, QColor::fromRgb(d->textColor.red(),
01241                                            d->textColor.green(),
01242                                            d->textColor.blue(), 0));
01243 
01244     painter->setBrush(gradient);
01245     painter->setPen(Qt::NoPen);
01246     painter->drawEllipse(QRectF(QPointF(.0, .0), size));
01247 }
01248 
01249 void IconWidget::setText(const QString &text)
01250 {
01251     d->text = KGlobal::locale()->removeAcceleratorMarker(text);
01252     // cause a relayout
01253     d->currentSize = QSizeF(-1, -1);
01254     //try to relayout, needed if an icon was never shown before
01255     if (!isVisible()) {
01256         QStyleOptionGraphicsItem styleoption;
01257         d->layoutIcons(&styleoption);
01258     }
01259     updateGeometry();
01260     if (!parentWidget() || !parentWidget()->layout()) {
01261         resize(preferredSize());
01262     }
01263 }
01264 
01265 QString IconWidget::text() const
01266 {
01267     return d->text;
01268 }
01269 
01270 void IconWidget::setInfoText(const QString &text)
01271 {
01272     d->infoText = text;
01273     // cause a relayout
01274     d->currentSize = QSizeF(-1, -1);
01275     //try to relayout, needed if an icon was never shown before
01276     if (!isVisible()) {
01277         QStyleOptionGraphicsItem styleoption;
01278         d->layoutIcons(&styleoption);
01279     }
01280     updateGeometry();
01281     if (!parentWidget() || !parentWidget()->layout()) {
01282         resize(preferredSize());
01283     }
01284 }
01285 
01286 QString IconWidget::infoText() const
01287 {
01288     return d->infoText;
01289 }
01290 
01291 QIcon IconWidget::icon() const
01292 {
01293     return d->icon;
01294 }
01295 
01296 void IconWidget::setIcon(const QString &icon)
01297 {
01298     if (icon.isEmpty()) {
01299         setIcon(QIcon());
01300         return;
01301     }
01302 
01303     setIcon(KIcon(icon));
01304 }
01305 
01306 void IconWidget::setIcon(const QIcon &icon)
01307 {
01308     setSvg(QString());
01309 
01310     /*fade to the new icon, but to not bee a too big hog, not do that when:
01311       - the fade animation is already running
01312       - the icon is under mouse
01313       - one betwen the old and new icon is null*/
01314     if (!(d->states & IconWidgetPrivate::HoverState) && !d->iconChangeTimer->isActive() && d->oldIcon.isNull() && !d->icon.isNull() && !icon.isNull()) {
01315         d->oldIcon = d->icon;
01316         d->animateMainIcon(true, d->states);
01317     } else {
01318         d->oldIcon = QIcon();
01319     }
01320     d->iconChangeTimer->start(300);
01321     d->icon = icon;
01322     update();
01323 }
01324 
01325 QSizeF IconWidget::iconSize() const
01326 {
01327     return d->iconSize;
01328 }
01329 
01330 void IconWidget::setPreferredIconSize(const QSizeF &size)
01331 {
01332     d->preferredIconSize = size;
01333     updateGeometry();
01334 }
01335 
01336 QSizeF IconWidget::preferredIconSize() const
01337 {
01338     return d->preferredIconSize;
01339 }
01340 
01341 void IconWidget::setMinimumIconSize(const QSizeF &size)
01342 {
01343     d->minimumIconSize = size;
01344     updateGeometry();
01345 }
01346 
01347 QSizeF IconWidget::minimumIconSize() const
01348 {
01349     return d->minimumIconSize;
01350 }
01351 
01352 void IconWidget::setMaximumIconSize(const QSizeF &size)
01353 {
01354     d->maximumIconSize = size;
01355     updateGeometry();
01356 }
01357 
01358 QSizeF IconWidget::maximumIconSize() const
01359 {
01360     return d->maximumIconSize;
01361 }
01362 
01363 bool IconWidget::isDown()
01364 {
01365     return d->states & IconWidgetPrivate::PressedState;
01366 }
01367 
01368 void IconWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
01369 {
01370     if (event->button() != Qt::LeftButton) {
01371         QGraphicsWidget::mousePressEvent(event);
01372         return;
01373     }
01374 
01375     if (KGlobalSettings::singleClick() || (receivers(SIGNAL(clicked()))) > 0) {
01376         d->states |= IconWidgetPrivate::PressedState;
01377     }
01378     d->clickStartPos = scenePos();
01379 
01380     bool handled = false;
01381     foreach (IconAction *action, d->cornerActions) {
01382         handled = action->event(event->type(), event->pos());
01383         if (handled) {
01384             break;
01385         }
01386     }
01387 
01388     if (!handled && boundingRect().contains(event->pos())) {
01389         emit pressed(true);
01390     }
01391 
01392     update();
01393 }
01394 
01395 void IconWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
01396 {
01397     if (~d->states & IconWidgetPrivate::PressedState) {
01398         QGraphicsWidget::mouseMoveEvent(event);
01399         return;
01400     }
01401 
01402     if (boundingRect().contains(event->pos())) {
01403         if (~d->states & IconWidgetPrivate::HoverState) {
01404             d->states |= IconWidgetPrivate::HoverState;
01405             update();
01406         }
01407     } else {
01408         if (d->states & IconWidgetPrivate::HoverState) {
01409             d->states &= ~IconWidgetPrivate::HoverState;
01410             update();
01411         }
01412     }
01413 }
01414 
01415 void IconWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
01416 {
01417     if (~d->states & IconWidgetPrivate::PressedState) {
01418         QGraphicsWidget::mouseMoveEvent(event);
01419         return;
01420     }
01421 
01422     d->states &= ~IconWidgetPrivate::PressedState;
01423 
01424     //don't pass click when the mouse was moved
01425     bool handled = d->clickStartPos != scenePos();
01426     if (!handled) {
01427         foreach (IconAction *action, d->cornerActions) {
01428             if (action->event(event->type(), event->pos())) {
01429                 handled = true;
01430                 break;
01431             }
01432         }
01433     }
01434 
01435     if (!handled) {
01436         if (boundingRect().contains(event->pos())) {
01437             emit clicked();
01438             if (KGlobalSettings::singleClick()) {
01439                emit activated();
01440             }
01441 
01442             if (d->action && d->action->menu()) {
01443                 d->action->menu()->popup(event->screenPos());
01444             }
01445         }
01446         emit pressed(false);
01447     }
01448 
01449     update();
01450 }
01451 
01452 void IconWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
01453 {
01454     Q_UNUSED(event)
01455 
01456     d->states |= IconWidgetPrivate::PressedState;
01457 
01458     emit doubleClicked();
01459     if (!KGlobalSettings::singleClick()) {
01460         emit activated();
01461     }
01462 
01463     update();
01464 }
01465 
01466 void IconWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
01467 {
01468     //kDebug();
01469     foreach (IconAction *action, d->cornerActions) {
01470         action->show();
01471         action->event(event->type(), event->pos());
01472     }
01473 
01474     d->oldIcon = QIcon();
01475     d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState);
01476 
01477     QGraphicsWidget::hoverEnterEvent(event);
01478 }
01479 
01480 void IconWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
01481 {
01482     //kDebug() << d->cornerActions;
01483     foreach (IconAction *action, d->cornerActions) {
01484         action->hide();
01485         action->event(event->type(), event->pos());
01486     }
01487     // d->states &= ~IconWidgetPrivate::HoverState; // Will be set once progress is zero again ...
01488     //if an eventfilter stolen the mousereleaseevent remove the pressed state here
01489     d->states &= ~IconWidgetPrivate::PressedState;
01490 
01491     d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState);
01492 
01493     QGraphicsWidget::hoverLeaveEvent(event);
01494 }
01495 
01496 bool IconWidget::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
01497 {
01498     Q_UNUSED(watched)
01499 
01500     if (event->type() == QEvent::GraphicsSceneDragEnter) {
01501         d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState);
01502     } else if (event->type() == QEvent::GraphicsSceneDragLeave) {
01503         d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState);
01504     }
01505 
01506     return false;
01507 }
01508 
01509 void IconWidget::setPressed(bool pressed)
01510 {
01511     if (pressed) {
01512         d->states |= IconWidgetPrivate::ManualPressedState;
01513         d->states |= IconWidgetPrivate::PressedState;
01514     } else {
01515         d->states &= ~IconWidgetPrivate::ManualPressedState;
01516         d->states &= ~IconWidgetPrivate::PressedState;
01517     }
01518     update();
01519 }
01520 
01521 void IconWidget::setUnpressed()
01522 {
01523     setPressed(false);
01524 }
01525 
01526 void IconWidgetPrivate::svgChanged()
01527 {
01528     iconSvgElementChanged = true;
01529     q->update();
01530 }
01531 
01532 void IconWidget::setOrientation(Qt::Orientation orientation)
01533 {
01534     d->orientation = orientation;
01535     resize(sizeFromIconSize(d->iconSize.width()));
01536 }
01537 
01538 Qt::Orientation IconWidget::orientation() const
01539 {
01540     return d->orientation;
01541 }
01542 
01543 void IconWidget::invertLayout(bool invert)
01544 {
01545     d->invertLayout = invert;
01546 }
01547 
01548 bool IconWidget::invertedLayout() const
01549 {
01550     return d->invertLayout;
01551 }
01552 
01553 QSizeF IconWidget::sizeFromIconSize(const qreal iconWidth) const
01554 {
01555     d->setActiveMargins();
01556     if (d->text.isEmpty() && d->infoText.isEmpty()) {
01557         //no text, just the icon size
01558         return d->addMargin(QSizeF(iconWidth, iconWidth), IconWidgetPrivate::ItemMargin);
01559     }
01560 
01561     QFontMetricsF fm(font());
01562     qreal width = 0;
01563 
01564     if (d->orientation == Qt::Vertical) {
01565         width = qMax(d->maxWordWidth(d->text),
01566                      d->maxWordWidth(d->infoText)) +
01567                      fm.width("xxx") +
01568                      d->verticalMargin[IconWidgetPrivate::TextMargin].left +
01569                      d->verticalMargin[IconWidgetPrivate::TextMargin].right;
01570 
01571         width = qMax(width,
01572                      iconWidth +
01573                      d->verticalMargin[IconWidgetPrivate::IconMargin].left +
01574                      d->verticalMargin[IconWidgetPrivate::IconMargin].right);
01575     } else {
01576         width = iconWidth +
01577                 d->horizontalMargin[IconWidgetPrivate::IconMargin].left +
01578                 d->horizontalMargin[IconWidgetPrivate::IconMargin].right +
01579                 qMax(fm.width(d->text), fm.width(d->infoText)) + fm.width("xxx") +
01580                 d->horizontalMargin[IconWidgetPrivate::TextMargin].left +
01581                 d->horizontalMargin[IconWidgetPrivate::TextMargin].right;
01582     }
01583 
01584     qreal height;
01585     qreal textHeight;
01586 
01587     QStyleOptionGraphicsItem option;
01588     option.state = QStyle::State_None;
01589     option.rect = QRect(0, 0, width, QWIDGETSIZE_MAX);
01590     textHeight = d->displaySizeHint(&option, width).height();
01591 
01592     if (d->orientation == Qt::Vertical) {
01593         height = iconWidth + textHeight +
01594                  d->verticalMargin[IconWidgetPrivate::TextMargin].top +
01595                  d->verticalMargin[IconWidgetPrivate::TextMargin].bottom +
01596                  d->verticalMargin[IconWidgetPrivate::IconMargin].top +
01597                  d->verticalMargin[IconWidgetPrivate::IconMargin].bottom;
01598     } else {
01599         //Horizontal
01600         height = qMax(iconWidth +
01601                       d->verticalMargin[IconWidgetPrivate::IconMargin].top +
01602                       d->verticalMargin[IconWidgetPrivate::IconMargin].bottom,
01603                       textHeight +
01604                       d->verticalMargin[IconWidgetPrivate::TextMargin].top +
01605                       d->verticalMargin[IconWidgetPrivate::TextMargin].bottom);
01606     }
01607 
01608     return d->addMargin(QSizeF(width, height), IconWidgetPrivate::ItemMargin);
01609 }
01610 
01611 void IconWidget::changeEvent(QEvent *event)
01612 {
01613     d->changeEvent(event);
01614     QGraphicsWidget::changeEvent(event);
01615 }
01616 
01617 } // namespace Plasma
01618 
01619 #include "iconwidget.moc"
01620 #include "iconwidget_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Wed May 2 2012 17:36:10 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

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

kdelibs-4.8.3 API Reference

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