#include <QPropertyAnimation>
#include <QStyleOptionRubberBand>
#include <QTimer>
+#include <QVariantAnimation>
namespace {
// Delay in ms for triggering the next autoscroll
const int RepeatingAutoScrollDelay = 1000 / 60;
+
+ // Copied from the Kirigami.Units.shortDuration
+ const int RubberFadeSpeed = 150;
+
+ const char* RubberPropertyName = "_kitemviews_rubberBandPosition";
}
#ifndef QT_NO_ACCESSIBILITY
if (!m_headerWidget->automaticColumnResizing()) {
// The column-width of new roles are still 0. Apply the preferred
// column-width as default with.
- foreach (const QByteArray& role, m_visibleRoles) {
+ for (const QByteArray& role : qAsConst(m_visibleRoles)) {
if (m_headerWidget->columnWidth(role) == 0) {
const qreal width = m_headerWidget->preferredColumnWidth(role);
m_headerWidget->setColumnWidth(role, width);
}
if (newOffset != scrollOffset()) {
- emit scrollTo(newOffset);
+ Q_EMIT scrollTo(newOffset);
}
}
}
{
QGraphicsWidget::paint(painter, option, widget);
+ for (auto animation : qAsConst(m_rubberBandAnimations)) {
+ QRectF rubberBandRect = animation->property(RubberPropertyName).toRectF();
+
+ const QPointF topLeft = rubberBandRect.topLeft();
+ if (scrollOrientation() == Qt::Vertical) {
+ rubberBandRect.moveTo(topLeft.x(), topLeft.y() - scrollOffset());
+ } else {
+ rubberBandRect.moveTo(topLeft.x() - scrollOffset(), topLeft.y());
+ }
+
+ QStyleOptionRubberBand opt;
+ initStyleOption(&opt);
+ opt.shape = QRubberBand::Rectangle;
+ opt.opaque = false;
+ opt.rect = rubberBandRect.toRect();
+
+ painter->save();
+
+ painter->setOpacity(animation->currentValue().toReal());
+ style()->drawControl(QStyle::CE_RubberBand, &opt, painter);
+
+ painter->restore();
+ }
+
if (m_rubberBand->isActive()) {
QRectF rubberBandRect = QRectF(m_rubberBand->startPosition(),
m_rubberBand->endPosition()).normalized();
doLayout(NoAnimation);
onScrollOrientationChanged(orientation, previousOrientation);
- emit scrollOrientationChanged(orientation, previousOrientation);
+ Q_EMIT scrollOrientationChanged(orientation, previousOrientation);
}
Qt::Orientation KItemListView::scrollOrientation() const
m_sizeHintResolver->itemsInserted(itemRanges);
int previouslyInsertedCount = 0;
- foreach (const KItemRange& range, itemRanges) {
+ for (const KItemRange& range : itemRanges) {
// range.index is related to the model before anything has been inserted.
// As in each loop the current item-range gets inserted the index must
// be increased by the already previously inserted items.
QVector<int> itemsToMove;
// Remove all KItemListWidget instances that got deleted
- foreach (KItemListWidget* widget, m_visibleItems) {
+ // Iterate over a const copy because the container is mutated within the loop
+ // directly and in `recycleWidget()` (https://bugs.kde.org/show_bug.cgi?id=428374)
+ const auto visibleItems = m_visibleItems;
+ for (KItemListWidget* widget : visibleItems) {
const int i = widget->index();
if (i < firstRemovedIndex) {
continue;
// after the deleted items. It is important to update them in ascending
// order to prevent overlaps when setting the new index.
std::sort(itemsToMove.begin(), itemsToMove.end());
- foreach (int i, itemsToMove) {
+ for (int i : qAsConst(itemsToMove)) {
KItemListWidget* widget = m_visibleItems.value(i);
Q_ASSERT(widget);
const int newIndex = i - count;
updatePreferredColumnWidths(itemRanges);
}
- foreach (const KItemRange& itemRange, itemRanges) {
+ for (const KItemRange& itemRange : itemRanges) {
const int index = itemRange.index;
const int count = itemRange.count;
connect(m_rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListView::slotRubberBandPosChanged);
m_skipAutoScrollForRubberBand = true;
} else {
+ QRectF rubberBandRect = QRectF(m_rubberBand->startPosition(),
+ m_rubberBand->endPosition()).normalized();
+
+ auto animation = new QVariantAnimation(this);
+ animation->setStartValue(1.0);
+ animation->setEndValue(0.0);
+ animation->setDuration(RubberFadeSpeed);
+ animation->setProperty(RubberPropertyName, rubberBandRect);
+
+ QEasingCurve curve;
+ curve.setType(QEasingCurve::BezierSpline);
+ curve.addCubicBezierSegment(QPointF(0.4, 0.0), QPointF(1.0, 1.0), QPointF(1.0, 1.0));
+ animation->setEasingCurve(curve);
+
+ connect(animation, &QVariantAnimation::valueChanged, this, [=](const QVariant&) {
+ update();
+ });
+ connect(animation, &QVariantAnimation::finished, this, [=]() {
+ m_rubberBandAnimations.removeAll(animation);
+ delete animation;
+ });
+ animation->start();
+ m_rubberBandAnimations << animation;
+
disconnect(m_rubberBand, &KItemListRubberBand::startPositionChanged, this, &KItemListView::slotRubberBandPosChanged);
disconnect(m_rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListView::slotRubberBandPosChanged);
m_skipAutoScrollForRubberBand = false;
setVisibleRoles(current);
- emit visibleRolesChanged(current, previous);
+ Q_EMIT visibleRolesChanged(current, previous);
}
void KItemListView::triggerAutoScrolling()
{
disconnectRoleEditingSignals(index);
- emit roleEditingCanceled(index, role, value);
+ Q_EMIT roleEditingCanceled(index, role, value);
m_editingRole = false;
}
{
disconnectRoleEditingSignals(index);
- emit roleEditingFinished(index, role, value);
+ Q_EMIT roleEditingFinished(index, role, value);
m_editingRole = false;
}
}
// Delete invisible KItemListWidget instances that have not been reused
- foreach (int index, reusableItems) {
+ for (int index : qAsConst(reusableItems)) {
recycleWidget(m_visibleItems.value(index));
}
{
const qreal newScrollOffset = m_layouter->scrollOffset();
if (m_oldScrollOffset != newScrollOffset) {
- emit scrollOffsetChanged(newScrollOffset, m_oldScrollOffset);
+ Q_EMIT scrollOffsetChanged(newScrollOffset, m_oldScrollOffset);
m_oldScrollOffset = newScrollOffset;
}
const qreal newMaximumScrollOffset = m_layouter->maximumScrollOffset();
if (m_oldMaximumScrollOffset != newMaximumScrollOffset) {
- emit maximumScrollOffsetChanged(newMaximumScrollOffset, m_oldMaximumScrollOffset);
+ Q_EMIT maximumScrollOffsetChanged(newMaximumScrollOffset, m_oldMaximumScrollOffset);
m_oldMaximumScrollOffset = newMaximumScrollOffset;
}
const qreal newItemOffset = m_layouter->itemOffset();
if (m_oldItemOffset != newItemOffset) {
- emit itemOffsetChanged(newItemOffset, m_oldItemOffset);
+ Q_EMIT itemOffsetChanged(newItemOffset, m_oldItemOffset);
m_oldItemOffset = newItemOffset;
}
const qreal newMaximumItemOffset = m_layouter->maximumItemOffset();
if (m_oldMaximumItemOffset != newMaximumItemOffset) {
- emit maximumItemOffsetChanged(newMaximumItemOffset, m_oldMaximumItemOffset);
+ Q_EMIT maximumItemOffsetChanged(newMaximumItemOffset, m_oldMaximumItemOffset);
m_oldMaximumItemOffset = newMaximumItemOffset;
}
}
const QFontMetricsF fontMetrics(m_headerWidget->font());
const int gripMargin = m_headerWidget->style()->pixelMetric(QStyle::PM_HeaderGripMargin);
const int headerMargin = m_headerWidget->style()->pixelMetric(QStyle::PM_HeaderMargin);
- foreach (const QByteArray& visibleRole, visibleRoles()) {
+ for (const QByteArray& visibleRole : qAsConst(m_visibleRoles)) {
const QString headerText = m_model->roleDescription(visibleRole);
const qreal headerWidth = fontMetrics.width(headerText) + gripMargin + headerMargin * 2;
widths.insert(visibleRole, headerWidth);
const KItemListWidgetCreatorBase* creator = widgetCreator();
int calculatedItemCount = 0;
bool maxTimeExceeded = false;
- foreach (const KItemRange& itemRange, itemRanges) {
+ for (const KItemRange& itemRange : itemRanges) {
const int startIndex = itemRange.index;
const int endIndex = startIndex + itemRange.count - 1;
for (int i = startIndex; i <= endIndex; ++i) {
- foreach (const QByteArray& visibleRole, visibleRoles()) {
+ for (const QByteArray& visibleRole : qAsConst(m_visibleRoles)) {
qreal maxWidth = widths.value(visibleRole, 0);
const qreal width = creator->preferredRoleColumnWidth(visibleRole, i, this);
maxWidth = qMax(width, maxWidth);
void KItemListView::updateWidgetColumnWidths(KItemListWidget* widget)
{
- foreach (const QByteArray& role, m_visibleRoles) {
+ for (const QByteArray& role : qAsConst(m_visibleRoles)) {
widget->setColumnWidth(role, m_headerWidget->columnWidth(role));
}
}
Q_ASSERT(m_itemSize.isEmpty());
const int itemCount = m_model->count();
int rangesItemCount = 0;
- foreach (const KItemRange& range, itemRanges) {
+ for (const KItemRange& range : itemRanges) {
rangesItemCount += range.count;
}
if (itemCount == rangesItemCount) {
const QHash<QByteArray, qreal> preferredWidths = preferredColumnWidths(itemRanges);
- foreach (const QByteArray& role, m_visibleRoles) {
+ for (const QByteArray& role : qAsConst(m_visibleRoles)) {
m_headerWidget->setPreferredColumnWidth(role, preferredWidths.value(role));
}
} else {
// size does not use the available view-size the size of the
// first role will get stretched.
- foreach (const QByteArray& role, m_visibleRoles) {
+ for (const QByteArray& role : qAsConst(m_visibleRoles)) {
const qreal preferredWidth = m_headerWidget->preferredColumnWidth(role);
m_headerWidget->setColumnWidth(role, preferredWidth);
}
qreal KItemListView::columnWidthsSum() const
{
qreal widthsSum = 0;
- foreach (const QByteArray& role, m_visibleRoles) {
+ for (const QByteArray& role : qAsConst(m_visibleRoles)) {
widthsSum += m_headerWidget->columnWidth(role);
}
return widthsSum;
groupHeaderHeight += 2 * m_styleOption.horizontalMargin;
groupHeaderMargin = m_styleOption.horizontalMargin;
} else if (m_itemSize.isEmpty()){
- groupHeaderHeight += 4 * m_styleOption.padding;
+ groupHeaderHeight += 2 * m_styleOption.padding;
groupHeaderMargin = m_styleOption.iconSize / 2;
} else {
groupHeaderHeight += 2 * m_styleOption.padding + m_styleOption.verticalMargin;