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 <QApplication>
16 #include <QPropertyAnimation>
17 #include <QStyleOption>
19 KItemListWidgetInformant::KItemListWidgetInformant()
23 KItemListWidgetInformant::~KItemListWidgetInformant()
27 KItemListWidget::KItemListWidget(KItemListWidgetInformant
* informant
, QGraphicsItem
* parent
) :
28 QGraphicsWidget(parent
),
29 m_informant(informant
),
34 m_alternateBackground(false),
35 m_enabledSelectionToggle(false),
42 m_hoverCache(nullptr),
43 m_hoverAnimation(nullptr),
44 m_selectionToggle(nullptr),
49 KItemListWidget::~KItemListWidget()
54 void KItemListWidget::setIndex(int index
)
56 if (m_index
!= index
) {
57 delete m_selectionToggle
;
58 m_selectionToggle
= nullptr;
60 if (m_hoverAnimation
) {
61 m_hoverAnimation
->stop();
70 int KItemListWidget::index() const
75 void KItemListWidget::setData(const QHash
<QByteArray
, QVariant
>& data
,
76 const QSet
<QByteArray
>& roles
)
79 if (roles
.isEmpty()) {
83 foreach (const QByteArray
& role
, roles
) {
84 m_data
[role
] = data
[role
];
86 dataChanged(m_data
, roles
);
91 QHash
<QByteArray
, QVariant
> KItemListWidget::data() const
96 void KItemListWidget::paint(QPainter
* painter
, const QStyleOptionGraphicsItem
* option
, QWidget
* widget
)
100 if (m_alternateBackground
) {
101 const QColor backgroundColor
= m_styleOption
.palette
.color(QPalette::AlternateBase
);
102 const QRectF
backgroundRect(0, 0, size().width(), size().height());
103 painter
->fillRect(backgroundRect
, backgroundColor
);
106 if (m_selected
&& m_editedRole
.isEmpty()) {
107 const QStyle::State
activeState(isActiveWindow() ? QStyle::State_Active
: 0);
108 drawItemStyleOption(painter
, widget
, activeState
|
109 QStyle::State_Enabled
|
110 QStyle::State_Selected
|
114 if (m_current
&& m_editedRole
.isEmpty()) {
115 QStyleOptionFocusRect focusRectOption
;
116 initStyleOption(&focusRectOption
);
117 focusRectOption
.rect
= textFocusRect().toRect();
118 focusRectOption
.state
= QStyle::State_Enabled
| QStyle::State_Item
| QStyle::State_KeyboardFocusChange
;
120 focusRectOption
.state
|= QStyle::State_Selected
;
123 style()->drawPrimitive(QStyle::PE_FrameFocusRect
, &focusRectOption
, painter
, widget
);
126 if (m_hoverOpacity
> 0.0) {
128 // Initialize the m_hoverCache pixmap to improve the drawing performance
129 // when fading the hover background
130 m_hoverCache
= new QPixmap(size().toSize());
131 m_hoverCache
->fill(Qt::transparent
);
133 QPainter
pixmapPainter(m_hoverCache
);
134 const QStyle::State
activeState(isActiveWindow() ? QStyle::State_Active
: 0);
135 drawItemStyleOption(&pixmapPainter
, widget
, activeState
|
136 QStyle::State_Enabled
|
137 QStyle::State_MouseOver
|
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
;
163 void KItemListWidget::setColumnWidth(const QByteArray
& role
, qreal width
)
165 const qreal previousWidth
= m_columnWidths
.value(role
);
166 if (previousWidth
!= width
) {
167 m_columnWidths
.insert(role
, width
);
168 columnWidthChanged(role
, width
, previousWidth
);
173 qreal
KItemListWidget::columnWidth(const QByteArray
& role
) const
175 return m_columnWidths
.value(role
);
178 void KItemListWidget::setStyleOption(const KItemListStyleOption
& option
)
180 if (m_styleOption
== option
) {
184 const KItemListStyleOption previous
= m_styleOption
;
186 m_styleOption
= option
;
187 styleOptionChanged(option
, previous
);
191 const KItemListStyleOption
& KItemListWidget::styleOption() const
193 return m_styleOption
;
196 void KItemListWidget::setSelected(bool selected
)
198 if (m_selected
!= selected
) {
199 m_selected
= selected
;
200 if (m_selectionToggle
) {
201 m_selectionToggle
->setChecked(selected
);
203 selectedChanged(selected
);
208 bool KItemListWidget::isSelected() const
213 void KItemListWidget::setCurrent(bool current
)
215 if (m_current
!= current
) {
217 currentChanged(current
);
222 bool KItemListWidget::isCurrent() const
227 void KItemListWidget::setHovered(bool hovered
)
229 if (hovered
== m_hovered
) {
235 if (!m_hoverAnimation
) {
236 m_hoverAnimation
= new QPropertyAnimation(this, "hoverOpacity", this);
237 const int duration
= style()->styleHint(QStyle::SH_Widget_Animate
) ? 200 : 1;
238 m_hoverAnimation
->setDuration(duration
);
239 connect(m_hoverAnimation
, &QPropertyAnimation::finished
, this, &KItemListWidget::slotHoverAnimationFinished
);
241 m_hoverAnimation
->stop();
244 const qreal startValue
= qMax(hoverOpacity(), qreal(0.1));
245 m_hoverAnimation
->setStartValue(startValue
);
246 m_hoverAnimation
->setEndValue(1.0);
247 if (m_enabledSelectionToggle
&& !(QApplication::mouseButtons() & Qt::LeftButton
)) {
248 initializeSelectionToggle();
251 m_hoverAnimation
->setStartValue(hoverOpacity());
252 m_hoverAnimation
->setEndValue(0.0);
255 m_hoverAnimation
->start();
257 hoveredChanged(hovered
);
261 bool KItemListWidget::isHovered() const
266 void KItemListWidget::setHoverPosition(const QPointF
& pos
)
268 if (m_selectionToggle
) {
269 m_selectionToggle
->setHovered(selectionToggleRect().contains(pos
));
273 void KItemListWidget::setAlternateBackground(bool enable
)
275 if (m_alternateBackground
!= enable
) {
276 m_alternateBackground
= enable
;
277 alternateBackgroundChanged(enable
);
282 bool KItemListWidget::alternateBackground() const
284 return m_alternateBackground
;
287 void KItemListWidget::setEnabledSelectionToggle(bool enable
)
289 if (m_enabledSelectionToggle
!= enable
) {
290 m_enabledSelectionToggle
= enable
;
295 bool KItemListWidget::enabledSelectionToggle() const
297 return m_enabledSelectionToggle
;
300 void KItemListWidget::setSiblingsInformation(const QBitArray
& siblings
)
302 const QBitArray previous
= m_siblingsInfo
;
303 m_siblingsInfo
= siblings
;
304 siblingsInformationChanged(m_siblingsInfo
, previous
);
308 QBitArray
KItemListWidget::siblingsInformation() const
310 return m_siblingsInfo
;
313 void KItemListWidget::setEditedRole(const QByteArray
& role
)
315 if (m_editedRole
!= role
) {
316 const QByteArray previous
= m_editedRole
;
318 editedRoleChanged(role
, previous
);
322 QByteArray
KItemListWidget::editedRole() const
327 bool KItemListWidget::contains(const QPointF
& point
) const
329 if (!QGraphicsWidget::contains(point
)) {
333 return iconRect().contains(point
) ||
334 textRect().contains(point
) ||
335 expansionToggleRect().contains(point
) ||
336 selectionToggleRect().contains(point
);
339 QRectF
KItemListWidget::textFocusRect() const
344 QRectF
KItemListWidget::selectionToggleRect() const
349 QRectF
KItemListWidget::expansionToggleRect() const
354 QPixmap
KItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem
* option
,
357 QPixmap
pixmap(size().toSize() * widget
->devicePixelRatio());
358 pixmap
.setDevicePixelRatio(widget
->devicePixelRatio());
359 pixmap
.fill(Qt::transparent
);
361 QPainter
painter(&pixmap
);
363 const bool oldAlternateBackground
= m_alternateBackground
;
364 const bool wasSelected
= m_selected
;
365 const bool wasHovered
= m_hovered
;
367 setAlternateBackground(false);
370 paint(&painter
, option
, widget
);
372 setAlternateBackground(oldAlternateBackground
);
373 setSelected(wasSelected
);
374 setHovered(wasHovered
);
379 void KItemListWidget::dataChanged(const QHash
<QByteArray
, QVariant
>& current
,
380 const QSet
<QByteArray
>& roles
)
386 void KItemListWidget::visibleRolesChanged(const QList
<QByteArray
>& current
,
387 const QList
<QByteArray
>& previous
)
393 void KItemListWidget::columnWidthChanged(const QByteArray
& role
,
402 void KItemListWidget::styleOptionChanged(const KItemListStyleOption
& current
,
403 const KItemListStyleOption
& previous
)
409 void KItemListWidget::currentChanged(bool current
)
414 void KItemListWidget::selectedChanged(bool selected
)
419 void KItemListWidget::hoveredChanged(bool hovered
)
424 void KItemListWidget::alternateBackgroundChanged(bool enabled
)
429 void KItemListWidget::siblingsInformationChanged(const QBitArray
& current
, const QBitArray
& previous
)
435 void KItemListWidget::editedRoleChanged(const QByteArray
& current
, const QByteArray
& previous
)
441 void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent
* event
)
443 QGraphicsWidget::resizeEvent(event
);
446 if (m_selectionToggle
) {
447 const QRectF
& toggleRect
= selectionToggleRect();
448 m_selectionToggle
->setPos(toggleRect
.topLeft());
449 m_selectionToggle
->resize(toggleRect
.size());
453 qreal
KItemListWidget::hoverOpacity() const
455 return m_hoverOpacity
;
458 void KItemListWidget::slotHoverAnimationFinished()
460 if (!m_hovered
&& m_selectionToggle
) {
461 m_selectionToggle
->deleteLater();
462 m_selectionToggle
= nullptr;
466 void KItemListWidget::initializeSelectionToggle()
468 Q_ASSERT(m_enabledSelectionToggle
);
470 if (!m_selectionToggle
) {
471 m_selectionToggle
= new KItemListSelectionToggle(this);
474 const QRectF toggleRect
= selectionToggleRect();
475 m_selectionToggle
->setPos(toggleRect
.topLeft());
476 m_selectionToggle
->resize(toggleRect
.size());
478 m_selectionToggle
->setChecked(isSelected());
481 void KItemListWidget::setHoverOpacity(qreal opacity
)
483 m_hoverOpacity
= opacity
;
484 if (m_selectionToggle
) {
485 m_selectionToggle
->setOpacity(opacity
);
488 if (m_hoverOpacity
<= 0.0) {
490 m_hoverCache
= nullptr;
496 void KItemListWidget::clearHoverCache()
499 m_hoverCache
= nullptr;
502 void KItemListWidget::drawItemStyleOption(QPainter
* painter
, QWidget
* widget
, QStyle::State styleState
)
504 QStyleOptionViewItem viewItemOption
;
505 initStyleOption(&viewItemOption
);
506 viewItemOption
.state
= styleState
;
507 viewItemOption
.viewItemPosition
= QStyleOptionViewItem::OnlyOne
;
508 viewItemOption
.showDecorationSelected
= true;
509 viewItemOption
.rect
= selectionRect().toRect();
510 style()->drawPrimitive(QStyle::PE_PanelItemViewItem
, &viewItemOption
, painter
, widget
);