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

Plasma

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • 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
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal