diff --git a/src/qt/animated_pixmap.cpp b/src/qt/animated_pixmap.cpp new file mode 100644 index 0000000..9003e7c --- /dev/null +++ b/src/qt/animated_pixmap.cpp @@ -0,0 +1,56 @@ +/* Copyright 2020, Michele Santullo + * This file is part of memoserv. + * + * Memoserv is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Memoserv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Memoserv. If not, see . + */ + +#include "animated_pixmap.hpp" +#include + +namespace duck { +AnimatedPixmap::AnimatedPixmap (bool loop) : + m_frame(0), + m_loop(loop) +{ +} + +AnimatedPixmap::~AnimatedPixmap() noexcept = default; + +void AnimatedPixmap::push_back (QPixmap&& frame) { + m_frames.push_back(std::move(frame)); +} + +std::size_t AnimatedPixmap::frame_count() const { + return m_frames.size(); +} + +QSize AnimatedPixmap::size() const { + return { + (m_frames.empty() ? EmptyPixmapWidth : m_frames.front().width()), + (m_frames.empty() ? EmptyPixmapHeight : m_frames.front().height()) + }; +} + +void AnimatedPixmap::advance_frame() { + ++m_frame; + if (m_loop) + m_frame = (not m_frames.empty() ? m_frame % m_frames.size() : 0); + else + m_frame = std::min(m_frame, m_frames.size()); +} + +const QPixmap& AnimatedPixmap::current_frame() const { + return m_frames[m_frame]; +} +} //namespace duck diff --git a/src/qt/widgets/animated_icon.hpp b/src/qt/animated_pixmap.hpp similarity index 54% rename from src/qt/widgets/animated_icon.hpp rename to src/qt/animated_pixmap.hpp index ec54a28..4c206a1 100644 --- a/src/qt/widgets/animated_icon.hpp +++ b/src/qt/animated_pixmap.hpp @@ -17,43 +17,32 @@ #pragma once -#include #include #include -namespace duck::widget { -class AnimatedIcon : public QWidget { - Q_OBJECT +namespace duck { +class AnimatedPixmap { public: - static const constexpr unsigned int EmptyIconWidth = 50; - static const constexpr unsigned int EmptyIconHeight = EmptyIconWidth; + static const constexpr int EmptyPixmapWidth = -1; + static const constexpr int EmptyPixmapHeight = EmptyPixmapWidth; - AnimatedIcon (AnimatedIcon&&) = default; - AnimatedIcon (const AnimatedIcon&) = delete; - explicit AnimatedIcon (QWidget* parent=nullptr, float fps=24.0f, bool loop=true); - ~AnimatedIcon() noexcept; + AnimatedPixmap (AnimatedPixmap&&) = default; + AnimatedPixmap (const AnimatedPixmap&) = delete; + AnimatedPixmap (bool loop); + ~AnimatedPixmap() noexcept; - AnimatedIcon& operator= (AnimatedIcon&&) = default; - - QSize minimumSizeHint() const override; - QSize sizeHint() const override; + AnimatedPixmap& operator= (AnimatedPixmap&&) = default; void push_back (QPixmap&& frame); - std::size_t size() const; + std::size_t frame_count() const; + QSize size() const; - unsigned int width() const; - unsigned int height() const; - -public slots: void advance_frame(); - -protected: - void paintEvent (QPaintEvent* event) override; + const QPixmap& current_frame() const; private: std::vector m_frames; std::size_t m_frame; - float m_fps; bool m_loop; }; -} //namespace duck::widget +} //namespace duck diff --git a/src/qt/make_qt_animation.cpp b/src/qt/make_qt_animation.cpp index 8250908..a45376d 100644 --- a/src/qt/make_qt_animation.cpp +++ b/src/qt/make_qt_animation.cpp @@ -21,15 +21,15 @@ #include namespace duck { - std::unique_ptr make_qt_animation (const mc::psx::ConstBlock& block, int width, int height, float fps) { + AnimatedPixmap make_qt_animation (const mc::psx::ConstBlock& block, int width, int height) { using mc::icon_fetch; - auto retval = std::make_unique(); + AnimatedPixmap retval(true); for (const auto& frame : icon_fetch(block, width, height)) { QPixmap pix(width, height); pix.loadFromData(reinterpret_cast(frame.data()), frame.size(), "BMP"); - retval->push_back(std::move(pix)); + retval.push_back(std::move(pix)); } return retval; diff --git a/src/qt/make_qt_animation.hpp b/src/qt/make_qt_animation.hpp index d2e0c89..4e495b6 100644 --- a/src/qt/make_qt_animation.hpp +++ b/src/qt/make_qt_animation.hpp @@ -17,8 +17,7 @@ #pragma once -#include "widgets/animated_icon.hpp" -#include +#include "animated_pixmap.hpp" namespace mc::psx { template class BasicBlock; @@ -26,10 +25,9 @@ using ConstBlock = BasicBlock; } //namespace mc::psx namespace duck { - std::unique_ptr make_qt_animation ( + AnimatedPixmap make_qt_animation ( const mc::psx::ConstBlock& block, int width, - int height, - float fps + int height ); } //namespace duck diff --git a/src/qt/meson.build b/src/qt/meson.build index a4cb59e..8fa4df4 100644 --- a/src/qt/meson.build +++ b/src/qt/meson.build @@ -9,7 +9,6 @@ moc_files = qt5.preprocess( 'memoserv_win.hpp', 'version_info_win.hpp', 'widgets/block_grid.hpp', - 'widgets/animated_icon.hpp', ], #ui_files: 'main_window.ui', moc_extra_arguments: ['-DMAKES_MY_MOC_HEADER_COMPILE'], @@ -36,8 +35,8 @@ executable(app_name, project_config_file, gitrev_config_file, 'widgets/block_grid.cpp', - 'widgets/animated_icon.cpp', 'make_qt_animation.cpp', + 'animated_pixmap.cpp', include_directories: inc, dependencies: [qt5_dep, fslib_dep, memcard_dep], install: true, diff --git a/src/qt/widgets/animated_icon.cpp b/src/qt/widgets/animated_icon.cpp deleted file mode 100644 index d374a1e..0000000 --- a/src/qt/widgets/animated_icon.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright 2020, Michele Santullo - * This file is part of memoserv. - * - * Memoserv is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Memoserv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Memoserv. If not, see . - */ - -#include "animated_icon.hpp" -#include -#include -#include - -namespace duck::widget { -namespace { -} //unnamed namespace - -AnimatedIcon::AnimatedIcon (QWidget* parent, float fps, bool loop) : - QWidget(parent), - m_frame(0), - m_fps(fps), - m_loop(loop) -{ - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); -} - -AnimatedIcon::~AnimatedIcon() noexcept = default; - -QSize AnimatedIcon::minimumSizeHint() const { - return {static_cast(width()), static_cast(height())}; -} - -QSize AnimatedIcon::sizeHint() const { - return {static_cast(width()), static_cast(height())}; -} - -void AnimatedIcon::push_back (QPixmap&& frame) { - m_frames.push_back(std::move(frame)); -} - -std::size_t AnimatedIcon::size() const { - return m_frames.size(); -} - -unsigned int AnimatedIcon::width() const { - return (m_frames.empty() ? EmptyIconWidth : m_frames.front().width()); -} - -unsigned int AnimatedIcon::height() const { - return (m_frames.empty() ? EmptyIconHeight : m_frames.front().height()); -} - -void AnimatedIcon::advance_frame() { - ++m_frame; - if (m_loop) - m_frame = (not m_frames.empty() ? m_frame % m_frames.size() : 0); - else - m_frame = std::min(m_frame, m_frames.size()); - update(); -} - -void AnimatedIcon::paintEvent (QPaintEvent* event) { - if (m_frame < m_frames.size()) { - QPainter painter(this); - painter.drawPixmap(0, 0, m_frames[m_frame]); - } -} - -} //namespace duck::widget diff --git a/src/qt/widgets/block_grid.cpp b/src/qt/widgets/block_grid.cpp index db89d6d..8d08d07 100644 --- a/src/qt/widgets/block_grid.cpp +++ b/src/qt/widgets/block_grid.cpp @@ -17,28 +17,19 @@ #include "block_grid.hpp" #include -#include +#include +#include +#include namespace duck::widget { namespace { const constexpr int g_icon_spacing = 3; } //unnamed namespace -BlockGrid::BlockGrid (QWidget* parent) : - BlockGrid(parent, 3) -{ -} - BlockGrid::BlockGrid (QWidget* parent, unsigned int columns) : QWidget(parent), - m_columns(columns), - m_block_lay(nullptr) + m_columns(columns) { - auto block_lay = std::make_unique(); - block_lay->setSpacing(g_icon_spacing); - m_block_lay = block_lay.get(); - m_block_lay->setColumnStretch(m_columns, 1); - this->setLayout(block_lay.release()); } BlockGrid::~BlockGrid() noexcept = default; @@ -48,39 +39,61 @@ QSize BlockGrid::minimumSizeHint() const { } QSize BlockGrid::sizeHint() const { - const auto w = icon_width() * m_columns + g_icon_spacing * (1 + m_columns); - const unsigned int rows = size() / m_columns; - const auto h = icon_height() * rows + g_icon_spacing * (rows + 1); + if (m_columns) { + const auto w = icon_width() * m_columns + g_icon_spacing * (1 + m_columns); + const unsigned int rows = size() / m_columns; + const auto h = icon_height() * rows + g_icon_spacing * (rows + 1); - return {static_cast(w), static_cast(h)}; + return {static_cast(w), static_cast(h)}; + } + else { + return {-1, -1}; + } } unsigned int BlockGrid::icon_width() const { - return m_icons.empty() ? AnimatedIcon::EmptyIconWidth : m_icons.front()->width(); + return m_icons.empty() ? static_cast(g_icon_spacing) : m_icons.front().size().width(); } unsigned int BlockGrid::icon_height() const { - return m_icons.empty() ? AnimatedIcon::EmptyIconHeight : m_icons.front()->height(); + return m_icons.empty() ? static_cast(g_icon_spacing) : m_icons.front().size().height(); } -void BlockGrid::emplace_back (std::unique_ptr&& anim) { - const auto& columns = m_columns; - const auto count = this->size(); - - const int x = count % columns; - const int y = count / columns; - - { - const auto raw_ptr = anim.release(); - m_block_lay->addWidget(raw_ptr, y, x); - m_icons.push_back(raw_ptr); - } - - m_block_lay->setRowStretch(y, 0); - m_block_lay->setRowStretch(y + 1, 1); +void BlockGrid::push_back (AnimatedPixmap&& anim) { + m_icons.push_back(std::move(anim)); } std::size_t BlockGrid::size() const { return m_icons.size(); } + +unsigned int BlockGrid::columns() const { + if (m_columns) { + return m_columns; + } + else { + const auto widget_w = static_cast(std::max(this->width(), g_icon_spacing)); + const auto ico_spacing_uns = static_cast(g_icon_spacing); + + return (widget_w - ico_spacing_uns) / (icon_width() + ico_spacing_uns); + } +} + +void BlockGrid::paintEvent (QPaintEvent* event) { + QPainter painter(this); + const int max_col = static_cast(this->columns()); + int x = 0; + int y = 0; + int count = 0; + + for (auto& ico : m_icons) { + x = g_icon_spacing + (count % max_col) * (g_icon_spacing + ico.size().width()); + y = g_icon_spacing + (count / max_col) * (g_icon_spacing + ico.size().height()); + if (ico.frame_count()) { + painter.drawPixmap(x, y, ico.current_frame()); + } + + ++count; + } +} } //namespace duck::widget diff --git a/src/qt/widgets/block_grid.hpp b/src/qt/widgets/block_grid.hpp index ebf25ee..09e156f 100644 --- a/src/qt/widgets/block_grid.hpp +++ b/src/qt/widgets/block_grid.hpp @@ -17,7 +17,7 @@ #pragma once -#include "animated_icon.hpp" +#include "../animated_pixmap.hpp" #include #include #include @@ -28,8 +28,7 @@ namespace duck::widget { class BlockGrid : public QWidget { Q_OBJECT public: - explicit BlockGrid (QWidget* parent=nullptr); - BlockGrid (QWidget* parent, unsigned int columns); + explicit BlockGrid (QWidget* parent=nullptr, unsigned int columns=0); ~BlockGrid() noexcept; QSize minimumSizeHint() const override; @@ -38,12 +37,16 @@ public: unsigned int icon_width() const; unsigned int icon_height() const; - void emplace_back (std::unique_ptr&& anim); + void push_back (AnimatedPixmap&& anim); std::size_t size() const; +protected: + void paintEvent (QPaintEvent* event) override; + private: - std::vector m_icons; + unsigned int columns() const; + + std::vector m_icons; unsigned int m_columns; - QGridLayout* m_block_lay; }; } //namespace duck::widget