diff --git a/config.example.json b/config.example.json
index eb29998..52c8471 100644
--- a/config.example.json
+++ b/config.example.json
@@ -23,7 +23,7 @@
"window_height": 500
},
"sort": {
- "type": "size",
+ "type": "name",
"reverse": false
}
}
\ No newline at end of file
diff --git a/src/designer/main_window.ui b/src/designer/main_window.ui
index 9e38a54..2e02358 100644
--- a/src/designer/main_window.ui
+++ b/src/designer/main_window.ui
@@ -47,7 +47,7 @@
20
- 20
+ 10
diff --git a/src/images_carousel.cpp b/src/images_carousel.cpp
index 7dbca19..5954125 100644
--- a/src/images_carousel.cpp
+++ b/src/images_carousel.cpp
@@ -1,13 +1,15 @@
/*
* @Author: Uyanide pywang0608@foxmail.com
* @Date: 2025-08-05 01:22:53
- * @LastEditTime: 2025-08-06 00:47:21
+ * @LastEditTime: 2025-08-06 01:27:49
* @Description: Animated carousel widget for displaying and selecting images.
*/
#include "images_carousel.h"
#include
#include
+#include
+#include
#include
#include
@@ -30,7 +32,6 @@ ImagesCarousel::ImagesCarousel(const double itemAspectRatio,
: QWidget(parent),
ui(new Ui::ImagesCarousel),
m_updateTimer(new QTimer(this)),
- m_scrollAnimation(nullptr),
m_itemWidth(itemWidth),
m_itemHeight(static_cast(itemWidth / itemAspectRatio)),
m_itemFocusWidth(itemFocusWidth),
@@ -40,12 +41,41 @@ ImagesCarousel::ImagesCarousel(const double itemAspectRatio,
ui->setupUi(this);
m_imagesLayout = dynamic_cast(ui->scrollAreaWidgetContents->layout());
- connect(m_updateTimer, &QTimer::timeout, this, &ImagesCarousel::_updateImages);
+
+ // Load initial images
+ connect(m_updateTimer,
+ &QTimer::timeout,
+ this,
+ &ImagesCarousel::_updateImages);
+ connect(this,
+ &ImagesCarousel::imagesLoaded,
+ this,
+ [this]() {
+ _focusCurrImage();
+ disconnect(this, &ImagesCarousel::imagesLoaded, this, nullptr);
+ });
m_updateTimer->start(100);
- connect(this, &ImagesCarousel::imagesLoaded, this, [this]() {
- _focusCurrImage();
- });
+ // Auto focus when scrolling
+ m_scrollDebounceTimer = new QTimer(this);
+ m_scrollDebounceTimer->setSingleShot(true);
+ m_scrollDebounceTimer->setInterval(200);
+ connect(m_scrollDebounceTimer,
+ &QTimer::timeout,
+ this,
+ [this]() {
+ _onScrollBarValueChanged(m_pendingScrollValue);
+ });
+ connect(ui->scrollArea->horizontalScrollBar(),
+ &QScrollBar::valueChanged,
+ this,
+ [this](int value) {
+ m_pendingScrollValue = value;
+ if (m_suppressAutoFocus) {
+ return;
+ }
+ m_scrollDebounceTimer->start();
+ });
}
ImagesCarousel::~ImagesCarousel() {
@@ -57,7 +87,7 @@ ImagesCarousel::~ImagesCarousel() {
// ...
if (m_scrollAnimation) {
m_scrollAnimation->stop();
- delete m_scrollAnimation;
+ m_scrollAnimation->deleteLater();
}
}
@@ -199,7 +229,7 @@ void ImagesCarousel::_focusCurrImage() {
if (m_scrollAnimation) {
m_scrollAnimation->stop();
- delete m_scrollAnimation;
+ m_scrollAnimation->deleteLater();
m_scrollAnimation = nullptr;
}
@@ -208,9 +238,39 @@ void ImagesCarousel::_focusCurrImage() {
m_scrollAnimation->setStartValue(hScrollBar->value());
m_scrollAnimation->setEndValue(leftOffset);
m_scrollAnimation->setEasingCurve(QEasingCurve::OutCubic);
+
+ // Suppress auto focus during animation
+ connect(m_scrollAnimation,
+ &QPropertyAnimation::finished,
+ this,
+ [this]() {
+ m_suppressAutoFocus = false;
+ });
+ m_suppressAutoFocus = true;
m_scrollAnimation->start();
}
+void ImagesCarousel::_onScrollBarValueChanged(int value) {
+ // Stop the animation if it is running
+ if (m_scrollAnimation && m_scrollAnimation->state() == QPropertyAnimation::Running) {
+ m_scrollAnimation->stop();
+ m_scrollAnimation->deleteLater();
+ m_scrollAnimation = nullptr;
+ }
+ int centerOffset = (value + m_itemFocusWidth / 2);
+ int itemOffset = m_itemWidth + ui->scrollAreaWidgetContents->layout()->spacing();
+ int index = centerOffset / itemOffset;
+ if (index < 0 || index >= m_loadedImages.size()) {
+ return; // Out of bounds
+ }
+ if (index == m_currentIndex) {
+ return; // Already focused
+ }
+ _unfocusCurrImage();
+ m_currentIndex = index;
+ _focusCurrImage();
+}
+
ImageItem::ImageItem(const ImageData* data,
const int itemWidth,
const int itemHeight,
diff --git a/src/images_carousel.h b/src/images_carousel.h
index 06ef5ae..4c53f79 100644
--- a/src/images_carousel.h
+++ b/src/images_carousel.h
@@ -1,7 +1,7 @@
/*
* @Author: Uyanide pywang0608@foxmail.com
* @Date: 2025-08-05 01:22:53
- * @LastEditTime: 2025-08-06 00:47:12
+ * @LastEditTime: 2025-08-06 01:32:56
* @Description: Animated carousel widget for displaying and selecting images.
*/
#ifndef IMAGES_CAROUSEL_H
@@ -125,9 +125,11 @@ class ImagesCarousel : public QWidget {
private slots:
void _unfocusCurrImage();
+ void _onScrollBarValueChanged(int value);
public:
- void appendImages(const QStringList& paths);
+ void
+ appendImages(const QStringList& paths);
private:
Q_INVOKABLE void _addImageToQueue(const ImageData* data);
@@ -140,11 +142,14 @@ class ImagesCarousel : public QWidget {
QQueue m_imageQueue;
QList m_loadedImages;
QTimer* m_updateTimer;
- int m_currentIndex = 0;
- QPropertyAnimation* m_scrollAnimation;
- QHBoxLayout* m_imagesLayout = nullptr;
+ int m_currentIndex = 0;
+ QPropertyAnimation* m_scrollAnimation = nullptr;
+ QHBoxLayout* m_imagesLayout = nullptr;
QMutex m_imageCountMutex;
- int m_imageCount = 0;
+ int m_imageCount = 0;
+ bool m_suppressAutoFocus = false;
+ int m_pendingScrollValue = 0;
+ QTimer* m_scrollDebounceTimer = nullptr;
signals:
void imageFocused(const QString& path, const int index, const int count);
@@ -157,13 +162,17 @@ class ImagesCarouselScrollArea : public QScrollArea {
public:
explicit ImagesCarouselScrollArea(QWidget* parent = nullptr)
: QScrollArea(parent) {
- setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- setWidgetResizable(true);
+ // setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ // setWidgetResizable(true);
}
protected:
void keyPressEvent(QKeyEvent* event) override {
- event->ignore();
+ if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) {
+ event->ignore();
+ } else {
+ QScrollArea::keyPressEvent(event);
+ }
}
};