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