]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Merge branch 'release/21.12'
authorKai Uwe Broulik <kde@privat.broulik.de>
Fri, 25 Feb 2022 20:03:36 +0000 (21:03 +0100)
committerKai Uwe Broulik <kde@privat.broulik.de>
Fri, 25 Feb 2022 20:03:36 +0000 (21:03 +0100)
1  2 
src/kitemviews/kstandarditemlistwidget.cpp

index 74d48e32572a2b8aa1b2a8d8ff2f2dccbb2e0dca,62beb6e5358eea5cc4b20251235ff6556b95b7e8..e5c2f021bca0f7376a03f66fd1c581fd5f361bfe
@@@ -36,7 -36,7 +36,7 @@@ KStandardItemListWidgetInformant::~KSta
  {
  }
  
 -void KStandardItemListWidgetInformant::calculateItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const
 +void KStandardItemListWidgetInformant::calculateItemSizeHints(QVector<std::pair<qreal, bool>>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const
  {
      switch (static_cast<const KStandardItemListView*>(view)->itemLayout()) {
      case KStandardItemListView::IconsLayout:
@@@ -121,7 -121,7 +121,7 @@@ QFont KStandardItemListWidgetInformant:
      return baseFont;
  }
  
 -void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const
 +void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector<std::pair<qreal, bool>>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const
  {
      const KItemListStyleOption& option = view->styleOption();
      const QFont& normalFont = option.font;
      textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
  
      for (int index = 0; index < logicalHeightHints.count(); ++index) {
 -        if (logicalHeightHints.at(index) > 0.0) {
 +        if (logicalHeightHints.at(index).first > 0.0) {
              continue;
          }
  
          const QFont& font = itemIsLink(index, view) ? linkFont : normalFont;
  
          const QString& text = KStringHandler::preProcessWrap(itemText(index, view));
 -
 +        
          // Calculate the number of lines required for wrapping the name
          qreal textHeight = 0;
          QTextLayout layout(text, font);
          layout.beginLayout();
          QTextLine line;
          int lineCount = 0;
 +        bool isElided = false;
          while ((line = layout.createLine()).isValid()) {
              line.setLineWidth(maxWidth);
              line.naturalTextWidth();
  
              ++lineCount;
              if (lineCount == option.maxTextLines) {
 +                isElided = layout.createLine().isValid();
                  break;
              }
          }
          // Add one line for each additional information
          textHeight += additionalRolesSpacing;
  
 -        logicalHeightHints[index] = textHeight + spacingAndIconHeight;
 +        logicalHeightHints[index].first = textHeight + spacingAndIconHeight;
 +        logicalHeightHints[index].second = isElided;
      }
  
      logicalWidthHint = itemWidth;
  }
  
 -void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const
 +void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVector<std::pair<qreal, bool>>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const
  {
      const KItemListStyleOption& option = view->styleOption();
      const QFontMetrics& normalFontMetrics = option.fontMetrics;
      const QFontMetrics linkFontMetrics(customizedFontForLinks(option.font));
  
      for (int index = 0; index < logicalHeightHints.count(); ++index) {
 -        if (logicalHeightHints.at(index) > 0.0) {
 +        if (logicalHeightHints.at(index).first > 0.0) {
              continue;
          }
  
              width = maxWidth;
          }
  
 -        logicalHeightHints[index] = width;
 +        logicalHeightHints[index].first = width;
      }
  
      logicalWidthHint = height;
  }
  
 -void KStandardItemListWidgetInformant::calculateDetailsLayoutItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const
 +void KStandardItemListWidgetInformant::calculateDetailsLayoutItemSizeHints(QVector<std::pair<qreal, bool>>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const
  {
      const KItemListStyleOption& option = view->styleOption();
      const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height());
 -    logicalHeightHints.fill(height);
 +    logicalHeightHints.fill(std::make_pair(height, false));
      logicalWidthHint = -1.0;
  }
  
@@@ -250,7 -247,6 +250,7 @@@ KStandardItemListWidget::KStandardItemL
      m_pixmapPos(),
      m_pixmap(),
      m_scaledPixmapSize(),
 +    m_columnWidthSum(),
      m_iconRect(),
      m_hoverPixmap(),
      m_textRect(),
@@@ -294,18 -290,6 +294,18 @@@ KStandardItemListWidget::Layout KStanda
      return m_layout;
  }
  
 +void KStandardItemListWidget::setHighlightEntireRow(bool highlightEntireRow) {
 +    if (m_highlightEntireRow != highlightEntireRow) {
 +        m_highlightEntireRow = highlightEntireRow;
 +        m_dirtyLayout = true;
 +        update();
 +    }
 +}
 +
 +bool KStandardItemListWidget::highlightEntireRow() const {
 +    return m_highlightEntireRow;
 +}
 +
  void KStandardItemListWidget::setSupportsItemExpanding(bool supportsItemExpanding)
  {
      if (m_supportsItemExpanding != supportsItemExpanding) {
@@@ -419,7 -403,7 +419,7 @@@ void KStandardItemListWidget::paint(QPa
          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;
+             pos.rx() += (size().width() - m_rating.width() / m_rating.devicePixelRatioF()) / 2 - 2;
          }
          painter->drawPixmap(pos, m_rating);
      }
@@@ -507,11 -491,7 +507,11 @@@ QRectF KStandardItemListWidget::selecti
      case DetailsLayout: {
          const int padding = styleOption().padding;
          QRectF adjustedIconRect = iconRect().adjusted(-padding, -padding, padding, padding);
 -        return adjustedIconRect | m_textRect;
 +        QRectF result = adjustedIconRect | m_textRect;
 +        if (m_highlightEntireRow) {
 +            result.setRight(m_columnWidthSum + leadingPadding());
 +        }
 +        return result;
      }
  
      default:
@@@ -532,11 -512,12 +532,11 @@@ QRectF KStandardItemListWidget::selecti
  {
      const_cast<KStandardItemListWidget*>(this)->triggerCacheRefreshing();
  
 -    const int iconHeight = styleOption().iconSize;
 -
 +    const int widgetIconSize = iconSize();
      int toggleSize = KIconLoader::SizeSmall;
 -    if (iconHeight >= KIconLoader::SizeEnormous) {
 +    if (widgetIconSize >= KIconLoader::SizeEnormous) {
          toggleSize = KIconLoader::SizeMedium;
 -    } else if (iconHeight >= KIconLoader::SizeLarge) {
 +    } else if (widgetIconSize >= KIconLoader::SizeLarge) {
          toggleSize = KIconLoader::SizeSmallMedium;
      }
  
@@@ -727,16 -708,11 +727,16 @@@ void KStandardItemListWidget::columnWid
      m_dirtyLayout = true;
  }
  
 +void KStandardItemListWidget::leadingPaddingChanged(qreal padding) {
 +    Q_UNUSED(padding)
 +    m_dirtyLayout = true;
 +}
 +
  void KStandardItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
                                               const KItemListStyleOption& previous)
  {
 -    Q_UNUSED(current)
 -    Q_UNUSED(previous)
 +    KItemListWidget::styleOptionChanged(current, previous);
 +
      updateAdditionalInfoTextColor();
      m_dirtyLayout = true;
  }
@@@ -832,15 -808,6 +832,15 @@@ void KStandardItemListWidget::editedRol
      m_roleEditor->setFocus();
  }
  
 +void KStandardItemListWidget::iconSizeChanged(int current, int previous)
 +{
 +    KItemListWidget::iconSizeChanged(current, previous);
 +
 +    invalidateIconCache();
 +    triggerCacheRefreshing();
 +    update();
 +}
 +
  void KStandardItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
  {
      if (m_roleEditor) {
@@@ -933,13 -900,10 +933,13 @@@ void KStandardItemListWidget::triggerCa
      m_isHidden = isHidden();
      m_customizedFont = customizedFont(styleOption().font);
      m_customizedFontMetrics = QFontMetrics(m_customizedFont);
 +    m_columnWidthSum = std::accumulate(m_sortedVisibleRoles.begin(), m_sortedVisibleRoles.end(),
 +                                       qreal(), [this](qreal sum, const auto &role){ return sum + columnWidth(role); });
  
      updateExpansionArea();
      updateTextsCache();
      updatePixmapCache();
 +    clearHoverCache();
  
      m_dirtyLayout = false;
      m_dirtyContent = false;
@@@ -952,16 -916,12 +952,16 @@@ void KStandardItemListWidget::updateExp
          const QHash<QByteArray, QVariant> values = data();
          const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
          if (expandedParentsCount >= 0) {
 -            const KItemListStyleOption& option = styleOption();
 +            const int widgetIconSize = iconSize();
              const qreal widgetHeight = size().height();
 -            const qreal inc = (widgetHeight - option.iconSize) / 2;
 -            const qreal x = expandedParentsCount * widgetHeight + inc;
 +            const qreal inc = (widgetHeight - iconSize()) / 2;
 +            const qreal x =
 +                layoutDirection() == Qt::LeftToRight
 +                    ? expandedParentsCount * widgetHeight + inc
 +                    : size().width() - iconSize() - (expandedParentsCount * widgetHeight + inc);
              const qreal y = inc;
 -            m_expansionArea = QRectF(x, y, option.iconSize, option.iconSize);
 +            const qreal xPadding = m_highlightEntireRow ? leadingPadding() : 0;
 +            m_expansionArea = QRectF(xPadding + x, y, widgetIconSize, widgetIconSize);
              return;
          }
      }
@@@ -979,9 -939,8 +979,9 @@@ void KStandardItemListWidget::updatePix
      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 int widgetIconSize = iconSize();
 +    const int maxIconWidth = iconOnTop ? widgetSize.width() - 2 * padding : widgetIconSize;
 +    const int maxIconHeight = widgetIconSize;
  
      const QHash<QByteArray, QVariant> values = data();
  
      } 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);
 +        const auto width = (scaledIconSize + m_scaledPixmapSize.width()) / 2.0;
 +        const auto iPadding = 2.0 * padding;
 +        const auto x = textInfo->pos.x();
 +
 +        const QHash<QByteArray, QVariant> values = data();
 +        const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
 +        const int expansionOffset =
 +            (m_layout == DetailsLayout) ?
 +                size().height() + size().height() * expandedParentsCount :
 +                0;
 +
 +        m_pixmapPos.setX(layoutDirection() == Qt::LeftToRight
 +            ? x - iPadding - width + expansionOffset
 +            : size().width() - iPadding - width - expansionOffset);
  
          // 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
@@@ -1236,6 -1183,7 +1236,6 @@@ void KStandardItemListWidget::updateIco
      const KItemListStyleOption& option = styleOption();
      const qreal padding = option.padding;
      const qreal maxWidth = size().width() - 2 * padding;
 -    const qreal widgetHeight = size().height();
      const qreal lineSpacing = m_customizedFontMetrics.lineSpacing();
  
      // Initialize properties for the "text" role. It will be used as anchor
      layout.endLayout();
  
      // Use one line for each additional information
 -    const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
      nameTextInfo->staticText.setTextWidth(maxWidth);
 -    nameTextInfo->pos = QPointF(padding, widgetHeight -
 -                                         nameHeight -
 -                                         additionalRolesCount * lineSpacing -
 -                                         padding);
 +    nameTextInfo->pos = QPointF(padding, iconSize() + 2 * padding);
      m_textRect = QRectF(padding + (maxWidth - nameWidth) / 2,
                          nameTextInfo->pos.y(),
                          nameWidth,
                  requiredWidth = m_customizedFontMetrics.horizontalAdvance(elidedText);
              } else if (role == "rating") {
                  // Use the width of the rating pixmap, because the rating text is empty.
-                 requiredWidth = m_rating.width();
+                 requiredWidth = m_rating.width() / m_rating.devicePixelRatioF();
              }
          }
          layout.endLayout();
          textInfo->staticText.setTextWidth(maxWidth);
  
          const QRectF textRect(padding + (maxWidth - requiredWidth) / 2, y, requiredWidth, lineSpacing);
 -        m_textRect |= textRect;
 +
 +        // Ignore empty roles. Avoids a text rect taller than the area that actually contains text.
 +        if (!textRect.isEmpty()) {
 +            m_textRect |= textRect;
 +        }
  
          y += lineSpacing;
      }
