Plasma
iconwidget.cpp
Go to the documentation of this file.
00001 /* 00002 * Copyright 2007 by Aaron Seigo <aseigo@kde.org> 00003 * Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org> 00004 * Copyright 2007 by Matt Broadstone <mbroadst@gmail.com> 00005 * Copyright 2006-2007 Fredrik Höglund <fredrik@kde.org> 00006 * Copyright 2007 by Marco Martin <notmart@gmail.com> 00007 * Copyright 2008 by Alexis Ménard <darktears31@gmail.com> 00008 * 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU Library General Public License as 00011 * published by the Free Software Foundation; either version 2, or 00012 * (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details 00018 * 00019 * You should have received a copy of the GNU Library General Public 00020 * License along with this program; if not, write to the 00021 * Free Software Foundation, Inc., 00022 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00023 */ 00024 00025 #include "iconwidget.h" 00026 #include "iconwidget_p.h" 00027 00028 #include <QAction> 00029 #include <QApplication> 00030 #include <QGraphicsSceneMouseEvent> 00031 #include <QGraphicsView> 00032 #include <QMenu> 00033 #include <QPainter> 00034 #include <QStyleOptionGraphicsItem> 00035 #include <QTextLayout> 00036 #include <QTimer> 00037 00038 #include <kcolorscheme.h> 00039 #include <kdebug.h> 00040 #include <kglobalsettings.h> 00041 #include <kicon.h> 00042 #include <kiconeffect.h> 00043 #include <kiconloader.h> 00044 #include <kmimetype.h> 00045 #include <kurl.h> 00046 00047 #include "animator.h" 00048 #include "animations/animation.h" 00049 #include "paintutils.h" 00050 #include "private/themedwidgetinterface_p.h" 00051 #include "theme.h" 00052 00053 #include "svg.h" 00054 00055 /* 00056 TODO: 00057 Add these to a UrlIcon class 00058 void setUrl(const KUrl& url); 00059 KUrl url() const; 00060 */ 00061 00062 namespace Plasma 00063 { 00064 00065 IconHoverAnimation::IconHoverAnimation(QObject *parent) 00066 : QObject(parent), m_value(0), m_fadeIn(false) 00067 { 00068 } 00069 00070 qreal IconHoverAnimation::value() const 00071 { 00072 return m_value; 00073 } 00074 00075 bool IconHoverAnimation::fadeIn() const 00076 { 00077 return m_fadeIn; 00078 } 00079 00080 QPropertyAnimation *IconHoverAnimation::animation() const 00081 { 00082 return m_animation.data(); 00083 } 00084 00085 void IconHoverAnimation::setValue(qreal value) 00086 { 00087 m_value = value; 00088 QGraphicsWidget *item = static_cast<QGraphicsWidget*>(parent()); 00089 item->update(); 00090 } 00091 00092 void IconHoverAnimation::setFadeIn(bool fadeIn) 00093 { 00094 m_fadeIn = fadeIn; 00095 } 00096 00097 void IconHoverAnimation::setAnimation(QPropertyAnimation *animation) 00098 { 00099 m_animation = animation; 00100 } 00101 00102 IconWidgetPrivate::IconWidgetPrivate(IconWidget *i) 00103 : ActionWidgetInterface<IconWidget>(i), 00104 iconSvg(0), 00105 hoverAnimation(new IconHoverAnimation(q)), 00106 iconSize(48, 48), 00107 preferredIconSize(-1, -1), 00108 minimumIconSize(-1, -1), 00109 maximumIconSize(-1, -1), 00110 states(IconWidgetPrivate::NoState), 00111 orientation(Qt::Vertical), 00112 numDisplayLines(2), 00113 activeMargins(0), 00114 iconSvgElementChanged(false), 00115 invertLayout(false), 00116 drawBg(false), 00117 textBgCustomized(false) 00118 { 00119 } 00120 00121 IconWidgetPrivate::~IconWidgetPrivate() 00122 { 00123 qDeleteAll(cornerActions); 00124 delete hoverAnimation; 00125 } 00126 00127 void IconWidgetPrivate::readColors() 00128 { 00129 textColor = Plasma::Theme::defaultTheme()->color(Theme::TextColor); 00130 00131 if (qGray(textColor.rgb()) > 192) { 00132 shadowColor = Qt::black; 00133 } else { 00134 shadowColor = Qt::white; 00135 } 00136 00137 if (!textBgCustomized) { 00138 textBgColor = QColor(); 00139 } 00140 } 00141 00142 void IconWidgetPrivate::colorConfigChanged() 00143 { 00144 readColors(); 00145 if (drawBg) { 00146 qreal left, top, right, bottom; 00147 background->getMargins(left, top, right, bottom); 00148 setVerticalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom); 00149 setHorizontalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom); 00150 } 00151 q->update(); 00152 } 00153 00154 void IconWidgetPrivate::iconConfigChanged() 00155 { 00156 if (!icon.isNull()) { 00157 q->update(); 00158 } 00159 } 00160 00161 IconAction::IconAction(IconWidget *icon, QAction *action) 00162 : m_icon(icon), 00163 m_action(action), 00164 m_hovered(false), 00165 m_pressed(false), 00166 m_selected(false), 00167 m_visible(false) 00168 { 00169 } 00170 00171 void IconAction::show() 00172 { 00173 Animation *animation = m_animation.data(); 00174 if (!animation) { 00175 animation = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation, m_icon); 00176 animation->setTargetWidget(m_icon); 00177 m_animation = animation; 00178 } else if (animation->state() == QAbstractAnimation::Running) { 00179 animation->pause(); 00180 } 00181 00182 rebuildPixmap(); 00183 m_visible = true; 00184 00185 animation->setProperty("targetPixmap", m_pixmap); 00186 animation->setDirection(QAbstractAnimation::Forward); 00187 animation->start(); 00188 } 00189 00190 void IconAction::hide() 00191 { 00192 if (!m_animation) { 00193 return; 00194 } 00195 00196 Animation *animation = m_animation.data(); 00197 if (animation->state() == QAbstractAnimation::Running) { 00198 animation->pause(); 00199 } 00200 00201 m_visible = false; 00202 00203 animation->setDirection(QAbstractAnimation::Backward); 00204 animation->start(QAbstractAnimation::DeleteWhenStopped); 00205 } 00206 00207 bool IconAction::isVisible() const 00208 { 00209 return m_visible; 00210 } 00211 00212 bool IconAction::isAnimating() const 00213 { 00214 return !m_animation.isNull(); 00215 } 00216 00217 bool IconAction::isPressed() const 00218 { 00219 return m_pressed; 00220 } 00221 00222 bool IconAction::isHovered() const 00223 { 00224 return m_hovered; 00225 } 00226 00227 void IconAction::setSelected(bool selected) 00228 { 00229 m_selected = selected; 00230 } 00231 00232 bool IconAction::isSelected() const 00233 { 00234 return m_selected; 00235 } 00236 00237 void IconAction::setRect(const QRectF &rect) 00238 { 00239 m_rect = rect; 00240 } 00241 00242 QRectF IconAction::rect() const 00243 { 00244 return m_rect; 00245 } 00246 00247 void IconAction::rebuildPixmap() 00248 { 00249 // Determine proper QIcon mode based on selection status 00250 QIcon::Mode mode = m_selected ? QIcon::Selected : QIcon::Normal; 00251 00252 // Draw everything 00253 m_pixmap = QPixmap(26, 26); 00254 m_pixmap.fill(Qt::transparent); 00255 00256 int element = IconWidgetPrivate::Minibutton; 00257 if (m_pressed) { 00258 element = IconWidgetPrivate::MinibuttonPressed; 00259 } else if (m_hovered) { 00260 element = IconWidgetPrivate::MinibuttonHover; 00261 } 00262 00263 QPainter painter(&m_pixmap); 00264 m_icon->drawActionButtonBase(&painter, m_pixmap.size(), element); 00265 m_action->icon().paint(&painter, 2, 2, 22, 22, Qt::AlignCenter, mode); 00266 } 00267 00268 bool IconAction::event(QEvent::Type type, const QPointF &pos) 00269 { 00270 if (!m_action->isVisible() || !m_action->isEnabled()) { 00271 return false; 00272 } 00273 00274 if (m_icon->size().width() < m_rect.width() * 2.0 || 00275 m_icon->size().height() < m_rect.height() * 2.0) { 00276 return false; 00277 } 00278 00279 switch (type) { 00280 case QEvent::GraphicsSceneMousePress: 00281 { 00282 setSelected(m_rect.contains(pos)); 00283 return isSelected(); 00284 } 00285 break; 00286 00287 case QEvent::GraphicsSceneMouseMove: 00288 { 00289 bool wasSelected = isSelected(); 00290 bool active = m_rect.contains(pos); 00291 setSelected(wasSelected && active); 00292 return (wasSelected != isSelected()) || active; 00293 } 00294 break; 00295 00296 case QEvent::GraphicsSceneMouseRelease: 00297 { 00298 // kDebug() << "IconAction::event got a QEvent::MouseButtonRelease, " << isSelected(); 00299 bool wasSelected = isSelected(); 00300 setSelected(false); 00301 if (wasSelected) { 00302 m_action->trigger(); 00303 } 00304 00305 return wasSelected; 00306 } 00307 break; 00308 00309 case QEvent::GraphicsSceneHoverEnter: 00310 m_pressed = false; 00311 m_hovered = true; 00312 break; 00313 00314 case QEvent::GraphicsSceneHoverLeave: 00315 m_pressed = false; 00316 m_hovered = false; 00317 break; 00318 00319 default: 00320 break; 00321 } 00322 00323 return false; 00324 } 00325 00326 QAction *IconAction::action() const 00327 { 00328 return m_action; 00329 } 00330 00331 void IconAction::paint(QPainter *painter) const 00332 { 00333 if (!m_action->isVisible() || !m_action->isEnabled()) { 00334 return; 00335 } 00336 00337 if (m_icon->size().width() < m_rect.width() * 2.0 || 00338 m_icon->size().height() < m_rect.height() * 2.0) { 00339 return; 00340 } 00341 00342 Animation *animation = m_animation.data(); 00343 if (m_visible && !animation) { 00344 painter->drawPixmap(m_rect.toRect(), m_pixmap); 00345 } else { 00346 painter->drawPixmap(m_rect.toRect(), 00347 animation->property("currentPixmap").value<QPixmap>()); 00348 } 00349 } 00350 00351 IconWidget::IconWidget(QGraphicsItem *parent) 00352 : QGraphicsWidget(parent), 00353 d(new IconWidgetPrivate(this)) 00354 { 00355 d->init(); 00356 } 00357 00358 IconWidget::IconWidget(const QString &text, QGraphicsItem *parent) 00359 : QGraphicsWidget(parent), 00360 d(new IconWidgetPrivate(this)) 00361 { 00362 d->init(); 00363 setText(text); 00364 } 00365 00366 IconWidget::IconWidget(const QIcon &icon, const QString &text, QGraphicsItem *parent) 00367 : QGraphicsWidget(parent), 00368 d(new IconWidgetPrivate(this)) 00369 { 00370 d->init(); 00371 setText(text); 00372 setIcon(icon); 00373 } 00374 00375 IconWidget::~IconWidget() 00376 { 00377 delete d; 00378 } 00379 00380 void IconWidgetPrivate::init() 00381 { 00382 readColors(); 00383 00384 iconChangeTimer = new QTimer(q); 00385 iconChangeTimer->setSingleShot(true); 00386 00387 QObject::connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), q, SLOT(colorConfigChanged())); 00388 QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorConfigChanged())); 00389 QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), q, SLOT(iconConfigChanged())); 00390 00391 // setAcceptedMouseButtons(Qt::LeftButton); 00392 q->setAcceptsHoverEvents(true); 00393 q->setCacheMode(QGraphicsItem::DeviceCoordinateCache); 00394 00395 background = new Plasma::FrameSvg(q); 00396 background->setImagePath("widgets/viewitem"); 00397 background->setCacheAllRenderedFrames(true); 00398 background->setElementPrefix("hover"); 00399 00400 // Margins for horizontal mode (list views, tree views, table views) 00401 setHorizontalMargin(IconWidgetPrivate::TextMargin, 1, 1); 00402 setHorizontalMargin(IconWidgetPrivate::IconMargin, 1, 1); 00403 setHorizontalMargin(IconWidgetPrivate::ItemMargin, 0, 0); 00404 00405 // Margins for vertical mode (icon views) 00406 setVerticalMargin(IconWidgetPrivate::TextMargin, 6, 2); 00407 setVerticalMargin(IconWidgetPrivate::IconMargin, 1, 1); 00408 setVerticalMargin(IconWidgetPrivate::ItemMargin, 0, 0); 00409 00410 setActiveMargins(); 00411 currentSize = QSizeF(-1, -1); 00412 initTheming(); 00413 } 00414 00415 void IconWidget::addIconAction(QAction *action) 00416 { 00417 int count = d->cornerActions.count(); 00418 if (count >= IconWidgetPrivate::LastIconPosition) { 00419 kDebug() << "no more room for more actions!"; 00420 // just overlap it with the last item for now. ugly, but there you go. 00421 } 00422 00423 IconAction *iconAction = new IconAction(this, action); 00424 d->cornerActions.append(iconAction); 00425 connect(action, SIGNAL(destroyed(QObject*)), this, SLOT(actionDestroyed(QObject*))); 00426 00427 iconAction->setRect(d->actionRect(qMin((IconWidgetPrivate::ActionPosition)count, IconWidgetPrivate::LastIconPosition))); 00428 } 00429 00430 void IconWidget::removeIconAction(QAction *action) 00431 { 00432 //WARNING: do NOT access the action pointer passed in, as it may already be 00433 //be destroyed. see IconWidgetPrivate::actionDestroyed(QObject*) 00434 int count = 0; 00435 bool found = false; 00436 foreach (IconAction *iconAction, d->cornerActions) { 00437 if (found) { 00438 iconAction->setRect(d->actionRect((IconWidgetPrivate::ActionPosition)count)); 00439 } else if (!action || iconAction->action() == action) { 00440 delete iconAction; 00441 d->cornerActions.removeAll(iconAction); 00442 } 00443 00444 if (count < IconWidgetPrivate::LastIconPosition) { 00445 ++count; 00446 } 00447 } 00448 00449 // redraw since an action has been deleted. 00450 update(); 00451 } 00452 00453 void IconWidgetPrivate::actionDestroyed(QObject *action) 00454 { 00455 q->removeIconAction(static_cast<QAction*>(action)); 00456 } 00457 00458 void IconWidget::setAction(QAction *action) 00459 { 00460 d->setAction(action); 00461 } 00462 00463 QAction *IconWidget::action() const 00464 { 00465 return d->action; 00466 } 00467 00468 int IconWidget::numDisplayLines() 00469 { 00470 return d->numDisplayLines; 00471 } 00472 00473 void IconWidget::setNumDisplayLines(int numLines) 00474 { 00475 if (numLines > d->maxDisplayLines) { 00476 d->numDisplayLines = d->maxDisplayLines; 00477 } else { 00478 d->numDisplayLines = numLines; 00479 } 00480 } 00481 00482 void IconWidget::setDrawBackground(bool draw) 00483 { 00484 if (d->drawBg != draw) { 00485 d->drawBg = draw; 00486 00487 QStyle *style = QApplication::style(); 00488 int focusHMargin = draw ? style->pixelMetric(QStyle::PM_FocusFrameHMargin) : 1; 00489 int focusVMargin = draw ? style->pixelMetric(QStyle::PM_FocusFrameVMargin) : 1; 00490 d->setHorizontalMargin(IconWidgetPrivate::TextMargin, focusHMargin, focusVMargin); 00491 d->setHorizontalMargin(IconWidgetPrivate::IconMargin, focusHMargin, focusVMargin); 00492 d->setVerticalMargin(IconWidgetPrivate::IconMargin, focusHMargin, focusVMargin); 00493 d->currentSize = QSizeF(-1, -1); 00494 00495 if (draw) { 00496 qreal left, top, right, bottom; 00497 d->background->getMargins(left, top, right, bottom); 00498 d->setHorizontalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom); 00499 d->setVerticalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom); 00500 } else { 00501 d->setHorizontalMargin(IconWidgetPrivate::ItemMargin, 0, 0); 00502 d->setVerticalMargin(IconWidgetPrivate::ItemMargin, 0, 0); 00503 } 00504 00505 update(); 00506 updateGeometry(); 00507 } 00508 } 00509 00510 bool IconWidget::drawBackground() const 00511 { 00512 return d->drawBg; 00513 } 00514 00515 QPainterPath IconWidget::shape() const 00516 { 00517 if (!d->drawBg || d->currentSize.width() < 1) { 00518 return QGraphicsItem::shape(); 00519 } 00520 00521 return PaintUtils::roundedRectangle( 00522 QRectF(QPointF(0.0, 0.0), d->currentSize).adjusted(-2, -2, 2, 2), 10.0); 00523 } 00524 00525 QSizeF IconWidgetPrivate::displaySizeHint(const QStyleOptionGraphicsItem *option, const qreal width) const 00526 { 00527 if (text.isEmpty() && infoText.isEmpty()) { 00528 return QSizeF(.0, .0); 00529 } 00530 00531 QString label = text; 00532 // const qreal maxWidth = (orientation == Qt::Vertical) ? iconSize.width() + 10 : 32757; 00533 // NOTE: find a way to use the other layoutText, it currently returns nominal width, when 00534 // we actually need the actual width. 00535 00536 qreal textWidth = width - 00537 horizontalMargin[IconWidgetPrivate::TextMargin].left - 00538 horizontalMargin[IconWidgetPrivate::TextMargin].right; 00539 00540 //allow only five lines of text 00541 const qreal maxHeight = 00542 numDisplayLines * QFontMetrics(q->font()).lineSpacing(); 00543 00544 // To compute the nominal size for the label + info, we'll just append 00545 // the information string to the label 00546 if (!infoText.isEmpty()) { 00547 label += QString(QChar::LineSeparator) + infoText; 00548 } 00549 00550 QTextLayout layout; 00551 setLayoutOptions(layout, option, q->orientation()); 00552 layout.setFont(q->font()); 00553 QSizeF size = layoutText(layout, label, QSizeF(textWidth, maxHeight)); 00554 00555 return addMargin(size, TextMargin); 00556 } 00557 00558 void IconWidgetPrivate::layoutIcons(const QStyleOptionGraphicsItem *option) 00559 { 00560 if (option->rect.size() == currentSize) { 00561 return; 00562 } 00563 00564 currentSize = option->rect.size(); 00565 iconSize = iconSizeForWidgetSize(option, currentSize); 00566 00567 int count = 0; 00568 foreach (IconAction *iconAction, cornerActions) { 00569 iconAction->setRect(actionRect((IconWidgetPrivate::ActionPosition)count)); 00570 ++count; 00571 } 00572 } 00573 00574 QSizeF IconWidgetPrivate::iconSizeForWidgetSize(const QStyleOptionGraphicsItem *option, const QSizeF &rect) 00575 { 00576 setActiveMargins(); 00577 00578 //calculate icon size based on the available space 00579 qreal iconWidth; 00580 00581 if (orientation == Qt::Vertical) { 00582 qreal heightAvail; 00583 //if there is text resize the icon in order to make room for the text 00584 if (text.isEmpty() && infoText.isEmpty()) { 00585 heightAvail = rect.height(); 00586 } else { 00587 heightAvail = rect.height() - 00588 displaySizeHint(option, rect.width()).height() - 00589 verticalMargin[IconWidgetPrivate::TextMargin].top - 00590 verticalMargin[IconWidgetPrivate::TextMargin].bottom; 00591 //never make a label higher than half the total height 00592 heightAvail = qMax(heightAvail, rect.height() / 2); 00593 } 00594 00595 //aspect ratio very "tall" 00596 if (!text.isEmpty() || !infoText.isEmpty()) { 00597 if (rect.width() < heightAvail) { 00598 iconWidth = rect.width() - 00599 verticalMargin[IconWidgetPrivate::IconMargin].left - 00600 verticalMargin[IconWidgetPrivate::IconMargin].right; 00601 } else { 00602 iconWidth = heightAvail - 00603 verticalMargin[IconWidgetPrivate::IconMargin].top - 00604 verticalMargin[IconWidgetPrivate::IconMargin].bottom; 00605 } 00606 } else { 00607 iconWidth = qMin(heightAvail, rect.width()); 00608 } 00609 00610 iconWidth -= verticalMargin[IconWidgetPrivate::ItemMargin].left + verticalMargin[IconWidgetPrivate::ItemMargin].right; 00611 } else { 00612 //Horizontal layout 00613 //if there is text resize the icon in order to make room for the text 00614 if (text.isEmpty() && infoText.isEmpty()) { 00615 // with no text, we just take up the whole geometry 00616 iconWidth = qMin(rect.height(), rect.width()); 00617 } else { 00618 iconWidth = rect.height() - 00619 horizontalMargin[IconWidgetPrivate::IconMargin].top - 00620 horizontalMargin[IconWidgetPrivate::IconMargin].bottom; 00621 } 00622 iconWidth -= horizontalMargin[IconWidgetPrivate::ItemMargin].top + horizontalMargin[IconWidgetPrivate::ItemMargin].bottom; 00623 } 00624 00625 QSizeF iconRect(iconWidth, iconWidth); 00626 00627 if (maximumIconSize.isValid()) { 00628 iconRect = iconRect.boundedTo(maximumIconSize); 00629 } 00630 00631 return iconRect; 00632 } 00633 00634 void IconWidget::setSvg(const QString &svgFilePath, const QString &elementId) 00635 { 00636 if (svgFilePath.isEmpty()) { 00637 if (d->iconSvg) { 00638 d->iconSvg->deleteLater(); 00639 d->iconSvg = 0; 00640 } 00641 return; 00642 } 00643 00644 if (!d->iconSvg) { 00645 d->iconSvg = new Plasma::Svg(this); 00646 connect(d->iconSvg, SIGNAL(repaintNeeded()), this, SLOT(svgChanged())); 00647 d->oldIcon = d->icon; 00648 } else { 00649 d->oldIcon = d->iconSvg->pixmap(d->iconSvgElement); 00650 } 00651 00652 d->iconSvg->setImagePath(svgFilePath); 00653 d->iconSvg->setContainsMultipleImages(!elementId.isNull()); 00654 d->iconSvgElement = elementId; 00655 d->iconSvgElementChanged = true; 00656 updateGeometry(); 00657 00658 if (!(d->states & IconWidgetPrivate::HoverState) && !d->iconChangeTimer->isActive() && !d->oldIcon.isNull()) { 00659 d->animateMainIcon(true, d->states); 00660 } else { 00661 d->oldIcon = QIcon(); 00662 update(); 00663 } 00664 d->iconChangeTimer->start(300); 00665 d->icon = QIcon(); 00666 } 00667 00668 QString IconWidget::svg() const 00669 { 00670 if (d->iconSvg) { 00671 if (d->iconSvg->isValid() && (d->iconSvgElement.isEmpty() || d->iconSvg->hasElement(d->iconSvgElement))) { 00672 return d->iconSvg->imagePath(); 00673 } else { 00674 return QString(); 00675 } 00676 } 00677 00678 return QString(); 00679 } 00680 00681 QSizeF IconWidget::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const 00682 { 00683 if (which == Qt::PreferredSize) { 00684 int iconSize; 00685 00686 if (d->preferredIconSize.isValid()) { 00687 iconSize = qMax(d->preferredIconSize.height(), d->preferredIconSize.width()); 00688 } else if (d->iconSvg) { 00689 QSizeF oldSize = d->iconSvg->size(); 00690 d->iconSvg->resize(); 00691 if (d->iconSvgElement.isNull()) { 00692 iconSize = qMax(d->iconSvg->size().width(), d->iconSvg->size().height()); 00693 } else { 00694 iconSize = qMax(d->iconSvg->elementSize(d->iconSvgElement).width(), d->iconSvg->elementSize(d->iconSvgElement).height()); 00695 } 00696 d->iconSvg->resize(oldSize); 00697 } else { 00698 iconSize = KIconLoader::SizeMedium; 00699 } 00700 00701 if (constraint.width() > 0 || constraint.height() > 0) { 00702 QSizeF constrainedWidgetSize(constraint); 00703 QSizeF maximumWidgetSize; 00704 00705 if (d->maximumIconSize.isValid()) { 00706 maximumWidgetSize = 00707 sizeFromIconSize(qMax(d->maximumIconSize.height(), d->maximumIconSize.width())); 00708 } else { 00709 maximumWidgetSize = 00710 QGraphicsWidget::sizeHint(Qt::MaximumSize); 00711 } 00712 00713 if (constrainedWidgetSize.width() <= 0) { 00714 constrainedWidgetSize.setWidth(maximumWidgetSize.width()); 00715 } 00716 if (constrainedWidgetSize.height() <= 0) { 00717 constrainedWidgetSize.setHeight(maximumWidgetSize.height()); 00718 } 00719 00720 QStyleOptionGraphicsItem option; 00721 QSizeF iconRect = 00722 d->iconSizeForWidgetSize(&option, constrainedWidgetSize); 00723 iconSize = 00724 qMin(iconSize, qMax<int>(iconRect.width(), iconRect.height())); 00725 } 00726 00727 return sizeFromIconSize(iconSize); 00728 } else if (which == Qt::MinimumSize) { 00729 if (d->minimumIconSize.isValid()) { 00730 return sizeFromIconSize(qMax(d->minimumIconSize.height(), d->minimumIconSize.width())); 00731 } 00732 00733 return sizeFromIconSize(KIconLoader::SizeSmall); 00734 } else { 00735 if (d->maximumIconSize.isValid()) { 00736 return sizeFromIconSize(qMax(d->maximumIconSize.height(), d->maximumIconSize.width())); 00737 } 00738 00739 return QGraphicsWidget::sizeHint(which, constraint); 00740 } 00741 } 00742 00743 void IconWidgetPrivate::animateMainIcon(bool show, const IconWidgetStates state) 00744 { 00745 if (show) { 00746 states = state; 00747 } 00748 00749 hoverAnimation->setFadeIn(show); 00750 00751 QPropertyAnimation *animation = hoverAnimation->animation(); 00752 if (!animation) { 00753 animation = new QPropertyAnimation(hoverAnimation, "value"); 00754 animation->setDuration(150); 00755 animation->setEasingCurve(QEasingCurve::OutQuad); 00756 animation->setStartValue(0.0); 00757 animation->setEndValue(1.0); 00758 hoverAnimation->setAnimation(animation); 00759 q->connect(animation, SIGNAL(finished()), q, SLOT(hoverAnimationFinished())); 00760 } else if (animation->state() == QAbstractAnimation::Running) { 00761 animation->pause(); 00762 } 00763 00764 animation->setDirection(show ? QAbstractAnimation::Forward : QAbstractAnimation::Backward); 00765 animation->start(show ? QAbstractAnimation::KeepWhenStopped : QAbstractAnimation::DeleteWhenStopped); 00766 q->update(); 00767 } 00768 00769 void IconWidgetPrivate::hoverAnimationFinished() 00770 { 00771 if (!hoverAnimation->fadeIn()) { 00772 states &= ~IconWidgetPrivate::HoverState; 00773 } 00774 } 00775 00776 void IconWidgetPrivate::drawBackground(QPainter *painter, IconWidgetState state) 00777 { 00778 if (!drawBg) { 00779 return; 00780 } 00781 00782 if (!(states & IconWidgetPrivate::HoverState) && !(states & IconWidgetPrivate::PressedState)) { 00783 return; 00784 } 00785 00786 if (state == IconWidgetPrivate::PressedState) { 00787 background->setElementPrefix("selected"); 00788 } else { 00789 background->setElementPrefix("hover"); 00790 } 00791 00792 if (qFuzzyCompare(hoverAnimation->value(), 1)) { 00793 background->resizeFrame(currentSize); 00794 background->paintFrame(painter); 00795 } else if (!qFuzzyCompare(hoverAnimation->value()+1, 1)) { 00796 background->resizeFrame(currentSize); 00797 QPixmap frame = background->framePixmap(); 00798 QPainter bufferPainter(&frame); 00799 bufferPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn); 00800 bufferPainter.fillRect(frame.rect(), QColor(0,0,0, 255*hoverAnimation->value())); 00801 bufferPainter.end(); 00802 painter->drawPixmap(QPoint(0,0), frame); 00803 } 00804 } 00805 00806 QPixmap IconWidgetPrivate::decoration(const QStyleOptionGraphicsItem *option, bool useHoverEffect, bool usePressedEffect) 00807 { 00808 QPixmap result; 00809 00810 QIcon::Mode mode = option->state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; 00811 QIcon::State state = option->state & QStyle::State_Open ? QIcon::On : QIcon::Off; 00812 00813 if (iconSvg) { 00814 if (iconSvgElementChanged || iconSvgPixmap.size() != iconSize.toSize()) { 00815 iconSvg->resize(iconSize); 00816 iconSvgPixmap = iconSvg->pixmap(iconSvgElement); 00817 iconSvgElementChanged = false; 00818 } 00819 result = iconSvgPixmap; 00820 } else { 00821 const QSize size = icon.actualSize(iconSize.toSize(), mode, state); 00822 result = icon.pixmap(size, mode, state); 00823 } 00824 00825 if (usePressedEffect) { 00826 result = result.scaled(result.size() * 0.9, Qt::KeepAspectRatio, Qt::SmoothTransformation); 00827 } 00828 00829 if (!result.isNull() && useHoverEffect) { 00830 KIconEffect *effect = KIconLoader::global()->iconEffect(); 00831 // Note that in KIconLoader terminology, active = hover. 00832 // We're assuming that the icon group is desktop/filemanager, since this 00833 // is KFileItemDelegate. 00834 if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) { 00835 if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) { 00836 result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState); 00837 } else { 00838 result = PaintUtils::transition( 00839 result, 00840 effect->apply(result, KIconLoader::Desktop, 00841 KIconLoader::ActiveState), hoverAnimation->value()); 00842 } 00843 } 00844 } else if (!result.isNull() && !oldIcon.isNull()) { 00845 if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) { 00846 oldIcon = QIcon(); 00847 } else { 00848 result = PaintUtils::transition( 00849 oldIcon.pixmap(result.size(), mode, state), 00850 result, hoverAnimation->value()); 00851 } 00852 } 00853 00854 return result; 00855 } 00856 00857 QPointF IconWidgetPrivate::iconPosition(const QStyleOptionGraphicsItem *option, 00858 const QPixmap &pixmap) const 00859 { 00860 const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin); 00861 00862 // Compute the nominal decoration rectangle 00863 const QSizeF size = addMargin(iconSize, IconWidgetPrivate::IconMargin); 00864 00865 Qt::LayoutDirection direction = iconDirection(option); 00866 00867 //alignment depends from orientation and option->direction 00868 Qt::Alignment alignment; 00869 if (text.isEmpty() && infoText.isEmpty()) { 00870 alignment = Qt::AlignCenter; 00871 } else if (orientation == Qt::Vertical) { 00872 alignment = Qt::Alignment(Qt::AlignHCenter | Qt::AlignTop); 00873 //Horizontal 00874 } else { 00875 alignment = QStyle::visualAlignment( 00876 direction, Qt::Alignment(Qt::AlignLeft | Qt::AlignVCenter)); 00877 } 00878 00879 const QRect iconRect = 00880 QStyle::alignedRect(direction, alignment, size.toSize(), itemRect.toRect()); 00881 00882 // Position the pixmap in the center of the rectangle 00883 QRect pixmapRect = pixmap.rect(); 00884 pixmapRect.moveCenter(iconRect.center()); 00885 00886 // add a gimmicky margin of 5px to y, TEMP TEMP TEMP 00887 // pixmapRect = pixmapRect.adjusted(0, 5, 0, 0); 00888 00889 return QPointF(pixmapRect.topLeft()); 00890 } 00891 00892 QRectF IconWidgetPrivate::labelRectangle(const QStyleOptionGraphicsItem *option, 00893 const QPixmap &icon, 00894 const QString &string) const 00895 { 00896 Q_UNUSED(string) 00897 00898 if (icon.isNull()) { 00899 return option->rect; 00900 } 00901 00902 const QSizeF decoSize = addMargin(iconSize, IconWidgetPrivate::IconMargin); 00903 const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin); 00904 QRectF textArea(QPointF(0, 0), itemRect.size()); 00905 00906 if (orientation == Qt::Vertical) { 00907 textArea.setTop(decoSize.height() + 1); 00908 } else { 00909 //Horizontal 00910 textArea.setLeft(decoSize.width() + 1); 00911 } 00912 00913 textArea.translate(itemRect.topLeft()); 00914 return QRectF(QStyle::visualRect(iconDirection(option), option->rect, textArea.toRect())); 00915 } 00916 00917 // Lays the text out in a rectangle no larger than constraints, eliding it as necessary 00918 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout, 00919 const QString &text, 00920 const QSizeF &constraints) const 00921 { 00922 const QSizeF size = layoutText(layout, text, constraints.width()); 00923 00924 if (size.width() > constraints.width() || size.height() > constraints.height()) { 00925 if (action) { 00926 q->setToolTip(action->toolTip()); 00927 } 00928 const QString elided = elidedText(layout, constraints); 00929 return layoutText(layout, elided, constraints.width()); 00930 } 00931 q->setToolTip(QString()); 00932 00933 return size; 00934 } 00935 00936 // Lays the text out in a rectangle no wider than maxWidth 00937 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout, const QString &text, qreal maxWidth) const 00938 { 00939 QFontMetricsF metrics(layout.font()); 00940 qreal leading = metrics.leading(); 00941 qreal height = 0.0; 00942 qreal widthUsed = 0.0; 00943 QTextLine line; 00944 00945 layout.setText(text); 00946 00947 layout.beginLayout(); 00948 00949 while ((line = layout.createLine()).isValid()) { 00950 line.setLineWidth(maxWidth); 00951 height += leading; 00952 line.setPosition(QPointF(0.0, height)); 00953 height += line.height(); 00954 widthUsed = qMax(widthUsed, line.naturalTextWidth()); 00955 } 00956 layout.endLayout(); 00957 00958 return QSizeF(widthUsed, height); 00959 } 00960 00961 // Elides the text in the layout, by iterating over each line in the layout, eliding 00962 // or word breaking the line if it's wider than the max width, and finally adding an 00963 // ellipses at the end of the last line, if there are more lines than will fit within 00964 // the vertical size constraints. 00965 QString IconWidgetPrivate::elidedText(QTextLayout &layout, const QSizeF &size) const 00966 { 00967 QFontMetricsF metrics(layout.font()); 00968 const QString text = layout.text(); 00969 qreal maxWidth = size.width(); 00970 qreal maxHeight = size.height(); 00971 qreal height = 0; 00972 00973 // Elide each line that has already been laid out in the layout. 00974 QString elided; 00975 elided.reserve(text.length()); 00976 00977 for (int i = 0; i < layout.lineCount(); i++) { 00978 QTextLine line = layout.lineAt(i); 00979 int start = line.textStart(); 00980 int length = line.textLength(); 00981 00982 height += metrics.leading(); 00983 if (height + line.height() + metrics.lineSpacing() > maxHeight) { 00984 // Unfortunately, if the line ends because of a line separator, 00985 // elidedText() will be too clever and keep adding lines until 00986 // it finds one that's too wide. 00987 if (line.naturalTextWidth() < maxWidth && 00988 start + length > 0 && 00989 text[start + length - 1] == QChar::LineSeparator) { 00990 elided += text.mid(start, length - 1); 00991 } else { 00992 elided += metrics.elidedText(text.mid(start), Qt::ElideRight, maxWidth); 00993 } 00994 break; 00995 } else if (line.naturalTextWidth() > maxWidth) { 00996 elided += metrics.elidedText(text.mid(start, length), Qt::ElideRight, maxWidth); 00997 } else { 00998 elided += text.mid(start, length); 00999 } 01000 01001 height += line.height(); 01002 } 01003 01004 return elided; 01005 } 01006 01007 void IconWidgetPrivate::layoutTextItems(const QStyleOptionGraphicsItem *option, 01008 const QPixmap &icon, QTextLayout *labelLayout, 01009 QTextLayout *infoLayout, QRectF *textBoundingRect) const 01010 { 01011 bool showInformation = false; 01012 01013 setLayoutOptions(*labelLayout, option, q->orientation()); 01014 01015 QFontMetricsF fm(labelLayout->font()); 01016 const QRectF textArea = labelRectangle(option, icon, text); 01017 QRectF textRect = subtractMargin(textArea, IconWidgetPrivate::TextMargin); 01018 01019 //kDebug() << this << "text area" << textArea << "text rect" << textRect; 01020 // Sizes and constraints for the different text parts 01021 QSizeF maxLabelSize = textRect.size(); 01022 QSizeF maxInfoSize = textRect.size(); 01023 QSizeF labelSize; 01024 QSizeF infoSize; 01025 01026 // If we have additional info text, and there's space for at least two lines of text, 01027 // adjust the max label size to make room for at least one line of the info text 01028 if (!infoText.isEmpty() && textRect.height() >= fm.lineSpacing() * 2) { 01029 infoLayout->setFont(labelLayout->font()); 01030 infoLayout->setTextOption(labelLayout->textOption()); 01031 01032 maxLabelSize.rheight() -= fm.lineSpacing(); 01033 showInformation = true; 01034 } 01035 01036 // Lay out the label text, and adjust the max info size based on the label size 01037 labelSize = layoutText(*labelLayout, text, maxLabelSize); 01038 maxInfoSize.rheight() -= labelSize.height(); 01039 01040 // Lay out the info text 01041 if (showInformation) { 01042 infoSize = layoutText(*infoLayout, infoText, maxInfoSize); 01043 } else { 01044 infoSize = QSizeF(0, 0); 01045 } 01046 // Compute the bounding rect of the text 01047 const Qt::Alignment alignment = labelLayout->textOption().alignment(); 01048 const QSizeF size(qMax(labelSize.width(), infoSize.width()), 01049 labelSize.height() + infoSize.height()); 01050 *textBoundingRect = 01051 QStyle::alignedRect(iconDirection(option), alignment, size.toSize(), textRect.toRect()); 01052 01053 // Compute the positions where we should draw the layouts 01054 haloRects.clear(); 01055 labelLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y())); 01056 QTextLine line; 01057 for (int i = 0; i < labelLayout->lineCount(); ++i) { 01058 line = labelLayout->lineAt(i); 01059 haloRects.append(line.naturalTextRect().translated(labelLayout->position().toPoint()).toRect()); 01060 } 01061 infoLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y() + labelSize.height())); 01062 for (int i = 0; i < infoLayout->lineCount(); ++i) { 01063 line = infoLayout->lineAt(i); 01064 haloRects.append(line.naturalTextRect().translated(infoLayout->position().toPoint()).toRect()); 01065 } 01066 //kDebug() << "final position is" << labelLayout->position(); 01067 } 01068 01069 QBrush IconWidgetPrivate::foregroundBrush(const QStyleOptionGraphicsItem *option) const 01070 { 01071 const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ? 01072 QPalette::Normal : QPalette::Disabled; 01073 01074 // Always use the highlight color for selected items 01075 if (option->state & QStyle::State_Selected) { 01076 return option->palette.brush(group, QPalette::HighlightedText); 01077 } 01078 return option->palette.brush(group, QPalette::Text); 01079 } 01080 01081 QBrush IconWidgetPrivate::backgroundBrush(const QStyleOptionGraphicsItem *option) const 01082 { 01083 const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ? 01084 QPalette::Normal : QPalette::Disabled; 01085 01086 QBrush background(Qt::NoBrush); 01087 01088 // Always use the highlight color for selected items 01089 if (option->state & QStyle::State_Selected) { 01090 background = option->palette.brush(group, QPalette::Highlight); 01091 } 01092 return background; 01093 } 01094 01095 void IconWidgetPrivate::drawTextItems(QPainter *painter, 01096 const QStyleOptionGraphicsItem *option, 01097 const QTextLayout &labelLayout, 01098 const QTextLayout &infoLayout) const 01099 { 01100 Q_UNUSED(option) 01101 01102 painter->save(); 01103 painter->setPen(textColor); 01104 01105 // the translation prevents odd rounding errors in labelLayout.position() 01106 // when applied to the canvas 01107 painter->translate(0.5, 0.5); 01108 01109 labelLayout.draw(painter, QPointF()); 01110 01111 if (!infoLayout.text().isEmpty()) { 01112 painter->setPen(textColor); 01113 infoLayout.draw(painter, QPointF()); 01114 } 01115 painter->restore(); 01116 } 01117 01118 void IconWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) 01119 { 01120 Q_UNUSED(widget); 01121 01122 //Lay out the main icon and action icons 01123 d->layoutIcons(option); 01124 01125 // Compute the metrics, and lay out the text items 01126 // ======================================================================== 01127 IconWidgetPrivate::IconWidgetState state = IconWidgetPrivate::NoState; 01128 if (d->states & IconWidgetPrivate::ManualPressedState) { 01129 state = IconWidgetPrivate::PressedState; 01130 } else if (d->states & IconWidgetPrivate::PressedState) { 01131 if (d->states & IconWidgetPrivate::HoverState) { 01132 state = IconWidgetPrivate::PressedState; 01133 } 01134 } else if (d->states & IconWidgetPrivate::HoverState) { 01135 state = IconWidgetPrivate::HoverState; 01136 } 01137 01138 QPixmap icon = d->decoration(option, state != IconWidgetPrivate::NoState, state & IconWidgetPrivate::PressedState); 01139 const QPointF iconPos = d->iconPosition(option, icon); 01140 01141 d->drawBackground(painter, state); 01142 01143 // draw icon 01144 if (!icon.isNull()) { 01145 painter->drawPixmap(iconPos, icon); 01146 } 01147 01148 // Draw corner actions 01149 foreach (const IconAction *action, d->cornerActions) { 01150 if (action->isAnimating()) { 01151 action->paint(painter); 01152 } 01153 } 01154 01155 // Draw text last because it is overlayed 01156 QTextLayout labelLayout, infoLayout; 01157 QRectF textBoundingRect; 01158 01159 d->layoutTextItems(option, icon, &labelLayout, &infoLayout, &textBoundingRect); 01160 01161 if (d->textBgColor != QColor() && d->textBgColor.alpha() > 0 && 01162 !(d->text.isEmpty() && d->infoText.isEmpty()) && 01163 !textBoundingRect.isEmpty() && 01164 !qFuzzyCompare(d->hoverAnimation->value(), (qreal)1.0)) { 01165 QRectF rect = textBoundingRect.adjusted(-2, -2, 4, 4).toAlignedRect(); 01166 painter->setPen(Qt::transparent); 01167 QColor color = d->textBgColor; 01168 color.setAlpha(60 * (1.0 - d->hoverAnimation->value())); 01169 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft()); 01170 gradient.setColorAt(0, color.lighter(120)); 01171 gradient.setColorAt(1, color.darker(120)); 01172 painter->setBrush(gradient); 01173 gradient.setColorAt(0, color.lighter(130)); 01174 gradient.setColorAt(1, color.darker(130)); 01175 painter->setPen(QPen(gradient, 0)); 01176 painter->setRenderHint(QPainter::Antialiasing); 01177 painter->drawPath(PaintUtils::roundedRectangle(rect.translated(0.5, 0.5), 4)); 01178 } 01179 01180 01181 if (d->shadowColor.value() < 128 || textBackgroundColor() != QColor()) { 01182 QPoint shadowPos; 01183 if (d->shadowColor.value() < 128) { 01184 shadowPos = QPoint(1, 2); 01185 } else { 01186 shadowPos = QPoint(0, 0); 01187 } 01188 01189 QImage shadow(textBoundingRect.size().toSize() + QSize(4, 4), 01190 QImage::Format_ARGB32_Premultiplied); 01191 shadow.fill(Qt::transparent); 01192 { 01193 QPainter buffPainter(&shadow); 01194 buffPainter.translate(-textBoundingRect.x(), -textBoundingRect.y()); 01195 d->drawTextItems(&buffPainter, option, labelLayout, infoLayout); 01196 } 01197 01198 PaintUtils::shadowBlur(shadow, 2, d->shadowColor); 01199 painter->drawImage(textBoundingRect.topLeft() + shadowPos, shadow); 01200 } else if (!(d->text.isEmpty() && d->infoText.isEmpty()) && 01201 !textBoundingRect.isEmpty()) { 01202 QRect labelRect = d->labelRectangle(option, icon, d->text).toRect(); 01203 01204 foreach (const QRect &rect, d->haloRects) { 01205 Plasma::PaintUtils::drawHalo(painter, rect); 01206 } 01207 } 01208 01209 d->drawTextItems(painter, option, labelLayout, infoLayout); 01210 } 01211 01212 void IconWidget::setTextBackgroundColor(const QColor &color) 01213 { 01214 d->textBgCustomized = true; 01215 d->textBgColor = color; 01216 update(); 01217 } 01218 01219 QColor IconWidget::textBackgroundColor() const 01220 { 01221 return d->textBgColor; 01222 } 01223 01224 void IconWidget::drawActionButtonBase(QPainter *painter, const QSize &size, int element) 01225 { 01226 qreal radius = size.width() / 2; 01227 QRadialGradient gradient(radius, radius, radius, radius, radius); 01228 int alpha; 01229 01230 if (element == IconWidgetPrivate::MinibuttonPressed) { 01231 alpha = 255; 01232 } else if (element == IconWidgetPrivate::MinibuttonHover) { 01233 alpha = 200; 01234 } else { 01235 alpha = 160; 01236 } 01237 gradient.setColorAt(0, QColor::fromRgb(d->textColor.red(), 01238 d->textColor.green(), 01239 d->textColor.blue(), alpha)); 01240 gradient.setColorAt(1, QColor::fromRgb(d->textColor.red(), 01241 d->textColor.green(), 01242 d->textColor.blue(), 0)); 01243 01244 painter->setBrush(gradient); 01245 painter->setPen(Qt::NoPen); 01246 painter->drawEllipse(QRectF(QPointF(.0, .0), size)); 01247 } 01248 01249 void IconWidget::setText(const QString &text) 01250 { 01251 d->text = KGlobal::locale()->removeAcceleratorMarker(text); 01252 // cause a relayout 01253 d->currentSize = QSizeF(-1, -1); 01254 //try to relayout, needed if an icon was never shown before 01255 if (!isVisible()) { 01256 QStyleOptionGraphicsItem styleoption; 01257 d->layoutIcons(&styleoption); 01258 } 01259 updateGeometry(); 01260 if (!parentWidget() || !parentWidget()->layout()) { 01261 resize(preferredSize()); 01262 } 01263 } 01264 01265 QString IconWidget::text() const 01266 { 01267 return d->text; 01268 } 01269 01270 void IconWidget::setInfoText(const QString &text) 01271 { 01272 d->infoText = text; 01273 // cause a relayout 01274 d->currentSize = QSizeF(-1, -1); 01275 //try to relayout, needed if an icon was never shown before 01276 if (!isVisible()) { 01277 QStyleOptionGraphicsItem styleoption; 01278 d->layoutIcons(&styleoption); 01279 } 01280 updateGeometry(); 01281 if (!parentWidget() || !parentWidget()->layout()) { 01282 resize(preferredSize()); 01283 } 01284 } 01285 01286 QString IconWidget::infoText() const 01287 { 01288 return d->infoText; 01289 } 01290 01291 QIcon IconWidget::icon() const 01292 { 01293 return d->icon; 01294 } 01295 01296 void IconWidget::setIcon(const QString &icon) 01297 { 01298 if (icon.isEmpty()) { 01299 setIcon(QIcon()); 01300 return; 01301 } 01302 01303 setIcon(KIcon(icon)); 01304 } 01305 01306 void IconWidget::setIcon(const QIcon &icon) 01307 { 01308 setSvg(QString()); 01309 01310 /*fade to the new icon, but to not bee a too big hog, not do that when: 01311 - the fade animation is already running 01312 - the icon is under mouse 01313 - one betwen the old and new icon is null*/ 01314 if (!(d->states & IconWidgetPrivate::HoverState) && !d->iconChangeTimer->isActive() && d->oldIcon.isNull() && !d->icon.isNull() && !icon.isNull()) { 01315 d->oldIcon = d->icon; 01316 d->animateMainIcon(true, d->states); 01317 } else { 01318 d->oldIcon = QIcon(); 01319 } 01320 d->iconChangeTimer->start(300); 01321 d->icon = icon; 01322 update(); 01323 } 01324 01325 QSizeF IconWidget::iconSize() const 01326 { 01327 return d->iconSize; 01328 } 01329 01330 void IconWidget::setPreferredIconSize(const QSizeF &size) 01331 { 01332 d->preferredIconSize = size; 01333 updateGeometry(); 01334 } 01335 01336 QSizeF IconWidget::preferredIconSize() const 01337 { 01338 return d->preferredIconSize; 01339 } 01340 01341 void IconWidget::setMinimumIconSize(const QSizeF &size) 01342 { 01343 d->minimumIconSize = size; 01344 updateGeometry(); 01345 } 01346 01347 QSizeF IconWidget::minimumIconSize() const 01348 { 01349 return d->minimumIconSize; 01350 } 01351 01352 void IconWidget::setMaximumIconSize(const QSizeF &size) 01353 { 01354 d->maximumIconSize = size; 01355 updateGeometry(); 01356 } 01357 01358 QSizeF IconWidget::maximumIconSize() const 01359 { 01360 return d->maximumIconSize; 01361 } 01362 01363 bool IconWidget::isDown() 01364 { 01365 return d->states & IconWidgetPrivate::PressedState; 01366 } 01367 01368 void IconWidget::mousePressEvent(QGraphicsSceneMouseEvent *event) 01369 { 01370 if (event->button() != Qt::LeftButton) { 01371 QGraphicsWidget::mousePressEvent(event); 01372 return; 01373 } 01374 01375 if (KGlobalSettings::singleClick() || (receivers(SIGNAL(clicked()))) > 0) { 01376 d->states |= IconWidgetPrivate::PressedState; 01377 } 01378 d->clickStartPos = scenePos(); 01379 01380 bool handled = false; 01381 foreach (IconAction *action, d->cornerActions) { 01382 handled = action->event(event->type(), event->pos()); 01383 if (handled) { 01384 break; 01385 } 01386 } 01387 01388 if (!handled && boundingRect().contains(event->pos())) { 01389 emit pressed(true); 01390 } 01391 01392 update(); 01393 } 01394 01395 void IconWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event) 01396 { 01397 if (~d->states & IconWidgetPrivate::PressedState) { 01398 QGraphicsWidget::mouseMoveEvent(event); 01399 return; 01400 } 01401 01402 if (boundingRect().contains(event->pos())) { 01403 if (~d->states & IconWidgetPrivate::HoverState) { 01404 d->states |= IconWidgetPrivate::HoverState; 01405 update(); 01406 } 01407 } else { 01408 if (d->states & IconWidgetPrivate::HoverState) { 01409 d->states &= ~IconWidgetPrivate::HoverState; 01410 update(); 01411 } 01412 } 01413 } 01414 01415 void IconWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) 01416 { 01417 if (~d->states & IconWidgetPrivate::PressedState) { 01418 QGraphicsWidget::mouseMoveEvent(event); 01419 return; 01420 } 01421 01422 d->states &= ~IconWidgetPrivate::PressedState; 01423 01424 //don't pass click when the mouse was moved 01425 bool handled = d->clickStartPos != scenePos(); 01426 if (!handled) { 01427 foreach (IconAction *action, d->cornerActions) { 01428 if (action->event(event->type(), event->pos())) { 01429 handled = true; 01430 break; 01431 } 01432 } 01433 } 01434 01435 if (!handled) { 01436 if (boundingRect().contains(event->pos())) { 01437 emit clicked(); 01438 if (KGlobalSettings::singleClick()) { 01439 emit activated(); 01440 } 01441 01442 if (d->action && d->action->menu()) { 01443 d->action->menu()->popup(event->screenPos()); 01444 } 01445 } 01446 emit pressed(false); 01447 } 01448 01449 update(); 01450 } 01451 01452 void IconWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) 01453 { 01454 Q_UNUSED(event) 01455 01456 d->states |= IconWidgetPrivate::PressedState; 01457 01458 emit doubleClicked(); 01459 if (!KGlobalSettings::singleClick()) { 01460 emit activated(); 01461 } 01462 01463 update(); 01464 } 01465 01466 void IconWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event) 01467 { 01468 //kDebug(); 01469 foreach (IconAction *action, d->cornerActions) { 01470 action->show(); 01471 action->event(event->type(), event->pos()); 01472 } 01473 01474 d->oldIcon = QIcon(); 01475 d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState); 01476 01477 QGraphicsWidget::hoverEnterEvent(event); 01478 } 01479 01480 void IconWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) 01481 { 01482 //kDebug() << d->cornerActions; 01483 foreach (IconAction *action, d->cornerActions) { 01484 action->hide(); 01485 action->event(event->type(), event->pos()); 01486 } 01487 // d->states &= ~IconWidgetPrivate::HoverState; // Will be set once progress is zero again ... 01488 //if an eventfilter stolen the mousereleaseevent remove the pressed state here 01489 d->states &= ~IconWidgetPrivate::PressedState; 01490 01491 d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState); 01492 01493 QGraphicsWidget::hoverLeaveEvent(event); 01494 } 01495 01496 bool IconWidget::sceneEventFilter(QGraphicsItem *watched, QEvent *event) 01497 { 01498 Q_UNUSED(watched) 01499 01500 if (event->type() == QEvent::GraphicsSceneDragEnter) { 01501 d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState); 01502 } else if (event->type() == QEvent::GraphicsSceneDragLeave) { 01503 d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState); 01504 } 01505 01506 return false; 01507 } 01508 01509 void IconWidget::setPressed(bool pressed) 01510 { 01511 if (pressed) { 01512 d->states |= IconWidgetPrivate::ManualPressedState; 01513 d->states |= IconWidgetPrivate::PressedState; 01514 } else { 01515 d->states &= ~IconWidgetPrivate::ManualPressedState; 01516 d->states &= ~IconWidgetPrivate::PressedState; 01517 } 01518 update(); 01519 } 01520 01521 void IconWidget::setUnpressed() 01522 { 01523 setPressed(false); 01524 } 01525 01526 void IconWidgetPrivate::svgChanged() 01527 { 01528 iconSvgElementChanged = true; 01529 q->update(); 01530 } 01531 01532 void IconWidget::setOrientation(Qt::Orientation orientation) 01533 { 01534 d->orientation = orientation; 01535 resize(sizeFromIconSize(d->iconSize.width())); 01536 } 01537 01538 Qt::Orientation IconWidget::orientation() const 01539 { 01540 return d->orientation; 01541 } 01542 01543 void IconWidget::invertLayout(bool invert) 01544 { 01545 d->invertLayout = invert; 01546 } 01547 01548 bool IconWidget::invertedLayout() const 01549 { 01550 return d->invertLayout; 01551 } 01552 01553 QSizeF IconWidget::sizeFromIconSize(const qreal iconWidth) const 01554 { 01555 d->setActiveMargins(); 01556 if (d->text.isEmpty() && d->infoText.isEmpty()) { 01557 //no text, just the icon size 01558 return d->addMargin(QSizeF(iconWidth, iconWidth), IconWidgetPrivate::ItemMargin); 01559 } 01560 01561 QFontMetricsF fm(font()); 01562 qreal width = 0; 01563 01564 if (d->orientation == Qt::Vertical) { 01565 width = qMax(d->maxWordWidth(d->text), 01566 d->maxWordWidth(d->infoText)) + 01567 fm.width("xxx") + 01568 d->verticalMargin[IconWidgetPrivate::TextMargin].left + 01569 d->verticalMargin[IconWidgetPrivate::TextMargin].right; 01570 01571 width = qMax(width, 01572 iconWidth + 01573 d->verticalMargin[IconWidgetPrivate::IconMargin].left + 01574 d->verticalMargin[IconWidgetPrivate::IconMargin].right); 01575 } else { 01576 width = iconWidth + 01577 d->horizontalMargin[IconWidgetPrivate::IconMargin].left + 01578 d->horizontalMargin[IconWidgetPrivate::IconMargin].right + 01579 qMax(fm.width(d->text), fm.width(d->infoText)) + fm.width("xxx") + 01580 d->horizontalMargin[IconWidgetPrivate::TextMargin].left + 01581 d->horizontalMargin[IconWidgetPrivate::TextMargin].right; 01582 } 01583 01584 qreal height; 01585 qreal textHeight; 01586 01587 QStyleOptionGraphicsItem option; 01588 option.state = QStyle::State_None; 01589 option.rect = QRect(0, 0, width, QWIDGETSIZE_MAX); 01590 textHeight = d->displaySizeHint(&option, width).height(); 01591 01592 if (d->orientation == Qt::Vertical) { 01593 height = iconWidth + textHeight + 01594 d->verticalMargin[IconWidgetPrivate::TextMargin].top + 01595 d->verticalMargin[IconWidgetPrivate::TextMargin].bottom + 01596 d->verticalMargin[IconWidgetPrivate::IconMargin].top + 01597 d->verticalMargin[IconWidgetPrivate::IconMargin].bottom; 01598 } else { 01599 //Horizontal 01600 height = qMax(iconWidth + 01601 d->verticalMargin[IconWidgetPrivate::IconMargin].top + 01602 d->verticalMargin[IconWidgetPrivate::IconMargin].bottom, 01603 textHeight + 01604 d->verticalMargin[IconWidgetPrivate::TextMargin].top + 01605 d->verticalMargin[IconWidgetPrivate::TextMargin].bottom); 01606 } 01607 01608 return d->addMargin(QSizeF(width, height), IconWidgetPrivate::ItemMargin); 01609 } 01610 01611 void IconWidget::changeEvent(QEvent *event) 01612 { 01613 d->changeEvent(event); 01614 QGraphicsWidget::changeEvent(event); 01615 } 01616 01617 } // namespace Plasma 01618 01619 #include "iconwidget.moc" 01620 #include "iconwidget_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Wed May 2 2012 17:36:10 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Wed May 2 2012 17:36:10 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.