C++ / fmt (pull_request) Successful in 3s
JS/TS / fmt (pull_request) Successful in 15s
JS/TS / lint (pull_request) Successful in 17s
Python / static (pull_request) Successful in 58s
Rust / fmt (pull_request) Successful in 1m4s
Rust / build (pull_request) Successful in 2m14s
C++ / build (pull_request) Successful in 2m36s
Rust / clippy (pull_request) Successful in 1m30s
Python / verify (pull_request) Successful in 2m53s
C++ / clang-tidy (pull_request) Successful in 4m4s
250 lines
6.1 KiB
C++
250 lines
6.1 KiB
C++
#pragma once
|
|
|
|
#include <QElapsedTimer>
|
|
#include <QEasingCurve>
|
|
#include <QList>
|
|
#include <QPointF>
|
|
#include <QQuickItem>
|
|
#include <QQmlComponent>
|
|
#include <QQmlEngine>
|
|
#include <QVariantAnimation>
|
|
#include <QVariantList>
|
|
#include <QVector>
|
|
#include <qtypes.h>
|
|
#include <qvectornd.h>
|
|
|
|
namespace ZShell::components {
|
|
|
|
class CarouselView : public QQuickItem {
|
|
Q_OBJECT
|
|
QML_ELEMENT
|
|
|
|
Q_PROPERTY(
|
|
QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY
|
|
delegateChanged)
|
|
Q_PROPERTY(QVariantList model READ model WRITE setModel NOTIFY modelChanged)
|
|
|
|
Q_PROPERTY(
|
|
qreal focalWidth READ focalWidth WRITE setFocalWidth NOTIFY
|
|
focalWidthChanged)
|
|
Q_PROPERTY(
|
|
qreal minEdgeWidth READ minEdgeWidth WRITE setMinEdgeWidth NOTIFY
|
|
minEdgeWidthChanged)
|
|
Q_PROPERTY(
|
|
qreal itemSpacing READ itemSpacing WRITE setItemSpacing NOTIFY
|
|
itemSpacingChanged)
|
|
Q_PROPERTY(
|
|
qreal tileHeight READ tileHeight WRITE setTileHeight NOTIFY
|
|
tileHeightChanged)
|
|
Q_PROPERTY(
|
|
qreal maxWidth READ maxWidth WRITE setMaxWidth NOTIFY maxWidthChanged)
|
|
|
|
Q_PROPERTY(
|
|
int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY
|
|
currentIndexChanged)
|
|
|
|
Q_PROPERTY(
|
|
QQuickItem* currentItem READ currentItem NOTIFY currentItemChanged)
|
|
|
|
Q_PROPERTY(
|
|
int glideDuration READ glideDuration WRITE setGlideDuration NOTIFY
|
|
glideDurationChanged)
|
|
Q_PROPERTY(
|
|
QEasingCurve::Type glideEasingType READ glideEasingType WRITE
|
|
setGlideEasingType NOTIFY glideEasingTypeChanged)
|
|
|
|
Q_PROPERTY(
|
|
QVariantMap delegateProperties READ delegateProperties WRITE
|
|
setDelegateProperties NOTIFY delegatePropertiesChanged)
|
|
|
|
public:
|
|
explicit CarouselView(QQuickItem* parent = nullptr);
|
|
~CarouselView() override;
|
|
|
|
QQmlComponent* delegate() const { return m_delegate; }
|
|
void setDelegate(QQmlComponent* c);
|
|
|
|
QVariantList model() const { return m_model; }
|
|
void setModel(const QVariantList& m);
|
|
|
|
qreal focalWidth() const { return m_focalWidth; }
|
|
void setFocalWidth(qreal v);
|
|
|
|
qreal minEdgeWidth() const { return m_minEdgeWidth; }
|
|
void setMinEdgeWidth(qreal v);
|
|
|
|
qreal itemSpacing() const { return m_itemSpacing; }
|
|
void setItemSpacing(qreal v);
|
|
|
|
qreal tileHeight() const { return m_tileHeight; }
|
|
void setTileHeight(qreal v);
|
|
|
|
qreal maxWidth() const { return m_maxWidth; }
|
|
void setMaxWidth(qreal v);
|
|
|
|
int currentIndex() const { return m_currentRealIndex; }
|
|
void setCurrentIndex(int idx);
|
|
|
|
QQuickItem* currentItem() const { return m_currentItem; }
|
|
|
|
int glideDuration() const { return m_glideDuration; }
|
|
void setGlideDuration(int v);
|
|
|
|
QEasingCurve::Type glideEasingType() const { return m_glideEasingType; }
|
|
void setGlideEasingType(QEasingCurve::Type t);
|
|
|
|
QVariantMap delegateProperties() const { return m_delegateProperties; }
|
|
void setDelegateProperties(const QVariantMap& v);
|
|
|
|
Q_INVOKABLE void goToIndex(int realIndex);
|
|
Q_INVOKABLE void incrementCurrentIndex();
|
|
Q_INVOKABLE void decrementCurrentIndex();
|
|
|
|
Q_INVOKABLE void jumpToIndex(int realIndex);
|
|
|
|
signals:
|
|
void delegateChanged();
|
|
void modelChanged();
|
|
void focalWidthChanged();
|
|
void minEdgeWidthChanged();
|
|
void itemSpacingChanged();
|
|
void tileHeightChanged();
|
|
void maxWidthChanged();
|
|
void currentIndexChanged();
|
|
void currentItemChanged();
|
|
void glideDurationChanged();
|
|
void glideEasingTypeChanged();
|
|
void delegatePropertiesChanged();
|
|
|
|
void activated(int realIndex, QVariant modelData);
|
|
void previewIndexChanged(int realIndex, QVariant modelData);
|
|
|
|
protected:
|
|
bool childMouseEventFilter(QQuickItem* item, QEvent* event) override;
|
|
|
|
void geometryChange(const QRectF& newGeo, const QRectF& oldGeo) override;
|
|
|
|
void mousePressEvent(QMouseEvent* event) override;
|
|
void mouseMoveEvent(QMouseEvent* event) override;
|
|
void mouseReleaseEvent(QMouseEvent* event) override;
|
|
void mouseUngrabEvent() override;
|
|
void wheelEvent(QWheelEvent* event) override;
|
|
|
|
private slots:
|
|
void handleDelegateActivate();
|
|
|
|
private:
|
|
struct Arrangement {
|
|
int n = 0;
|
|
qreal width = 0;
|
|
qreal outerSpacing = 0;
|
|
|
|
QVector<qreal> sizes;
|
|
QVector<qreal> centers;
|
|
|
|
qreal effectiveExtraWidth = 0;
|
|
};
|
|
|
|
struct Slot {
|
|
QQuickItem* item = nullptr;
|
|
int virtualIndex = 0;
|
|
int realIndex = -1;
|
|
bool active = false;
|
|
};
|
|
|
|
struct VelocitySample {
|
|
qint64 t;
|
|
qreal x;
|
|
};
|
|
|
|
void rebuildArrangement();
|
|
void relayout();
|
|
|
|
Arrangement arrangementForCount(int n) const;
|
|
|
|
int layoutCapacityForWidth(qreal width) const;
|
|
qreal targetWidthForMaxWidth(qreal maxWidth) const;
|
|
|
|
void updateSlotContent(Slot& slot, int virtualIndex);
|
|
|
|
void positionSlot(const Slot& slot) const;
|
|
|
|
void applyPropertiesToItem(QQuickItem* item, int realIndex) const;
|
|
|
|
qreal pitch() const { return m_focalWidth + m_itemSpacing; }
|
|
|
|
qreal contentXForIndex(qreal index) const;
|
|
int indexForContentX(qreal x) const;
|
|
qreal snapTargetX(qreal x) const;
|
|
|
|
void snapToNearest();
|
|
void glideTo(qreal dest);
|
|
void cancelAnimations();
|
|
|
|
qreal keylineSize(int io) const;
|
|
qreal sampleSize(qreal childLoc) const;
|
|
qreal continuousIndex() const;
|
|
|
|
int realIndexOf(int virtualIndex) const;
|
|
|
|
void updateCurrentIndexFromContentX(bool emitPreview);
|
|
|
|
void updateCurrentItem();
|
|
|
|
void wrapContentIfNeeded();
|
|
void centerInstantlyOnReal(int realIndex);
|
|
|
|
QQuickItem* acquireItem();
|
|
void releaseAllItems();
|
|
|
|
void addVelocitySample(qint64 t, qreal x);
|
|
qreal sampledVelocity() const;
|
|
|
|
QQmlComponent* m_delegate = nullptr;
|
|
QVariantList m_model;
|
|
QVariantMap m_delegateProperties;
|
|
|
|
qreal m_focalWidth = 0;
|
|
qreal m_minEdgeWidth = 56;
|
|
qreal m_itemSpacing = 8;
|
|
qreal m_tileHeight = 0;
|
|
qreal m_maxWidth = 0;
|
|
|
|
Arrangement m_arrangement;
|
|
|
|
int m_layoutCapacity = 0;
|
|
|
|
qreal m_contentX = 0;
|
|
int m_currentVirtualIndex = 0;
|
|
int m_currentRealIndex = -1;
|
|
int m_previewRealIndex = -1;
|
|
|
|
QQuickItem* m_currentItem = nullptr;
|
|
|
|
int m_centerBlockStart = 0;
|
|
|
|
QList<Slot> m_slots;
|
|
|
|
int m_glideDuration = 250;
|
|
QEasingCurve::Type m_glideEasingType = QEasingCurve::OutCubic;
|
|
QVariantAnimation* m_glideAnim = nullptr;
|
|
|
|
bool m_dragging = false;
|
|
bool m_dragActive = false;
|
|
|
|
QPointF m_pressPos;
|
|
qreal m_pressContentX = 0;
|
|
|
|
QElapsedTimer m_dragTimer;
|
|
|
|
QVector<VelocitySample> m_velocitySamples;
|
|
static constexpr qint64 kVelocitySampleWindowMs = 80;
|
|
|
|
QVariantAnimation* m_flickAnim = nullptr;
|
|
|
|
bool m_initializedLayout = false;
|
|
bool m_relayoutQueued = false;
|
|
};
|
|
|
|
} // namespace ZShell::components
|