refactor: remove unnecessary list
This commit is contained in:
+43
-37
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author: Uyanide pywang0608@foxmail.com
|
* @Author: Uyanide pywang0608@foxmail.com
|
||||||
* @Date: 2025-08-05 01:22:53
|
* @Date: 2025-08-05 01:22:53
|
||||||
* @LastEditTime: 2025-12-01 00:58:12
|
* @LastEditTime: 2025-12-01 01:40:01
|
||||||
* @Description: Animated carousel widget for displaying and selecting images.
|
* @Description: Animated carousel widget for displaying and selecting images.
|
||||||
*/
|
*/
|
||||||
#include "images_carousel.h"
|
#include "images_carousel.h"
|
||||||
@@ -14,11 +14,11 @@
|
|||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
#include <QThreadPool>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <algorithm>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
|
#include "image_item.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "ui_images_carousel.h"
|
#include "ui_images_carousel.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
@@ -87,7 +87,7 @@ void ImagesCarousel::_onImagesLoaded() {
|
|||||||
}
|
}
|
||||||
if (m_initialImagesLoaded) {
|
if (m_initialImagesLoaded) {
|
||||||
// No images loaded
|
// No images loaded
|
||||||
if (m_loadedImages.isEmpty()) {
|
if (!getLoadedImagesCount()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Focus the first image
|
// Focus the first image
|
||||||
@@ -102,8 +102,6 @@ void ImagesCarousel::_onImagesLoaded() {
|
|||||||
|
|
||||||
ImagesCarousel::~ImagesCarousel() {
|
ImagesCarousel::~ImagesCarousel() {
|
||||||
delete ui;
|
delete ui;
|
||||||
// memory of items in m_loadedImages managed by Qt parent-child system
|
|
||||||
// ...
|
|
||||||
if (m_scrollAnimation) {
|
if (m_scrollAnimation) {
|
||||||
m_scrollAnimation->stop();
|
m_scrollAnimation->stop();
|
||||||
m_scrollAnimation->deleteLater();
|
m_scrollAnimation->deleteLater();
|
||||||
@@ -132,7 +130,6 @@ void ImagesCarousel::appendImages(const QStringList& paths) {
|
|||||||
&ImagesCarousel::_processImageInsertQueue);
|
&ImagesCarousel::_processImageInsertQueue);
|
||||||
m_imageInsertQueueTimer->start();
|
m_imageInsertQueueTimer->start();
|
||||||
}
|
}
|
||||||
m_loadedImages.reserve(m_loadedImages.size() + paths.size());
|
|
||||||
emit loadingStarted(paths.size());
|
emit loadingStarted(paths.size());
|
||||||
for (const QString& path : paths) {
|
for (const QString& path : paths) {
|
||||||
ImageLoader* loader = new ImageLoader(path, this);
|
ImageLoader* loader = new ImageLoader(path, this);
|
||||||
@@ -162,7 +159,7 @@ void ImagesCarousel::_insertImageQueue(const ImageData* data) {
|
|||||||
int ImagesCarousel::_insertImage(const ImageData* data) {
|
int ImagesCarousel::_insertImage(const ImageData* data) {
|
||||||
// Increase loaded count regardless of success or failure
|
// Increase loaded count regardless of success or failure
|
||||||
Defer defer([this]() {
|
Defer defer([this]() {
|
||||||
emit imageLoaded(m_loadedImages.size());
|
emit imageLoaded(getLoadedImagesCount());
|
||||||
{
|
{
|
||||||
QMutexLocker countLocker(&m_countMutex);
|
QMutexLocker countLocker(&m_countMutex);
|
||||||
if (++m_loadedImagesCount >= m_addedImagesCount) {
|
if (++m_loadedImagesCount >= m_addedImagesCount) {
|
||||||
@@ -204,26 +201,26 @@ int ImagesCarousel::_insertImage(const ImageData* data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// insert into correct position based on sort type and direction
|
// insert into correct position based on sort type and direction
|
||||||
qint64 insertPos = m_loadedImages.size();
|
qint64 insertPos = getLoadedImagesCount();
|
||||||
if (m_sortType != Config::SortType::None) {
|
if (m_sortType != Config::SortType::None) {
|
||||||
auto cmp = cmpFuncs[static_cast<int>(m_sortType)];
|
auto cmp = cmpFuncs[static_cast<int>(m_sortType)];
|
||||||
auto reverse = m_sortReverse;
|
auto reverse = m_sortReverse;
|
||||||
|
|
||||||
auto it = std::upper_bound(
|
int left = 0, right = getLoadedImagesCount();
|
||||||
m_loadedImages.begin(),
|
while (left < right) {
|
||||||
m_loadedImages.end(),
|
int mid = left + (right - left) / 2;
|
||||||
item,
|
if (reverse ? cmp(item, getImageItemAt(mid)) : cmp(getImageItemAt(mid), item)) {
|
||||||
[cmp, reverse](const ImageItem* a, const ImageItem* b) {
|
right = mid;
|
||||||
return reverse ? cmp(b, a) : cmp(a, b);
|
} else {
|
||||||
});
|
left = mid + 1;
|
||||||
|
}
|
||||||
insertPos = std::distance(m_loadedImages.begin(), it);
|
}
|
||||||
|
insertPos = left;
|
||||||
}
|
}
|
||||||
connect(item,
|
connect(item,
|
||||||
&ImageItem::clicked,
|
&ImageItem::clicked,
|
||||||
this,
|
this,
|
||||||
&ImagesCarousel::_onItemClicked);
|
&ImagesCarousel::_onItemClicked);
|
||||||
m_loadedImages.insert(insertPos, item);
|
|
||||||
m_imagesLayout->insertWidget(insertPos, item);
|
m_imagesLayout->insertWidget(insertPos, item);
|
||||||
return insertPos;
|
return insertPos;
|
||||||
}
|
}
|
||||||
@@ -247,7 +244,7 @@ void ImagesCarousel::_processImageInsertQueue() {
|
|||||||
// Update focusing index if any
|
// Update focusing index if any
|
||||||
if (m_currentIndex >= 0) {
|
if (m_currentIndex >= 0) {
|
||||||
m_currentIndex = currPos;
|
m_currentIndex = currPos;
|
||||||
if (m_currentIndex < 0 || m_currentIndex >= m_loadedImages.size()) {
|
if (m_currentIndex < 0 || m_currentIndex >= getLoadedImagesCount()) {
|
||||||
m_currentIndex = 0;
|
m_currentIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,46 +280,49 @@ void ImageLoader::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ImagesCarousel::focusNextImage() {
|
void ImagesCarousel::focusNextImage() {
|
||||||
|
const auto count = getLoadedImagesCount();
|
||||||
// If no focus, focus the first image
|
// If no focus, focus the first image
|
||||||
if (m_currentIndex < 0) {
|
if (m_currentIndex < 0) {
|
||||||
if (m_loadedImages.isEmpty()) return;
|
if (!count) return;
|
||||||
m_currentIndex = 0;
|
m_currentIndex = 0;
|
||||||
focusCurrImage();
|
focusCurrImage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unfocusCurrImage();
|
unfocusCurrImage();
|
||||||
if (m_loadedImages.size() <= 1) return;
|
if (count <= 1) return;
|
||||||
m_currentIndex++;
|
m_currentIndex++;
|
||||||
if (m_currentIndex >= m_loadedImages.size()) {
|
if (m_currentIndex >= count) {
|
||||||
m_currentIndex = 0;
|
m_currentIndex = 0;
|
||||||
}
|
}
|
||||||
focusCurrImage();
|
focusCurrImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImagesCarousel::focusPrevImage() {
|
void ImagesCarousel::focusPrevImage() {
|
||||||
|
const auto count = getLoadedImagesCount();
|
||||||
// If no focus, focus the last image
|
// If no focus, focus the last image
|
||||||
if (m_currentIndex < 0) {
|
if (m_currentIndex < 0) {
|
||||||
if (m_loadedImages.isEmpty()) return;
|
if (!count) return;
|
||||||
m_currentIndex = m_loadedImages.size() - 1;
|
m_currentIndex = count - 1;
|
||||||
focusCurrImage();
|
focusCurrImage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_loadedImages.size() <= 1) return;
|
if (count <= 1) return;
|
||||||
unfocusCurrImage();
|
unfocusCurrImage();
|
||||||
m_currentIndex--;
|
m_currentIndex--;
|
||||||
if (m_currentIndex < 0) {
|
if (m_currentIndex < 0) {
|
||||||
m_currentIndex = m_loadedImages.size() - 1;
|
m_currentIndex = count - 1;
|
||||||
}
|
}
|
||||||
focusCurrImage();
|
focusCurrImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImagesCarousel::unfocusCurrImage() {
|
void ImagesCarousel::unfocusCurrImage() {
|
||||||
if (m_currentIndex < 0) return;
|
if (m_currentIndex < 0) return;
|
||||||
if (m_currentIndex >= m_loadedImages.size()) {
|
if (m_currentIndex >= getLoadedImagesCount()) {
|
||||||
warn(QString("Invalid index to unfocus: %1").arg(m_currentIndex));
|
warn(QString("Invalid index to unfocus: %1").arg(m_currentIndex));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_loadedImages[m_currentIndex]->setFocus(false, m_animationEnabled);
|
auto item = getImageItemAt(m_currentIndex);
|
||||||
|
if (item) item->setFocus(false, m_animationEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ImagesCarousel::_focusingLeftOffset(int index) {
|
int ImagesCarousel::_focusingLeftOffset(int index) {
|
||||||
@@ -334,14 +334,19 @@ int ImagesCarousel::_focusingLeftOffset(int index) {
|
|||||||
void ImagesCarousel::focusCurrImage() {
|
void ImagesCarousel::focusCurrImage() {
|
||||||
// If no focus, do nothing
|
// If no focus, do nothing
|
||||||
if (m_currentIndex < 0) return;
|
if (m_currentIndex < 0) return;
|
||||||
if (m_currentIndex >= m_loadedImages.size()) {
|
if (m_currentIndex >= getLoadedImagesCount()) {
|
||||||
warn(QString("Invalid index to focus: %1").arg(m_currentIndex));
|
warn(QString("Invalid index to focus: %1").arg(m_currentIndex));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_loadedImages[m_currentIndex]->setFocus(true, m_animationEnabled);
|
auto item = getImageItemAt(m_currentIndex);
|
||||||
emit imageFocused(m_loadedImages[m_currentIndex]->getFileFullPath(),
|
if (!item) {
|
||||||
|
warn(QString("Failed to get item at index: %1").arg(m_currentIndex));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item->setFocus(true, m_animationEnabled);
|
||||||
|
emit imageFocused(item->getFileFullPath(),
|
||||||
m_currentIndex,
|
m_currentIndex,
|
||||||
m_loadedImages.size());
|
getLoadedImagesCount());
|
||||||
auto hScrollBar = ui->scrollArea->horizontalScrollBar();
|
auto hScrollBar = ui->scrollArea->horizontalScrollBar();
|
||||||
int leftOffset = _focusingLeftOffset(m_currentIndex);
|
int leftOffset = _focusingLeftOffset(m_currentIndex);
|
||||||
if (leftOffset < 0) {
|
if (leftOffset < 0) {
|
||||||
@@ -389,7 +394,7 @@ void ImagesCarousel::_onScrollBarValueChanged(int value) {
|
|||||||
int itemOffset = m_itemWidth + ui->scrollAreaWidgetContents->layout()->spacing();
|
int itemOffset = m_itemWidth + ui->scrollAreaWidgetContents->layout()->spacing();
|
||||||
int index = centerOffset / itemOffset;
|
int index = centerOffset / itemOffset;
|
||||||
|
|
||||||
if (index < 0 || index >= m_loadedImages.size()) {
|
if (index < 0 || index >= getLoadedImagesCount()) {
|
||||||
return; // Out of bounds
|
return; // Out of bounds
|
||||||
}
|
}
|
||||||
if (index == m_currentIndex) {
|
if (index == m_currentIndex) {
|
||||||
@@ -404,14 +409,15 @@ void ImagesCarousel::_onItemClicked(const QString& path) {
|
|||||||
// if (m_suppressAutoFocus) return;
|
// if (m_suppressAutoFocus) return;
|
||||||
unfocusCurrImage();
|
unfocusCurrImage();
|
||||||
// Most likely the clicked item is near the current index
|
// Most likely the clicked item is near the current index
|
||||||
|
const auto count = getLoadedImagesCount();
|
||||||
for (int i = m_currentIndex, j = m_currentIndex + 1;
|
for (int i = m_currentIndex, j = m_currentIndex + 1;
|
||||||
i >= 0 || j < m_loadedImages.size();
|
i >= 0 || j < count;
|
||||||
--i, ++j) {
|
--i, ++j) {
|
||||||
if (i >= 0 && m_loadedImages[i]->getFileFullPath() == path) {
|
if (i >= 0 && getImageItemAt(i)->getFileFullPath() == path) {
|
||||||
m_currentIndex = i;
|
m_currentIndex = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (j < m_loadedImages.size() && m_loadedImages[j]->getFileFullPath() == path) {
|
if (j < count && getImageItemAt(j)->getFileFullPath() == path) {
|
||||||
m_currentIndex = j;
|
m_currentIndex = j;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-12
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author: Uyanide pywang0608@foxmail.com
|
* @Author: Uyanide pywang0608@foxmail.com
|
||||||
* @Date: 2025-08-05 01:22:53
|
* @Date: 2025-08-05 01:22:53
|
||||||
* @LastEditTime: 2025-12-01 00:59:39
|
* @LastEditTime: 2025-12-01 01:36:04
|
||||||
* @Description: Animated carousel widget for displaying and selecting images.
|
* @Description: Animated carousel widget for displaying and selecting images.
|
||||||
*/
|
*/
|
||||||
#ifndef IMAGES_CAROUSEL_H
|
#ifndef IMAGES_CAROUSEL_H
|
||||||
@@ -12,18 +12,13 @@
|
|||||||
|
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QLabel>
|
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QObject>
|
|
||||||
#include <QPixmap>
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QPropertyAnimation>
|
#include <QPropertyAnimation>
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
#include <QRunnable>
|
#include <QRunnable>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QThreadPool>
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "image_item.h"
|
#include "image_item.h"
|
||||||
@@ -70,15 +65,28 @@ class ImagesCarousel : public QWidget {
|
|||||||
static constexpr int s_processBatchSize = 30; // items
|
static constexpr int s_processBatchSize = 30; // items
|
||||||
|
|
||||||
[[nodiscard]] QString getCurrentImagePath() const {
|
[[nodiscard]] QString getCurrentImagePath() const {
|
||||||
if (m_currentIndex < 0 || m_currentIndex >= m_loadedImages.size()) {
|
if (m_currentIndex >= 0 && m_currentIndex < getLoadedImagesCount()) {
|
||||||
return "";
|
auto item = getImageItemAt(m_currentIndex);
|
||||||
|
if (item) {
|
||||||
|
return item->getFileFullPath();
|
||||||
}
|
}
|
||||||
return m_loadedImages[m_currentIndex]->getFileFullPath();
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should always be called in the main thread
|
// Should always be called in the main thread
|
||||||
[[nodiscard]] qsizetype getLoadedImagesCount() {
|
[[nodiscard]] qsizetype getLoadedImagesCount() const {
|
||||||
return m_loadedImages.size();
|
return m_imagesLayout->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] ImageItem* getImageItemAt(int index) const {
|
||||||
|
if (index < 0 || index >= getLoadedImagesCount()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return dynamic_cast<ImageItem*>(
|
||||||
|
m_imagesLayout
|
||||||
|
->itemAt(index)
|
||||||
|
->widget());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] qsizetype getAddedImagesCount() {
|
[[nodiscard]] qsizetype getAddedImagesCount() {
|
||||||
@@ -126,7 +134,6 @@ class ImagesCarousel : public QWidget {
|
|||||||
ImagesCarouselScrollArea* m_scrollArea = nullptr;
|
ImagesCarouselScrollArea* m_scrollArea = nullptr;
|
||||||
|
|
||||||
// Items and counters
|
// Items and counters
|
||||||
QVector<ImageItem*> m_loadedImages; // m_loadedImages.size() may != m_loadedImagesCount
|
|
||||||
int m_loadedImagesCount = 0; // increase when _insertImage is called OR ImageLoader::run() is called with m_stopSign as true
|
int m_loadedImagesCount = 0; // increase when _insertImage is called OR ImageLoader::run() is called with m_stopSign as true
|
||||||
int m_addedImagesCount = 0; // increase when appendImages called
|
int m_addedImagesCount = 0; // increase when appendImages called
|
||||||
QMutex m_countMutex; // for m_loadedImagesCount and m_addedImagesCount
|
QMutex m_countMutex; // for m_loadedImagesCount and m_addedImagesCount
|
||||||
|
|||||||
Reference in New Issue
Block a user