aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2022-09-06 01:13:42 -0400
committerGravatar Chris Xiong <chirs241097@gmail.com> 2022-09-06 01:13:42 -0400
commit532ea00ea6ec0e20898ef009e432ea1f55dc8db1 (patch)
tree53bd9a8fba8a8bcca02ad6b84f3863aa3120fb7c
parentad93efafe98029ff72dec710949ea168d648dbd7 (diff)
downloaddeduper-532ea00ea6ec0e20898ef009e432ea1f55dc8db1.tar.xz
Transitioning to using ListView to show images.
The old widgets are not yet removed. A LOT of old sh*t needs rewriting for removing them. (Note to self) Other TODOs: - Convert all keyevents to qactions. - Convert main window to an actual main window. - Move file loading logic out of main.cpp (or not, doesn't even matter). - Move subsliced signatures into library.
-rw-r--r--mingui/CMakeLists.txt1
-rw-r--r--mingui/imageitem.cpp129
-rw-r--r--mingui/imageitem.hpp39
-rw-r--r--mingui/mingui.cpp47
-rw-r--r--mingui/mingui.hpp7
5 files changed, 223 insertions, 0 deletions
diff --git a/mingui/CMakeLists.txt b/mingui/CMakeLists.txt
index 3a53455..3503f98 100644
--- a/mingui/CMakeLists.txt
+++ b/mingui/CMakeLists.txt
@@ -17,6 +17,7 @@ set(CMAKE_AUTOUIC ON)
add_executable(mingui
main.cpp
mingui.cpp
+ imageitem.cpp
)
target_link_libraries(mingui
diff --git a/mingui/imageitem.cpp b/mingui/imageitem.cpp
new file mode 100644
index 0000000..ec7dc94
--- /dev/null
+++ b/mingui/imageitem.cpp
@@ -0,0 +1,129 @@
+#include "imageitem.hpp"
+
+#include <algorithm>
+
+#include <QDebug>
+#include <QFileInfo>
+#include <QPixmap>
+#include <QListView>
+#include <QScrollBar>
+#include <QFontMetrics>
+#include <QPainter>
+#include <QLocale>
+
+ImageItem::ImageItem(QString fn, QString dispn, QKeySequence hotkey, double pxratio)
+{
+ this->setText(dispn);
+ this->setData(fn, ImageItemRoles::path_role);
+ this->setData(QFileInfo(fn).size(), ImageItemRoles::file_size_role);
+ this->setCheckable(true);
+ QPixmap pm(fn);
+ pm.setDevicePixelRatio(pxratio);
+ this->setData(pm.size(), ImageItemRoles::dimension_role);
+ this->setData(hotkey, ImageItemRoles::hotkey_role);
+ this->setData(pm, Qt::ItemDataRole::DecorationRole);
+}
+
+void ImageItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ QRect imr = option.rect;
+ imr.adjust(MARGIN + BORDER, MARGIN + BORDER, -MARGIN - BORDER, -MARGIN - BORDER);
+ QFont bfnt(option.font);
+ bfnt.setBold(true);
+ QFontMetrics bfm(bfnt);
+ imr.adjust(0, 0, 0, -2 * HKPADD - bfm.height() - LINESP);
+
+ QRect selr = option.rect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
+ QStyleOptionViewItem so(option);
+ so.rect = selr;
+ if (index.data(Qt::ItemDataRole::CheckStateRole).value<Qt::CheckState>() == Qt::CheckState::Checked)
+ so.state |= QStyle::StateFlag::State_Selected;
+ so.state |= QStyle::StateFlag::State_Active;
+ option.widget->style()->drawPrimitive(QStyle::PrimitiveElement::PE_PanelItemViewItem, &so, painter, option.widget);
+
+
+ QPixmap pm = index.data(Qt::ItemDataRole::DecorationRole).value<QPixmap>();
+ QSize imd = pm.size().scaled(imr.size(), Qt::AspectRatioMode::KeepAspectRatio);
+ painter->setRenderHint(QPainter::RenderHint::SmoothPixmapTransform);
+ painter->drawPixmap(QRect(imr.topLeft(), imd), pm);
+ QPoint dtopright = QRect(imr.topLeft(),imd).bottomLeft();
+
+ QPoint hko = dtopright + QPoint(HKPADD, HKPADD + LINESP);
+ QKeySequence ks = index.data(ImageItem::ImageItemRoles::hotkey_role).value<QKeySequence>();
+ QString kss = ks.toString();
+ QRect r = bfm.boundingRect(kss);
+ r.moveTopLeft(hko);
+ QRect hkbg = r.adjusted(-HKPADD, -HKPADD, HKPADD, HKPADD);
+ if (hkbg.width() < hkbg.height())
+ {
+ int shift = (hkbg.height() - hkbg.width()) / 2;
+ r.adjust(shift, 0, shift, 0);
+ hkbg.setWidth(hkbg.height());
+ }
+ painter->setPen(QPen(QBrush(), 0));
+ painter->setBrush(option.widget->palette().color(QPalette::ColorGroup::Normal, QPalette::ColorRole::Light));
+ painter->drawRoundedRect(hkbg.adjusted(HKSHDS, HKSHDS, HKSHDS, HKSHDS), 4, 4);
+ painter->setBrush(option.widget->palette().color(QPalette::ColorGroup::Normal, QPalette::ColorRole::WindowText));
+ painter->drawRoundedRect(hkbg, 4, 4);
+ painter->setPen(option.widget->palette().color(QPalette::ColorGroup::Normal, QPalette::ColorRole::Window));
+ painter->setBrush(QBrush());
+ painter->setFont(bfnt);
+ painter->drawText(r, kss);
+
+ QPoint ftopright = hkbg.topRight() + QPoint(LINESP + HKSHDS, 0);
+ QSize dim = index.data(ImageItem::ImageItemRoles::dimension_role).value<QSize>();
+ qint64 fsz = index.data(ImageItem::ImageItemRoles::file_size_role).value<qint64>();
+ QString infos = QString("%1 x %2, %3")
+ .arg(dim.width()).arg(dim.height())
+ .arg(QLocale::system().formattedDataSize(fsz, 3));
+ QString fns = index.data(Qt::ItemDataRole::DisplayRole).toString();
+ r = option.fontMetrics.boundingRect(infos);
+ r.moveTopLeft(ftopright + QPoint(0, (hkbg.height() - r.height()) / 2));
+ painter->setFont(option.font);
+ painter->setPen(option.widget->palette().color(QPalette::ColorGroup::Normal, QPalette::ColorRole::Text));
+ painter->drawText(r, infos);
+ r = option.fontMetrics.boundingRect(fns);
+ r.moveTopRight(QPoint(option.rect.right() - MARGIN - BORDER, ftopright.y() + (hkbg.height() - r.height()) / 2));
+ painter->drawText(r, fns);
+ /*
+ painter->setPen(QColor(Qt::GlobalColor::red));
+ painter->drawRect(QRect(imr.topLeft(), imd));
+ painter->drawRect(txt);
+ painter->setPen(option.widget->palette().color(QPalette::ColorRole::Text));
+ */
+}
+
+QSize ImageItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ const QListView *lw = qobject_cast<const QListView*>(option.widget);
+ QSize vpsz = lw->maximumViewportSize();
+ QScrollBar *vsc = lw->verticalScrollBar();
+ if (vsc->isVisible())
+ vpsz.setWidth(vpsz.width() - vsc->size().width());
+ QScrollBar *hsc = lw->horizontalScrollBar();
+ if (hsc->isVisible())
+ vpsz.setHeight(vpsz.height() - vsc->size().height());
+ QPixmap pm = index.data(Qt::ItemDataRole::DecorationRole).value<QPixmap>();
+ QSize onscsz = pm.size() / pm.devicePixelRatioF();
+ int imh = onscsz.height();
+ if (onscsz.width() > vpsz.width() - 2 * MARGIN - 2 * BORDER)
+ imh = (vpsz.width() - 2 * MARGIN - 2 * BORDER) / (double)onscsz.width() * onscsz.height();
+
+ QFont fnt(option.font);
+ fnt.setBold(true);
+ QFontMetrics fm(fnt);
+ int extra_height = 2 * MARGIN + 2 * BORDER + LINESP + fm.height() + 2 * HKPADD + HKSHDS;
+ int min_height = 64;
+ int max_height = imh;
+
+ QSize ret(vpsz);
+ ret.setHeight(vpsz.height() / index.model()->rowCount() - lw->spacing());
+ ret.setHeight(std::max(min_height + extra_height, ret.height()));
+ ret.setHeight(std::min(max_height + extra_height, ret.height()));
+ return ret;
+}
+
+void ImageItemDelegate::resize(const QModelIndex &index)
+{
+ Q_EMIT sizeHintChanged(index);
+}
diff --git a/mingui/imageitem.hpp b/mingui/imageitem.hpp
new file mode 100644
index 0000000..8c9397e
--- /dev/null
+++ b/mingui/imageitem.hpp
@@ -0,0 +1,39 @@
+#ifndef IMAGEITEM_HPP
+#define IMAGEITEM_HPP
+
+#include <QStandardItem>
+#include <QAbstractItemDelegate>
+#include <QStyleOptionViewItem>
+#include <QModelIndex>
+
+class ImageItem : public QStandardItem
+{
+public:
+ enum ImageItemRoles
+ {
+ path_role = Qt::ItemDataRole::UserRole + 0x1000,
+ dimension_role,
+ file_size_role,
+ hotkey_role
+ };
+ ImageItem(QString fn, QString dispn, QKeySequence hotkey, double pxratio = 1.0);
+};
+
+class ImageItemDelegate : public QAbstractItemDelegate
+{
+ Q_OBJECT
+private:
+ const static int MARGIN = 3;
+ const static int BORDER = 3;
+ const static int HKPADD = 4;
+ const static int LINESP = 4;
+ const static int HKSHDS = 2;
+public:
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ void resize(const QModelIndex &index);
+Q_SIGNALS:
+ void sizeHintChanged(const QModelIndex &index);
+};
+
+#endif
diff --git a/mingui/mingui.cpp b/mingui/mingui.cpp
index ab1a083..94f7e81 100644
--- a/mingui/mingui.cpp
+++ b/mingui/mingui.cpp
@@ -1,4 +1,5 @@
#include "mingui.hpp"
+#include "imageitem.hpp"
#include <cstdio>
#include <cwchar>
@@ -8,6 +9,8 @@
#include <QKeyEvent>
#include <QString>
#include <QScrollArea>
+#include <QListView>
+#include <QStandardItemModel>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
@@ -59,9 +62,39 @@ MinGuiWidget::MinGuiWidget()
infopanel = new QTextEdit(this);
infopanel->setReadOnly(true);
imgcontainer = new QWidget(this);
+ lw = new QListView(this);
+ im = new QStandardItemModel(this);
+ lw->setModel(im);
+ id = new ImageItemDelegate();
+ lw->setItemDelegate(id);
+ lw->setSelectionMode(QAbstractItemView::SelectionMode::NoSelection);
+ lw->setResizeMode(QListView::ResizeMode::Adjust);
+ QObject::connect(lw, &QListView::clicked, [this](const QModelIndex &i) {
+ auto cs = i.data(Qt::ItemDataRole::CheckStateRole).value<Qt::CheckState>();
+ if (cs == Qt::CheckState::Checked)
+ cs = Qt::CheckState::Unchecked;
+ else cs = Qt::CheckState::Checked;
+ this->im->setData(i, cs, Qt::ItemDataRole::CheckStateRole);
+ });
+ QObject::connect(lw, &QListView::doubleClicked, [this](const QModelIndex &i) {
+ auto cs = i.data(Qt::ItemDataRole::CheckStateRole).value<Qt::CheckState>();
+ if (cs == Qt::CheckState::Checked)
+ cs = Qt::CheckState::Unchecked;
+ else cs = Qt::CheckState::Checked;
+ this->im->setData(i, cs, Qt::ItemDataRole::CheckStateRole);
+ QDesktopServices::openUrl(QUrl::fromLocalFile(i.data(ImageItem::ImageItemRoles::path_role).toString()));
+ });
+ QObject::connect(im, &QStandardItemModel::itemChanged, [this](QStandardItem *i) {
+ ImageItem *itm = static_cast<ImageItem*>(i);
+ QModelIndex idx = itm->index();
+ bool checked = itm->data(Qt::ItemDataRole::CheckStateRole) == Qt::CheckState::Checked;
+ if (checked != marks[idx.row()])
+ this->mark_toggle(idx.row());
+ });
sa = new QScrollArea(this);
sa->setFrameStyle(QFrame::Shape::NoFrame);
l->addWidget(sa);
+ l->addWidget(lw);
l->addWidget(infopanel);
marked.clear();
infopanel->setText("bleh");
@@ -74,6 +107,7 @@ void MinGuiWidget::show_images(const std::vector<fs::path> &fns)
current_set = fns;
marks.clear();
imgw.clear();
+ im->clear();
qDeleteAll(imgcontainer->children());
sa->takeWidget();
imgcontainer->setLayout(new QVBoxLayout(imgcontainer));
@@ -94,6 +128,7 @@ void MinGuiWidget::show_images(const std::vector<fs::path> &fns)
{
marks.push_back(marked.find(f) != marked.end());
ImageWidget *tw = new ImageWidget(f, f.native().substr(common_pfx.length()), idx, max_width, max_height, this);
+ im->appendRow(new ImageItem(fsstr_to_qstring(f.native()), fsstr_to_qstring(f.native().substr(common_pfx.length())), keys[idx], lw->devicePixelRatioF()));
QObject::connect(tw, &ImageWidget::clicked, [this, idx] { this->mark_toggle(idx); });
imgw.push_back(tw);
imgcontainer->layout()->addWidget(tw);
@@ -230,10 +265,14 @@ void MinGuiWidget::mark_view_update(bool update_msg)
if (marks[i])
{
p.setColor(QPalette::ColorRole::Window, Qt::GlobalColor::red);
+ im->item(i)->setCheckState(Qt::CheckState::Checked);
++m;
}
else
+ {
p.setColor(QPalette::ColorRole::Window, this->palette().color(QPalette::ColorRole::Window));
+ im->item(i)->setCheckState(Qt::CheckState::Unchecked);
+ }
imgw[i]->setBackgroundRole(QPalette::ColorRole::Window);
imgw[i]->setAutoFillBackground(true);
imgw[i]->setPalette(p);
@@ -301,6 +340,14 @@ void MinGuiWidget::keyReleaseEvent(QKeyEvent *e)
}
}
+void MinGuiWidget::resizeEvent(QResizeEvent *e)
+{
+ QWidget::resizeEvent(e);
+ if (!id || !im) return;
+ for (int i = 0; i < im->rowCount(); ++i)
+ id->resize(im->indexFromItem(im->item(i)));
+}
+
void MinGuiWidget::closeEvent(QCloseEvent *e)
{
if (QMessageBox::StandardButton::Yes ==
diff --git a/mingui/mingui.hpp b/mingui/mingui.hpp
index 755b6ad..aa71596 100644
--- a/mingui/mingui.hpp
+++ b/mingui/mingui.hpp
@@ -13,6 +13,9 @@ class QLabel;
class QStatusBar;
class QScrollArea;
class QTextEdit;
+class QListView;
+class QStandardItemModel;
+class ImageItemDelegate;
namespace fs = std::filesystem;
@@ -26,6 +29,9 @@ private:
QWidget *imgcontainer;
QStatusBar *sb;
QScrollArea *sa;
+ QListView *lw;
+ QStandardItemModel *im = nullptr;
+ ImageItemDelegate *id = nullptr;
std::size_t ngroups, curgroup;
bool nohotkeywarn;
void mark_toggle(std::size_t x);
@@ -41,6 +47,7 @@ private:
protected:
void keyPressEvent(QKeyEvent *e) override;
void keyReleaseEvent(QKeyEvent *e) override;
+ void resizeEvent(QResizeEvent *e) override;
void closeEvent(QCloseEvent *e) override;
public:
MinGuiWidget();