move carouselview to standalone c++ component, fix crash due to memory leak in wallpaper object creation
C++ / fmt (pull_request) Successful in 3s
JS/TS / lint (pull_request) Successful in 18s
JS/TS / fmt (pull_request) Successful in 17s
Python / fmt (pull_request) Successful in 28s
Python / lint (pull_request) Successful in 30s
Python / test (pull_request) Successful in 1m5s
Python / typecheck (pull_request) Successful in 1m24s
Rust / fmt (pull_request) Successful in 31s
C++ / build (pull_request) Successful in 2m21s
Rust / build (pull_request) Successful in 1m47s
Python / buildcheck (pull_request) Successful in 2m18s
Rust / clippy (pull_request) Successful in 1m12s
C++ / clang-tidy (pull_request) Successful in 4m3s
C++ / fmt (pull_request) Successful in 3s
JS/TS / lint (pull_request) Successful in 18s
JS/TS / fmt (pull_request) Successful in 17s
Python / fmt (pull_request) Successful in 28s
Python / lint (pull_request) Successful in 30s
Python / test (pull_request) Successful in 1m5s
Python / typecheck (pull_request) Successful in 1m24s
Rust / fmt (pull_request) Successful in 31s
C++ / build (pull_request) Successful in 2m21s
Rust / build (pull_request) Successful in 1m47s
Python / buildcheck (pull_request) Successful in 2m18s
Rust / clippy (pull_request) Successful in 1m12s
C++ / clang-tidy (pull_request) Successful in 4m3s
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
#pragma once
|
||||
|
||||
#include <QQuickItem>
|
||||
#include <QQmlComponent>
|
||||
#include <QQmlEngine>
|
||||
#include <QVariantList>
|
||||
#include <QVariantAnimation>
|
||||
#include <QEasingCurve>
|
||||
#include <QElapsedTimer>
|
||||
#include <QPointF>
|
||||
#include <QVector>
|
||||
#include <QList>
|
||||
|
||||
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(
|
||||
int glideDuration READ glideDuration WRITE setGlideDuration NOTIFY
|
||||
glideDurationChanged)
|
||||
Q_PROPERTY(
|
||||
QEasingCurve::Type glideEasingType READ glideEasingType WRITE
|
||||
setGlideEasingType NOTIFY glideEasingTypeChanged)
|
||||
|
||||
// Extra properties (e.g. { visibilities: root.visibilities }) forwarded
|
||||
// verbatim onto every delegate instance as a property of the same name.
|
||||
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); // jumps (animated glide) to a real index
|
||||
|
||||
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);
|
||||
|
||||
// Animated (glides).
|
||||
Q_INVOKABLE void goToIndex(int realIndex);
|
||||
Q_INVOKABLE void incrementCurrentIndex();
|
||||
Q_INVOKABLE void decrementCurrentIndex();
|
||||
|
||||
// Instant, no animation -- use for initial placement (e.g. restoring the
|
||||
// saved wallpaper on Component.onCompleted) where a glide would be wrong.
|
||||
Q_INVOKABLE void jumpToIndex(int realIndex);
|
||||
|
||||
signals:
|
||||
void delegateChanged();
|
||||
void modelChanged();
|
||||
void focalWidthChanged();
|
||||
void minEdgeWidthChanged();
|
||||
void itemSpacingChanged();
|
||||
void tileHeightChanged();
|
||||
void maxWidthChanged();
|
||||
void currentIndexChanged();
|
||||
void glideDurationChanged();
|
||||
void glideEasingTypeChanged();
|
||||
void delegatePropertiesChanged();
|
||||
|
||||
// Emitted when the currently-centred delegate is clicked while already
|
||||
// centred (i.e. "activate/select this one").
|
||||
void activated(int realIndex, QVariant modelData);
|
||||
// Emitted continuously as the centred item changes, for preview-on-scroll
|
||||
// behaviour (used to drive Wallpapers.preview() from QML).
|
||||
void previewIndexChanged(int realIndex, QVariant modelData);
|
||||
|
||||
protected:
|
||||
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;
|
||||
QVector<qreal> sizes; // sizes[0] = focal, sizes[i] = i-th side item
|
||||
QVector<qreal>
|
||||
centers; // centers[0] = 0, centers[i] = i-th side centre offset
|
||||
qreal effectiveExtraWidth = 0;
|
||||
};
|
||||
|
||||
struct Slot {
|
||||
QQuickItem* item = nullptr;
|
||||
int virtualIndex =
|
||||
0; // which "virtual" (unbounded) index this slot currently renders
|
||||
int realIndex = -1; // resolved model index, -1 if none / hidden
|
||||
bool active = false;
|
||||
};
|
||||
|
||||
void rebuildArrangement();
|
||||
void relayout(); // recomputes window + positions every slot (one pass)
|
||||
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 keylineCenter(int io) const;
|
||||
qreal keylineSize(int io) const;
|
||||
qreal sampleCenter(qreal childLoc) const;
|
||||
qreal sampleSize(qreal childLoc) const;
|
||||
|
||||
int realIndexOf(int virtualIndex) const;
|
||||
void updateCurrentIndexFromContentX(bool emitPreview);
|
||||
void wrapContentIfNeeded();
|
||||
void centerInstantlyOnReal(int realIndex); // no animation, no glide
|
||||
|
||||
QQuickItem* acquireItem();
|
||||
void releaseAllItems();
|
||||
|
||||
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;
|
||||
|
||||
qreal m_contentX = 0;
|
||||
int m_currentVirtualIndex = 0;
|
||||
int m_currentRealIndex = -1;
|
||||
int m_previewRealIndex = -1;
|
||||
|
||||
static constexpr int kLoopMultiplier = 401;
|
||||
int m_centerBlockStart = 0;
|
||||
|
||||
QList<Slot>
|
||||
m_slots; // pooled delegate slots, unordered; window recomputed each relayout
|
||||
|
||||
int m_glideDuration = 250;
|
||||
QEasingCurve::Type m_glideEasingType = QEasingCurve::OutCubic;
|
||||
QVariantAnimation* m_glideAnim = nullptr;
|
||||
|
||||
// Drag / flick state
|
||||
bool m_dragging = false;
|
||||
bool m_dragActive = false; // exceeded the drag threshold
|
||||
QPointF m_pressPos;
|
||||
qreal m_pressContentX = 0;
|
||||
QElapsedTimer m_dragTimer;
|
||||
qreal m_lastMoveX = 0;
|
||||
qint64 m_lastMoveT = 0;
|
||||
qreal m_velocity = 0; // px/sec
|
||||
QVariantAnimation* m_flickAnim = nullptr;
|
||||
|
||||
bool m_initializedLayout = false;
|
||||
bool m_relayoutQueued = false;
|
||||
};
|
||||
|
||||
}; // namespace ZShell::components
|
||||
Reference in New Issue
Block a user