X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/97415005de040885cb63ea01fdb879e20226a2f2..e57f6215659ee36877c7c36c9e3fcba0ba5d03a0:/src/kitemviews/kitemlistwidget.cpp diff --git a/src/kitemviews/kitemlistwidget.cpp b/src/kitemviews/kitemlistwidget.cpp index 65fc911bd..c06e46339 100644 --- a/src/kitemviews/kitemlistwidget.cpp +++ b/src/kitemviews/kitemlistwidget.cpp @@ -1,32 +1,18 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * Based on the Itemviews NG project from Trolltech Labs: * - * http://qt.gitorious.org/qt-labs/itemviews-ng * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ +/* + * SPDX-FileCopyrightText: 2011 Peter Penz + * + * Based on the Itemviews NG project from Trolltech Labs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ #include "kitemlistwidget.h" #include "kitemlistview.h" -#include "kitemmodelbase.h" - #include "private/kitemlistselectiontoggle.h" +#include +#include #include #include @@ -41,26 +27,32 @@ KItemListWidgetInformant::~KItemListWidgetInformant() { } -KItemListWidget::KItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent) : - QGraphicsWidget(parent, 0), - m_informant(informant), - m_index(-1), - m_selected(false), - m_current(false), - m_hovered(false), - m_alternateBackground(false), - m_enabledSelectionToggle(false), - m_data(), - m_visibleRoles(), - m_columnWidths(), - m_styleOption(), - m_siblingsInfo(), - m_hoverOpacity(0), - m_hoverCache(0), - m_hoverAnimation(0), - m_selectionToggle(0), - m_editedRole() -{ +KItemListWidget::KItemListWidget(KItemListWidgetInformant *informant, QGraphicsItem *parent) + : QGraphicsWidget(parent) + , m_informant(informant) + , m_index(-1) + , m_selected(false) + , m_current(false) + , m_hovered(false) + , m_expansionAreaHovered(false) + , m_alternateBackground(false) + , m_enabledSelectionToggle(false) + , m_clickHighlighted(false) + , m_data() + , m_visibleRoles() + , m_columnWidths() + , m_leftPadding(0) + , m_rightPadding(0) + , m_styleOption() + , m_siblingsInfo() + , m_hoverOpacity(0) + , m_hoverCache(nullptr) + , m_hoverSequenceIndex(0) + , m_selectionToggle(nullptr) + , m_editedRole() + , m_iconSize(-1) +{ + connect(&m_hoverSequenceTimer, &QTimer::timeout, this, &KItemListWidget::slotHoverSequenceTimerTimeout); } KItemListWidget::~KItemListWidget() @@ -72,12 +64,10 @@ void KItemListWidget::setIndex(int index) { if (m_index != index) { delete m_selectionToggle; - m_selectionToggle = 0; + m_selectionToggle = nullptr; + + m_hoverOpacity = 0; - if (m_hoverAnimation) { - m_hoverAnimation->stop(); - m_hoverOpacity = 0; - } clearHoverCache(); m_index = index; @@ -89,15 +79,14 @@ int KItemListWidget::index() const return m_index; } -void KItemListWidget::setData(const QHash& data, - const QSet& roles) +void KItemListWidget::setData(const QHash &data, const QSet &roles) { clearHoverCache(); if (roles.isEmpty()) { m_data = data; dataChanged(m_data); } else { - foreach (const QByteArray& role, roles) { + for (const QByteArray &role : roles) { m_data[role] = data[role]; } dataChanged(m_data, roles); @@ -110,34 +99,35 @@ QHash KItemListWidget::data() const return m_data; } -void KItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +QVariant KItemListWidget::value(const QByteArray &key) const +{ + return m_data.value(key); +} + +void KItemListWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { - Q_UNUSED(option); + Q_UNUSED(option) if (m_alternateBackground) { - const QColor backgroundColor = m_styleOption.palette.color(QPalette::AlternateBase); + QColor backgroundColor = m_styleOption.palette.color(QPalette::AlternateBase); + if (!widget->hasFocus()) { + QColor baseColor = m_styleOption.palette.color(QPalette::Base); + if (baseColor.lightnessF() > 0.5) { + // theme seems light + backgroundColor = backgroundColor.lighter(101); + } else { + // theme seems dark + backgroundColor = backgroundColor.darker(101); + } + } + const QRectF backgroundRect(0, 0, size().width(), size().height()); painter->fillRect(backgroundRect, backgroundColor); } - if (m_selected && m_editedRole.isEmpty()) { - const QStyle::State activeState(isActiveWindow() ? QStyle::State_Active : 0); - drawItemStyleOption(painter, widget, activeState | - QStyle::State_Enabled | - QStyle::State_Selected | - QStyle::State_Item); - } - - if (m_current && m_editedRole.isEmpty()) { - QStyleOptionFocusRect focusRectOption; - focusRectOption.initFrom(widget); - focusRectOption.rect = textFocusRect().toRect(); - focusRectOption.state = QStyle::State_Enabled | QStyle::State_Item | QStyle::State_KeyboardFocusChange; - if (m_selected) { - focusRectOption.state |= QStyle::State_Selected; - } - - style()->drawPrimitive(QStyle::PE_FrameFocusRect, &focusRectOption, painter, widget); + if ((m_selected || m_current) && m_editedRole.isEmpty()) { + const QStyle::State activeState(isActiveWindow() && widget->hasFocus() ? QStyle::State_Active : 0); + drawItemStyleOption(painter, widget, activeState | QStyle::State_Enabled | QStyle::State_Selected | QStyle::State_Item); } if (m_hoverOpacity > 0.0) { @@ -148,11 +138,8 @@ void KItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* o m_hoverCache->fill(Qt::transparent); QPainter pixmapPainter(m_hoverCache); - const QStyle::State activeState(isActiveWindow() ? QStyle::State_Active : 0); - drawItemStyleOption(&pixmapPainter, widget, activeState | - QStyle::State_Enabled | - QStyle::State_MouseOver | - QStyle::State_Item); + const QStyle::State activeState(isActiveWindow() && widget->hasFocus() ? QStyle::State_Active | QStyle::State_Enabled : 0); + drawItemStyleOption(&pixmapPainter, widget, activeState | QStyle::State_MouseOver | QStyle::State_Item); } const qreal opacity = painter->opacity(); @@ -162,7 +149,7 @@ void KItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* o } } -void KItemListWidget::setVisibleRoles(const QList& roles) +void KItemListWidget::setVisibleRoles(const QList &roles) { const QList previousRoles = m_visibleRoles; m_visibleRoles = roles; @@ -176,8 +163,7 @@ QList KItemListWidget::visibleRoles() const return m_visibleRoles; } - -void KItemListWidget::setColumnWidth(const QByteArray& role, qreal width) +void KItemListWidget::setColumnWidth(const QByteArray &role, qreal width) { const qreal previousWidth = m_columnWidths.value(role); if (previousWidth != width) { @@ -187,22 +173,56 @@ void KItemListWidget::setColumnWidth(const QByteArray& role, qreal width) } } -qreal KItemListWidget::columnWidth(const QByteArray& role) const +qreal KItemListWidget::columnWidth(const QByteArray &role) const { return m_columnWidths.value(role); } -void KItemListWidget::setStyleOption(const KItemListStyleOption& option) +void KItemListWidget::setSidePadding(qreal leftPaddingWidth, qreal rightPaddingWidth) { + bool changed = false; + if (m_leftPadding != leftPaddingWidth) { + m_leftPadding = leftPaddingWidth; + changed = true; + } + + if (m_rightPadding != rightPaddingWidth) { + m_rightPadding = rightPaddingWidth; + changed = true; + } + + if (!changed) { + return; + } + + sidePaddingChanged(leftPaddingWidth, rightPaddingWidth); + update(); +} + +qreal KItemListWidget::leftPadding() const +{ + return m_leftPadding; +} + +qreal KItemListWidget::rightPadding() const +{ + return m_rightPadding; +} + +void KItemListWidget::setStyleOption(const KItemListStyleOption &option) +{ + if (m_styleOption == option) { + return; + } + const KItemListStyleOption previous = m_styleOption; clearHoverCache(); m_styleOption = option; - styleOptionChanged(option, previous); update(); } -const KItemListStyleOption& KItemListWidget::styleOption() const +const KItemListStyleOption &KItemListWidget::styleOption() const { return m_styleOption; } @@ -246,27 +266,32 @@ void KItemListWidget::setHovered(bool hovered) 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(); + m_hoverSequenceIndex = 0; if (hovered) { - const qreal startValue = qMax(hoverOpacity(), qreal(0.1)); - m_hoverAnimation->setStartValue(startValue); - m_hoverAnimation->setEndValue(1.0); + setHoverOpacity(1.0); + if (m_enabledSelectionToggle && !(QApplication::mouseButtons() & Qt::LeftButton)) { initializeSelectionToggle(); } + + hoverSequenceStarted(); + + const KConfigGroup globalConfig(KSharedConfig::openConfig(), QStringLiteral("PreviewSettings")); + const int interval = globalConfig.readEntry("HoverSequenceInterval", 700); + + m_hoverSequenceTimer.start(interval); } else { - m_hoverAnimation->setStartValue(hoverOpacity()); - m_hoverAnimation->setEndValue(0.0); - } + setHoverOpacity(0.0); + + if (m_selectionToggle) { + m_selectionToggle->deleteLater(); + m_selectionToggle = nullptr; + } - m_hoverAnimation->start(); + hoverSequenceEnded(); + m_hoverSequenceTimer.stop(); + } hoveredChanged(hovered); update(); @@ -277,7 +302,21 @@ bool KItemListWidget::isHovered() const return m_hovered; } -void KItemListWidget::setHoverPosition(const QPointF& pos) +void KItemListWidget::setExpansionAreaHovered(bool hovered) +{ + if (hovered == m_expansionAreaHovered) { + return; + } + m_expansionAreaHovered = hovered; + update(); +} + +bool KItemListWidget::expansionAreaHovered() const +{ + return m_expansionAreaHovered; +} + +void KItemListWidget::setHoverPosition(const QPointF &pos) { if (m_selectionToggle) { m_selectionToggle->setHovered(selectionToggleRect().contains(pos)); @@ -302,6 +341,17 @@ void KItemListWidget::setEnabledSelectionToggle(bool enable) { if (m_enabledSelectionToggle != enable) { m_enabledSelectionToggle = enable; + + // We want the change to take effect immediately. + if (m_enabledSelectionToggle) { + if (m_hovered) { + initializeSelectionToggle(); + } + } else if (m_selectionToggle) { + m_selectionToggle->deleteLater(); + m_selectionToggle = nullptr; + } + update(); } } @@ -311,7 +361,7 @@ bool KItemListWidget::enabledSelectionToggle() const return m_enabledSelectionToggle; } -void KItemListWidget::setSiblingsInformation(const QBitArray& siblings) +void KItemListWidget::setSiblingsInformation(const QBitArray &siblings) { const QBitArray previous = m_siblingsInfo; m_siblingsInfo = siblings; @@ -324,7 +374,7 @@ QBitArray KItemListWidget::siblingsInformation() const return m_siblingsInfo; } -void KItemListWidget::setEditedRole(const QByteArray& role) +void KItemListWidget::setEditedRole(const QByteArray &role) { if (m_editedRole != role) { const QByteArray previous = m_editedRole; @@ -338,16 +388,27 @@ QByteArray KItemListWidget::editedRole() const return m_editedRole; } -bool KItemListWidget::contains(const QPointF& point) const +void KItemListWidget::setIconSize(int iconSize) +{ + if (m_iconSize != iconSize) { + const int previousIconSize = m_iconSize; + m_iconSize = iconSize; + iconSizeChanged(iconSize, previousIconSize); + } +} + +int KItemListWidget::iconSize() const +{ + return m_iconSize; +} + +bool KItemListWidget::contains(const QPointF &point) const { if (!QGraphicsWidget::contains(point)) { return false; } - return iconRect().contains(point) || - textRect().contains(point) || - expansionToggleRect().contains(point) || - selectionToggleRect().contains(point); + return selectionRectFull().contains(point) || expansionToggleRect().contains(point); } QRectF KItemListWidget::textFocusRect() const @@ -365,8 +426,7 @@ QRectF KItemListWidget::expansionToggleRect() const return QRectF(); } -QPixmap KItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem* option, - QWidget* widget) +QPixmap KItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem *option, QWidget *widget) { QPixmap pixmap(size().toSize() * widget->devicePixelRatio()); pixmap.setDevicePixelRatio(widget->devicePixelRatio()); @@ -379,7 +439,6 @@ QPixmap KItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem* option const bool wasHovered = m_hovered; setAlternateBackground(false); - setSelected(false); setHovered(false); paint(&painter, option, widget); @@ -391,91 +450,123 @@ QPixmap KItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem* option return pixmap; } -void KItemListWidget::dataChanged(const QHash& current, - const QSet& roles) +void KItemListWidget::startActivateSoonAnimation(int timeUntilActivation) { - Q_UNUSED(current); - Q_UNUSED(roles); + Q_UNUSED(timeUntilActivation) } -void KItemListWidget::visibleRolesChanged(const QList& current, - const QList& previous) +void KItemListWidget::dataChanged(const QHash ¤t, const QSet &roles) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(roles) } -void KItemListWidget::columnWidthChanged(const QByteArray& role, - qreal current, - qreal previous) +void KItemListWidget::visibleRolesChanged(const QList ¤t, const QList &previous) { - Q_UNUSED(role); - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) } -void KItemListWidget::styleOptionChanged(const KItemListStyleOption& current, - const KItemListStyleOption& previous) +void KItemListWidget::columnWidthChanged(const QByteArray &role, qreal current, qreal previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(role) + Q_UNUSED(current) + Q_UNUSED(previous) +} + +void KItemListWidget::sidePaddingChanged(qreal leftPaddingWidth, qreal rightPaddingWidth) +{ + Q_UNUSED(leftPaddingWidth) + Q_UNUSED(rightPaddingWidth) +} + +void KItemListWidget::styleOptionChanged(const KItemListStyleOption ¤t, const KItemListStyleOption &previous) +{ + Q_UNUSED(previous) + + // set the initial value of m_iconSize if not set + if (m_iconSize == -1) { + m_iconSize = current.iconSize; + } } void KItemListWidget::currentChanged(bool current) { - Q_UNUSED(current); + Q_UNUSED(current) } void KItemListWidget::selectedChanged(bool selected) { - Q_UNUSED(selected); + Q_UNUSED(selected) } void KItemListWidget::hoveredChanged(bool hovered) { - Q_UNUSED(hovered); + Q_UNUSED(hovered) } void KItemListWidget::alternateBackgroundChanged(bool enabled) { - Q_UNUSED(enabled); + Q_UNUSED(enabled) +} + +void KItemListWidget::siblingsInformationChanged(const QBitArray ¤t, const QBitArray &previous) +{ + Q_UNUSED(current) + Q_UNUSED(previous) } -void KItemListWidget::siblingsInformationChanged(const QBitArray& current, const QBitArray& previous) +void KItemListWidget::editedRoleChanged(const QByteArray ¤t, const QByteArray &previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) } -void KItemListWidget::editedRoleChanged(const QByteArray& current, const QByteArray& previous) +void KItemListWidget::iconSizeChanged(int current, int previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) } -void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event) +void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent *event) { QGraphicsWidget::resizeEvent(event); clearHoverCache(); if (m_selectionToggle) { - const QRectF& toggleRect = selectionToggleRect(); + const QRectF &toggleRect = selectionToggleRect(); m_selectionToggle->setPos(toggleRect.topLeft()); m_selectionToggle->resize(toggleRect.size()); } } +void KItemListWidget::hoverSequenceStarted() +{ +} + +void KItemListWidget::hoverSequenceIndexChanged(int sequenceIndex) +{ + Q_UNUSED(sequenceIndex); +} + +void KItemListWidget::hoverSequenceEnded() +{ +} + qreal KItemListWidget::hoverOpacity() const { return m_hoverOpacity; } -void KItemListWidget::slotHoverAnimationFinished() +int KItemListWidget::hoverSequenceIndex() const { - if (!m_hovered && m_selectionToggle) { - m_selectionToggle->deleteLater(); - m_selectionToggle = 0; - } + return m_hoverSequenceIndex; +} + +void KItemListWidget::slotHoverSequenceTimerTimeout() +{ + m_hoverSequenceIndex++; + hoverSequenceIndexChanged(m_hoverSequenceIndex); } void KItemListWidget::initializeSelectionToggle() @@ -502,7 +593,7 @@ void KItemListWidget::setHoverOpacity(qreal opacity) if (m_hoverOpacity <= 0.0) { delete m_hoverCache; - m_hoverCache = 0; + m_hoverCache = nullptr; } update(); @@ -511,17 +602,69 @@ void KItemListWidget::setHoverOpacity(qreal opacity) void KItemListWidget::clearHoverCache() { delete m_hoverCache; - m_hoverCache = 0; + m_hoverCache = nullptr; } -void KItemListWidget::drawItemStyleOption(QPainter* painter, QWidget* widget, QStyle::State styleState) +bool KItemListWidget::isPressed() const +{ + return m_clickHighlighted; +} + +void KItemListWidget::setPressed(bool enabled) +{ + if (m_clickHighlighted != enabled) { + m_clickHighlighted = enabled; + clearHoverCache(); + update(); + } +} + +void KItemListWidget::drawItemStyleOption(QPainter *painter, QWidget *widget, QStyle::State styleState) { QStyleOptionViewItem viewItemOption; - viewItemOption.initFrom(widget); + constexpr int roundness = 5; // From Breeze style. + constexpr qreal penWidth = 1.5; + initStyleOption(&viewItemOption); viewItemOption.state = styleState; viewItemOption.viewItemPosition = QStyleOptionViewItem::OnlyOne; viewItemOption.showDecorationSelected = true; - viewItemOption.rect = selectionRect().toRect(); - widget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewItemOption, painter, widget); + viewItemOption.rect = selectionRectFull().toRect(); + QPainterPath path; + path.addRoundedRect(selectionRectFull().adjusted(penWidth, penWidth, -penWidth, -penWidth), roundness, roundness); + QColor backgroundColor{widget->palette().color(QPalette::Accent)}; + painter->setRenderHint(QPainter::Antialiasing); + bool current = m_current && styleState & QStyle::State_Active; + + // Background item, alpha values are from + // https://invent.kde.org/plasma/libplasma/-/blob/master/src/desktoptheme/breeze/widgets/viewitem.svg + backgroundColor.setAlphaF(0.0); + + if (m_clickHighlighted) { + backgroundColor.setAlphaF(1.0); + } else { + if (m_selected && m_hovered) { + backgroundColor.setAlphaF(0.40); + } else if (m_selected) { + backgroundColor.setAlphaF(0.32); + } else if (m_hovered) { + backgroundColor = widget->palette().color(QPalette::Text); + backgroundColor.setAlphaF(0.06); + } + } + + painter->fillPath(path, backgroundColor); + + // Focus decoration + if (current) { + QColor focusColor{widget->palette().color(QPalette::Accent)}; + focusColor = m_styleOption.palette.color(QPalette::Base).lightnessF() > 0.5 ? focusColor.darker(110) : focusColor.lighter(110); + focusColor.setAlphaF(m_selected || m_hovered ? 0.8 : 0.6); + // Set the pen color lighter or darker depending on background color + QPen pen{focusColor, penWidth}; + pen.setCosmetic(true); + painter->setPen(pen); + painter->drawPath(path); + } } +#include "moc_kitemlistwidget.cpp"