void KItemListWidget::setHovered(bool hovered) { if (hovered == m_hovered) { return; } m_hovered = hovered; if (!m_hoverAnimation) { m_hoverAnimation = new QPropertyAnimation(this, "hoverOpacity", this); const int duration = style()->styleHint(QStyle::SH_Widget_Animate) ? 200 : 1; m_hoverAnimation->setDuration(duration); connect(m_hoverAnimation, &QPropertyAnimation::finished, this, &KItemListWidget::slotHoverAnimationFinished); } m_hoverAnimation->stop(); if (hovered) { const qreal startValue = qMax(hoverOpacity(), qreal(0.1)); m_hoverAnimation->setStartValue(startValue); m_hoverAnimation->setEndValue(1.0); if (m_enabledSelectionToggle && !(QApplication::mouseButtons() & Qt::LeftButton)) { initializeSelectionToggle(); } } else { m_hoverAnimation->setStartValue(hoverOpacity()); m_hoverAnimation->setEndValue(0.0); } m_hoverAnimation->start(); hoveredChanged(hovered); update(); }
void KStandardItemListWidget::updatePixmapCache() { // Precondition: Requires already updated m_textPos values to calculate // the remaining height when the alignment is vertical. const QSizeF widgetSize = size(); const bool iconOnTop = (m_layout == IconsLayout); const KItemListStyleOption& option = styleOption(); const qreal padding = option.padding; const int maxIconWidth = iconOnTop ? widgetSize.width() - 2 * padding : option.iconSize; const int maxIconHeight = option.iconSize; const QHash<QByteArray, QVariant> values = data(); bool updatePixmap = (m_pixmap.width() != maxIconWidth || m_pixmap.height() != maxIconHeight); if (!updatePixmap && m_dirtyContent) { updatePixmap = m_dirtyContentRoles.isEmpty() || m_dirtyContentRoles.contains("iconPixmap") || m_dirtyContentRoles.contains("iconName") || m_dirtyContentRoles.contains("iconOverlays"); } if (updatePixmap) { m_pixmap = values["iconPixmap"].value<QPixmap>(); if (m_pixmap.isNull()) { // Use the icon that fits to the MIME-type QString iconName = values["iconName"].toString(); if (iconName.isEmpty()) { // The icon-name has not been not resolved by KFileItemModelRolesUpdater, // use a generic icon as fallback iconName = QLatin1String("unknown"); } m_pixmap = pixmapForIcon(iconName, maxIconHeight); } else if (m_pixmap.width() != maxIconWidth || m_pixmap.height() != maxIconHeight) { // A custom pixmap has been applied. Assure that the pixmap // is scaled to the maximum available size. KPixmapModifier::scale(m_pixmap, QSize(maxIconWidth, maxIconHeight)); } const QStringList overlays = values["iconOverlays"].toStringList(); // Strangely KFileItem::overlays() returns empty string-values, so // we need to check first whether an overlay must be drawn at all. // It is more efficient to do it here, as KIconLoader::drawOverlays() // assumes that an overlay will be drawn and has some additional // setup time. foreach (const QString& overlay, overlays) { if (!overlay.isEmpty()) { // There is at least one overlay, draw all overlays above m_pixmap // and cancel the check KIconLoader::global()->drawOverlays(overlays, m_pixmap, KIconLoader::Desktop); break; } } if (m_isCut) { KIconEffect* effect = KIconLoader::global()->iconEffect(); m_pixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::DisabledState); } if (m_isHidden) { KIconEffect::semiTransparent(m_pixmap); } if (isSelected()) { const QColor color = palette().brush(QPalette::Normal, QPalette::Highlight).color(); QImage image = m_pixmap.toImage(); KIconEffect::colorize(image, color, 1.0f); m_pixmap = QPixmap::fromImage(image); } } if (!m_overlay.isNull()) { QPainter painter(&m_pixmap); painter.drawPixmap(0, m_pixmap.height() - m_overlay.height(), m_overlay); } int scaledIconSize = 0; if (iconOnTop) { const TextInfo* textInfo = m_textInfo.value("text"); scaledIconSize = static_cast<int>(textInfo->pos.y() - 2 * padding); } else { const int textRowsCount = (m_layout == CompactLayout) ? visibleRoles().count() : 1; const qreal requiredTextHeight = textRowsCount * m_customizedFontMetrics.height(); scaledIconSize = (requiredTextHeight < maxIconHeight) ? widgetSize.height() - 2 * padding : maxIconHeight; } const int maxScaledIconWidth = iconOnTop ? widgetSize.width() - 2 * padding : scaledIconSize; const int maxScaledIconHeight = scaledIconSize; m_scaledPixmapSize = m_pixmap.size(); m_scaledPixmapSize.scale(maxScaledIconWidth, maxScaledIconHeight, Qt::KeepAspectRatio); if (iconOnTop) { // Center horizontally and align on bottom within the icon-area m_pixmapPos.setX((widgetSize.width() - m_scaledPixmapSize.width()) / 2); m_pixmapPos.setY(padding + scaledIconSize - m_scaledPixmapSize.height()); } else { // Center horizontally and vertically within the icon-area const TextInfo* textInfo = m_textInfo.value("text"); m_pixmapPos.setX(textInfo->pos.x() - 2 * padding - (scaledIconSize + m_scaledPixmapSize.width()) / 2); m_pixmapPos.setY(padding + (scaledIconSize - m_scaledPixmapSize.height()) / 2); } m_iconRect = QRectF(m_pixmapPos, QSizeF(m_scaledPixmapSize)); // Prepare the pixmap that is used when the item gets hovered if (isHovered()) { m_hoverPixmap = m_pixmap; KIconEffect* effect = KIconLoader::global()->iconEffect(); // In the KIconLoader terminology, active = hover. if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) { m_hoverPixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::ActiveState); } else { m_hoverPixmap = m_pixmap; } } else if (hoverOpacity() <= 0.0) { // No hover animation is ongoing. Clear m_hoverPixmap to save memory. m_hoverPixmap = QPixmap(); } }
void KStandardItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { const_cast<KStandardItemListWidget*>(this)->triggerCacheRefreshing(); KItemListWidget::paint(painter, option, widget); if (!m_expansionArea.isEmpty()) { drawSiblingsInformation(painter); } const KItemListStyleOption& itemListStyleOption = styleOption(); if (isHovered()) { // Blend the unhovered and hovered pixmap if the hovering // animation is ongoing if (hoverOpacity() < 1.0) { drawPixmap(painter, m_pixmap); } const qreal opacity = painter->opacity(); painter->setOpacity(hoverOpacity() * opacity); drawPixmap(painter, m_hoverPixmap); painter->setOpacity(opacity); } else { drawPixmap(painter, m_pixmap); } painter->setFont(m_customizedFont); painter->setPen(m_isHidden ? m_additionalInfoTextColor : textColor()); const TextInfo* textInfo = m_textInfo.value("text"); if (!textInfo) { // It seems that we can end up here even if m_textInfo does not contain // the key "text", see bug 306167. According to triggerCacheRefreshing(), // this can only happen if the index is negative. This can happen when // the item is about to be removed, see KItemListView::slotItemsRemoved(). // TODO: try to reproduce the crash and find a better fix. return; } painter->drawStaticText(textInfo->pos, textInfo->staticText); bool clipAdditionalInfoBounds = false; if (m_supportsItemExpanding) { // Prevent a possible overlapping of the additional-information texts // with the icon. This can happen if the user has minimized the width // of the name-column to a very small value. const qreal minX = m_pixmapPos.x() + m_pixmap.width() + 4 * itemListStyleOption.padding; if (textInfo->pos.x() + columnWidth("text") > minX) { clipAdditionalInfoBounds = true; painter->save(); painter->setClipRect(minX, 0, size().width() - minX, size().height(), Qt::IntersectClip); } } painter->setPen(m_additionalInfoTextColor); painter->setFont(m_customizedFont); for (int i = 1; i < m_sortedVisibleRoles.count(); ++i) { const TextInfo* textInfo = m_textInfo.value(m_sortedVisibleRoles[i]); painter->drawStaticText(textInfo->pos, textInfo->staticText); } if (!m_rating.isNull()) { const TextInfo* ratingTextInfo = m_textInfo.value("rating"); QPointF pos = ratingTextInfo->pos; const Qt::Alignment align = ratingTextInfo->staticText.textOption().alignment(); if (align & Qt::AlignHCenter) { pos.rx() += (size().width() - m_rating.width()) / 2 - 2; } painter->drawPixmap(pos, m_rating); } if (clipAdditionalInfoBounds) { painter->restore(); } #ifdef KSTANDARDITEMLISTWIDGET_DEBUG painter->setBrush(Qt::NoBrush); painter->setPen(Qt::green); painter->drawRect(m_iconRect); painter->setPen(Qt::red); painter->drawText(QPointF(0, m_customizedFontMetrics.height()), QString::number(index())); painter->drawRect(rect()); #endif }