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
,
83 const QSet
<QByteArray
>& roles
)
86 if (roles
.isEmpty()) {
90 for (const QByteArray
& role
: roles
) {
91 m_data
[role
] = data
[role
];
93 dataChanged(m_data
, roles
);
98 QHash
<QByteArray
, QVariant
> KItemListWidget::data() const
103 void KItemListWidget::paint(QPainter
* painter
, const QStyleOptionGraphicsItem
* option
, QWidget
* widget
)
107 if (m_alternateBackground
) {
108 const QColor backgroundColor
= m_styleOption
.palette
.color(QPalette::AlternateBase
);
109 const QRectF
backgroundRect(0, 0, size().width(), size().height());
110 painter
->fillRect(backgroundRect
, backgroundColor
);
113 if (m_selected
&& m_editedRole
.isEmpty()) {
114 const QStyle::State
activeState(isActiveWindow() ? QStyle::State_Active
: 0);
115 drawItemStyleOption(painter
, widget
, activeState
|
116 QStyle::State_Enabled
|
117 QStyle::State_Selected
|
121 if (m_current
&& m_editedRole
.isEmpty()) {
122 QStyleOptionFocusRect focusRectOption
;
123 initStyleOption(&focusRectOption
);
124 focusRectOption
.rect
= textFocusRect().toRect();
125 focusRectOption
.state
= QStyle::State_Enabled
| QStyle::State_Item
| QStyle::State_KeyboardFocusChange
;
127 focusRectOption
.state
|= QStyle::State_Selected
;
130 style()->drawPrimitive(QStyle::PE_FrameFocusRect
, &focusRectOption
, painter
, widget
);
133 if (m_hoverOpacity
> 0.0) {
135 // Initialize the m_hoverCache pixmap to improve the drawing performance
136 // when fading the hover background
137 m_hoverCache
= new QPixmap(size().toSize());
138 m_hoverCache
->fill(Qt::transparent
);
140 QPainter
pixmapPainter(m_hoverCache
);
141 const QStyle::State
activeState(isActiveWindow() ? QStyle::State_Active
: 0);
142 drawItemStyleOption(&pixmapPainter
, widget
, activeState
|
143 QStyle::State_Enabled
|
144 QStyle::State_MouseOver
|
148 const qreal opacity
= painter
->opacity();
149 painter
->setOpacity(m_hoverOpacity
* opacity
);
150 painter
->drawPixmap(0, 0, *m_hoverCache
);
151 painter
->setOpacity(opacity
);
155 void KItemListWidget::setVisibleRoles(const QList
<QByteArray
>& roles
)
157 const QList
<QByteArray
> previousRoles
= m_visibleRoles
;
158 m_visibleRoles
= roles
;
160 visibleRolesChanged(roles
, previousRoles
);
164 QList
<QByteArray
> KItemListWidget::visibleRoles() const
166 return m_visibleRoles
;
170 void KItemListWidget::setColumnWidth(const QByteArray
& role
, qreal width
)
172 const qreal previousWidth
= m_columnWidths
.value(role
);
173 if (previousWidth
!= width
) {
174 m_columnWidths
.insert(role
, width
);
175 columnWidthChanged(role
, width
, previousWidth
);
180 qreal
KItemListWidget::columnWidth(const QByteArray
& role
) const
182 return m_columnWidths
.value(role
);
185 qreal
KItemListWidget::sidePadding() const {
186 return m_sidePadding
;
189 void KItemListWidget::setSidePadding(qreal width
) {
190 if (m_sidePadding
!= width
){
191 m_sidePadding
= width
;
192 sidePaddingChanged(width
);
197 void KItemListWidget::setStyleOption(const KItemListStyleOption
& option
)
199 if (m_styleOption
== option
) {
203 const KItemListStyleOption previous
= m_styleOption
;
205 m_styleOption
= option
;
206 styleOptionChanged(option
, previous
);
210 const KItemListStyleOption
& KItemListWidget::styleOption() const
212 return m_styleOption
;
215 void KItemListWidget::setSelected(bool selected
)
217 if (m_selected
!= selected
) {
218 m_selected
= selected
;
219 if (m_selectionToggle
) {
220 m_selectionToggle
->setChecked(selected
);
222 selectedChanged(selected
);
227 bool KItemListWidget::isSelected() const
232 void KItemListWidget::setCurrent(bool current
)
234 if (m_current
!= current
) {
236 currentChanged(current
);
241 bool KItemListWidget::isCurrent() const
246 void KItemListWidget::setHovered(bool hovered
)
248 if (hovered
== m_hovered
) {
254 if (!m_hoverAnimation
) {
255 m_hoverAnimation
= new QPropertyAnimation(this, "hoverOpacity", this);
256 const int duration
= style()->styleHint(QStyle::SH_Widget_Animate
) ? 200 : 1;
257 m_hoverAnimation
->setDuration(duration
);
258 connect(m_hoverAnimation
, &QPropertyAnimation::finished
, this, &KItemListWidget::slotHoverAnimationFinished
);
260 m_hoverAnimation
->stop();
262 m_hoverSequenceIndex
= 0;
265 const qreal startValue
= qMax(hoverOpacity(), qreal(0.1));
266 m_hoverAnimation
->setStartValue(startValue
);
267 m_hoverAnimation
->setEndValue(1.0);
268 if (m_enabledSelectionToggle
&& !(QApplication::mouseButtons() & Qt::LeftButton
)) {
269 initializeSelectionToggle();
272 hoverSequenceStarted();
274 const KConfigGroup
globalConfig(KSharedConfig::openConfig(), "PreviewSettings");
275 const int interval
= globalConfig
.readEntry("HoverSequenceInterval", 700);
277 m_hoverSequenceTimer
.start(interval
);
279 m_hoverAnimation
->setStartValue(hoverOpacity());
280 m_hoverAnimation
->setEndValue(0.0);
282 hoverSequenceEnded();
283 m_hoverSequenceTimer
.stop();
286 m_hoverAnimation
->start();
288 hoveredChanged(hovered
);
292 bool KItemListWidget::isHovered() const
297 void KItemListWidget::setExpansionAreaHovered(bool hovered
)
299 if (hovered
== m_expansionAreaHovered
) {
302 m_expansionAreaHovered
= hovered
;
306 bool KItemListWidget::expansionAreaHovered() const
308 return m_expansionAreaHovered
;
311 void KItemListWidget::setHoverPosition(const QPointF
& pos
)
313 if (m_selectionToggle
) {
314 m_selectionToggle
->setHovered(selectionToggleRect().contains(pos
));
318 void KItemListWidget::setAlternateBackground(bool enable
)
320 if (m_alternateBackground
!= enable
) {
321 m_alternateBackground
= enable
;
322 alternateBackgroundChanged(enable
);
327 bool KItemListWidget::alternateBackground() const
329 return m_alternateBackground
;
332 void KItemListWidget::setEnabledSelectionToggle(bool enable
)
334 if (m_enabledSelectionToggle
!= enable
) {
335 m_enabledSelectionToggle
= enable
;
337 // We want the change to take effect immediately.
338 if (m_enabledSelectionToggle
) {
340 initializeSelectionToggle();
342 } else if (m_selectionToggle
) {
343 m_selectionToggle
->deleteLater();
344 m_selectionToggle
= nullptr;
351 bool KItemListWidget::enabledSelectionToggle() const
353 return m_enabledSelectionToggle
;
356 void KItemListWidget::setSiblingsInformation(const QBitArray
& siblings
)
358 const QBitArray previous
= m_siblingsInfo
;
359 m_siblingsInfo
= siblings
;
360 siblingsInformationChanged(m_siblingsInfo
, previous
);
364 QBitArray
KItemListWidget::siblingsInformation() const
366 return m_siblingsInfo
;
369 void KItemListWidget::setEditedRole(const QByteArray
& role
)
371 if (m_editedRole
!= role
) {
372 const QByteArray previous
= m_editedRole
;
374 editedRoleChanged(role
, previous
);
378 QByteArray
KItemListWidget::editedRole() const
383 void KItemListWidget::setIconSize(int iconSize
)
385 if (m_iconSize
!= iconSize
) {
386 const int previousIconSize
= m_iconSize
;
387 m_iconSize
= iconSize
;
388 iconSizeChanged(iconSize
, previousIconSize
);
392 int KItemListWidget::iconSize() const
397 bool KItemListWidget::contains(const QPointF
& point
) const
399 if (!QGraphicsWidget::contains(point
)) {
403 return iconRect().contains(point
) ||
404 textRect().contains(point
) ||
405 expansionToggleRect().contains(point
) ||
406 selectionToggleRect().contains(point
);
409 QRectF
KItemListWidget::textFocusRect() const
414 QRectF
KItemListWidget::selectionToggleRect() const
419 QRectF
KItemListWidget::expansionToggleRect() const
424 QPixmap
KItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem
* option
,
427 QPixmap
pixmap(size().toSize() * widget
->devicePixelRatio());
428 pixmap
.setDevicePixelRatio(widget
->devicePixelRatio());
429 pixmap
.fill(Qt::transparent
);
431 QPainter
painter(&pixmap
);
433 const bool oldAlternateBackground
= m_alternateBackground
;
434 const bool wasSelected
= m_selected
;
435 const bool wasHovered
= m_hovered
;
437 setAlternateBackground(false);
440 paint(&painter
, option
, widget
);
442 setAlternateBackground(oldAlternateBackground
);
443 setSelected(wasSelected
);
444 setHovered(wasHovered
);
449 void KItemListWidget::dataChanged(const QHash
<QByteArray
, QVariant
>& current
,
450 const QSet
<QByteArray
>& roles
)
456 void KItemListWidget::visibleRolesChanged(const QList
<QByteArray
>& current
,
457 const QList
<QByteArray
>& previous
)
463 void KItemListWidget::columnWidthChanged(const QByteArray
& role
,
472 void KItemListWidget::sidePaddingChanged(qreal width
)
477 void KItemListWidget::styleOptionChanged(const KItemListStyleOption
& current
,
478 const KItemListStyleOption
& previous
)
482 // set the initial value of m_iconSize if not set
483 if (m_iconSize
== -1) {
484 m_iconSize
= current
.iconSize
;
488 void KItemListWidget::currentChanged(bool current
)
493 void KItemListWidget::selectedChanged(bool selected
)
498 void KItemListWidget::hoveredChanged(bool hovered
)
503 void KItemListWidget::alternateBackgroundChanged(bool enabled
)
508 void KItemListWidget::siblingsInformationChanged(const QBitArray
& current
, const QBitArray
& previous
)
514 void KItemListWidget::editedRoleChanged(const QByteArray
& current
, const QByteArray
& previous
)
520 void KItemListWidget::iconSizeChanged(int current
, int previous
)
526 void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent
* event
)
528 QGraphicsWidget::resizeEvent(event
);
531 if (m_selectionToggle
) {
532 const QRectF
& toggleRect
= selectionToggleRect();
533 m_selectionToggle
->setPos(toggleRect
.topLeft());
534 m_selectionToggle
->resize(toggleRect
.size());
538 void KItemListWidget::hoverSequenceStarted()
542 void KItemListWidget::hoverSequenceIndexChanged(int sequenceIndex
)
544 Q_UNUSED(sequenceIndex
);
547 void KItemListWidget::hoverSequenceEnded()
551 qreal
KItemListWidget::hoverOpacity() const
553 return m_hoverOpacity
;
556 int KItemListWidget::hoverSequenceIndex() const
558 return m_hoverSequenceIndex
;
561 void KItemListWidget::slotHoverAnimationFinished()
563 if (!m_hovered
&& m_selectionToggle
) {
564 m_selectionToggle
->deleteLater();
565 m_selectionToggle
= nullptr;
569 void KItemListWidget::slotHoverSequenceTimerTimeout()
571 m_hoverSequenceIndex
++;
572 hoverSequenceIndexChanged(m_hoverSequenceIndex
);
575 void KItemListWidget::initializeSelectionToggle()
577 Q_ASSERT(m_enabledSelectionToggle
);
579 if (!m_selectionToggle
) {
580 m_selectionToggle
= new KItemListSelectionToggle(this);
583 const QRectF toggleRect
= selectionToggleRect();
584 m_selectionToggle
->setPos(toggleRect
.topLeft());
585 m_selectionToggle
->resize(toggleRect
.size());
587 m_selectionToggle
->setChecked(isSelected());
590 void KItemListWidget::setHoverOpacity(qreal opacity
)
592 m_hoverOpacity
= opacity
;
593 if (m_selectionToggle
) {
594 m_selectionToggle
->setOpacity(opacity
);
597 if (m_hoverOpacity
<= 0.0) {
599 m_hoverCache
= nullptr;
605 void KItemListWidget::clearHoverCache()
608 m_hoverCache
= nullptr;
611 void KItemListWidget::drawItemStyleOption(QPainter
* painter
, QWidget
* widget
, QStyle::State styleState
)
613 QStyleOptionViewItem viewItemOption
;
614 initStyleOption(&viewItemOption
);
615 viewItemOption
.state
= styleState
;
616 viewItemOption
.viewItemPosition
= QStyleOptionViewItem::OnlyOne
;
617 viewItemOption
.showDecorationSelected
= true;
618 viewItemOption
.rect
= selectionRect().toRect();
619 style()->drawPrimitive(QStyle::PE_PanelItemViewItem
, &viewItemOption
, painter
, widget
);