00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "iconwidget.h"
00026 #include "iconwidget_p.h"
00027
00028 #include <QAction>
00029 #include <QApplication>
00030 #include <QPainter>
00031 #include <QGraphicsSceneMouseEvent>
00032 #include <QGraphicsView>
00033 #include <QStyleOptionGraphicsItem>
00034 #include <QTextLayout>
00035
00036 #include <kglobalsettings.h>
00037 #include <kiconeffect.h>
00038 #include <kiconloader.h>
00039 #include <kicon.h>
00040 #include <kurl.h>
00041 #include <krun.h>
00042 #include <kmimetype.h>
00043 #include <kdebug.h>
00044 #include <kcolorscheme.h>
00045
00046 #include <plasma/paintutils.h>
00047 #include <plasma/theme.h>
00048
00049 #include "animator.h"
00050 #include "svg.h"
00051
00052
00053
00054
00055
00056
00057
00058
00059 namespace Plasma
00060 {
00061
00062 IconWidgetPrivate::IconWidgetPrivate(IconWidget *i)
00063 : ActionWidgetInterface<IconWidget>(i),
00064 q(i),
00065 iconSvg(0),
00066 hoverAnimId(-1),
00067 hoverAlpha(20 / 255),
00068 iconSize(48, 48),
00069 states(IconWidgetPrivate::NoState),
00070 orientation(Qt::Vertical),
00071 numDisplayLines(2),
00072 activeMargins(0),
00073 iconSvgElementChanged(false),
00074 fadeIn(false),
00075 invertLayout(false),
00076 drawBg(false),
00077 textBgCustomized(false)
00078 {
00079 }
00080
00081 IconWidgetPrivate::~IconWidgetPrivate()
00082 {
00083 qDeleteAll(cornerActions);
00084 }
00085
00086 void IconWidgetPrivate::readColors()
00087 {
00088 textColor = Plasma::Theme::defaultTheme()->color(Theme::TextColor);
00089
00090 if (qGray(textColor.rgb()) > 192) {
00091 shadowColor = Qt::black;
00092 } else {
00093 shadowColor = Qt::white;
00094 }
00095
00096 if (!textBgCustomized) {
00097 textBgColor = Theme::defaultTheme()->color(Theme::HighlightColor);
00098 }
00099 }
00100
00101 void IconWidgetPrivate::colorConfigChanged()
00102 {
00103 readColors();
00104 q->update();
00105 }
00106
00107 void IconWidgetPrivate::iconConfigChanged()
00108 {
00109 if (!icon.isNull()) {
00110 q->update();
00111 }
00112 }
00113
00114 IconAction::IconAction(IconWidget *icon, QAction *action)
00115 : m_icon(icon),
00116 m_action(action),
00117 m_hovered(false),
00118 m_pressed(false),
00119 m_selected(false),
00120 m_visible(false),
00121 m_animationId(-1)
00122 {
00123 }
00124
00125 void IconAction::show()
00126 {
00127 if (m_animationId) {
00128 Animator::self()->stopElementAnimation(m_animationId);
00129 }
00130
00131 rebuildPixmap();
00132
00133 m_animationId = Animator::self()->animateElement(m_icon, Animator::AppearAnimation);
00134 Animator::self()->setInitialPixmap(m_animationId, m_pixmap);
00135 m_visible = true;
00136 }
00137
00138 void IconAction::hide()
00139 {
00140 if (m_animationId) {
00141 Animator::self()->stopElementAnimation(m_animationId);
00142 }
00143
00144 rebuildPixmap();
00145
00146 m_animationId = Animator::self()->animateElement(m_icon, Animator::DisappearAnimation);
00147 Animator::self()->setInitialPixmap(m_animationId, m_pixmap);
00148 m_visible = false;
00149 }
00150
00151 bool IconAction::isVisible() const
00152 {
00153 return m_visible;
00154 }
00155
00156 bool IconAction::isPressed() const
00157 {
00158 return m_pressed;
00159 }
00160
00161 bool IconAction::isHovered() const
00162 {
00163 return m_hovered;
00164 }
00165
00166 void IconAction::setSelected(bool selected)
00167 {
00168 m_selected = selected;
00169 }
00170
00171 bool IconAction::isSelected() const
00172 {
00173 return m_selected;
00174 }
00175
00176 void IconAction::setRect(const QRectF &rect)
00177 {
00178 m_rect = rect;
00179 }
00180
00181 QRectF IconAction::rect() const
00182 {
00183 return m_rect;
00184 }
00185
00186 void IconAction::rebuildPixmap()
00187 {
00188
00189 QIcon::Mode mode = QIcon::Normal;
00190 if (m_selected) {
00191 mode = QIcon::Selected;
00192 }
00193
00194
00195 m_pixmap = QPixmap(26, 26);
00196 m_pixmap.fill(Qt::transparent);
00197
00198 int element = IconWidgetPrivate::Minibutton;
00199 if (m_pressed) {
00200 element = IconWidgetPrivate::MinibuttonPressed;
00201 } else if (m_hovered) {
00202 element = IconWidgetPrivate::MinibuttonHover;
00203 }
00204
00205 QPainter painter(&m_pixmap);
00206 m_icon->drawActionButtonBase(&painter, m_pixmap.size(), element);
00207 m_action->icon().paint(&painter, 2, 2, 22, 22, Qt::AlignCenter, mode);
00208 }
00209
00210 bool IconAction::event(QEvent::Type type, const QPointF &pos)
00211 {
00212 if (m_icon->size().width() < m_rect.width() * 2.0 ||
00213 m_icon->size().height() < m_rect.height() * 2.0) {
00214 return false;
00215 }
00216
00217 switch (type) {
00218 case QEvent::GraphicsSceneMousePress:
00219 {
00220 setSelected(m_rect.contains(pos));
00221 return isSelected();
00222 }
00223 break;
00224
00225 case QEvent::GraphicsSceneMouseMove:
00226 {
00227 bool wasSelected = isSelected();
00228 bool active = m_rect.contains(pos);
00229 setSelected(wasSelected && active);
00230 return (wasSelected != isSelected()) || active;
00231 }
00232 break;
00233
00234 case QEvent::GraphicsSceneMouseRelease:
00235 {
00236
00237 bool wasSelected = isSelected();
00238 setSelected(false);
00239 if (wasSelected) {
00240 m_action->trigger();
00241 }
00242
00243 return wasSelected;
00244 }
00245 break;
00246
00247 case QEvent::GraphicsSceneHoverEnter:
00248 m_pressed = false;
00249 m_hovered = true;
00250 break;
00251
00252 case QEvent::GraphicsSceneHoverLeave:
00253 m_pressed = false;
00254 m_hovered = false;
00255 break;
00256
00257 default:
00258 break;
00259 }
00260
00261 return false;
00262 }
00263
00264 int IconAction::animationId() const
00265 {
00266 return m_animationId;
00267 }
00268
00269 QAction *IconAction::action() const
00270 {
00271 return m_action;
00272 }
00273
00274 void IconAction::paint(QPainter *painter) const
00275 {
00276 if (m_icon->size().width() < m_rect.width() * 2.0 ||
00277 m_icon->size().height() < m_rect.height() * 2.0) {
00278 return;
00279 }
00280
00281 QPixmap animPixmap = Animator::self()->currentPixmap(m_animationId);
00282
00283 if (m_visible && animPixmap.isNull()) {
00284 painter->drawPixmap(m_rect.toRect(), m_pixmap);
00285 } else {
00286 painter->drawPixmap(m_rect.toRect(), animPixmap);
00287 }
00288 }
00289
00290 IconWidget::IconWidget(QGraphicsItem *parent)
00291 : QGraphicsWidget(parent),
00292 d(new IconWidgetPrivate(this))
00293 {
00294 d->init();
00295 }
00296
00297 IconWidget::IconWidget(const QString &text, QGraphicsItem *parent)
00298 : QGraphicsWidget(parent),
00299 d(new IconWidgetPrivate(this))
00300 {
00301 d->init();
00302 setText(text);
00303 }
00304
00305 IconWidget::IconWidget(const QIcon &icon, const QString &text, QGraphicsItem *parent)
00306 : QGraphicsWidget(parent),
00307 d(new IconWidgetPrivate(this))
00308 {
00309 d->init();
00310 setText(text);
00311 setIcon(icon);
00312 }
00313
00314 IconWidget::~IconWidget()
00315 {
00316 delete d;
00317 }
00318
00319 void IconWidgetPrivate::init()
00320 {
00321 readColors();
00322 QObject::connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), q, SLOT(colorConfigChanged()));
00323 QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorConfigChanged()));
00324 QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), q, SLOT(iconConfigChanged()));
00325
00326
00327 q->setAcceptsHoverEvents(true);
00328
00329
00330 setHorizontalMargin(IconWidgetPrivate::TextMargin, 1, 1);
00331 setHorizontalMargin(IconWidgetPrivate::IconMargin, 1, 1);
00332 setHorizontalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
00333
00334
00335 setVerticalMargin(IconWidgetPrivate::TextMargin, 6, 2);
00336 setVerticalMargin(IconWidgetPrivate::IconMargin, 1, 1);
00337 setVerticalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
00338
00339 setActiveMargins();
00340 currentSize = QSizeF(-1, -1);
00341
00342 background = new Plasma::FrameSvg(q);
00343 background->setImagePath("widgets/viewitem");
00344 background->setCacheAllRenderedFrames(true);
00345 }
00346
00347 void IconWidget::addIconAction(QAction *action)
00348 {
00349 int count = d->cornerActions.count();
00350 if (count >= IconWidgetPrivate::LastIconPosition) {
00351 kDebug() << "no more room for more actions!";
00352
00353 }
00354
00355 IconAction *iconAction = new IconAction(this, action);
00356 d->cornerActions.append(iconAction);
00357 connect(action, SIGNAL(destroyed(QObject*)), this, SLOT(actionDestroyed(QObject*)));
00358
00359 iconAction->setRect(d->actionRect(qMin((IconWidgetPrivate::ActionPosition)count, IconWidgetPrivate::LastIconPosition)));
00360 }
00361
00362 void IconWidget::removeIconAction(QAction *action)
00363 {
00364
00365
00366 int count = 0;
00367 bool found = false;
00368 foreach (IconAction *iconAction, d->cornerActions) {
00369 if (found) {
00370 iconAction->setRect(d->actionRect((IconWidgetPrivate::ActionPosition)count));
00371 } else if (iconAction->action() == action) {
00372 delete iconAction;
00373 d->cornerActions.removeAll(iconAction);
00374 }
00375
00376 if (count < IconWidgetPrivate::LastIconPosition) {
00377 ++count;
00378 }
00379 }
00380
00381
00382 update();
00383 }
00384
00385 void IconWidgetPrivate::actionDestroyed(QObject *action)
00386 {
00387 q->removeIconAction(static_cast<QAction*>(action));
00388 }
00389
00390 void IconWidget::setAction(QAction *action)
00391 {
00392 d->setAction(action);
00393 }
00394
00395 QAction *IconWidget::action() const
00396 {
00397 return d->action;
00398 }
00399
00400 int IconWidget::numDisplayLines()
00401 {
00402 return d->numDisplayLines;
00403 }
00404
00405 void IconWidget::setNumDisplayLines(int numLines)
00406 {
00407 if (numLines > d->maxDisplayLines) {
00408 d->numDisplayLines = d->maxDisplayLines;
00409 } else {
00410 d->numDisplayLines = numLines;
00411 }
00412 }
00413
00414 void IconWidget::setDrawBackground(bool draw)
00415 {
00416 if (d->drawBg != draw) {
00417 d->drawBg = draw;
00418
00419 QStyle *style = QApplication::style();
00420 int focusHMargin = draw ? style->pixelMetric(QStyle::PM_FocusFrameHMargin) : 1;
00421 int focusVMargin = draw ? style->pixelMetric(QStyle::PM_FocusFrameVMargin) : 1;
00422 d->setHorizontalMargin(IconWidgetPrivate::TextMargin, focusHMargin, focusVMargin);
00423 d->setHorizontalMargin(IconWidgetPrivate::IconMargin, focusHMargin, focusVMargin);
00424 d->setVerticalMargin(IconWidgetPrivate::IconMargin, focusHMargin, focusVMargin);
00425 d->currentSize = QSizeF(-1, -1);
00426
00427 update();
00428 }
00429 }
00430
00431 bool IconWidget::drawBackground() const
00432 {
00433 return d->drawBg;
00434 }
00435
00436 QPainterPath IconWidget::shape() const
00437 {
00438 if (!d->drawBg || d->currentSize.width() < 1) {
00439 return QGraphicsItem::shape();
00440 }
00441
00442 return PaintUtils::roundedRectangle(
00443 QRectF(QPointF(0.0, 0.0), d->currentSize).adjusted(-2, -2, 2, 2), 10.0);
00444 }
00445
00446 QSizeF IconWidgetPrivate::displaySizeHint(const QStyleOptionGraphicsItem *option, const qreal width) const
00447 {
00448 if (text.isEmpty() && infoText.isEmpty()) {
00449 return QSizeF(.0, .0);
00450 }
00451
00452 QString label = text;
00453
00454
00455
00456
00457 qreal textWidth = width -
00458 horizontalMargin[IconWidgetPrivate::TextMargin].left -
00459 horizontalMargin[IconWidgetPrivate::TextMargin].right;
00460
00461
00462 const qreal maxHeight =
00463 numDisplayLines * Plasma::Theme::defaultTheme()->fontMetrics().lineSpacing();
00464
00465
00466
00467 if (!infoText.isEmpty()) {
00468 label += QString(QChar::LineSeparator) + infoText;
00469 }
00470
00471 QTextLayout layout;
00472 setLayoutOptions(layout, option, q->orientation());
00473 QSizeF size = layoutText(layout, option, label, QSizeF(textWidth, maxHeight));
00474
00475 return addMargin(size, TextMargin);
00476 }
00477
00478 void IconWidgetPrivate::layoutIcons(const QStyleOptionGraphicsItem *option)
00479 {
00480 if (q->size() == currentSize) {
00481 return;
00482 }
00483
00484 currentSize = q->size();
00485 setActiveMargins();
00486
00487
00488 qreal iconWidth;
00489
00490 if (orientation == Qt::Vertical) {
00491 qreal heightAvail;
00492
00493 if (text.isEmpty() && infoText.isEmpty()) {
00494 heightAvail = currentSize.height();
00495 } else {
00496 heightAvail = currentSize.height() -
00497 displaySizeHint(option, currentSize.width()).height() -
00498 verticalMargin[IconWidgetPrivate::TextMargin].top -
00499 verticalMargin[IconWidgetPrivate::TextMargin].bottom;
00500
00501 heightAvail = qMax(heightAvail, currentSize.height() / 2);
00502 }
00503
00504
00505 if (currentSize.width() < heightAvail) {
00506 iconWidth = currentSize.width() -
00507 horizontalMargin[IconWidgetPrivate::IconMargin].left -
00508 horizontalMargin[IconWidgetPrivate::IconMargin].right;
00509 } else {
00510 iconWidth = heightAvail -
00511 verticalMargin[IconWidgetPrivate::IconMargin].top -
00512 verticalMargin[IconWidgetPrivate::IconMargin].bottom;
00513 }
00514 } else {
00515
00516 QFontMetricsF fm(q->font());
00517
00518
00519 if (text.isEmpty() && infoText.isEmpty()) {
00520
00521 iconWidth = currentSize.height() -
00522 horizontalMargin[IconWidgetPrivate::IconMargin].left -
00523 horizontalMargin[IconWidgetPrivate::IconMargin].right;
00524 } else {
00525 iconWidth = currentSize.height() -
00526 verticalMargin[IconWidgetPrivate::IconMargin].top -
00527 verticalMargin[IconWidgetPrivate::IconMargin].bottom;
00528 }
00529 }
00530
00531 iconSize = QSizeF(iconWidth, iconWidth);
00532
00533 int count = 0;
00534 foreach (IconAction *iconAction, cornerActions) {
00535 iconAction->setRect(actionRect((IconWidgetPrivate::ActionPosition)count));
00536 ++count;
00537 }
00538 }
00539
00540 void IconWidget::setSvg(const QString &svgFilePath, const QString &elementId)
00541 {
00542 if (!d->iconSvg) {
00543 d->iconSvg = new Plasma::Svg(this);
00544 connect(d->iconSvg, SIGNAL(repaintNeeded()), this, SLOT(svgChanged()));
00545 }
00546
00547 d->iconSvg->setImagePath(svgFilePath);
00548 d->iconSvg->setContainsMultipleImages(!elementId.isNull());
00549 d->iconSvgElement = elementId;
00550 d->iconSvgElementChanged = true;
00551 d->icon = QIcon();
00552 update();
00553 }
00554
00555 QString IconWidget::svg() const
00556 {
00557 if (d->iconSvg) {
00558 return d->iconSvg->imagePath();
00559 }
00560
00561 return QString();
00562 }
00563
00564 void IconWidgetPrivate::hoverEffect(bool show)
00565 {
00566 if (show) {
00567 states |= IconWidgetPrivate::HoverState;
00568 }
00569
00570 fadeIn = show;
00571 const int FadeInDuration = 150;
00572
00573 if (hoverAnimId != -1) {
00574 Animator::self()->stopCustomAnimation(hoverAnimId);
00575 }
00576
00577 hoverAnimId = Animator::self()->customAnimation(
00578 40 / (1000 / FadeInDuration), FadeInDuration,
00579 Animator::EaseOutCurve, q, "hoverAnimationUpdate");
00580 }
00581
00582 void IconWidgetPrivate::hoverAnimationUpdate(qreal progress)
00583 {
00584 if (fadeIn) {
00585 hoverAlpha = progress;
00586 } else {
00587
00588
00589 hoverAlpha = qMin(1 - progress, hoverAlpha);
00590 }
00591
00592 if (qFuzzyCompare(qreal(1.0), progress)) {
00593 hoverAnimId = -1;
00594
00595 if (!fadeIn) {
00596 states &= ~IconWidgetPrivate::HoverState;
00597 }
00598 }
00599
00600 q->update();
00601 }
00602
00603 void IconWidgetPrivate::drawBackground(QPainter *painter, IconWidgetState state)
00604 {
00605 if (!drawBg) {
00606 return;
00607 }
00608
00609 if (state == IconWidgetPrivate::PressedState) {
00610 background->setElementPrefix("selected");
00611 } else {
00612 background->setElementPrefix("hover");
00613 }
00614
00615 if (qFuzzyCompare(hoverAlpha, 1)) {
00616 background->resizeFrame(currentSize);
00617 background->paintFrame(painter);
00618 } else if (!qFuzzyCompare(hoverAlpha+1, 1)) {
00619 background->resizeFrame(currentSize);
00620 QPixmap frame = background->framePixmap();
00621 QPainter bufferPainter(&frame);
00622 bufferPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00623 bufferPainter.fillRect(frame.rect(), QColor(0,0,0, 255*hoverAlpha));
00624 bufferPainter.end();
00625 painter->drawPixmap(QPoint(0,0), frame);
00626 }
00627 }
00628
00629 QPixmap IconWidgetPrivate::decoration(const QStyleOptionGraphicsItem *option, bool useHoverEffect, bool usePressedEffect)
00630 {
00631 QPixmap result;
00632
00633 QIcon::Mode mode = option->state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled;
00634 QIcon::State state = option->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
00635
00636 if (iconSvg) {
00637 if (iconSvgElementChanged || iconSvgPixmap.size() != iconSize.toSize()) {
00638 QImage img(iconSize.toSize(), QImage::Format_ARGB32_Premultiplied);
00639 {
00640 img.fill(0);
00641 QPainter p(&img);
00642 iconSvg->resize(iconSize);
00643 iconSvg->paint(&p, img.rect(), iconSvgElement);
00644 }
00645 iconSvgPixmap = QPixmap::fromImage(img);
00646 iconSvgElementChanged = false;
00647 }
00648 result = iconSvgPixmap;
00649 } else {
00650 const QSize size = icon.actualSize(iconSize.toSize(), mode, state);
00651 result = icon.pixmap(size, mode, state);
00652 }
00653
00654 if (usePressedEffect) {
00655 result = result.scaled(result.size() * 0.9, Qt::KeepAspectRatio);
00656 }
00657
00658
00659 if (!result.isNull() && useHoverEffect) {
00660 KIconEffect *effect = KIconLoader::global()->iconEffect();
00661
00662
00663
00664 if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
00665 if (qFuzzyCompare(qreal(1.0), hoverAlpha)) {
00666 result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState);
00667 } else {
00668 result = PaintUtils::transition(
00669 result,
00670 effect->apply(result, KIconLoader::Desktop,
00671 KIconLoader::ActiveState), hoverAlpha);
00672 }
00673 }
00674 }
00675
00676 return result;
00677 }
00678
00679 QPointF IconWidgetPrivate::iconPosition(const QStyleOptionGraphicsItem *option,
00680 const QPixmap &pixmap) const
00681 {
00682 const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
00683
00684
00685 const QSizeF size = addMargin(iconSize, IconWidgetPrivate::IconMargin);
00686
00687 Qt::LayoutDirection direction = iconDirection(option);
00688
00689
00690 Qt::Alignment alignment;
00691 if (text.isEmpty() && infoText.isEmpty()) {
00692 alignment = Qt::AlignCenter;
00693 } else if (orientation == Qt::Vertical) {
00694 alignment = Qt::Alignment(Qt::AlignHCenter | Qt::AlignTop);
00695
00696 } else {
00697 alignment = QStyle::visualAlignment(
00698 direction, Qt::Alignment(Qt::AlignLeft | Qt::AlignVCenter));
00699 }
00700
00701 const QRect iconRect =
00702 QStyle::alignedRect(direction, alignment, size.toSize(), itemRect.toRect());
00703
00704
00705 QRect pixmapRect = pixmap.rect();
00706 pixmapRect.moveCenter(iconRect.center());
00707
00708
00709
00710
00711 return QPointF(pixmapRect.topLeft());
00712 }
00713
00714 QRectF IconWidgetPrivate::labelRectangle(const QStyleOptionGraphicsItem *option,
00715 const QPixmap &icon,
00716 const QString &string) const
00717 {
00718 Q_UNUSED(string)
00719
00720 if (icon.isNull()) {
00721 return option->rect;
00722 }
00723
00724 const QSizeF decoSize = addMargin(iconSize, IconWidgetPrivate::IconMargin);
00725 const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
00726 QRectF textArea(QPointF(0, 0), itemRect.size());
00727
00728 if (orientation == Qt::Vertical) {
00729 textArea.setTop(decoSize.height() + 1);
00730 } else {
00731
00732 textArea.setLeft(decoSize.width() + 1);
00733 }
00734
00735 textArea.translate(itemRect.topLeft());
00736 return QRectF(QStyle::visualRect(iconDirection(option), option->rect, textArea.toRect()));
00737 }
00738
00739
00740 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout, const QStyleOptionGraphicsItem *option,
00741 const QString &text, const QSizeF &constraints) const
00742 {
00743 const QSizeF size = layoutText(layout, text, constraints.width());
00744
00745 if (size.width() > constraints.width() || size.height() > constraints.height()) {
00746 if (action) {
00747 q->setToolTip(action->text());
00748 }
00749 const QString elided = elidedText(layout, option, constraints);
00750 return layoutText(layout, elided, constraints.width());
00751 }
00752 q->setToolTip(QString());
00753
00754 return size;
00755 }
00756
00757
00758 QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout, const QString &text, qreal maxWidth) const
00759 {
00760 QFontMetricsF metrics(layout.font());
00761 qreal leading = metrics.leading();
00762 qreal height = 0.0;
00763 qreal widthUsed = 0.0;
00764 QTextLine line;
00765
00766 layout.setText(text);
00767
00768 layout.beginLayout();
00769
00770 while ((line = layout.createLine()).isValid()) {
00771 line.setLineWidth(maxWidth);
00772 height += leading;
00773 line.setPosition(QPointF(0.0, height));
00774 height += line.height();
00775 widthUsed = qMax(widthUsed, line.naturalTextWidth());
00776 }
00777 layout.endLayout();
00778
00779 return QSizeF(widthUsed, height);
00780 }
00781
00782
00783
00784
00785
00786 QString IconWidgetPrivate::elidedText(QTextLayout &layout, const QStyleOptionGraphicsItem *option,
00787 const QSizeF &size) const
00788 {
00789 Q_UNUSED(option)
00790
00791 QFontMetricsF metrics(layout.font());
00792 const QString text = layout.text();
00793 qreal maxWidth = size.width();
00794 qreal maxHeight = size.height();
00795 qreal height = 0;
00796
00797
00798 QString elided;
00799 elided.reserve(text.length());
00800
00801 for (int i = 0; i < layout.lineCount(); i++) {
00802 QTextLine line = layout.lineAt(i);
00803 int start = line.textStart();
00804 int length = line.textLength();
00805
00806 height += metrics.leading();
00807 if (height + line.height() + metrics.lineSpacing() > maxHeight) {
00808
00809
00810
00811 if (line.naturalTextWidth() < maxWidth &&
00812 start + length > 0 &&
00813 text[start + length - 1] == QChar::LineSeparator) {
00814 elided += text.mid(start, length - 1);
00815 } else {
00816 elided += metrics.elidedText(text.mid(start), Qt::ElideRight, maxWidth);
00817 }
00818 break;
00819 } else if (line.naturalTextWidth() > maxWidth) {
00820 elided += metrics.elidedText(text.mid(start, length), Qt::ElideRight, maxWidth);
00821 } else {
00822 elided += text.mid(start, length);
00823 }
00824
00825 height += line.height();
00826 }
00827
00828 return elided;
00829 }
00830
00831 void IconWidgetPrivate::layoutTextItems(const QStyleOptionGraphicsItem *option,
00832 const QPixmap &icon, QTextLayout *labelLayout,
00833 QTextLayout *infoLayout, QRectF *textBoundingRect) const
00834 {
00835 bool showInformation = false;
00836
00837 setLayoutOptions(*labelLayout, option, q->orientation());
00838
00839 QFontMetricsF fm(labelLayout->font());
00840 const QRectF textArea = labelRectangle(option, icon, text);
00841 QRectF textRect = subtractMargin(textArea, IconWidgetPrivate::TextMargin);
00842
00843
00844
00845 QSizeF maxLabelSize = textRect.size();
00846 QSizeF maxInfoSize = textRect.size();
00847 QSizeF labelSize;
00848 QSizeF infoSize;
00849
00850
00851
00852 if (!infoText.isEmpty() && textRect.height() >= fm.lineSpacing() * 2) {
00853 infoLayout->setFont(labelLayout->font());
00854 infoLayout->setTextOption(labelLayout->textOption());
00855
00856 maxLabelSize.rheight() -= fm.lineSpacing();
00857 showInformation = true;
00858 }
00859
00860
00861 labelSize = layoutText(*labelLayout, option, text, maxLabelSize);
00862 maxInfoSize.rheight() -= labelSize.height();
00863
00864
00865 if (showInformation) {
00866 infoSize = layoutText(*infoLayout, option, infoText, maxInfoSize);
00867 } else {
00868 infoSize = QSizeF(0, 0);
00869 }
00870
00871 const Qt::Alignment alignment = labelLayout->textOption().alignment();
00872 const QSizeF size(qMax(labelSize.width(), infoSize.width()),
00873 labelSize.height() + infoSize.height());
00874 *textBoundingRect =
00875 QStyle::alignedRect(iconDirection(option), alignment, size.toSize(), textRect.toRect());
00876
00877
00878 labelLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y()));
00879 infoLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y() + labelSize.height()));
00880
00881 }
00882
00883 QBrush IconWidgetPrivate::foregroundBrush(const QStyleOptionGraphicsItem *option) const
00884 {
00885 const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
00886 QPalette::Normal : QPalette::Disabled;
00887
00888
00889 if (option->state & QStyle::State_Selected) {
00890 return option->palette.brush(group, QPalette::HighlightedText);
00891 }
00892 return option->palette.brush(group, QPalette::Text);
00893 }
00894
00895 QBrush IconWidgetPrivate::backgroundBrush(const QStyleOptionGraphicsItem *option) const
00896 {
00897 const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
00898 QPalette::Normal : QPalette::Disabled;
00899
00900 QBrush background(Qt::NoBrush);
00901
00902
00903 if (option->state & QStyle::State_Selected) {
00904 background = option->palette.brush(group, QPalette::Highlight);
00905 }
00906 return background;
00907 }
00908
00909 void IconWidgetPrivate::drawTextItems(QPainter *painter,
00910 const QStyleOptionGraphicsItem *option,
00911 const QTextLayout &labelLayout,
00912 const QTextLayout &infoLayout) const
00913 {
00914 Q_UNUSED(option)
00915
00916 painter->save();
00917 painter->setPen(textColor);
00918
00919
00920
00921 painter->translate(0.5, 0.5);
00922
00923 labelLayout.draw(painter, QPointF());
00924
00925 if (!infoLayout.text().isEmpty()) {
00926 painter->setPen(textColor);
00927 infoLayout.draw(painter, QPointF());
00928 }
00929 painter->restore();
00930 }
00931
00932 void IconWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
00933 {
00934 Q_UNUSED(widget);
00935
00936
00937 d->layoutIcons(option);
00938
00939
00940
00941 IconWidgetPrivate::IconWidgetState state = IconWidgetPrivate::NoState;
00942 if (d->states & IconWidgetPrivate::ManualPressedState) {
00943 state = IconWidgetPrivate::PressedState;
00944 } else if (d->states & IconWidgetPrivate::PressedState) {
00945 if (d->states & IconWidgetPrivate::HoverState) {
00946 state = IconWidgetPrivate::PressedState;
00947 }
00948 } else if (d->states & IconWidgetPrivate::HoverState) {
00949 state = IconWidgetPrivate::HoverState;
00950 }
00951
00952 QPixmap icon = d->decoration(option, state != IconWidgetPrivate::NoState, state & IconWidgetPrivate::PressedState);
00953 const QPointF iconPos = d->iconPosition(option, icon);
00954
00955 d->drawBackground(painter, state);
00956
00957
00958 if (!icon.isNull()) {
00959 painter->drawPixmap(iconPos, icon);
00960 }
00961
00962
00963 foreach (const IconAction *action, d->cornerActions) {
00964 if (action->animationId()) {
00965 action->paint(painter);
00966 }
00967 }
00968
00969
00970 QTextLayout labelLayout, infoLayout;
00971 QRectF textBoundingRect;
00972
00973
00974 d->layoutTextItems(option, icon, &labelLayout, &infoLayout, &textBoundingRect);
00975
00976 QImage shadow(textBoundingRect.size().toSize() + QSize(4, 4),
00977 QImage::Format_ARGB32_Premultiplied);
00978 shadow.fill(Qt::transparent);
00979 {
00980 QPainter buffPainter(&shadow);
00981 buffPainter.translate(-textBoundingRect.x(), -textBoundingRect.y());
00982 d->drawTextItems(&buffPainter, option, labelLayout, infoLayout);
00983 }
00984
00985 QPoint shadowOffset = QPoint(1, 2);
00986 if (d->shadowColor.value() > 128) {
00987 shadowOffset = QPoint(0, 1);
00988 }
00989
00990
00991 if (d->textBgColor != QColor() &&
00992 !(d->text.isEmpty() && d->infoText.isEmpty()) &&
00993 !textBoundingRect.isEmpty()) {
00994 QRectF rect = textBoundingRect.adjusted(-2, -2, 4, 4);
00995 painter->setPen(Qt::transparent);
00996 QColor color = d->textBgColor;
00997 color.setAlpha(60 * (1.0 - d->hoverAlpha));
00998 painter->setBrush(color);
00999 painter->setRenderHint(QPainter::Antialiasing);
01000 painter->drawPath(PaintUtils::roundedRectangle(rect, 4));
01001 }
01002
01003 PaintUtils::shadowBlur(shadow, 2, d->shadowColor);
01004 painter->drawImage(textBoundingRect.topLeft() + shadowOffset, shadow);
01005 d->drawTextItems(painter, option, labelLayout, infoLayout);
01006 }
01007
01008 void IconWidget::setTextBackgroundColor(const QColor &color)
01009 {
01010 d->textBgCustomized = true;
01011 d->textBgColor = color;
01012 update();
01013 }
01014
01015 QColor IconWidget::textBackgroundColor() const
01016 {
01017 return d->textBgColor;
01018 }
01019
01020 void IconWidget::drawActionButtonBase(QPainter *painter, const QSize &size, int element)
01021 {
01022 qreal radius = size.width() / 2;
01023 QRadialGradient gradient(radius, radius, radius, radius, radius);
01024 int alpha;
01025
01026 if (element == IconWidgetPrivate::MinibuttonPressed) {
01027 alpha = 255;
01028 } else if (element == IconWidgetPrivate::MinibuttonHover) {
01029 alpha = 200;
01030 } else {
01031 alpha = 160;
01032 }
01033 gradient.setColorAt(0, QColor::fromRgb(d->textColor.red(),
01034 d->textColor.green(),
01035 d->textColor.blue(), alpha));
01036 gradient.setColorAt(1, QColor::fromRgb(d->textColor.red(),
01037 d->textColor.green(),
01038 d->textColor.blue(), 0));
01039
01040 painter->setBrush(gradient);
01041 painter->setPen(Qt::NoPen);
01042 painter->drawEllipse(QRectF(QPointF(.0, .0), size));
01043 }
01044
01045 void IconWidget::setText(const QString &text)
01046 {
01047 d->text = KGlobal::locale()->removeAcceleratorMarker(text);
01048
01049 d->currentSize = QSizeF(-1, -1);
01050
01051 if (!isVisible()) {
01052 QStyleOptionGraphicsItem styleoption;
01053 d->layoutIcons(&styleoption);
01054 }
01055 resize(sizeFromIconSize(d->iconSize.width()));
01056 }
01057
01058 QString IconWidget::text() const
01059 {
01060 return d->text;
01061 }
01062
01063 void IconWidget::setInfoText(const QString &text)
01064 {
01065 d->infoText = text;
01066
01067 d->currentSize = QSizeF(-1, -1);
01068
01069 if (!isVisible()) {
01070 d->layoutIcons(new QStyleOptionGraphicsItem);
01071 }
01072 resize(sizeFromIconSize(d->iconSize.width()));
01073 }
01074
01075 QString IconWidget::infoText() const
01076 {
01077 return d->infoText;
01078 }
01079
01080 QIcon IconWidget::icon() const
01081 {
01082 return d->icon;
01083 }
01084
01085 void IconWidget::setIcon(const QString &icon)
01086 {
01087 if (icon.isEmpty()) {
01088 setIcon(QIcon());
01089 return;
01090 }
01091
01092 setIcon(KIcon(icon));
01093 }
01094
01095 void IconWidget::setIcon(const QIcon &icon)
01096 {
01097 d->icon = icon;
01098 update();
01099 }
01100
01101 QSizeF IconWidget::iconSize() const
01102 {
01103 return d->iconSize;
01104 }
01105
01106 bool IconWidget::isDown()
01107 {
01108 return d->states & IconWidgetPrivate::PressedState;
01109 }
01110
01111 void IconWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
01112 {
01113 if (event->button() != Qt::LeftButton) {
01114 QGraphicsWidget::mousePressEvent(event);
01115 return;
01116 }
01117
01118 d->states |= IconWidgetPrivate::PressedState;
01119 d->clickStartPos = scenePos();
01120
01121 bool handled = false;
01122 foreach (IconAction *action, d->cornerActions) {
01123 handled = action->event(event->type(), event->pos());
01124 if (handled) {
01125 break;
01126 }
01127 }
01128
01129 if (!handled && boundingRect().contains(event->pos())) {
01130 emit pressed(true);
01131 }
01132
01133 update();
01134 }
01135
01136 void IconWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
01137 {
01138 if (~d->states & IconWidgetPrivate::PressedState) {
01139 QGraphicsWidget::mouseMoveEvent(event);
01140 return;
01141 }
01142
01143 if (boundingRect().contains(event->pos())) {
01144 if (~d->states & IconWidgetPrivate::HoverState) {
01145 d->states |= IconWidgetPrivate::HoverState;
01146 update();
01147 }
01148 } else {
01149 if (d->states & IconWidgetPrivate::HoverState) {
01150 d->states &= ~IconWidgetPrivate::HoverState;
01151 update();
01152 }
01153 }
01154 }
01155
01156 void IconWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
01157 {
01158 if (~d->states & IconWidgetPrivate::PressedState) {
01159 QGraphicsWidget::mouseMoveEvent(event);
01160 return;
01161 }
01162
01163 d->states &= ~IconWidgetPrivate::PressedState;
01164
01165
01166 bool handled = d->clickStartPos != scenePos();
01167 if (!handled) {
01168 foreach (IconAction *action, d->cornerActions) {
01169 if (action->event(event->type(), event->pos())) {
01170 handled = true;
01171 break;
01172 }
01173 }
01174 }
01175
01176 if (!handled) {
01177 if (boundingRect().contains(event->pos())) {
01178 emit clicked();
01179 if (KGlobalSettings::singleClick()) {
01180 emit activated();
01181 }
01182 }
01183 emit pressed(false);
01184 }
01185
01186 update();
01187 }
01188
01189 void IconWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
01190 {
01191 Q_UNUSED(event)
01192
01193 emit doubleClicked();
01194 if (!KGlobalSettings::singleClick()) {
01195 emit activated();
01196 }
01197 }
01198
01199 void IconWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
01200 {
01201
01202 foreach (IconAction *action, d->cornerActions) {
01203 action->show();
01204 action->event(event->type(), event->pos());
01205 }
01206
01207 d->hoverEffect(true);
01208 update();
01209
01210 QGraphicsWidget::hoverEnterEvent(event);
01211 }
01212
01213 void IconWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
01214 {
01215
01216 foreach (IconAction *action, d->cornerActions) {
01217 action->hide();
01218 action->event(event->type(), event->pos());
01219 }
01220
01221 d->hoverEffect(false);
01222 update();
01223
01224 QGraphicsWidget::hoverLeaveEvent(event);
01225 }
01226
01227 bool IconWidget::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
01228 {
01229 Q_UNUSED(watched)
01230
01231 if (event->type() == QEvent::GraphicsSceneDragEnter) {
01232 d->hoverEffect(true);
01233 update();
01234 } else if (event->type() == QEvent::GraphicsSceneDragLeave) {
01235 d->hoverEffect(false);
01236 update();
01237 }
01238
01239 return false;
01240 }
01241
01242 void IconWidget::setPressed(bool pressed)
01243 {
01244 if (pressed) {
01245 d->states |= IconWidgetPrivate::ManualPressedState;
01246 d->states |= IconWidgetPrivate::PressedState;
01247 } else {
01248 d->states &= ~IconWidgetPrivate::ManualPressedState;
01249 d->states &= ~IconWidgetPrivate::PressedState;
01250 }
01251 update();
01252 }
01253
01254 void IconWidget::setUnpressed()
01255 {
01256 setPressed(false);
01257 }
01258
01259 void IconWidgetPrivate::svgChanged()
01260 {
01261 iconSvgElementChanged = true;
01262 q->update();
01263 }
01264
01265 void IconWidget::setOrientation(Qt::Orientation orientation)
01266 {
01267 d->orientation = orientation;
01268 resize(sizeFromIconSize(d->iconSize.width()));
01269 }
01270
01271 Qt::Orientation IconWidget::orientation() const
01272 {
01273 return d->orientation;
01274 }
01275
01276 void IconWidget::invertLayout(bool invert)
01277 {
01278 d->invertLayout = invert;
01279 }
01280
01281 bool IconWidget::invertedLayout() const
01282 {
01283 return d->invertLayout;
01284 }
01285
01286 QSizeF IconWidget::sizeFromIconSize(const qreal iconWidth) const
01287 {
01288 if (d->text.isEmpty() && d->infoText.isEmpty()) {
01289
01290 return d->addMargin(d->addMargin(QSizeF(iconWidth, iconWidth), IconWidgetPrivate::IconMargin),
01291 IconWidgetPrivate::ItemMargin);
01292 }
01293
01294 QFontMetricsF fm = Plasma::Theme::defaultTheme()->fontMetrics();
01295 qreal width = 0;
01296
01297 if (d->orientation == Qt::Vertical) {
01298
01299 width = qMax(fm.width(d->text.left(12)),
01300 fm.width(d->infoText.left(12))) +
01301 fm.width("xx") +
01302 d->horizontalMargin[IconWidgetPrivate::TextMargin].left +
01303 d->horizontalMargin[IconWidgetPrivate::TextMargin].right;
01304
01305 width = qMax(width,
01306 iconWidth +
01307 d->horizontalMargin[IconWidgetPrivate::IconMargin].left +
01308 d->horizontalMargin[IconWidgetPrivate::IconMargin].right);
01309 } else {
01310 width = iconWidth +
01311 d->horizontalMargin[IconWidgetPrivate::IconMargin].left +
01312 d->horizontalMargin[IconWidgetPrivate::IconMargin].right +
01313 qMax(fm.width(d->text), fm.width(d->infoText)) + fm.width("xx") +
01314 d->horizontalMargin[IconWidgetPrivate::TextMargin].left +
01315 d->horizontalMargin[IconWidgetPrivate::TextMargin].right;
01316 }
01317
01318 qreal height;
01319 qreal textHeight;
01320
01321 QStyleOptionGraphicsItem option;
01322 option.state = QStyle::State_None;
01323 option.rect = boundingRect().toRect();
01324 textHeight = d->displaySizeHint(&option, width).height();
01325
01326 if (d->orientation == Qt::Vertical) {
01327 height = iconWidth + textHeight +
01328 d->verticalMargin[IconWidgetPrivate::TextMargin].top +
01329 d->verticalMargin[IconWidgetPrivate::TextMargin].bottom +
01330 d->verticalMargin[IconWidgetPrivate::IconMargin].top +
01331 d->verticalMargin[IconWidgetPrivate::IconMargin].bottom;
01332 } else {
01333
01334 height = qMax(iconWidth +
01335 d->verticalMargin[IconWidgetPrivate::IconMargin].top +
01336 d->verticalMargin[IconWidgetPrivate::IconMargin].bottom,
01337 textHeight +
01338 d->verticalMargin[IconWidgetPrivate::TextMargin].top +
01339 d->verticalMargin[IconWidgetPrivate::TextMargin].bottom);
01340 }
01341
01342 return d->addMargin(QSizeF(width, height), IconWidgetPrivate::ItemMargin);
01343 }
01344
01345 }
01346
01347 #include "iconwidget.moc"