2 * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com>
4 * Based on the Itemviews NG project from Trolltech Labs
6 * SPDX-License-Identifier: GPL-2.0-or-later
9 #include "kitemlistwidget.h"
11 #include "kitemlistview.h"
12 #include "private/kitemlistselectiontoggle.h"
14 #include <KConfigGroup>
15 #include <KSharedConfig>
17 #include <QApplication>
19 #include <QPropertyAnimation>
20 #include <QStyleOption>
22 KItemListWidgetInformant::KItemListWidgetInformant()
26 KItemListWidgetInformant::~KItemListWidgetInformant()
30 KItemListWidget::KItemListWidget(KItemListWidgetInformant
*informant
, QGraphicsItem
*parent
)
31 : QGraphicsWidget(parent
)
32 , m_informant(informant
)
37 , m_expansionAreaHovered(false)
38 , m_alternateBackground(false)
39 , m_enabledSelectionToggle(false)
46 , m_hoverCache(nullptr)
47 , m_hoverAnimation(nullptr)
48 , m_hoverSequenceIndex(0)
49 , m_selectionToggle(nullptr)
53 connect(&m_hoverSequenceTimer
, &QTimer::timeout
, this, &KItemListWidget::slotHoverSequenceTimerTimeout
);
56 KItemListWidget::~KItemListWidget()
61 void KItemListWidget::setIndex(int index
)
63 if (m_index
!= index
) {
64 delete m_selectionToggle
;
65 m_selectionToggle
= nullptr;
67 if (m_hoverAnimation
) {
68 m_hoverAnimation
->stop();
77 int KItemListWidget::index() const
82 void KItemListWidget::setData(const QHash
<QByteArray
, QVariant
> &data
, const QSet
<QByteArray
> &roles
)
85 if (roles
.isEmpty()) {
89 for (const QByteArray
&role
: roles
) {
90 m_data
[role
] = data
[role
];
92 dataChanged(m_data
, roles
);
97 QHash
<QByteArray
, QVariant
> KItemListWidget::data() const
102 void KItemListWidget::paint(QPainter
*painter
, const QStyleOptionGraphicsItem
*option
, QWidget
*widget
)
106 if (m_alternateBackground
) {
107 const QColor backgroundColor
= m_styleOption
.palette
.color(QPalette::AlternateBase
);
108 const QRectF
backgroundRect(0, 0, size().width(), size().height());
109 painter
->fillRect(backgroundRect
, backgroundColor
);
112 if (m_selected
&& m_editedRole
.isEmpty()) {
113 const QStyle::State
activeState(isActiveWindow() ? QStyle::State_Active
: 0);
114 drawItemStyleOption(painter
, widget
, activeState
| QStyle::State_Enabled
| QStyle::State_Selected
| QStyle::State_Item
);
117 if (m_current
&& m_editedRole
.isEmpty()) {
118 QStyleOptionFocusRect focusRectOption
;
119 initStyleOption(&focusRectOption
);
120 focusRectOption
.rect
= textFocusRect().toRect();
121 focusRectOption
.state
= QStyle::State_Enabled
| QStyle::State_Item
| QStyle::State_KeyboardFocusChange
;
123 focusRectOption
.state
|= QStyle::State_Selected
;
126 style()->drawPrimitive(QStyle::PE_FrameFocusRect
, &focusRectOption
, painter
, widget
);
129 if (m_hoverOpacity
> 0.0) {
131 // Initialize the m_hoverCache pixmap to improve the drawing performance
132 // when fading the hover background
133 m_hoverCache
= new QPixmap(size().toSize());
134 m_hoverCache
->fill(Qt::transparent
);
136 QPainter
pixmapPainter(m_hoverCache
);
137 const QStyle::State
activeState(isActiveWindow() ? QStyle::State_Active
: 0);
138 drawItemStyleOption(&pixmapPainter
, widget
, activeState
| QStyle::State_Enabled
| QStyle::State_MouseOver
| QStyle::State_Item
);
141 const qreal opacity
= painter
->opacity();
142 painter
->setOpacity(m_hoverOpacity
* opacity
);
143 painter
->drawPixmap(0, 0, *m_hoverCache
);
144 painter
->setOpacity(opacity
);
148 void KItemListWidget::setVisibleRoles(const QList
<QByteArray
> &roles
)
150 const QList
<QByteArray
> previousRoles
= m_visibleRoles
;
151 m_visibleRoles
= roles
;
153 visibleRolesChanged(roles
, previousRoles
);
157 QList
<QByteArray
> KItemListWidget::visibleRoles() const
159 return m_visibleRoles
;
162 void KItemListWidget::setColumnWidth(const QByteArray
&role
, qreal width
)
164 const qreal previousWidth
= m_columnWidths
.value(role
);
165 if (previousWidth
!= width
) {
166 m_columnWidths
.insert(role
, width
);
167 columnWidthChanged(role
, width
, previousWidth
);
172 qreal
KItemListWidget::columnWidth(const QByteArray
&role
) const
174 return m_columnWidths
.value(role
);
177 qreal
KItemListWidget::sidePadding() const
179 return m_sidePadding
;
182 void KItemListWidget::setSidePadding(qreal width
)
184 if (m_sidePadding
!= width
) {
185 m_sidePadding
= width
;
186 sidePaddingChanged(width
);
191 void KItemListWidget::setStyleOption(const KItemListStyleOption
&option
)
193 if (m_styleOption
== option
) {
197 const KItemListStyleOption previous
= m_styleOption
;
199 m_styleOption
= option
;
200 styleOptionChanged(option
, previous
);
204 const KItemListStyleOption
&KItemListWidget::styleOption() const
206 return m_styleOption
;
209 void KItemListWidget::setSelected(bool selected
)
211 if (m_selected
!= selected
) {
212 m_selected
= selected
;
213 if (m_selectionToggle
) {
214 m_selectionToggle
->setChecked(selected
);
216 selectedChanged(selected
);
221 bool KItemListWidget::isSelected() const
226 void KItemListWidget::setCurrent(bool current
)
228 if (m_current
!= current
) {
230 currentChanged(current
);
235 bool KItemListWidget::isCurrent() const
240 void KItemListWidget::setHovered(bool hovered
)
242 if (hovered
== m_hovered
) {
248 if (!m_hoverAnimation
) {
249 m_hoverAnimation
= new QPropertyAnimation(this, "hoverOpacity", this);
250 const int duration
= style()->styleHint(QStyle::SH_Widget_Animate
) ? 200 : 1;
251 m_hoverAnimation
->setDuration(duration
);
252 connect(m_hoverAnimation
, &QPropertyAnimation::finished
, this, &KItemListWidget::slotHoverAnimationFinished
);
254 m_hoverAnimation
->stop();
256 m_hoverSequenceIndex
= 0;
259 const qreal startValue
= qMax(hoverOpacity(), qreal(0.1));
260 m_hoverAnimation
->setStartValue(startValue
);
261 m_hoverAnimation
->setEndValue(1.0);
262 if (m_enabledSelectionToggle
&& !(QApplication::mouseButtons() & Qt::LeftButton
)) {
263 initializeSelectionToggle();
266 hoverSequenceStarted();
268 const KConfigGroup
globalConfig(KSharedConfig::openConfig(), "PreviewSettings");
269 const int interval
= globalConfig
.readEntry("HoverSequenceInterval", 700);
271 m_hoverSequenceTimer
.start(interval
);
273 m_hoverAnimation
->setStartValue(hoverOpacity());
274 m_hoverAnimation
->setEndValue(0.0);
276 hoverSequenceEnded();
277 m_hoverSequenceTimer
.stop();
280 m_hoverAnimation
->start();
282 hoveredChanged(hovered
);
286 bool KItemListWidget::isHovered() const
291 void KItemListWidget::setExpansionAreaHovered(bool hovered
)
293 if (hovered
== m_expansionAreaHovered
) {
296 m_expansionAreaHovered
= hovered
;
300 bool KItemListWidget::expansionAreaHovered() const
302 return m_expansionAreaHovered
;
305 void KItemListWidget::setHoverPosition(const QPointF
&pos
)
307 if (m_selectionToggle
) {
308 m_selectionToggle
->setHovered(selectionToggleRect().contains(pos
));
312 void KItemListWidget::setAlternateBackground(bool enable
)
314 if (m_alternateBackground
!= enable
) {
315 m_alternateBackground
= enable
;
316 alternateBackgroundChanged(enable
);
321 bool KItemListWidget::alternateBackground() const
323 return m_alternateBackground
;
326 void KItemListWidget::setEnabledSelectionToggle(bool enable
)
328 if (m_enabledSelectionToggle
!= enable
) {
329 m_enabledSelectionToggle
= enable
;
331 // We want the change to take effect immediately.
332 if (m_enabledSelectionToggle
) {
334 initializeSelectionToggle();
336 } else if (m_selectionToggle
) {
337 m_selectionToggle
->deleteLater();
338 m_selectionToggle
= nullptr;
345 bool KItemListWidget::enabledSelectionToggle() const
347 return m_enabledSelectionToggle
;
350 void KItemListWidget::setSiblingsInformation(const QBitArray
&siblings
)
352 const QBitArray previous
= m_siblingsInfo
;
353 m_siblingsInfo
= siblings
;
354 siblingsInformationChanged(m_siblingsInfo
, previous
);
358 QBitArray
KItemListWidget::siblingsInformation() const
360 return m_siblingsInfo
;
363 void KItemListWidget::setEditedRole(const QByteArray
&role
)
365 if (m_editedRole
!= role
) {
366 const QByteArray previous
= m_editedRole
;
368 editedRoleChanged(role
, previous
);
372 QByteArray
KItemListWidget::editedRole() const
377 void KItemListWidget::setIconSize(int iconSize
)
379 if (m_iconSize
!= iconSize
) {
380 const int previousIconSize
= m_iconSize
;
381 m_iconSize
= iconSize
;
382 iconSizeChanged(iconSize
, previousIconSize
);
386 int KItemListWidget::iconSize() const
391 bool KItemListWidget::contains(const QPointF
&point
) const
393 if (!QGraphicsWidget::contains(point
)) {
397 return iconRect().contains(point
) || textRect().contains(point
) || expansionToggleRect().contains(point
) || selectionToggleRect().contains(point
);
400 QRectF
KItemListWidget::textFocusRect() const
405 QRectF
KItemListWidget::selectionToggleRect() const
410 QRectF
KItemListWidget::expansionToggleRect() const
415 QPixmap
KItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem
*option
, QWidget
*widget
)
417 QPixmap
pixmap(size().toSize() * widget
->devicePixelRatio());
418 pixmap
.setDevicePixelRatio(widget
->devicePixelRatio());
419 pixmap
.fill(Qt::transparent
);
421 QPainter
painter(&pixmap
);
423 const bool oldAlternateBackground
= m_alternateBackground
;
424 const bool wasSelected
= m_selected
;
425 const bool wasHovered
= m_hovered
;
427 setAlternateBackground(false);
430 paint(&painter
, option
, widget
);
432 setAlternateBackground(oldAlternateBackground
);
433 setSelected(wasSelected
);
434 setHovered(wasHovered
);
439 void KItemListWidget::dataChanged(const QHash
<QByteArray
, QVariant
> ¤t
, const QSet
<QByteArray
> &roles
)
445 void KItemListWidget::visibleRolesChanged(const QList
<QByteArray
> ¤t
, const QList
<QByteArray
> &previous
)
451 void KItemListWidget::columnWidthChanged(const QByteArray
&role
, qreal current
, qreal previous
)
458 void KItemListWidget::sidePaddingChanged(qreal width
)
463 void KItemListWidget::styleOptionChanged(const KItemListStyleOption
¤t
, const KItemListStyleOption
&previous
)
467 // set the initial value of m_iconSize if not set
468 if (m_iconSize
== -1) {
469 m_iconSize
= current
.iconSize
;
473 void KItemListWidget::currentChanged(bool current
)
478 void KItemListWidget::selectedChanged(bool selected
)
483 void KItemListWidget::hoveredChanged(bool hovered
)
488 void KItemListWidget::alternateBackgroundChanged(bool enabled
)
493 void KItemListWidget::siblingsInformationChanged(const QBitArray
¤t
, const QBitArray
&previous
)
499 void KItemListWidget::editedRoleChanged(const QByteArray
¤t
, const QByteArray
&previous
)
505 void KItemListWidget::iconSizeChanged(int current
, int previous
)
511 void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent
*event
)
513 QGraphicsWidget::resizeEvent(event
);
516 if (m_selectionToggle
) {
517 const QRectF
&toggleRect
= selectionToggleRect();
518 m_selectionToggle
->setPos(toggleRect
.topLeft());
519 m_selectionToggle
->resize(toggleRect
.size());
523 void KItemListWidget::hoverSequenceStarted()
527 void KItemListWidget::hoverSequenceIndexChanged(int sequenceIndex
)
529 Q_UNUSED(sequenceIndex
);
532 void KItemListWidget::hoverSequenceEnded()
536 qreal
KItemListWidget::hoverOpacity() const
538 return m_hoverOpacity
;
541 int KItemListWidget::hoverSequenceIndex() const
543 return m_hoverSequenceIndex
;
546 void KItemListWidget::slotHoverAnimationFinished()
548 if (!m_hovered
&& m_selectionToggle
) {
549 m_selectionToggle
->deleteLater();
550 m_selectionToggle
= nullptr;
554 void KItemListWidget::slotHoverSequenceTimerTimeout()
556 m_hoverSequenceIndex
++;
557 hoverSequenceIndexChanged(m_hoverSequenceIndex
);
560 void KItemListWidget::initializeSelectionToggle()
562 Q_ASSERT(m_enabledSelectionToggle
);
564 if (!m_selectionToggle
) {
565 m_selectionToggle
= new KItemListSelectionToggle(this);
568 const QRectF toggleRect
= selectionToggleRect();
569 m_selectionToggle
->setPos(toggleRect
.topLeft());
570 m_selectionToggle
->resize(toggleRect
.size());
572 m_selectionToggle
->setChecked(isSelected());
575 void KItemListWidget::setHoverOpacity(qreal opacity
)
577 m_hoverOpacity
= opacity
;
578 if (m_selectionToggle
) {
579 m_selectionToggle
->setOpacity(opacity
);
582 if (m_hoverOpacity
<= 0.0) {
584 m_hoverCache
= nullptr;
590 void KItemListWidget::clearHoverCache()
593 m_hoverCache
= nullptr;
596 void KItemListWidget::drawItemStyleOption(QPainter
*painter
, QWidget
*widget
, QStyle::State styleState
)
598 QStyleOptionViewItem viewItemOption
;
599 initStyleOption(&viewItemOption
);
600 viewItemOption
.state
= styleState
;
601 viewItemOption
.viewItemPosition
= QStyleOptionViewItem::OnlyOne
;
602 viewItemOption
.showDecorationSelected
= true;
603 viewItemOption
.rect
= selectionRect().toRect();
604 style()->drawPrimitive(QStyle::PE_PanelItemViewItem
, &viewItemOption
, painter
, widget
);