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