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

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

Skip menu "kdelibs"
  • 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
Generated for kdelibs by doxygen 1.7.5
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