X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/bcde430bd532436db31a16f6efff46b32ab38bc1..cebcf8db:/src/kitemviews/kstandarditemlistwidget.cpp diff --git a/src/kitemviews/kstandarditemlistwidget.cpp b/src/kitemviews/kstandarditemlistwidget.cpp index e37013f95..c8a6955b9 100644 --- a/src/kitemviews/kstandarditemlistwidget.cpp +++ b/src/kitemviews/kstandarditemlistwidget.cpp @@ -10,10 +10,12 @@ #include "kfileitemmodel.h" #include "private/kfileitemclipboard.h" #include "private/kitemlistroleeditor.h" +#include "private/kitemviewsutils.h" #include "private/kpixmapmodifier.h" #include #include +#include #include #include @@ -23,6 +25,7 @@ #include #include #include +#include // #define KSTANDARDITEMLISTWIDGET_DEBUG @@ -294,11 +297,6 @@ void KStandardItemListWidget::setLayout(Layout layout) } } -KStandardItemListWidget::Layout KStandardItemListWidget::layout() const -{ - return m_layout; -} - void KStandardItemListWidget::setHighlightEntireRow(bool highlightEntireRow) { if (m_highlightEntireRow != highlightEntireRow) { @@ -539,6 +537,7 @@ QRectF KStandardItemListWidget::selectionToggleRect() const { const_cast(this)->triggerCacheRefreshing(); + const QRectF widgetIconRect = iconRect(); const int widgetIconSize = iconSize(); int toggleSize = KIconLoader::SizeSmall; if (widgetIconSize >= KIconLoader::SizeEnormous) { @@ -547,7 +546,7 @@ QRectF KStandardItemListWidget::selectionToggleRect() const toggleSize = KIconLoader::SizeSmallMedium; } - QPointF pos = iconRect().topLeft(); + QPointF pos = widgetIconRect.topLeft(); // If the selection toggle has a very small distance to the // widget borders, the size of the selection toggle will get @@ -568,6 +567,10 @@ QRectF KStandardItemListWidget::selectionToggleRect() const pos.setX(0); } + if (QApplication::isRightToLeft()) { + pos.setX(widgetIconRect.right() - (pos.x() + toggleSize - widgetIconRect.left())); + } + return QRectF(pos, QSizeF(toggleSize, toggleSize)); } @@ -593,6 +596,55 @@ QPixmap KStandardItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem return clippedPixmap; } +void KStandardItemListWidget::startActivateSoonAnimation(int timeUntilActivation) +{ + if (m_activateSoonAnimation) { + m_activateSoonAnimation->stop(); // automatically DeleteWhenStopped + } + + m_activateSoonAnimation = new QVariantAnimation{this}; + m_activateSoonAnimation->setStartValue(0.0); + m_activateSoonAnimation->setEndValue(1.0); + m_activateSoonAnimation->setDuration(timeUntilActivation); + + const QVariant originalIconName{data()["iconName"]}; + connect(m_activateSoonAnimation, &QVariantAnimation::valueChanged, this, [originalIconName, this](const QVariant &value) { + auto progress = value.toFloat(); + + QVariant wantedIconName; + if (progress < 0.333) { + wantedIconName = "folder-open"; + } else if (progress < 0.666) { + wantedIconName = originalIconName; + } else { + wantedIconName = "folder-open"; + } + + QHash itemData{data()}; + if (itemData["iconName"] != wantedIconName) { + itemData.insert("iconName", wantedIconName); + setData(itemData); + invalidateIconCache(); + } + }); + + connect(m_activateSoonAnimation, &QObject::destroyed, this, [originalIconName, this]() { + QHash itemData{data()}; + if (itemData["iconName"] == "folder-open") { + itemData.insert("iconName", originalIconName); + setData(itemData); + invalidateIconCache(); + } + }); + + m_activateSoonAnimation->start(QAbstractAnimation::DeleteWhenStopped); +} + +bool KStandardItemListWidget::isIconControlledByActivateSoonAnimation() const +{ + return m_activateSoonAnimation && data()["iconName"] == "folder-open"; +} + KItemListWidgetInformant *KStandardItemListWidget::createInformant() { return new KStandardItemListWidgetInformant(); @@ -740,7 +792,9 @@ void KStandardItemListWidget::styleOptionChanged(const KItemListStyleOption &cur void KStandardItemListWidget::hoveredChanged(bool hovered) { - Q_UNUSED(hovered) + if (!hovered && m_activateSoonAnimation) { + m_activateSoonAnimation->stop(); // automatically DeleteWhenStopped + } m_dirtyLayout = true; } @@ -821,6 +875,7 @@ void KStandardItemListWidget::editedRoleChanged(const QByteArray ¤t, const rect.setWidth(parent->width() - rect.left()); } m_roleEditor->setGeometry(rect.toRect()); + m_roleEditor->autoAdjustSize(); m_roleEditor->show(); m_roleEditor->setFocus(); } @@ -964,6 +1019,7 @@ void KStandardItemListWidget::updatePixmapCache() const bool iconOnTop = (m_layout == IconsLayout); const KItemListStyleOption &option = styleOption(); const qreal padding = option.padding; + const qreal dpr = KItemViewsUtils::devicePixelRatio(this); const int widgetIconSize = iconSize(); const int maxIconWidth = iconOnTop ? widgetSize.width() - 2 * padding : widgetIconSize; @@ -982,7 +1038,7 @@ void KStandardItemListWidget::updatePixmapCache() int sequenceIndex = hoverSequenceIndex(); - if (values.contains("hoverSequencePixmaps")) { + if (values.contains("hoverSequencePixmaps") && !isIconControlledByActivateSoonAnimation()) { // Use one of the hover sequence pixmaps instead of the default // icon pixmap. @@ -1002,7 +1058,7 @@ void KStandardItemListWidget::updatePixmapCache() } } - if (m_pixmap.isNull()) { + if (m_pixmap.isNull() && !isIconControlledByActivateSoonAnimation()) { m_pixmap = values["iconPixmap"].value(); } @@ -1024,7 +1080,7 @@ void KStandardItemListWidget::updatePixmapCache() } else if (m_pixmap.width() / m_pixmap.devicePixelRatio() != maxIconWidth || m_pixmap.height() / m_pixmap.devicePixelRatio() != 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) * qApp->devicePixelRatio()); + KPixmapModifier::scale(m_pixmap, QSize(maxIconWidth, maxIconHeight) * dpr); } if (m_pixmap.isNull()) { @@ -1033,8 +1089,14 @@ void KStandardItemListWidget::updatePixmapCache() } if (m_isCut) { - KIconEffect *effect = KIconLoader::global()->iconEffect(); - m_pixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::DisabledState); +#if KICONTHEMES_VERSION >= QT_VERSION_CHECK(6, 5, 0) + KIconEffect::toDisabled(m_pixmap); +#else + QImage img = m_pixmap.toImage(); + KIconEffect::toGray(img, 1); + KIconEffect::semiTransparent(img); + m_pixmap = QPixmap::fromImage(img); +#endif } if (m_isHidden) { @@ -1072,8 +1134,8 @@ void KStandardItemListWidget::updatePixmapCache() const int maxScaledIconHeight = scaledIconSize; m_scaledPixmapSize = m_pixmap.size(); - m_scaledPixmapSize.scale(maxScaledIconWidth * qApp->devicePixelRatio(), maxScaledIconHeight * qApp->devicePixelRatio(), Qt::KeepAspectRatio); - m_scaledPixmapSize = m_scaledPixmapSize / qApp->devicePixelRatio(); + m_scaledPixmapSize.scale(maxScaledIconWidth * dpr, maxScaledIconHeight * dpr, Qt::KeepAspectRatio); + m_scaledPixmapSize = m_scaledPixmapSize / dpr; if (iconOnTop) { // Center horizontally and align on bottom within the icon-area @@ -1082,7 +1144,11 @@ void KStandardItemListWidget::updatePixmapCache() } else { // Center horizontally and vertically within the icon-area const TextInfo *textInfo = m_textInfo.value("text"); - m_pixmapPos.setX(textInfo->pos.x() - 2.0 * padding - (scaledIconSize + m_scaledPixmapSize.width()) / 2.0); + if (QApplication::isRightToLeft() && m_layout == CompactLayout) { + m_pixmapPos.setX(size().width() - padding - (scaledIconSize + m_scaledPixmapSize.width()) / 2.0); + } else { + m_pixmapPos.setX(textInfo->pos.x() - 2.0 * padding - (scaledIconSize + m_scaledPixmapSize.width()) / 2.0); + } // Derive icon's vertical center from the center of the text frame, including // any necessary adjustment if the font's midline is offset from the frame center @@ -1103,13 +1169,13 @@ void KStandardItemListWidget::updatePixmapCache() // 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; - } +#if KICONTHEMES_VERSION >= QT_VERSION_CHECK(6, 5, 0) + KIconEffect::toActive(m_hoverPixmap); +#else + QImage img = m_pixmap.toImage(); + KIconEffect::toGamma(img, 0.7); + m_hoverPixmap = QPixmap::fromImage(img); +#endif } else if (hoverOpacity() <= 0.0) { // No hover animation is ongoing. Clear m_hoverPixmap to save memory. m_hoverPixmap = QPixmap(); @@ -1125,6 +1191,9 @@ void KStandardItemListWidget::updateTextsCache() textOption.setAlignment(Qt::AlignHCenter); break; case CompactLayout: + textOption.setAlignment(QApplication::isRightToLeft() ? Qt::AlignRight : Qt::AlignLeft); + textOption.setWrapMode(QTextOption::NoWrap); + break; case DetailsLayout: textOption.setAlignment(Qt::AlignLeft); textOption.setWrapMode(QTextOption::NoWrap); @@ -1170,7 +1239,7 @@ void KStandardItemListWidget::updateTextsCache() if (ratingSize.width() > availableWidth) { ratingSize.rwidth() = availableWidth; } - const qreal dpr = qApp->devicePixelRatio(); + const qreal dpr = KItemViewsUtils::devicePixelRatio(this); m_rating = QPixmap(ratingSize.toSize() * dpr); m_rating.setDevicePixelRatio(dpr); m_rating.fill(Qt::transparent); @@ -1194,11 +1263,7 @@ QString KStandardItemListWidget::elideRightKeepExtension(const QString &text, in if (elidingWidth > extensionWidth && extensionLength < 6 && (float(extensionWidth) / float(elidingWidth)) < 0.3) { // if we have room to display the file extension and the extension is not too long QString ret = m_customizedFontMetrics.elidedText(text.chopped(extensionLength), Qt::ElideRight, elidingWidth - extensionWidth); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - ret.append(text.rightRef(extensionLength)); -#else ret.append(QStringView(text).right(extensionLength)); -#endif return ret; } } @@ -1354,9 +1419,9 @@ void KStandardItemListWidget::updateCompactLayoutTextCache() const qreal textLinesHeight = qMax(visibleRoles().count(), 1) * lineSpacing; qreal maximumRequiredTextWidth = 0; - const qreal x = option.padding * 3 + iconSize(); + const qreal x = QApplication::isRightToLeft() ? option.padding : option.padding * 3 + iconSize(); qreal y = qRound((widgetHeight - textLinesHeight) / 2); - const qreal maxWidth = size().width() - x - option.padding; + const qreal maxWidth = size().width() - iconSize() - 4 * option.padding; for (const QByteArray &role : std::as_const(m_sortedVisibleRoles)) { const QString text = escapeString(roleText(role, values)); TextInfo *textInfo = m_textInfo.value(role); @@ -1451,8 +1516,8 @@ void KStandardItemListWidget::updateAdditionalInfoTextColor() if (m_customTextColor.isValid()) { c1 = m_customTextColor; } else if (isSelected() && hasFocus && (m_layout != DetailsLayout || m_highlightEntireRow)) { - // The detail text colour needs to match the main text (HighlightedText) for the same level - // of readability. We short circuit early here to avoid interpolating with another colour. + // The detail text color needs to match the main text (HighlightedText) for the same level + // of readability. We short circuit early here to avoid interpolating with another color. m_additionalInfoTextColor = styleOption().palette.color(QPalette::HighlightedText); return; } else { @@ -1472,9 +1537,10 @@ void KStandardItemListWidget::updateAdditionalInfoTextColor() void KStandardItemListWidget::drawPixmap(QPainter *painter, const QPixmap &pixmap) { if (m_scaledPixmapSize != pixmap.size() / pixmap.devicePixelRatio()) { + const qreal dpr = KItemViewsUtils::devicePixelRatio(this); QPixmap scaledPixmap = pixmap; - KPixmapModifier::scale(scaledPixmap, m_scaledPixmapSize * qApp->devicePixelRatio()); - scaledPixmap.setDevicePixelRatio(qApp->devicePixelRatio()); + KPixmapModifier::scale(scaledPixmap, m_scaledPixmapSize * dpr); + scaledPixmap.setDevicePixelRatio(dpr); painter->drawPixmap(m_pixmapPos, scaledPixmap); #ifdef KSTANDARDITEMLISTWIDGET_DEBUG @@ -1558,10 +1624,7 @@ void KStandardItemListWidget::closeRoleEditor() QPixmap KStandardItemListWidget::pixmapForIcon(const QString &name, const QStringList &overlays, int size, QIcon::Mode mode) const { static const QIcon fallbackIcon = QIcon::fromTheme(QStringLiteral("unknown")); - qreal dpr = qApp->devicePixelRatio(); - if (scene() && !scene()->views().isEmpty()) { - dpr = scene()->views().constFirst()->devicePixelRatioF(); - } + const qreal dpr = KItemViewsUtils::devicePixelRatio(this); size *= dpr; @@ -1585,30 +1648,12 @@ QPixmap KStandardItemListWidget::pixmapForIcon(const QString &name, const QStrin // 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. for (const QString &overlay : overlays) { if (!overlay.isEmpty()) { - int state = KIconLoader::DefaultState; - - switch (mode) { - case QIcon::Normal: - break; - case QIcon::Active: - state = KIconLoader::ActiveState; - break; - case QIcon::Disabled: - state = KIconLoader::DisabledState; - break; - case QIcon::Selected: - state = KIconLoader::SelectedState; - break; - } - // There is at least one overlay, draw all overlays above m_pixmap // and cancel the check - KIconLoader::global()->drawOverlays(overlays, pixmap, KIconLoader::Desktop, state); + const QSize size = pixmap.size(); + pixmap = KIconUtils::addOverlays(pixmap, overlays).pixmap(size, mode); break; } }