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