diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2019-06-27 10:27:02 -0400 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2019-07-02 10:10:19 -0400 |
| commit | 1c0024b2feda8b5c152d2e211205601ee807e517 (patch) | |
| tree | 41c54eea23eb434c8dfd94ceb4fd6a81d8a6dec0 /src | |
| parent | 933a2c7d1086ebc87ee2d214deaa3752ea8c6cf1 (diff) | |
moved all images classes into a namespace with shorter names
split theme and metrics into their own class
added filename to thumbs
Diffstat (limited to 'src')
| -rw-r--r-- | src/modinfodialog.ui | 8 | ||||
| -rw-r--r-- | src/modinfodialogimages.cpp | 379 | ||||
| -rw-r--r-- | src/modinfodialogimages.h | 251 |
3 files changed, 399 insertions, 239 deletions
diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index e745967d..3da13261 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -207,14 +207,14 @@ <number>0</number>
</property>
<item>
- <widget class="ImagesThumbnails" name="imagesThumbnails" native="true">
+ <widget class="ImagesTabHelpers::ThumbnailsWidget" name="imagesThumbnails" native="true">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
</widget>
</item>
<item>
- <widget class="ImagesScrollbar" name="imagesScrollerVBar">
+ <widget class="ImagesTabHelpers::Scrollbar" name="imagesScrollerVBar">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@@ -1239,13 +1239,13 @@ p, li { white-space: pre-wrap; } <header>texteditor.h</header>
</customwidget>
<customwidget>
- <class>ImagesThumbnails</class>
+ <class>ImagesTabHelpers::ThumbnailsWidget</class>
<extends>QWidget</extends>
<header>modinfodialogimages.h</header>
<container>1</container>
</customwidget>
<customwidget>
- <class>ImagesScrollbar</class>
+ <class>ImagesTabHelpers::Scrollbar</class>
<extends>QScrollBar</extends>
<header>modinfodialogimages.h</header>
</customwidget>
diff --git a/src/modinfodialogimages.cpp b/src/modinfodialogimages.cpp index 7738d55f..8c323ac6 100644 --- a/src/modinfodialogimages.cpp +++ b/src/modinfodialogimages.cpp @@ -3,6 +3,8 @@ #include "settings.h" #include "utility.h" +using namespace ImagesTabHelpers; + QSize resizeWithAspectRatio(const QSize& original, const QSize& available) { const auto ratio = std::min({ @@ -32,7 +34,6 @@ ImagesTab::ImagesTab( QWidget* parent, Ui::ModInfoDialog* ui, int id) : ModInfoDialogTab(oc, plugin, parent, ui, id), m_image(new ScalableImage), - m_margins(3), m_border(1), m_padding(0), m_spacing(5), m_ddsAvailable(false), m_ddsEnabled(false) { getSupportedFormats(); @@ -69,11 +70,19 @@ ImagesTab::ImagesTab( auto list = std::make_unique<QListWidget>(); parentWidget()->style()->polish(list.get()); - m_colors.border = QColor(Qt::black); - m_colors.background = QColor(Qt::black); - m_colors.selection = list->palette().color(QPalette::Highlight); + m_theme.borderColor = QColor(Qt::black); + m_theme.backgroundColor = QColor(Qt::black); + m_theme.textColor = list->palette().color(QPalette::WindowText); + + m_theme.highlightBackgroundColor = list->palette().color(QPalette::Highlight); + m_theme.highlightTextColor = list->palette().color(QPalette::HighlightedText); + + m_theme.font = list->font(); - m_image->setColors(m_colors.border, m_colors.background); + const QFontMetrics fm(m_theme.font); + m_metrics.textHeight = fm.height(); + + m_image->setColors(m_theme.borderColor, m_theme.backgroundColor); } } @@ -165,8 +174,8 @@ void ImagesTab::switchToFiltered() if (hasTextFilter) { // check filter widget const auto m = m_filter.matches([&](auto&& what) { - return f.path.contains(what, Qt::CaseInsensitive); - }); + return f.path().contains(what, Qt::CaseInsensitive); + }); if (!m) { // no match, skip @@ -176,7 +185,7 @@ void ImagesTab::switchToFiltered() if (!m_ddsEnabled) { // skip .dds files - if (f.path.endsWith(".dds", Qt::CaseInsensitive)) { + if (f.path().endsWith(".dds", Qt::CaseInsensitive)) { continue; } } @@ -227,9 +236,9 @@ void ImagesTab::select(std::size_t i) // pass a null image in setImage() below f->ensureOriginalLoaded(); - ui->imagesPath->setText(QDir::toNativeSeparators(f->path)); + ui->imagesPath->setText(QDir::toNativeSeparators(f->path())); ui->imagesExplore->setEnabled(true); - m_image->setImage(f->original); + m_image->setImage(f->original()); ensureVisible(i); } else { ui->imagesPath->clear(); @@ -297,7 +306,7 @@ std::size_t ImagesTab::fileIndexAtPos(const QPoint& p) const // this is the index relative to the top const auto offset = geo.indexAt(p); - if (offset == ImagesGeometry::BadIndex) { + if (offset == BadIndex) { return BadIndex; } @@ -314,7 +323,7 @@ std::size_t ImagesTab::fileIndexAtPos(const QPoint& p) const return i; } -const ImagesTab::File* ImagesTab::fileAtPos(const QPoint& p) const +const File* ImagesTab::fileAtPos(const QPoint& p) const { const auto i = fileIndexAtPos(p); if (i >= m_files.size()) { @@ -324,11 +333,9 @@ const ImagesTab::File* ImagesTab::fileAtPos(const QPoint& p) const return m_files.get(i); } -ImagesGeometry ImagesTab::makeGeometry() const +Geometry ImagesTab::makeGeometry() const { - return ImagesGeometry( - ui->imagesThumbnails->size(), - m_margins, m_border, m_padding, m_spacing); + return Geometry(ui->imagesThumbnails->size(), m_metrics); } void ImagesTab::paintThumbnailsArea(QPaintEvent* e) @@ -362,13 +369,14 @@ void ImagesTab::paintThumbnail(const PaintContext& cx) paintThumbnailBackground(cx); paintThumbnailBorder(cx); paintThumbnailImage(cx); + paintThumbnailText(cx); } void ImagesTab::paintThumbnailBackground(const PaintContext& cx) { if (m_files.selectedIndex() == cx.fileIndex) { const auto rect = cx.geo.thumbRect(cx.thumbIndex); - cx.painter.fillRect(rect, m_colors.selection); + cx.painter.fillRect(rect, m_theme.highlightBackgroundColor); } } @@ -381,30 +389,46 @@ void ImagesTab::paintThumbnailBorder(const PaintContext& cx) borderRect.setRight(borderRect.right() - 1); borderRect.setBottom(borderRect.bottom() - 1); - cx.painter.setPen(m_colors.border); + cx.painter.setPen(m_theme.borderColor); cx.painter.drawRect(borderRect); } void ImagesTab::paintThumbnailImage(const PaintContext& cx) { - if (cx.file->failed) { + if (cx.file->failed()) { return; } - if (needsReload(cx.geo, *cx.file)) { - reload(cx.geo, *cx.file); - } - - if (cx.file->thumbnail.isNull()) { - return; - } + cx.file->loadIfNeeded(cx.geo); const auto imageRect = cx.geo.imageRect(cx.thumbIndex); const auto scaledThumbRect = centeredRect( - imageRect, cx.file->thumbnail.size()); + imageRect, cx.file->thumbnail().size()); - cx.painter.fillRect(scaledThumbRect, m_colors.background); - cx.painter.drawImage(scaledThumbRect, cx.file->thumbnail); + cx.painter.fillRect(scaledThumbRect, m_theme.backgroundColor); + cx.painter.drawImage(scaledThumbRect, cx.file->thumbnail()); +} + +void ImagesTab::paintThumbnailText(const PaintContext& cx) +{ + const auto tr = cx.geo.textRect(cx.thumbIndex); + + if (cx.fileIndex == m_files.selectedIndex()) { + cx.painter.setPen(m_theme.highlightTextColor); + } else { + cx.painter.setPen(m_theme.textColor); + } + + cx.painter.setFont(m_theme.font); + + QFontMetrics fm(m_theme.font); + + const auto text = fm.elidedText( + cx.file->filename(), Qt::ElideRight, tr.width()); + + const auto flags = Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine; + + cx.painter.drawText(tr, flags, text); } void ImagesTab::scrollAreaResized(const QSize&) @@ -487,14 +511,14 @@ void ImagesTab::showTooltip(QHelpEvent* e) } QToolTip::showText( - e->globalPos(), QDir::toNativeSeparators(f->path), + e->globalPos(), QDir::toNativeSeparators(f->path()), ui->imagesThumbnails); } void ImagesTab::onExplore() { if (auto* f=m_files.selectedFile()) { - MOBase::shell::ExploreFile(f->path); + MOBase::shell::ExploreFile(f->path()); } } @@ -512,34 +536,6 @@ void ImagesTab::onFilterChanged() update(); } -bool ImagesTab::needsReload(const ImagesGeometry& geo, const File& file) const -{ - if (file.failed) { - return false; - } - - if (file.original.isNull() || file.thumbnail.isNull()) { - return true; - } - - const auto scaledSize = geo.scaledImageSize(file.original.size()); - return (file.thumbnail.size() != scaledSize); -} - -void ImagesTab::reload(const ImagesGeometry& geo, File& file) -{ - file.failed = false; - file.ensureOriginalLoaded(); - - if (file.failed) { - return; - } - - file.thumbnail = file.original.scaled( - geo.scaledImageSize(file.original.size()), - Qt::IgnoreAspectRatio, Qt::SmoothTransformation); -} - void ImagesTab::updateScrollbar() { if (m_files.size() == 0) { @@ -565,40 +561,56 @@ void ImagesTab::updateScrollbar() } -void ImagesThumbnails::setTab(ImagesTab* tab) +namespace ImagesTabHelpers +{ + +void Scrollbar::setTab(ImagesTab* tab) +{ + m_tab = tab; +} + +void Scrollbar::wheelEvent(QWheelEvent* e) +{ + if (m_tab) { + m_tab->thumbnailAreaWheelEvent(e); + } +} + + +void ThumbnailsWidget::setTab(ImagesTab* tab) { m_tab = tab; } -void ImagesThumbnails::paintEvent(QPaintEvent* e) +void ThumbnailsWidget::paintEvent(QPaintEvent* e) { if (m_tab) { m_tab->paintThumbnailsArea(e); } } -void ImagesThumbnails::mousePressEvent(QMouseEvent* e) +void ThumbnailsWidget::mousePressEvent(QMouseEvent* e) { if (m_tab) { m_tab->thumbnailAreaMouseEvent(e); } } -void ImagesThumbnails::wheelEvent(QWheelEvent* e) +void ThumbnailsWidget::wheelEvent(QWheelEvent* e) { if (m_tab) { m_tab->thumbnailAreaWheelEvent(e); } } -void ImagesThumbnails::resizeEvent(QResizeEvent* e) +void ThumbnailsWidget::resizeEvent(QResizeEvent* e) { if (m_tab) { m_tab->scrollAreaResized(e->size()); } } -void ImagesThumbnails::keyPressEvent(QKeyEvent* e) +void ThumbnailsWidget::keyPressEvent(QKeyEvent* e) { if (m_tab) { if (m_tab->thumbnailAreaKeyPressEvent(e)) { @@ -609,7 +621,7 @@ void ImagesThumbnails::keyPressEvent(QKeyEvent* e) QWidget::keyPressEvent(e); } -bool ImagesThumbnails::event(QEvent* e) +bool ThumbnailsWidget::event(QEvent* e) { if (e->type() == QEvent::ToolTip) { m_tab->showTooltip(static_cast<QHelpEvent*>(e)); @@ -620,19 +632,6 @@ bool ImagesThumbnails::event(QEvent* e) } -void ImagesScrollbar::setTab(ImagesTab* tab) -{ - m_tab = tab; -} - -void ImagesScrollbar::wheelEvent(QWheelEvent* e) -{ - if (m_tab) { - m_tab->thumbnailAreaWheelEvent(e); - } -} - - ScalableImage::ScalableImage(QString path) : m_path(std::move(path)), m_border(1) { @@ -724,104 +723,220 @@ void ScalableImage::paintEvent(QPaintEvent* e) } -ImagesGeometry::ImagesGeometry( - const QSize& widgetSize, int margins, int border, int padding, int spacing) : - m_widgetSize(widgetSize), - m_margins(margins), m_padding(padding), m_border(border), - m_spacing(spacing), m_topRect(calcTopRect()) +Metrics::Metrics() : + margins(3), + border(1), + padding(0), + spacing(5), + textSpacing(2), + textHeight(0) +{ +} + + +Geometry::Geometry(QSize widgetSize, Metrics metrics) + : m_widgetSize(widgetSize), m_metrics(metrics), m_topRect(calcTopRect()) { } -QRect ImagesGeometry::calcTopRect() const +QRect Geometry::calcTopRect() const { const auto thumbWidth = m_widgetSize.width(); - const auto imageSize = thumbWidth - (m_margins * 2) - (m_border * 2) - (m_padding * 2); + const auto& m = m_metrics; + + const auto imageSize = + thumbWidth - + (m.margins * 2) - + (m.border * 2) - + (m.padding * 2); + const auto thumbHeight = - m_margins + m_border + m_padding + + m.margins + + m.border + m.padding + imageSize + - m_border + m_padding + m_margins; + m.padding + m.border + + m.textSpacing + m.textHeight + + m.margins; return {0, 0, thumbWidth, thumbHeight}; } -std::size_t ImagesGeometry::fullyVisibleCount() const +std::size_t Geometry::fullyVisibleCount() const { const auto r = thumbRect(0); - const auto visible = (m_widgetSize.height() / (r.height() + m_spacing)); + + const auto thumbWithSpacing = r.height() + m_metrics.spacing; + const auto visible = (m_widgetSize.height() / thumbWithSpacing); + return static_cast<std::size_t>(visible); } -QRect ImagesGeometry::thumbRect(std::size_t i) const +QRect Geometry::thumbRect(std::size_t i) const { // rect for the top thumbnail QRect r = m_topRect; // move down - const auto thumbWithSpacing = m_spacing + r.height(); + const auto thumbWithSpacing = m_metrics.spacing + r.height(); r.translate(0, static_cast<int>(i * thumbWithSpacing)); return r; } -QRect ImagesGeometry::borderRect(std::size_t i) const +QRect Geometry::borderRect(std::size_t i) const { auto r = thumbRect(i); + const auto& m = m_metrics; - // remove margins - const auto m = m_margins; - r.adjust(m, m, -m, -m); + // remove margins and text + r.adjust(m.margins, m.margins, -m.margins, -m.margins); + + // remove text + r.adjust(0, 0, 0, -(m.textSpacing + m.textHeight)); return r; } -QRect ImagesGeometry::imageRect(std::size_t i) const +QRect Geometry::imageRect(std::size_t i) const { auto r = borderRect(i); // remove border and padding - const auto m = m_border + m_padding; + const auto m = m_metrics.border + m_metrics.padding; r.adjust(m, m, -m, -m); return r; } -std::size_t ImagesGeometry::indexAt(const QPoint& p) const +QRect Geometry::textRect(std::size_t i) const +{ + const auto r = borderRect(i); + + return QRect( + r.left(), + r.bottom() + m_metrics.textSpacing, + r.width(), + m_metrics.textHeight); +} + +QRect Geometry::selectionRect(std::size_t i) const +{ + const auto br = borderRect(i); + const auto tr = textRect(i); + + return QRect( + br.left(), + br.top(), + br.width(), + tr.bottom() - br.top()); +} + +std::size_t Geometry::indexAt(const QPoint& p) const { // calculate index purely based on y position - const std::size_t offset = p.y() / (m_topRect.height() + m_spacing); + const std::size_t offset = p.y() / (m_topRect.height() + m_metrics.spacing); - if (!borderRect(offset).contains(p)) { + if (!selectionRect(offset).contains(p)) { return BadIndex; } return offset; } -QSize ImagesGeometry::scaledImageSize(const QSize& originalSize) const +QSize Geometry::scaledImageSize(const QSize& originalSize) const { const auto availableSize = imageRect(0).size(); return resizeWithAspectRatio(originalSize, availableSize); } -void ImagesGeometry::dump() const + +File::File(QString path) + : m_path(std::move(path)), m_failed(false) +{ +} + +void File::ensureOriginalLoaded() +{ + if (m_original.isNull()) { + if (!m_original.load(m_path)) { + qCritical() << "failed to load image from " << m_path; + m_failed = true; + } + } +} + +const QString& File::path() const +{ + return m_path; +} + +const QString& File::filename() const +{ + if (m_filename.isEmpty()) { + m_filename = QFileInfo(m_path).fileName(); + } + + return m_filename; +} + +const QImage& File::original() const { - qDebug() - << "ImagesTab geometry:\n" - << " . widget size: " << m_widgetSize << "\n" - << " . margins: " << m_margins << "\n" - << " . border: " << m_border << "\n" - << " . padding: " << m_padding << "\n" - << " . spacing: " << m_spacing << "\n" - << " . top rect: " << m_topRect; + return m_original; } +const QImage& File::thumbnail() const +{ + return m_thumbnail; +} + +bool File::failed() const +{ + return m_failed; +} + +void File::loadIfNeeded(const Geometry& geo) +{ + if (needsLoad(geo)) { + load(geo); + } +} + +bool File::needsLoad(const Geometry& geo) const +{ + if (m_failed) { + return false; + } + + if (m_original.isNull() || m_thumbnail.isNull()) { + return true; + } -ImagesTab::Files::Files() + const auto scaledSize = geo.scaledImageSize(m_original.size()); + return (m_thumbnail.size() != scaledSize); +} + +void File::load(const Geometry& geo) +{ + m_failed = false; + ensureOriginalLoaded(); + + if (m_failed) { + return; + } + + const auto scaledSize = geo.scaledImageSize(m_original.size()); + + m_thumbnail = m_original.scaled( + scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); +} + + +Files::Files() : m_selection(BadIndex), m_filtered(false) { } -void ImagesTab::Files::clear() +void Files::clear() { m_allFiles.clear(); m_filteredFiles.clear(); @@ -829,17 +944,17 @@ void ImagesTab::Files::clear() m_filtered = false; } -void ImagesTab::Files::add(File f) +void Files::add(File f) { m_allFiles.emplace_back(std::move(f)); } -void ImagesTab::Files::addFiltered(File* f) +void Files::addFiltered(File* f) { m_filteredFiles.push_back(f); } -bool ImagesTab::Files::empty() const +bool Files::empty() const { if (m_filtered) { return m_filteredFiles.empty(); @@ -848,7 +963,7 @@ bool ImagesTab::Files::empty() const } } -std::size_t ImagesTab::Files::size() const +std::size_t Files::size() const { if (m_filtered) { return m_filteredFiles.size(); @@ -857,19 +972,19 @@ std::size_t ImagesTab::Files::size() const } } -void ImagesTab::Files::switchToAll() +void Files::switchToAll() { m_filtered = false; m_filteredFiles.clear(); } -void ImagesTab::Files::switchToFiltered() +void Files::switchToFiltered() { m_filtered = true; m_filteredFiles.clear(); } -const ImagesTab::File* ImagesTab::Files::get(std::size_t i) const +const File* Files::get(std::size_t i) const { if (m_filtered) { if (i < m_filteredFiles.size()) { @@ -884,12 +999,12 @@ const ImagesTab::File* ImagesTab::Files::get(std::size_t i) const return nullptr; } -ImagesTab::File* ImagesTab::Files::get(std::size_t i) +File* Files::get(std::size_t i) { return const_cast<File*>(std::as_const(*this).get(i)); } -std::size_t ImagesTab::Files::indexOf(const File* f) const +std::size_t Files::indexOf(const File* f) const { if (m_filtered) { for (std::size_t i=0; i<m_filteredFiles.size(); ++i) { @@ -908,32 +1023,40 @@ std::size_t ImagesTab::Files::indexOf(const File* f) const return BadIndex; } -const ImagesTab::File* ImagesTab::Files::selectedFile() const +const File* Files::selectedFile() const { return get(m_selection); } -ImagesTab::File* ImagesTab::Files::selectedFile() +File* Files::selectedFile() { return get(m_selection); } -std::size_t ImagesTab::Files::selectedIndex() const +std::size_t Files::selectedIndex() const { return m_selection; } -void ImagesTab::Files::select(std::size_t i) +void Files::select(std::size_t i) { m_selection = i; } -std::vector<ImagesTab::File>& ImagesTab::Files::allFiles() +std::vector<File>& Files::allFiles() { return m_allFiles; } -bool ImagesTab::Files::isFiltered() const +bool Files::isFiltered() const { return m_filtered; } + + +PaintContext::PaintContext(QWidget* w, Geometry geo) + : painter(w), geo(geo), file(nullptr), thumbIndex(0), fileIndex(0) +{ +} + +} // namespace diff --git a/src/modinfodialogimages.h b/src/modinfodialogimages.h index 5ce66d5d..0d34b46a 100644 --- a/src/modinfodialogimages.h +++ b/src/modinfodialogimages.h @@ -7,10 +7,15 @@ class ImagesTab; +namespace ImagesTabHelpers +{ + +static constexpr std::size_t BadIndex = std::numeric_limits<std::size_t>::max(); + // vertical scrollbar, this is only to handle wheel events to scroll by one // instead of the system's scroll setting // -class ImagesScrollbar : public QScrollBar +class Scrollbar : public QScrollBar { public: using QScrollBar::QScrollBar; @@ -29,7 +34,7 @@ private: // widget inside the scroller, calls ImagesTab::paintThumbnailArea() when // needed and also forwards mouse clicks and tooltip events // -class ImagesThumbnails : public QWidget +class ThumbnailsWidget : public QWidget { Q_OBJECT; @@ -101,15 +106,47 @@ private: }; +struct Theme +{ + QColor borderColor, backgroundColor, textColor; + QColor highlightBackgroundColor, highlightTextColor; + QFont font; +}; + + +struct Metrics +{ + // space outside the thumbnail border + int margins; + + // size of the border + int border; + + // space between the border and the image + int padding; + + // spacing between the thumbnail and the text + int textSpacing; + + // height of the text + int textHeight; + + // spacing between thumbnails + int spacing; + + Metrics(); +}; + + // handles all the geometry calculations by ImagesTab for painting or handling // mouse clicks // // a thumbnail looks like this: // -// +-----------------------+ <-- thumb rect +// +-----------------------+ <--- thumb rect // | margins | // | | -// | +-border--------+ <------ border rect +// | +-border--------+ <------- border rect // | | padding | | // | | | | // | | +-------+ <----------- image rect @@ -119,6 +156,10 @@ private: // | | +-------+ | | // | | | | // | +---------------+ | +// | text spacing | +// | +---------------+ <------- text rect +// | | text | | +// | +---------------+ | // | | // +-----------------------+ // @@ -130,15 +171,10 @@ private: // .... // // -class ImagesGeometry +class Geometry { public: - // returned by indexAt() if the point is outside any possible thumbnail - static constexpr std::size_t BadIndex = - std::numeric_limits<std::size_t>::max(); - - ImagesGeometry( - const QSize& widgetSize, int margins, int border, int padding, int spacing); + Geometry(QSize widgetSize, Metrics metrics); // returns the number of images fully visible in the widget // @@ -156,9 +192,20 @@ public: // QRect imageRect(std::size_t i) const; + // rectangle of the text for the given thumbnail + // + QRect textRect(std::size_t i) const; + + // rectangle that responds to selection: includes the border and extends down + // to the text + // + QRect selectionRect(std::size_t i) const; + // returns the index of the image at the given point; this does not take into // account any scrolling, the image at the top of widget is always 0 // + // returns BadIndex if there's no thumbnail at this point + // std::size_t indexAt(const QPoint& p) const; // returns the size of the image that fits in imageRect() while keeping the @@ -166,25 +213,12 @@ public: // QSize scaledImageSize(const QSize& originalSize) const; - // dumps stuff to qDebug() - // - void dump() const; - private: // size of the widget containing all the thumbnails const QSize m_widgetSize; - // space outside the thumbnail border - const int m_margins; - - // size of the border - const int m_border; - - // space between the border and the image - const int m_padding; - - // spacing between thumbnails - const int m_spacing; + // metrics + const Metrics m_metrics; // rectangle of the first thumbnail on top const QRect m_topRect; @@ -196,112 +230,116 @@ private: }; -class ImagesTab : public ModInfoDialogTab +class File { - Q_OBJECT; - friend class ImagesScrollbar; - friend class ImagesThumbnails; - public: - ImagesTab( - OrganizerCore& oc, PluginContainer& plugin, - QWidget* parent, Ui::ModInfoDialog* ui, int id); + File(QString path); - void clear() override; - bool feedFile(const QString& rootPath, const QString& fullPath) override; - void update() override; - void saveState(Settings& s) override; - void restoreState(const Settings& s) override; + void ensureOriginalLoaded(); + + const QString& path() const; + const QString& filename() const; + const QImage& original() const; + const QImage& thumbnail() const; + bool failed() const; + + void loadIfNeeded(const Geometry& geo); private: - static constexpr std::size_t BadIndex = - std::numeric_limits<std::size_t>::max(); + QString m_path; + mutable QString m_filename; + QImage m_original, m_thumbnail; + bool m_failed; + + bool needsLoad(const Geometry& geo) const; + void load(const Geometry& geo); +}; + + +class Files +{ +public: + Files(); + + void clear(); - struct File - { - QString path; - QImage original, thumbnail; - bool failed = false; + void add(File f); + void addFiltered(File* f); - File(QString path) - : path(std::move(path)) - { - } + bool empty() const; + std::size_t size() const; - void ensureOriginalLoaded() - { - if (original.isNull()) { - if (!original.load(path)) { - qCritical() << "failed to load image from " << path; - failed = true; - } - } - } - }; + void switchToAll(); + void switchToFiltered(); - struct Colors - { - QColor border, background, selection; - }; + const File* get(std::size_t i) const; + File* get(std::size_t i); + std::size_t indexOf(const File* f) const; - struct PaintContext - { - mutable QPainter painter; - ImagesGeometry geo; - File* file; - std::size_t thumbIndex; - std::size_t fileIndex; + const File* selectedFile() const; + File* selectedFile(); + std::size_t selectedIndex() const; + void select(std::size_t i); - PaintContext(QWidget* w, ImagesGeometry geo) - : painter(w), geo(geo), file(nullptr), thumbIndex(0), fileIndex(0) - { - } - }; + std::vector<File>& allFiles(); - class Files - { - public: - Files(); + bool isFiltered() const; - void clear(); +private: + std::vector<File> m_allFiles; + std::vector<File*> m_filteredFiles; + std::size_t m_selection; + bool m_filtered; +}; - void add(File f); - void addFiltered(File* f); - bool empty() const; - std::size_t size() const; +struct PaintContext +{ + mutable QPainter painter; + Geometry geo; + File* file; + std::size_t thumbIndex; + std::size_t fileIndex; - void switchToAll(); - void switchToFiltered(); + PaintContext(QWidget* w, Geometry geo); +}; - const File* get(std::size_t i) const; - File* get(std::size_t i); - std::size_t indexOf(const File* f) const; +} // namespace - const File* selectedFile() const; - File* selectedFile(); - std::size_t selectedIndex() const; - void select(std::size_t i); - std::vector<File>& allFiles(); +class ImagesTab : public ModInfoDialogTab +{ + Q_OBJECT; + friend class ImagesTabHelpers::Scrollbar; + friend class ImagesTabHelpers::ThumbnailsWidget; - bool isFiltered() const; +public: + ImagesTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui, int id); - private: - std::vector<File> m_allFiles; - std::vector<File*> m_filteredFiles; - std::size_t m_selection; - bool m_filtered; - }; + void clear() override; + bool feedFile(const QString& rootPath, const QString& fullPath) override; + void update() override; + void saveState(Settings& s) override; + void restoreState(const Settings& s) override; +private: + using ScalableImage = ImagesTabHelpers::ScalableImage; + using Files = ImagesTabHelpers::Files; + using File = ImagesTabHelpers::File; + using Theme = ImagesTabHelpers::Theme; + using Metrics = ImagesTabHelpers::Metrics; + using PaintContext = ImagesTabHelpers::PaintContext; + using Geometry = ImagesTabHelpers::Geometry; ScalableImage* m_image; std::vector<QString> m_supportedFormats; Files m_files; - int m_margins, m_border, m_padding, m_spacing; FilterWidget m_filter; bool m_ddsAvailable, m_ddsEnabled; - Colors m_colors; + Theme m_theme; + Metrics m_metrics; void getSupportedFormats(); void enableDDS(bool b); @@ -325,18 +363,17 @@ private: std::size_t fileIndexAtPos(const QPoint& p) const; const File* fileAtPos(const QPoint& p) const; - ImagesGeometry makeGeometry() const; + Geometry makeGeometry() const; void paintThumbnail(const PaintContext& cx); void paintThumbnailBackground(const PaintContext& cx); void paintThumbnailBorder(const PaintContext& cx); void paintThumbnailImage(const PaintContext& cx); + void paintThumbnailText(const PaintContext& cx); void checkFiltering(); void switchToAll(); void switchToFiltered(); - bool needsReload(const ImagesGeometry& geo, const File& file) const; - void reload(const ImagesGeometry& geo, File& file); void updateScrollbar(); }; |
