From 85f2d9bae40afd718f4e3a8afb98cbc1dc2dd406 Mon Sep 17 00:00:00 2001 From: ponchio Date: Wed, 31 Jan 2024 02:26:24 +0100 Subject: [PATCH] added image grid visualization. --- relightlab/flowlayout.cpp | 136 ++++++++++++++++++++++++++++++++++++++ relightlab/flowlayout.h | 41 ++++++++++++ relightlab/imageframe.cpp | 33 ++++++++- relightlab/imageframe.h | 6 ++ relightlab/imagegrid.cpp | 47 +++++++++++++ relightlab/imagegrid.h | 26 ++++++++ relightlab/imagelist.cpp | 1 - relightlab/relightapp.cpp | 2 - relightlab/relightapp.h | 2 +- relightlab/relightlab.pro | 8 ++- 10 files changed, 293 insertions(+), 9 deletions(-) create mode 100644 relightlab/flowlayout.cpp create mode 100644 relightlab/flowlayout.h create mode 100644 relightlab/imagegrid.cpp create mode 100644 relightlab/imagegrid.h diff --git a/relightlab/flowlayout.cpp b/relightlab/flowlayout.cpp new file mode 100644 index 00000000..38874c0c --- /dev/null +++ b/relightlab/flowlayout.cpp @@ -0,0 +1,136 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include + +#include "flowlayout.h" + +FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) + : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing) { + setContentsMargins(margin, margin, margin, margin); +} + +FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing) + : m_hSpace(hSpacing), m_vSpace(vSpacing) { + setContentsMargins(margin, margin, margin, margin); +} + +FlowLayout::~FlowLayout() { + QLayoutItem *item; + while ((item = takeAt(0))) + delete item; +} + +void FlowLayout::addItem(QLayoutItem *item) { + itemList.append(item); +} + +int FlowLayout::horizontalSpacing() const { + if (m_hSpace >= 0) { + return m_hSpace; + } else { + return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); + } +} + +int FlowLayout::verticalSpacing() const { + if (m_vSpace >= 0) { + return m_vSpace; + } else { + return smartSpacing(QStyle::PM_LayoutVerticalSpacing); + } +} + +int FlowLayout::count() const { + return itemList.size(); +} + +QLayoutItem *FlowLayout::itemAt(int index) const { + return itemList.value(index); +} + +QLayoutItem *FlowLayout::takeAt(int index) { + if (index >= 0 && index < itemList.size()) + return itemList.takeAt(index); + return nullptr; +} + +Qt::Orientations FlowLayout::expandingDirections() const { + return { }; +} + +bool FlowLayout::hasHeightForWidth() const { + return true; +} + +int FlowLayout::heightForWidth(int width) const { + int height = doLayout(QRect(0, 0, width, 0), true); + return height; +} + +void FlowLayout::setGeometry(const QRect &rect) { + QLayout::setGeometry(rect); + doLayout(rect, false); +} + +QSize FlowLayout::sizeHint() const { + return minimumSize(); +} + +QSize FlowLayout::minimumSize() const { + QSize size; + for (const QLayoutItem *item : itemList) + size = size.expandedTo(item->minimumSize()); + + const QMargins margins = contentsMargins(); + size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); + return size; +} + +int FlowLayout::doLayout(const QRect &rect, bool testOnly) const { + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); + int x = effectiveRect.x(); + int y = effectiveRect.y(); + int lineHeight = 0; + + for (QLayoutItem *item : itemList) { + const QWidget *wid = item->widget(); + int spaceX = horizontalSpacing(); + if (spaceX == -1) + spaceX = wid->style()->layoutSpacing( + QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); + int spaceY = verticalSpacing(); + if (spaceY == -1) + spaceY = wid->style()->layoutSpacing( + QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); + + int nextX = x + item->sizeHint().width() + spaceX; + if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { + x = effectiveRect.x(); + y = y + lineHeight + spaceY; + nextX = x + item->sizeHint().width() + spaceX; + lineHeight = 0; + } + + if (!testOnly) + item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); + + x = nextX; + lineHeight = qMax(lineHeight, item->sizeHint().height()); + } + return y + lineHeight - rect.y() + bottom; +} + +int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const { + QObject *parent = this->parent(); + if (!parent) { + return -1; + } else if (parent->isWidgetType()) { + QWidget *pw = static_cast(parent); + return pw->style()->pixelMetric(pm, nullptr, pw); + } else { + return static_cast(parent)->spacing(); + } +} diff --git a/relightlab/flowlayout.h b/relightlab/flowlayout.h new file mode 100644 index 00000000..bd400b3a --- /dev/null +++ b/relightlab/flowlayout.h @@ -0,0 +1,41 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef FLOWLAYOUT_H +#define FLOWLAYOUT_H + +#include +#include +#include + +class FlowLayout : public QLayout +{ +public: + explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); + explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); + ~FlowLayout(); + + void addItem(QLayoutItem *item) override; + int horizontalSpacing() const; + int verticalSpacing() const; + Qt::Orientations expandingDirections() const override; + bool hasHeightForWidth() const override; + int heightForWidth(int) const override; + int count() const override; + QLayoutItem *itemAt(int index) const override; + QSize minimumSize() const override; + void setGeometry(const QRect &rect) override; + QSize sizeHint() const override; + QLayoutItem *takeAt(int index) override; + +private: + int doLayout(const QRect &rect, bool testOnly) const; + int smartSpacing(QStyle::PixelMetric pm) const; + + QList itemList; + int m_hSpace; + int m_vSpace; +}; + + +#endif // FLOWLAYOUT_H diff --git a/relightlab/imageframe.cpp b/relightlab/imageframe.cpp index 9e22de18..900406a3 100644 --- a/relightlab/imageframe.cpp +++ b/relightlab/imageframe.cpp @@ -10,6 +10,7 @@ #include "imageframe.h" #include "canvas.h" #include "imagelist.h" +#include "imagegrid.h" #include using namespace std; @@ -51,6 +52,9 @@ ImageFrame::ImageFrame() { image_list = new ImageList(); content->addWidget(image_list, 0); + image_grid = new ImageGrid(); + content->addWidget(image_grid, 1); + canvas = new Canvas(); content->addWidget(canvas, 1); @@ -68,6 +72,10 @@ ImageFrame::ImageFrame() { connect(image_list, SIGNAL(itemPressed(QListWidgetItem*)), this, SLOT(showImageItem(QListWidgetItem*))); + connect(qRelightApp->action("show_image"), SIGNAL(triggered(bool)), this, SLOT(imageMode())); + connect(qRelightApp->action("show_list"), SIGNAL(triggered(bool)), this, SLOT(listMode())); + connect(qRelightApp->action("show_grid"), SIGNAL(triggered(bool)), this, SLOT(gridMode())); + container->addLayout(content); status = new QStatusBar(); @@ -76,9 +84,10 @@ ImageFrame::ImageFrame() { void ImageFrame::init() { image_list->init(); + image_grid->init(); showImage(0); fit(); - showImage(0); + listMode(); //TODO actually use last used mode used by the user } void ImageFrame::showImage(int id) { @@ -86,7 +95,7 @@ void ImageFrame::showImage(int id) { image_list->setCurrentRow(id); qRelightApp->action("previous_image")->setEnabled(id != 0); - qRelightApp->action("next_image")->setEnabled(id != project.images.size()-1); + qRelightApp->action("next_image")->setEnabled(id != (int)project.images.size()-1); QString filename = project.images[id].filename; @@ -137,7 +146,7 @@ void ImageFrame::previousImage() { void ImageFrame::nextImage() { int current = image_list->currentRow(); - if(current++ == qRelightApp->project().images.size()-1) + if(current++ == (int)qRelightApp->project().images.size()-1) return; image_list->setCurrentRow(current); showImage(current); @@ -148,3 +157,21 @@ void ImageFrame::showImageItem(QListWidgetItem *item) { int id =item->listWidget()->currentRow(); showImage(id); } + +void ImageFrame::imageMode() { + canvas->show(); + image_list->hide(); + image_grid->hide(); +} +void ImageFrame::listMode() { + canvas->show(); + image_list->show(); + image_grid->hide(); + +} +void ImageFrame::gridMode() { + canvas->hide(); + image_list->hide(); + image_grid->show(); +} + diff --git a/relightlab/imageframe.h b/relightlab/imageframe.h index 27b71afc..bc8859fc 100644 --- a/relightlab/imageframe.h +++ b/relightlab/imageframe.h @@ -5,6 +5,7 @@ class Canvas; class ImageList; +class ImageGrid; class QStatusBar; class QGraphicsPixmapItem; @@ -17,6 +18,7 @@ class ImageFrame: public QFrame { public: enum Mode { SINGLE, LIST, THUMBNAILS }; ImageList *image_list = nullptr; + ImageGrid *image_grid = nullptr; Canvas *canvas = nullptr; QStatusBar *status = nullptr; ImageFrame(); @@ -31,6 +33,10 @@ public slots: void nextImage(); void showImageItem(QListWidgetItem *item); + void imageMode(); + void listMode(); + void gridMode(); + private: QGraphicsPixmapItem *imagePixmap = nullptr; QGraphicsScene *scene = nullptr; diff --git a/relightlab/imagegrid.cpp b/relightlab/imagegrid.cpp new file mode 100644 index 00000000..5784fc30 --- /dev/null +++ b/relightlab/imagegrid.cpp @@ -0,0 +1,47 @@ +#include "imagegrid.h" +#include "relightapp.h" +#include "flowlayout.h" + +#include +#include +#include +#include +#include + + +ImageThumb::ImageThumb(const QString& imagePath, const QString& text, QWidget* parent): QWidget(parent) { + + QVBoxLayout* layout = new QVBoxLayout(this); + + QLabel* thumb = new QLabel; + QImage img(imagePath); + img = img.scaledToHeight(256); + thumb->setPixmap(QPixmap::fromImage(img)); + layout->addWidget(thumb); + + QCheckBox *checkbox = new QCheckBox(text); + layout->addWidget(checkbox); + + layout->setSpacing(5); + layout->setContentsMargins(5, 5, 5, 5); +} + +ImageGrid::ImageGrid(QWidget *parent): QScrollArea(parent) { + + flowlayout = new FlowLayout(); + setWidgetResizable(true); + setWidget(new QWidget); + widget()->setLayout(flowlayout); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); +} + +void ImageGrid::init() { + Project &project = qRelightApp->project(); + + for(Image &img: project.images) { + QFileInfo info(img.filename); + ImageThumb *thumb = new ImageThumb(img.filename, info.fileName()); + flowlayout->addWidget(thumb); + } +} + diff --git a/relightlab/imagegrid.h b/relightlab/imagegrid.h new file mode 100644 index 00000000..ac00ab59 --- /dev/null +++ b/relightlab/imagegrid.h @@ -0,0 +1,26 @@ +#ifndef IMAGEGRID_H +#define IMAGEGRID_H + +#include +#include + + +class FlowLayout; + + +class ImageThumb : public QWidget { +public: + ImageThumb(const QString& imagePath, const QString& text, QWidget* parent = nullptr); +}; + + +class ImageGrid: public QScrollArea { +public: + ImageGrid(QWidget *parent = nullptr); + + void init(); +private: + FlowLayout *flowlayout = nullptr; +}; + +#endif // IMAGEGRID_H diff --git a/relightlab/imagelist.cpp b/relightlab/imagelist.cpp index 1a6a4afe..825d1521 100644 --- a/relightlab/imagelist.cpp +++ b/relightlab/imagelist.cpp @@ -13,6 +13,5 @@ void ImageList::init() { item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable); item->setCheckState(Qt::Unchecked); addItem(item); - } } diff --git a/relightlab/relightapp.cpp b/relightlab/relightapp.cpp index d12128c4..a06af212 100644 --- a/relightlab/relightapp.cpp +++ b/relightlab/relightapp.cpp @@ -46,8 +46,6 @@ RelightApp::RelightApp(int &argc, char **argv): QApplication(argc, argv) { addAction("show_list", "Show list", "", ""); addAction("show_grid", "Show grid", "", ""); } -RelightApp::~RelightApp() { -} void RelightApp::run() { mainwindow = new MainWindow; diff --git a/relightlab/relightapp.h b/relightlab/relightapp.h index ae176153..d2fcc785 100644 --- a/relightlab/relightapp.h +++ b/relightlab/relightapp.h @@ -23,7 +23,7 @@ class RelightApp: public QApplication { MainWindow *mainwindow = nullptr; RelightApp(int &argc, char **argv); - ~RelightApp(); + virtual ~RelightApp() {} void run(); public slots: diff --git a/relightlab/relightlab.pro b/relightlab/relightlab.pro index b27d8b9c..4305bd68 100644 --- a/relightlab/relightlab.pro +++ b/relightlab/relightlab.pro @@ -45,7 +45,9 @@ SOURCES += main.cpp \ tabwidget.cpp \ imageframe.cpp \ homeframe.cpp \ - imagelist.cpp + imagelist.cpp \ + flowlayout.cpp \ + imagegrid.cpp RESOURCES += \ res.qrc @@ -77,4 +79,6 @@ HEADERS += \ tabwidget.h \ imageframe.h \ homeframe.h \ - imagelist.h + imagelist.h \ + flowlayout.h \ + imagegrid.h