File indexing completed on 2024-04-28 05:45:10
0001 /* 0002 * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com> 0003 * 0004 * Based on the Itemviews NG project from Trolltech Labs 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "kitemlistwidget.h" 0010 0011 #include "kitemlistview.h" 0012 #include "private/kitemlistselectiontoggle.h" 0013 0014 #include <KConfigGroup> 0015 #include <KSharedConfig> 0016 0017 #include <QApplication> 0018 #include <QPainter> 0019 #include <QPropertyAnimation> 0020 #include <QStyleOption> 0021 0022 KItemListWidgetInformant::KItemListWidgetInformant() 0023 { 0024 } 0025 0026 KItemListWidgetInformant::~KItemListWidgetInformant() 0027 { 0028 } 0029 0030 KItemListWidget::KItemListWidget(KItemListWidgetInformant *informant, QGraphicsItem *parent) 0031 : QGraphicsWidget(parent) 0032 , m_informant(informant) 0033 , m_index(-1) 0034 , m_selected(false) 0035 , m_current(false) 0036 , m_hovered(false) 0037 , m_expansionAreaHovered(false) 0038 , m_alternateBackground(false) 0039 , m_enabledSelectionToggle(false) 0040 , m_data() 0041 , m_visibleRoles() 0042 , m_columnWidths() 0043 , m_sidePadding(0) 0044 , m_styleOption() 0045 , m_siblingsInfo() 0046 , m_hoverOpacity(0) 0047 , m_hoverCache(nullptr) 0048 , m_hoverSequenceIndex(0) 0049 , m_selectionToggle(nullptr) 0050 , m_editedRole() 0051 , m_iconSize(-1) 0052 { 0053 connect(&m_hoverSequenceTimer, &QTimer::timeout, this, &KItemListWidget::slotHoverSequenceTimerTimeout); 0054 } 0055 0056 KItemListWidget::~KItemListWidget() 0057 { 0058 clearHoverCache(); 0059 } 0060 0061 void KItemListWidget::setIndex(int index) 0062 { 0063 if (m_index != index) { 0064 delete m_selectionToggle; 0065 m_selectionToggle = nullptr; 0066 0067 m_hoverOpacity = 0; 0068 0069 clearHoverCache(); 0070 0071 m_index = index; 0072 } 0073 } 0074 0075 int KItemListWidget::index() const 0076 { 0077 return m_index; 0078 } 0079 0080 void KItemListWidget::setData(const QHash<QByteArray, QVariant> &data, const QSet<QByteArray> &roles) 0081 { 0082 clearHoverCache(); 0083 if (roles.isEmpty()) { 0084 m_data = data; 0085 dataChanged(m_data); 0086 } else { 0087 for (const QByteArray &role : roles) { 0088 m_data[role] = data[role]; 0089 } 0090 dataChanged(m_data, roles); 0091 } 0092 update(); 0093 } 0094 0095 QHash<QByteArray, QVariant> KItemListWidget::data() const 0096 { 0097 return m_data; 0098 } 0099 0100 void KItemListWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) 0101 { 0102 Q_UNUSED(option) 0103 0104 if (m_alternateBackground) { 0105 QColor backgroundColor = m_styleOption.palette.color(QPalette::AlternateBase); 0106 if (!widget->hasFocus()) { 0107 QColor baseColor = m_styleOption.palette.color(QPalette::Base); 0108 if (baseColor.lightnessF() > 0.5) { 0109 // theme seems light 0110 backgroundColor = backgroundColor.lighter(101); 0111 } else { 0112 // theme seems dark 0113 backgroundColor = backgroundColor.darker(101); 0114 } 0115 } 0116 0117 const QRectF backgroundRect(0, 0, size().width(), size().height()); 0118 painter->fillRect(backgroundRect, backgroundColor); 0119 } 0120 0121 if (m_selected && m_editedRole.isEmpty()) { 0122 const QStyle::State activeState(isActiveWindow() && widget->hasFocus() ? QStyle::State_Active : 0); 0123 drawItemStyleOption(painter, widget, activeState | QStyle::State_Enabled | QStyle::State_Selected | QStyle::State_Item); 0124 } 0125 0126 if (m_current && m_editedRole.isEmpty()) { 0127 QStyleOptionFocusRect focusRectOption; 0128 initStyleOption(&focusRectOption); 0129 focusRectOption.rect = textFocusRect().toRect(); 0130 focusRectOption.state = QStyle::State_Enabled | QStyle::State_Item | QStyle::State_KeyboardFocusChange; 0131 if (m_selected && widget->hasFocus()) { 0132 focusRectOption.state |= QStyle::State_Selected; 0133 } 0134 0135 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &focusRectOption, painter, widget); 0136 } 0137 0138 if (m_hoverOpacity > 0.0) { 0139 if (!m_hoverCache) { 0140 // Initialize the m_hoverCache pixmap to improve the drawing performance 0141 // when fading the hover background 0142 m_hoverCache = new QPixmap(size().toSize()); 0143 m_hoverCache->fill(Qt::transparent); 0144 0145 QPainter pixmapPainter(m_hoverCache); 0146 const QStyle::State activeState(isActiveWindow() && widget->hasFocus() ? QStyle::State_Active | QStyle::State_Enabled : 0); 0147 drawItemStyleOption(&pixmapPainter, widget, activeState | QStyle::State_MouseOver | QStyle::State_Item); 0148 } 0149 0150 const qreal opacity = painter->opacity(); 0151 painter->setOpacity(m_hoverOpacity * opacity); 0152 painter->drawPixmap(0, 0, *m_hoverCache); 0153 painter->setOpacity(opacity); 0154 } 0155 } 0156 0157 void KItemListWidget::setVisibleRoles(const QList<QByteArray> &roles) 0158 { 0159 const QList<QByteArray> previousRoles = m_visibleRoles; 0160 m_visibleRoles = roles; 0161 0162 visibleRolesChanged(roles, previousRoles); 0163 update(); 0164 } 0165 0166 QList<QByteArray> KItemListWidget::visibleRoles() const 0167 { 0168 return m_visibleRoles; 0169 } 0170 0171 void KItemListWidget::setColumnWidth(const QByteArray &role, qreal width) 0172 { 0173 const qreal previousWidth = m_columnWidths.value(role); 0174 if (previousWidth != width) { 0175 m_columnWidths.insert(role, width); 0176 columnWidthChanged(role, width, previousWidth); 0177 update(); 0178 } 0179 } 0180 0181 qreal KItemListWidget::columnWidth(const QByteArray &role) const 0182 { 0183 return m_columnWidths.value(role); 0184 } 0185 0186 qreal KItemListWidget::sidePadding() const 0187 { 0188 return m_sidePadding; 0189 } 0190 0191 void KItemListWidget::setSidePadding(qreal width) 0192 { 0193 if (m_sidePadding != width) { 0194 m_sidePadding = width; 0195 sidePaddingChanged(width); 0196 update(); 0197 } 0198 } 0199 0200 void KItemListWidget::setStyleOption(const KItemListStyleOption &option) 0201 { 0202 if (m_styleOption == option) { 0203 return; 0204 } 0205 0206 const KItemListStyleOption previous = m_styleOption; 0207 clearHoverCache(); 0208 m_styleOption = option; 0209 styleOptionChanged(option, previous); 0210 update(); 0211 } 0212 0213 const KItemListStyleOption &KItemListWidget::styleOption() const 0214 { 0215 return m_styleOption; 0216 } 0217 0218 void KItemListWidget::setSelected(bool selected) 0219 { 0220 if (m_selected != selected) { 0221 m_selected = selected; 0222 if (m_selectionToggle) { 0223 m_selectionToggle->setChecked(selected); 0224 } 0225 selectedChanged(selected); 0226 update(); 0227 } 0228 } 0229 0230 bool KItemListWidget::isSelected() const 0231 { 0232 return m_selected; 0233 } 0234 0235 void KItemListWidget::setCurrent(bool current) 0236 { 0237 if (m_current != current) { 0238 m_current = current; 0239 currentChanged(current); 0240 update(); 0241 } 0242 } 0243 0244 bool KItemListWidget::isCurrent() const 0245 { 0246 return m_current; 0247 } 0248 0249 void KItemListWidget::setHovered(bool hovered) 0250 { 0251 if (hovered == m_hovered) { 0252 return; 0253 } 0254 0255 m_hovered = hovered; 0256 0257 m_hoverSequenceIndex = 0; 0258 0259 if (hovered) { 0260 setHoverOpacity(1.0); 0261 0262 if (m_enabledSelectionToggle && !(QApplication::mouseButtons() & Qt::LeftButton)) { 0263 initializeSelectionToggle(); 0264 } 0265 0266 hoverSequenceStarted(); 0267 0268 const KConfigGroup globalConfig(KSharedConfig::openConfig(), QStringLiteral("PreviewSettings")); 0269 const int interval = globalConfig.readEntry("HoverSequenceInterval", 700); 0270 0271 m_hoverSequenceTimer.start(interval); 0272 } else { 0273 setHoverOpacity(0.0); 0274 0275 if (m_selectionToggle) { 0276 m_selectionToggle->deleteLater(); 0277 m_selectionToggle = nullptr; 0278 } 0279 0280 hoverSequenceEnded(); 0281 m_hoverSequenceTimer.stop(); 0282 } 0283 0284 hoveredChanged(hovered); 0285 update(); 0286 } 0287 0288 bool KItemListWidget::isHovered() const 0289 { 0290 return m_hovered; 0291 } 0292 0293 void KItemListWidget::setExpansionAreaHovered(bool hovered) 0294 { 0295 if (hovered == m_expansionAreaHovered) { 0296 return; 0297 } 0298 m_expansionAreaHovered = hovered; 0299 update(); 0300 } 0301 0302 bool KItemListWidget::expansionAreaHovered() const 0303 { 0304 return m_expansionAreaHovered; 0305 } 0306 0307 void KItemListWidget::setHoverPosition(const QPointF &pos) 0308 { 0309 if (m_selectionToggle) { 0310 m_selectionToggle->setHovered(selectionToggleRect().contains(pos)); 0311 } 0312 } 0313 0314 void KItemListWidget::setAlternateBackground(bool enable) 0315 { 0316 if (m_alternateBackground != enable) { 0317 m_alternateBackground = enable; 0318 alternateBackgroundChanged(enable); 0319 update(); 0320 } 0321 } 0322 0323 bool KItemListWidget::alternateBackground() const 0324 { 0325 return m_alternateBackground; 0326 } 0327 0328 void KItemListWidget::setEnabledSelectionToggle(bool enable) 0329 { 0330 if (m_enabledSelectionToggle != enable) { 0331 m_enabledSelectionToggle = enable; 0332 0333 // We want the change to take effect immediately. 0334 if (m_enabledSelectionToggle) { 0335 if (m_hovered) { 0336 initializeSelectionToggle(); 0337 } 0338 } else if (m_selectionToggle) { 0339 m_selectionToggle->deleteLater(); 0340 m_selectionToggle = nullptr; 0341 } 0342 0343 update(); 0344 } 0345 } 0346 0347 bool KItemListWidget::enabledSelectionToggle() const 0348 { 0349 return m_enabledSelectionToggle; 0350 } 0351 0352 void KItemListWidget::setSiblingsInformation(const QBitArray &siblings) 0353 { 0354 const QBitArray previous = m_siblingsInfo; 0355 m_siblingsInfo = siblings; 0356 siblingsInformationChanged(m_siblingsInfo, previous); 0357 update(); 0358 } 0359 0360 QBitArray KItemListWidget::siblingsInformation() const 0361 { 0362 return m_siblingsInfo; 0363 } 0364 0365 void KItemListWidget::setEditedRole(const QByteArray &role) 0366 { 0367 if (m_editedRole != role) { 0368 const QByteArray previous = m_editedRole; 0369 m_editedRole = role; 0370 editedRoleChanged(role, previous); 0371 } 0372 } 0373 0374 QByteArray KItemListWidget::editedRole() const 0375 { 0376 return m_editedRole; 0377 } 0378 0379 void KItemListWidget::setIconSize(int iconSize) 0380 { 0381 if (m_iconSize != iconSize) { 0382 const int previousIconSize = m_iconSize; 0383 m_iconSize = iconSize; 0384 iconSizeChanged(iconSize, previousIconSize); 0385 } 0386 } 0387 0388 int KItemListWidget::iconSize() const 0389 { 0390 return m_iconSize; 0391 } 0392 0393 bool KItemListWidget::contains(const QPointF &point) const 0394 { 0395 if (!QGraphicsWidget::contains(point)) { 0396 return false; 0397 } 0398 0399 return iconRect().contains(point) || textRect().contains(point) || expansionToggleRect().contains(point) || selectionToggleRect().contains(point); 0400 } 0401 0402 QRectF KItemListWidget::textFocusRect() const 0403 { 0404 return textRect(); 0405 } 0406 0407 QRectF KItemListWidget::selectionToggleRect() const 0408 { 0409 return QRectF(); 0410 } 0411 0412 QRectF KItemListWidget::expansionToggleRect() const 0413 { 0414 return QRectF(); 0415 } 0416 0417 QPixmap KItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem *option, QWidget *widget) 0418 { 0419 QPixmap pixmap(size().toSize() * widget->devicePixelRatio()); 0420 pixmap.setDevicePixelRatio(widget->devicePixelRatio()); 0421 pixmap.fill(Qt::transparent); 0422 0423 QPainter painter(&pixmap); 0424 0425 const bool oldAlternateBackground = m_alternateBackground; 0426 const bool wasSelected = m_selected; 0427 const bool wasHovered = m_hovered; 0428 0429 setAlternateBackground(false); 0430 setHovered(false); 0431 0432 paint(&painter, option, widget); 0433 0434 setAlternateBackground(oldAlternateBackground); 0435 setSelected(wasSelected); 0436 setHovered(wasHovered); 0437 0438 return pixmap; 0439 } 0440 0441 void KItemListWidget::dataChanged(const QHash<QByteArray, QVariant> ¤t, const QSet<QByteArray> &roles) 0442 { 0443 Q_UNUSED(current) 0444 Q_UNUSED(roles) 0445 } 0446 0447 void KItemListWidget::visibleRolesChanged(const QList<QByteArray> ¤t, const QList<QByteArray> &previous) 0448 { 0449 Q_UNUSED(current) 0450 Q_UNUSED(previous) 0451 } 0452 0453 void KItemListWidget::columnWidthChanged(const QByteArray &role, qreal current, qreal previous) 0454 { 0455 Q_UNUSED(role) 0456 Q_UNUSED(current) 0457 Q_UNUSED(previous) 0458 } 0459 0460 void KItemListWidget::sidePaddingChanged(qreal width) 0461 { 0462 Q_UNUSED(width) 0463 } 0464 0465 void KItemListWidget::styleOptionChanged(const KItemListStyleOption ¤t, const KItemListStyleOption &previous) 0466 { 0467 Q_UNUSED(previous) 0468 0469 // set the initial value of m_iconSize if not set 0470 if (m_iconSize == -1) { 0471 m_iconSize = current.iconSize; 0472 } 0473 } 0474 0475 void KItemListWidget::currentChanged(bool current) 0476 { 0477 Q_UNUSED(current) 0478 } 0479 0480 void KItemListWidget::selectedChanged(bool selected) 0481 { 0482 Q_UNUSED(selected) 0483 } 0484 0485 void KItemListWidget::hoveredChanged(bool hovered) 0486 { 0487 Q_UNUSED(hovered) 0488 } 0489 0490 void KItemListWidget::alternateBackgroundChanged(bool enabled) 0491 { 0492 Q_UNUSED(enabled) 0493 } 0494 0495 void KItemListWidget::siblingsInformationChanged(const QBitArray ¤t, const QBitArray &previous) 0496 { 0497 Q_UNUSED(current) 0498 Q_UNUSED(previous) 0499 } 0500 0501 void KItemListWidget::editedRoleChanged(const QByteArray ¤t, const QByteArray &previous) 0502 { 0503 Q_UNUSED(current) 0504 Q_UNUSED(previous) 0505 } 0506 0507 void KItemListWidget::iconSizeChanged(int current, int previous) 0508 { 0509 Q_UNUSED(current) 0510 Q_UNUSED(previous) 0511 } 0512 0513 void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent *event) 0514 { 0515 QGraphicsWidget::resizeEvent(event); 0516 clearHoverCache(); 0517 0518 if (m_selectionToggle) { 0519 const QRectF &toggleRect = selectionToggleRect(); 0520 m_selectionToggle->setPos(toggleRect.topLeft()); 0521 m_selectionToggle->resize(toggleRect.size()); 0522 } 0523 } 0524 0525 void KItemListWidget::hoverSequenceStarted() 0526 { 0527 } 0528 0529 void KItemListWidget::hoverSequenceIndexChanged(int sequenceIndex) 0530 { 0531 Q_UNUSED(sequenceIndex); 0532 } 0533 0534 void KItemListWidget::hoverSequenceEnded() 0535 { 0536 } 0537 0538 qreal KItemListWidget::hoverOpacity() const 0539 { 0540 return m_hoverOpacity; 0541 } 0542 0543 int KItemListWidget::hoverSequenceIndex() const 0544 { 0545 return m_hoverSequenceIndex; 0546 } 0547 0548 void KItemListWidget::slotHoverSequenceTimerTimeout() 0549 { 0550 m_hoverSequenceIndex++; 0551 hoverSequenceIndexChanged(m_hoverSequenceIndex); 0552 } 0553 0554 void KItemListWidget::initializeSelectionToggle() 0555 { 0556 Q_ASSERT(m_enabledSelectionToggle); 0557 0558 if (!m_selectionToggle) { 0559 m_selectionToggle = new KItemListSelectionToggle(this); 0560 } 0561 0562 const QRectF toggleRect = selectionToggleRect(); 0563 m_selectionToggle->setPos(toggleRect.topLeft()); 0564 m_selectionToggle->resize(toggleRect.size()); 0565 0566 m_selectionToggle->setChecked(isSelected()); 0567 } 0568 0569 void KItemListWidget::setHoverOpacity(qreal opacity) 0570 { 0571 m_hoverOpacity = opacity; 0572 if (m_selectionToggle) { 0573 m_selectionToggle->setOpacity(opacity); 0574 } 0575 0576 if (m_hoverOpacity <= 0.0) { 0577 delete m_hoverCache; 0578 m_hoverCache = nullptr; 0579 } 0580 0581 update(); 0582 } 0583 0584 void KItemListWidget::clearHoverCache() 0585 { 0586 delete m_hoverCache; 0587 m_hoverCache = nullptr; 0588 } 0589 0590 void KItemListWidget::drawItemStyleOption(QPainter *painter, QWidget *widget, QStyle::State styleState) 0591 { 0592 QStyleOptionViewItem viewItemOption; 0593 initStyleOption(&viewItemOption); 0594 viewItemOption.state = styleState; 0595 viewItemOption.viewItemPosition = QStyleOptionViewItem::OnlyOne; 0596 viewItemOption.showDecorationSelected = true; 0597 viewItemOption.rect = selectionRect().toRect(); 0598 style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewItemOption, painter, widget); 0599 } 0600 0601 #include "moc_kitemlistwidget.cpp"