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),
52 connect(&m_hoverSequenceTimer
, &QTimer::timeout
, this, &KItemListWidget::slotHoverSequenceTimerTimeout
);
55 KItemListWidget::~KItemListWidget()
60 void KItemListWidget::setIndex(int index
)
62 if (m_index
!= index
) {
63 delete m_selectionToggle
;
64 m_selectionToggle
= nullptr;
66 if (m_hoverAnimation
) {
67 m_hoverAnimation
->stop();
76 int KItemListWidget::index() const
81 void KItemListWidget::setData(const QHash
<QByteArray
, QVariant
>& data
,
82 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
|
115 QStyle::State_Enabled
|
116 QStyle::State_Selected
|
120 if (m_current
&& m_editedRole
.isEmpty()) {
121 QStyleOptionFocusRect focusRectOption
;
122 initStyleOption(&focusRectOption
);
123 focusRectOption
.rect
= textFocusRect().toRect();
124 focusRectOption
.state
= QStyle::State_Enabled
| QStyle::State_Item
| QStyle::State_KeyboardFocusChange
;
126 focusRectOption
.state
|= QStyle::State_Selected
;
129 style()->drawPrimitive(QStyle::PE_FrameFocusRect
, &focusRectOption
, painter
, widget
);
132 if (m_hoverOpacity
> 0.0) {
134 // Initialize the m_hoverCache pixmap to improve the drawing performance
135 // when fading the hover background
136 m_hoverCache
= new QPixmap(size().toSize());
137 m_hoverCache
->fill(Qt::transparent
);
139 QPainter
pixmapPainter(m_hoverCache
);
140 const QStyle::State
activeState(isActiveWindow() ? QStyle::State_Active
: 0);
141 drawItemStyleOption(&pixmapPainter
, widget
, activeState
|
142 QStyle::State_Enabled
|
143 QStyle::State_MouseOver
|
147 const qreal opacity
= painter
->opacity();
148 painter
->setOpacity(m_hoverOpacity
* opacity
);
149 painter
->drawPixmap(0, 0, *m_hoverCache
);
150 painter
->setOpacity(opacity
);
154 void KItemListWidget::setVisibleRoles(const QList
<QByteArray
>& roles
)
156 const QList
<QByteArray
> previousRoles
= m_visibleRoles
;
157 m_visibleRoles
= roles
;
159 visibleRolesChanged(roles
, previousRoles
);
163 QList
<QByteArray
> KItemListWidget::visibleRoles() const
165 return m_visibleRoles
;
169 void KItemListWidget::setColumnWidth(const QByteArray
& role
, qreal width
)
171 const qreal previousWidth
= m_columnWidths
.value(role
);
172 if (previousWidth
!= width
) {
173 m_columnWidths
.insert(role
, width
);
174 columnWidthChanged(role
, width
, previousWidth
);
179 qreal
KItemListWidget::columnWidth(const QByteArray
& role
) const
181 return m_columnWidths
.value(role
);
184 qreal
KItemListWidget::leadingPadding() const {
185 return m_leadingPadding
;
188 void KItemListWidget::setLeadingPadding(qreal width
) {
189 if (m_leadingPadding
!= width
){
190 m_leadingPadding
= width
;
191 leadingPaddingChanged(width
);
196 void KItemListWidget::setStyleOption(const KItemListStyleOption
& option
)
198 if (m_styleOption
== option
) {
202 const KItemListStyleOption previous
= m_styleOption
;
204 m_styleOption
= option
;
205 styleOptionChanged(option
, previous
);
209 const KItemListStyleOption
& KItemListWidget::styleOption() const
211 return m_styleOption
;
214 void KItemListWidget::setSelected(bool selected
)
216 if (m_selected
!= selected
) {
217 m_selected
= selected
;
218 if (m_selectionToggle
) {
219 m_selectionToggle
->setChecked(selected
);
221 selectedChanged(selected
);
226 bool KItemListWidget::isSelected() const
231 void KItemListWidget::setCurrent(bool current
)
233 if (m_current
!= current
) {
235 currentChanged(current
);
240 bool KItemListWidget::isCurrent() const
245 void KItemListWidget::setHovered(bool hovered
)
247 if (hovered
== m_hovered
) {
253 if (!m_hoverAnimation
) {
254 m_hoverAnimation
= new QPropertyAnimation(this, "hoverOpacity", this);
255 const int duration
= style()->styleHint(QStyle::SH_Widget_Animate
) ? 200 : 1;
256 m_hoverAnimation
->setDuration(duration
);
257 connect(m_hoverAnimation
, &QPropertyAnimation::finished
, this, &KItemListWidget::slotHoverAnimationFinished
);
259 m_hoverAnimation
->stop();
261 m_hoverSequenceIndex
= 0;
264 const qreal startValue
= qMax(hoverOpacity(), qreal(0.1));
265 m_hoverAnimation
->setStartValue(startValue
);
266 m_hoverAnimation
->setEndValue(1.0);
267 if (m_enabledSelectionToggle
&& !(QApplication::mouseButtons() & Qt::LeftButton
)) {
268 initializeSelectionToggle();
271 hoverSequenceStarted();
273 const KConfigGroup
globalConfig(KSharedConfig::openConfig(), "PreviewSettings");
274 const int interval
= globalConfig
.readEntry("HoverSequenceInterval", 700);
276 m_hoverSequenceTimer
.start(interval
);
278 m_hoverAnimation
->setStartValue(hoverOpacity());
279 m_hoverAnimation
->setEndValue(0.0);
281 hoverSequenceEnded();
282 m_hoverSequenceTimer
.stop();
285 m_hoverAnimation
->start();
287 hoveredChanged(hovered
);
291 bool KItemListWidget::isHovered() const
296 void KItemListWidget::setExpansionAreaHovered(bool hovered
)
298 if (hovered
== m_expansionAreaHovered
) {
301 m_expansionAreaHovered
= hovered
;
305 bool KItemListWidget::expansionAreaHovered() const
307 return m_expansionAreaHovered
;
310 void KItemListWidget::setHoverPosition(const QPointF
& pos
)
312 if (m_selectionToggle
) {
313 m_selectionToggle
->setHovered(selectionToggleRect().contains(pos
));
317 void KItemListWidget::setAlternateBackground(bool enable
)
319 if (m_alternateBackground
!= enable
) {
320 m_alternateBackground
= enable
;
321 alternateBackgroundChanged(enable
);
326 bool KItemListWidget::alternateBackground() const
328 return m_alternateBackground
;
331 void KItemListWidget::setEnabledSelectionToggle(bool enable
)
333 if (m_enabledSelectionToggle
!= enable
) {
334 m_enabledSelectionToggle
= enable
;
339 bool KItemListWidget::enabledSelectionToggle() const
341 return m_enabledSelectionToggle
;
344 void KItemListWidget::setSiblingsInformation(const QBitArray
& siblings
)
346 const QBitArray previous
= m_siblingsInfo
;
347 m_siblingsInfo
= siblings
;
348 siblingsInformationChanged(m_siblingsInfo
, previous
);
352 QBitArray
KItemListWidget::siblingsInformation() const
354 return m_siblingsInfo
;
357 void KItemListWidget::setEditedRole(const QByteArray
& role
)
359 if (m_editedRole
!= role
) {
360 const QByteArray previous
= m_editedRole
;
362 editedRoleChanged(role
, previous
);
366 QByteArray
KItemListWidget::editedRole() const
371 bool KItemListWidget::contains(const QPointF
& point
) const
373 if (!QGraphicsWidget::contains(point
)) {
377 return iconRect().contains(point
) ||
378 textRect().contains(point
) ||
379 expansionToggleRect().contains(point
) ||
380 selectionToggleRect().contains(point
);
383 QRectF
KItemListWidget::textFocusRect() const
388 QRectF
KItemListWidget::selectionToggleRect() const
393 QRectF
KItemListWidget::expansionToggleRect() const
398 QPixmap
KItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem
* option
,
401 QPixmap
pixmap(size().toSize() * widget
->devicePixelRatio());
402 pixmap
.setDevicePixelRatio(widget
->devicePixelRatio());
403 pixmap
.fill(Qt::transparent
);
405 QPainter
painter(&pixmap
);
407 const bool oldAlternateBackground
= m_alternateBackground
;
408 const bool wasSelected
= m_selected
;
409 const bool wasHovered
= m_hovered
;
411 setAlternateBackground(false);
414 paint(&painter
, option
, widget
);
416 setAlternateBackground(oldAlternateBackground
);
417 setSelected(wasSelected
);
418 setHovered(wasHovered
);
423 void KItemListWidget::dataChanged(const QHash
<QByteArray
, QVariant
>& current
,
424 const QSet
<QByteArray
>& roles
)
430 void KItemListWidget::visibleRolesChanged(const QList
<QByteArray
>& current
,
431 const QList
<QByteArray
>& previous
)
437 void KItemListWidget::columnWidthChanged(const QByteArray
& role
,
446 void KItemListWidget::leadingPaddingChanged(qreal width
)
451 void KItemListWidget::styleOptionChanged(const KItemListStyleOption
& current
,
452 const KItemListStyleOption
& previous
)
458 void KItemListWidget::currentChanged(bool current
)
463 void KItemListWidget::selectedChanged(bool selected
)
468 void KItemListWidget::hoveredChanged(bool hovered
)
473 void KItemListWidget::alternateBackgroundChanged(bool enabled
)
478 void KItemListWidget::siblingsInformationChanged(const QBitArray
& current
, const QBitArray
& previous
)
484 void KItemListWidget::editedRoleChanged(const QByteArray
& current
, const QByteArray
& previous
)
490 void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent
* event
)
492 QGraphicsWidget::resizeEvent(event
);
495 if (m_selectionToggle
) {
496 const QRectF
& toggleRect
= selectionToggleRect();
497 m_selectionToggle
->setPos(toggleRect
.topLeft());
498 m_selectionToggle
->resize(toggleRect
.size());
502 void KItemListWidget::hoverSequenceStarted()
506 void KItemListWidget::hoverSequenceIndexChanged(int sequenceIndex
)
508 Q_UNUSED(sequenceIndex
);
511 void KItemListWidget::hoverSequenceEnded()
515 qreal
KItemListWidget::hoverOpacity() const
517 return m_hoverOpacity
;
520 int KItemListWidget::hoverSequenceIndex() const
522 return m_hoverSequenceIndex
;
525 void KItemListWidget::slotHoverAnimationFinished()
527 if (!m_hovered
&& m_selectionToggle
) {
528 m_selectionToggle
->deleteLater();
529 m_selectionToggle
= nullptr;
533 void KItemListWidget::slotHoverSequenceTimerTimeout()
535 m_hoverSequenceIndex
++;
536 hoverSequenceIndexChanged(m_hoverSequenceIndex
);
539 void KItemListWidget::initializeSelectionToggle()
541 Q_ASSERT(m_enabledSelectionToggle
);
543 if (!m_selectionToggle
) {
544 m_selectionToggle
= new KItemListSelectionToggle(this);
547 const QRectF toggleRect
= selectionToggleRect();
548 m_selectionToggle
->setPos(toggleRect
.topLeft());
549 m_selectionToggle
->resize(toggleRect
.size());
551 m_selectionToggle
->setChecked(isSelected());
554 void KItemListWidget::setHoverOpacity(qreal opacity
)
556 m_hoverOpacity
= opacity
;
557 if (m_selectionToggle
) {
558 m_selectionToggle
->setOpacity(opacity
);
561 if (m_hoverOpacity
<= 0.0) {
563 m_hoverCache
= nullptr;
569 void KItemListWidget::clearHoverCache()
572 m_hoverCache
= nullptr;
575 void KItemListWidget::drawItemStyleOption(QPainter
* painter
, QWidget
* widget
, QStyle::State styleState
)
577 QStyleOptionViewItem viewItemOption
;
578 initStyleOption(&viewItemOption
);
579 viewItemOption
.state
= styleState
;
580 viewItemOption
.viewItemPosition
= QStyleOptionViewItem::OnlyOne
;
581 viewItemOption
.showDecorationSelected
= true;
582 viewItemOption
.rect
= selectionRect().toRect();
583 style()->drawPrimitive(QStyle::PE_PanelItemViewItem
, &viewItemOption
, painter
, widget
);