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"
KDE 4.6 API Reference