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