From fdab593c01964ff4e5bf6c7cc093b802d0a1bbf7 Mon Sep 17 00:00:00 2001 From: Peter Penz Date: Mon, 2 Apr 2012 22:15:57 +0200 Subject: [PATCH] Fix focus-rectangle issues Assure that the focus-rectangle exactly matches to the bottom of the rendered text. BUG: 297203 BUG: 289804 FIXED-IN: 4.9.0 --- src/kitemviews/kfileitemlistwidget.cpp | 67 ++++++++++++++++---------- src/kitemviews/kfileitemlistwidget.h | 1 + src/kitemviews/kitemlistwidget.cpp | 19 +++----- src/kitemviews/kitemlistwidget.h | 9 ++++ 4 files changed, 59 insertions(+), 37 deletions(-) diff --git a/src/kitemviews/kfileitemlistwidget.cpp b/src/kitemviews/kfileitemlistwidget.cpp index 4511b3b37..80a3a3183 100644 --- a/src/kitemviews/kfileitemlistwidget.cpp +++ b/src/kitemviews/kfileitemlistwidget.cpp @@ -179,6 +179,24 @@ QRectF KFileItemListWidget::textRect() const return m_textRect; } +QRectF KFileItemListWidget::textFocusRect() const +{ + const_cast(this)->triggerCacheRefreshing(); + if (m_layout == CompactLayout) { + // In the compact layout a larger textRect() is returned to be aligned + // with the iconRect(). This is useful to have a larger selection/hover-area + // when having a quite large icon size but only one line of text. Still the + // focus rectangle should be shown as narrow as possible around the text. + QRectF rect = m_textRect; + const TextInfo* topText = m_textInfo.value(m_sortedVisibleRoles.first()); + const TextInfo* bottomText = m_textInfo.value(m_sortedVisibleRoles.last()); + rect.setTop(topText->pos.y()); + rect.setBottom(bottomText->pos.y() + bottomText->staticText.size().height()); + return rect; + } + return m_textRect; +} + QRectF KFileItemListWidget::expansionToggleRect() const { const_cast(this)->triggerCacheRefreshing(); @@ -233,27 +251,26 @@ QSizeF KFileItemListWidget::itemSizeHint(int index, const KItemListView* view) const QString text = KStringHandler::preProcessWrap(values["name"].toString()); const qreal maxWidth = view->itemSize().width() - 2 * option.padding; - int textLinesCount = 0; QTextLine line; // Calculate the number of lines required for wrapping the name QTextOption textOption(Qt::AlignHCenter); textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + qreal textHeight = 0; QTextLayout layout(text, option.font); layout.setTextOption(textOption); layout.beginLayout(); while ((line = layout.createLine()).isValid()) { line.setLineWidth(maxWidth); line.naturalTextWidth(); - ++textLinesCount; + textHeight += line.height(); } layout.endLayout(); // Add one line for each additional information - textLinesCount += additionalRolesCount; - - const qreal height = textLinesCount * option.fontMetrics.height() + + const qreal height = textHeight + + additionalRolesCount * option.fontMetrics.lineSpacing() + option.iconSize + option.padding * 3; return QSizeF(view->itemSize().width(), height); @@ -271,7 +288,7 @@ QSizeF KFileItemListWidget::itemSizeHint(int index, const KItemListView* view) } const qreal width = option.padding * 4 + option.iconSize + maximumRequiredWidth; - const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.height()); + const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.lineSpacing()); return QSizeF(width, height); } @@ -679,7 +696,7 @@ void KFileItemListWidget::updateIconsLayoutTextCache() const qreal padding = option.padding; const qreal maxWidth = size().width() - 2 * padding; const qreal widgetHeight = size().height(); - const qreal fontHeight = option.fontMetrics.height(); + const qreal lineSpacing = option.fontMetrics.lineSpacing(); // Initialize properties for the "name" role. It will be used as anchor // for initializing the position of the other roles. @@ -687,8 +704,8 @@ void KFileItemListWidget::updateIconsLayoutTextCache() nameTextInfo->staticText.setText(KStringHandler::preProcessWrap(values["name"].toString())); // Calculate the number of lines required for the name and the required width - int textLinesCountForName = 0; - qreal requiredWidthForName = 0; + qreal nameWidth = 0; + qreal nameHeight = 0; QTextLine line; QTextLayout layout(nameTextInfo->staticText.text(), option.font); @@ -696,25 +713,25 @@ void KFileItemListWidget::updateIconsLayoutTextCache() layout.beginLayout(); while ((line = layout.createLine()).isValid()) { line.setLineWidth(maxWidth); - requiredWidthForName = qMax(requiredWidthForName, line.naturalTextWidth()); - ++textLinesCountForName; + nameWidth = qMax(nameWidth, line.naturalTextWidth()); + nameHeight += line.height(); } layout.endLayout(); // Use one line for each additional information - int textLinesCount = textLinesCountForName; const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0); - textLinesCount += additionalRolesCount; - nameTextInfo->staticText.setTextWidth(maxWidth); - nameTextInfo->pos = QPointF(padding, widgetHeight - textLinesCount * fontHeight - padding); - m_textRect = QRectF(padding + (maxWidth - requiredWidthForName) / 2, + nameTextInfo->pos = QPointF(padding, widgetHeight - + nameHeight - + additionalRolesCount * lineSpacing - + padding); + m_textRect = QRectF(padding + (maxWidth - nameWidth) / 2, nameTextInfo->pos.y(), - requiredWidthForName, - textLinesCountForName * fontHeight); + nameWidth, + nameHeight); // Calculate the position for each additional information - qreal y = nameTextInfo->pos.y() + textLinesCountForName * fontHeight; + qreal y = nameTextInfo->pos.y() + nameHeight; foreach (const QByteArray& role, m_sortedVisibleRoles) { if (role == "name") { continue; @@ -747,10 +764,10 @@ void KFileItemListWidget::updateIconsLayoutTextCache() textInfo->pos = QPointF(padding, y); textInfo->staticText.setTextWidth(maxWidth); - const QRectF textRect(padding + (maxWidth - requiredWidth) / 2, y, requiredWidth, fontHeight); + const QRectF textRect(padding + (maxWidth - requiredWidth) / 2, y, requiredWidth, lineSpacing); m_textRect |= textRect; - y += fontHeight; + y += lineSpacing; } // Add a padding to the text rectangle @@ -767,13 +784,13 @@ void KFileItemListWidget::updateCompactLayoutTextCache() const KItemListStyleOption& option = styleOption(); const qreal widgetHeight = size().height(); - const qreal fontHeight = option.fontMetrics.height(); - const qreal textLinesHeight = qMax(visibleRoles().count(), 1) * fontHeight; + const qreal lineSpacing = option.fontMetrics.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; - qreal y = (widgetHeight - textLinesHeight) / 2; + qreal y = qRound((widgetHeight - textLinesHeight) / 2); const qreal maxWidth = size().width() - x - option.padding; foreach (const QByteArray& role, m_sortedVisibleRoles) { const QString text = roleText(role, values); @@ -792,7 +809,7 @@ void KFileItemListWidget::updateCompactLayoutTextCache() maximumRequiredTextWidth = qMax(maximumRequiredTextWidth, requiredWidth); - y += fontHeight; + y += lineSpacing; } m_textRect = QRectF(x - option.padding, 0, maximumRequiredTextWidth + 2 * option.padding, widgetHeight); diff --git a/src/kitemviews/kfileitemlistwidget.h b/src/kitemviews/kfileitemlistwidget.h index d68a22405..44451360b 100644 --- a/src/kitemviews/kfileitemlistwidget.h +++ b/src/kitemviews/kfileitemlistwidget.h @@ -56,6 +56,7 @@ public: virtual QRectF iconRect() const; virtual QRectF textRect() const; + virtual QRectF textFocusRect() const; virtual QRectF expansionToggleRect() const; virtual QRectF selectionToggleRect() const; diff --git a/src/kitemviews/kitemlistwidget.cpp b/src/kitemviews/kitemlistwidget.cpp index b91e87167..b812bcf9d 100644 --- a/src/kitemviews/kitemlistwidget.cpp +++ b/src/kitemviews/kitemlistwidget.cpp @@ -122,17 +122,7 @@ void KItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* o if (isCurrent()) { QStyleOptionFocusRect focusRectOption; focusRectOption.initFrom(widget); - - const QRect iconBounds = iconRect().toRect(); - const QRect textBounds = textRect().toRect(); - if (iconBounds.bottom() > textBounds.top()) { - focusRectOption.rect = textBounds; - } else { - // See KItemListWidget::drawItemStyleOption(): The selection rectangle - // gets decreased. - focusRectOption.rect = textBounds.adjusted(1, 1, -1, -1); - } - + focusRectOption.rect = textFocusRect().toRect(); focusRectOption.state = QStyle::State_Enabled | QStyle::State_Item | QStyle::State_KeyboardFocusChange; if (m_selected) { focusRectOption.state |= QStyle::State_Selected; @@ -330,6 +320,11 @@ bool KItemListWidget::contains(const QPointF& point) const selectionToggleRect().contains(point); } +QRectF KItemListWidget::textFocusRect() const +{ + return textRect(); +} + QRectF KItemListWidget::selectionToggleRect() const { return QRectF(); @@ -460,7 +455,7 @@ void KItemListWidget::drawItemStyleOption(QPainter* painter, QWidget* widget, QS viewItemOption.state = styleState; viewItemOption.viewItemPosition = QStyleOptionViewItemV4::OnlyOne; viewItemOption.showDecorationSelected = true; - viewItemOption.rect = textBounds.adjusted(1, 0, -1, 0); + viewItemOption.rect = textBounds; widget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewItemOption, painter, widget); } diff --git a/src/kitemviews/kitemlistwidget.h b/src/kitemviews/kitemlistwidget.h index 66d96d449..4c8ff1a95 100644 --- a/src/kitemviews/kitemlistwidget.h +++ b/src/kitemviews/kitemlistwidget.h @@ -120,6 +120,15 @@ public: */ virtual QRectF textRect() const = 0; + /** + * @return Focus rectangle for indicating the current item. Per default + * textRect() will be returned. Overwrite this method if textRect() + * provides a larger rectangle than the actual text (e.g. to + * be aligned with the iconRect()). The textFocusRect() may not be + * outside the boundaries of textRect(). + */ + virtual QRectF textFocusRect() const; + /** * @return Rectangle for the selection-toggle that is used to select or deselect an item. * Per default an empty rectangle is returned which means that no selection-toggle -- 2.47.3