@@@ -1359,9 -1307,10 +1359,9 @@@ void KStandardItemListWidget::updateCom
      const qreal widgetHeight = size().height();
      const qreal lineSpacing = m_customizedFontMetrics.lineSpacing();
      const qreal textLinesHeight = qMax(visibleRoles().count(), 1) * lineSpacing;
 -    const int scaledIconSize = (textLinesHeight < option.iconSize) ? widgetHeight - 2 * option.padding : option.iconSize;
  
      qreal maximumRequiredTextWidth = 0;
 -    const qreal x = option.padding * 3 + scaledIconSize;
 +    const qreal x = option.padding * 3 + iconSize();
      qreal y = qRound((widgetHeight - textLinesHeight) / 2);
      const qreal maxWidth = size().width() - x - option.padding;
      for (const QByteArray& role : qAsConst(m_sortedVisibleRoles)) {
              textInfo->staticText.setText(elidedText);
          }
  
 -        textInfo->pos = QPointF(x, y);
 +        if (layoutDirection() == Qt::LeftToRight) {
 +            textInfo->pos = QPointF(x, y);
 +        } else {
 +            textInfo->pos = QPointF(x - size().height(), y);
 +        }
          textInfo->staticText.setTextWidth(maxWidth);
  
          maximumRequiredTextWidth = qMax(maximumRequiredTextWidth, requiredWidth);
          y += lineSpacing;
      }
  
 -    m_textRect = QRectF(x - option.padding, 0, maximumRequiredTextWidth + 2 * option.padding, widgetHeight);
 +    if (layoutDirection() == Qt::LeftToRight) {
 +        m_textRect = QRectF(x - option.padding, 0, maximumRequiredTextWidth + 2 * option.padding, widgetHeight);
 +    } else {
 +        m_textRect = QRectF(x - option.padding - size().height(), 0, maximumRequiredTextWidth + 2 * option.padding, widgetHeight);
 +    }
  }
  
  void KStandardItemListWidget::updateDetailsLayoutTextCache()
      const QHash<QByteArray, QVariant> values = data();
  
      const qreal widgetHeight = size().height();
 -    const int scaledIconSize = widgetHeight - 2 * option.padding;
      const int fontHeight = m_customizedFontMetrics.height();
  
      const qreal columnWidthInc = columnPadding(option);
 -    qreal firstColumnInc = scaledIconSize;
 +
 +    qreal firstColumnOffset = iconSize();
      if (m_supportsItemExpanding) {
 -        firstColumnInc += (m_expansionArea.left() + m_expansionArea.right() + widgetHeight) / 2;
 +        firstColumnOffset += (m_expansionArea.width() + widgetHeight) / 2;
      } else {
 -        firstColumnInc += option.padding;
 +        firstColumnOffset += option.padding + leadingPadding();
      }
  
 -    qreal x = firstColumnInc;
 +    qreal x = firstColumnOffset;
      const qreal y = qMax(qreal(option.padding), (widgetHeight - fontHeight) / 2);
  
      for (const QByteArray& role : qAsConst(m_sortedVisibleRoles)) {
          const qreal roleWidth = columnWidth(role);
          qreal availableTextWidth = roleWidth - columnWidthInc;
  
 +        const QHash<QByteArray, QVariant> values = data();
 +        const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
 +        const int expansionOffset = size().height() * expandedParentsCount;
 +
          const bool isTextRole = (role == "text");
          if (isTextRole) {
 -            availableTextWidth -= firstColumnInc;
 +            availableTextWidth -= firstColumnOffset - leadingPadding();
          }
  
          if (requiredWidth > availableTextWidth) {
  
          TextInfo* textInfo = m_textInfo.value(role);
          textInfo->staticText.setText(text);
 -        textInfo->pos = QPointF(x + columnWidthInc / 2, y);
 +        textInfo->pos = QPointF(x - (layoutDirection() == Qt::LeftToRight ? 0 : firstColumnOffset), y);
 +        if (layoutDirection() == Qt::LeftToRight) {
 +            textInfo->pos.rx() += columnWidthInc/2 + expansionOffset;
 +        } else {
 +            textInfo->pos.rx() -= expansionOffset;
 +            if (textInfo->pos.x() < iconSize()) {
 +                textInfo->pos.rx() = iconSize();
 +            }
 +        }
          x += roleWidth;
  
          if (isTextRole) {
  
              // The column after the name should always be aligned on the same x-position independent
              // from the expansion-level shown in the name column
 -            x -= firstColumnInc;
 +            x -= firstColumnOffset - leadingPadding();
          } else if (isRoleRightAligned(role)) {
              textInfo->pos.rx() += roleWidth - requiredWidth - columnWidthInc;
          }
@@@ -1479,11 -1408,8 +1479,11 @@@ void KStandardItemListWidget::updateAdd
      QColor c1;
      if (m_customTextColor.isValid()) {
          c1 = m_customTextColor;
 -    } else if (isSelected() && m_layout != DetailsLayout) {
 -        c1 = styleOption().palette.highlightedText().color();
 +    } else if (isSelected()) {
 +        // 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.
 +        m_additionalInfoTextColor = styleOption().palette.color(QPalette::HighlightedText);
 +        return;
      } else {
          c1 = styleOption().palette.text().color();
      }
@@@ -1519,27 -1445,18 +1519,27 @@@ void KStandardItemListWidget::drawPixma
  void KStandardItemListWidget::drawSiblingsInformation(QPainter* painter)
  {
      const int siblingSize = size().height();
 -    const int x = (m_expansionArea.left() + m_expansionArea.right() - siblingSize) / 2;
 -    QRect siblingRect(x, 0, siblingSize, siblingSize);
 +    const int x = (m_expansionArea.width() - siblingSize) / 2;
 +
 +    const QHash<QByteArray, QVariant> values = data();
 +    const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
 +    const int expansionOffset = siblingSize * expandedParentsCount;
 +
 +    QRect siblingRect(
 +        layoutDirection() == Qt::LeftToRight
 +            ? x + expansionOffset
 +            : size().width() - x - siblingSize - expansionOffset, 0, siblingSize, siblingSize);
  
 -    QStyleOption option;
 -    option.palette.setColor(QPalette::Text, option.palette.color(normalTextColorRole()));
      bool isItemSibling = true;
  
      const QBitArray siblings = siblingsInformation();
 +    QStyleOption option;
 +    option.direction = layoutDirection();
 +    const auto normalColor = option.palette.color(normalTextColorRole());
 +    const auto highlightColor = option.palette.color(expansionAreaHovered() ? QPalette::Highlight : normalTextColorRole());
      for (int i = siblings.count() - 1; i >= 0; --i) {
          option.rect = siblingRect;
          option.state = siblings.at(i) ? QStyle::State_Sibling : QStyle::State_None;
 -
          if (isItemSibling) {
              option.state |= QStyle::State_Item;
              if (m_isExpandable) {
              if (data().value("isExpanded").toBool()) {
                  option.state |= QStyle::State_Open;
              }
 +            option.palette.setColor(QPalette::Text, highlightColor);
              isItemSibling = false;
 +        } else {
 +            option.palette.setColor(QPalette::Text, normalColor);
          }
  
          style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, painter);
  
 -        siblingRect.translate(-siblingRect.width(), 0);
 +        if (layoutDirection() == Qt::LeftToRight) {
 +            siblingRect.translate(-siblingRect.width(), 0);
 +        } else {
 +            siblingRect.translate(siblingRect.width(), 0);
 +        }
      }
  }