Draw blank squares for empty blocks in the grid.

Import vectorwrapper, it's just too convenient. It's only used
in one place for now but I will probably use it more from now on.
This commit is contained in:
King_DuckZ 2020-03-28 21:33:46 +01:00
parent 88be1a1247
commit 0d287a60f1
8 changed files with 127 additions and 20 deletions

3
.gitmodules vendored
View file

@ -1,3 +1,6 @@
[submodule "subprojects/cxxopts"] [submodule "subprojects/cxxopts"]
path = subprojects/cxxopts path = subprojects/cxxopts
url = https://github.com/jarro2783/cxxopts.git url = https://github.com/jarro2783/cxxopts.git
[submodule "subprojects/vectorwrapper"]
path = subprojects/vectorwrapper
url = http://alarmpi.no-ip.org/gitan/King_DuckZ/vectorwrapper.git

View file

@ -50,4 +50,7 @@ cxxopts_incl = include_directories('subprojects/cxxopts/include', '.')
memcard_proj = subproject('memcard') memcard_proj = subproject('memcard')
memcard_dep = memcard_proj.get_variable('memcard_dep') memcard_dep = memcard_proj.get_variable('memcard_dep')
vectorwrapper_proj = subproject('vectorwrapper')
vectorwrapper_dep = vectorwrapper_proj.get_variable('vectorwrapper_dep')
subdir('src') subdir('src')

View file

@ -100,10 +100,11 @@ void MemoservWin::open_file_from_dialog() {
m_memcards.push_back(mc::psx::make_memory_card(file.toStdString())); m_memcards.push_back(mc::psx::make_memory_card(file.toStdString()));
auto& mc = m_memcards.back(); auto& mc = m_memcards.back();
auto grid = std::make_unique<widget::BlockGrid>(this, 3, g_icon_fps); auto grid = std::make_unique<widget::BlockGrid>(this, 5, 3, g_icon_fps);
grid->set_icon_size(g_icon_size);
for (const auto& block : mc) { for (const auto& block : mc) {
for (std::size_t n = 0; block.has_magic() and n < block.block_count(); ++n) { for (std::size_t n = 0; block.has_magic() and n < block.block_count(); ++n) {
grid->emplace_back(make_qt_animation(block, g_icon_size, g_icon_size, g_icon_fps)); grid->push_back(make_qt_animation(block, g_icon_size, g_icon_size));
} }
} }
m_main_lay->addWidget(grid.release(), 1, m_grid_count); m_main_lay->addWidget(grid.release(), 1, m_grid_count);

View file

@ -38,6 +38,11 @@ executable(app_name,
'make_qt_animation.cpp', 'make_qt_animation.cpp',
'animated_pixmap.cpp', 'animated_pixmap.cpp',
include_directories: inc, include_directories: inc,
dependencies: [qt5_dep, fslib_dep, memcard_dep], dependencies: [
qt5_dep,
fslib_dep,
memcard_dep,
vectorwrapper_dep
],
install: true, install: true,
) )

45
src/qt/vec.hpp Normal file
View file

@ -0,0 +1,45 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vectorwrapper/vectorwrapper.hpp>
#include <QPoint>
#include <cstddef>
namespace duck::detail {
struct VecSimpleXYPoint { int x, y; };
} //namespace duck::detail
namespace vwr {
template <>
struct VectorWrapperInfo<QPoint> {
enum { dimensions = 2 };
typedef int scalar_type;
typedef QPoint vector_type;
static_assert(sizeof(duck::detail::VecSimpleXYPoint) == sizeof(QPoint), "Unexpected QPoint size, maybe you will have to provide get_at()");
enum {
offset_x = offsetof(duck::detail::VecSimpleXYPoint, x),
offset_y = offsetof(duck::detail::VecSimpleXYPoint, y)
};
};
} //namespace vwr
namespace duck {
typedef vwr::Vec<QPoint> qtint2;
} //namespace duck

View file

@ -16,18 +16,36 @@
*/ */
#include "block_grid.hpp" #include "block_grid.hpp"
#include "vec.hpp"
#include <QPainter> #include <QPainter>
#include <QTimer> #include <QTimer>
#include <QPixmap>
#include <QPoint>
#include <algorithm> #include <algorithm>
namespace duck::widget { namespace duck::widget {
namespace { namespace {
const constexpr int g_icon_spacing = 3; const constexpr int g_icon_spacing = 3;
[[gnu::const]]
qtint2 scalar_to_point (int scalar, int max) {
return {
scalar % max,
scalar / max
};
}
[[gnu::const]]
qtint2 to_qtint2 (const QSize& sz) {
return {sz.width(), sz.height()};
}
} //unnamed namespace } //unnamed namespace
BlockGrid::BlockGrid (QWidget* parent, unsigned int columns, float fps) : BlockGrid::BlockGrid (QWidget* parent, unsigned int rows, unsigned int columns, float fps) :
QWidget(parent), QWidget(parent),
m_anim_timer(new QTimer(this)), m_anim_timer(new QTimer(this)),
m_icon_size(-1, -1),
m_rows(rows),
m_columns(columns) m_columns(columns)
{ {
fps = std::max(fps, 1.0f); fps = std::max(fps, 1.0f);
@ -43,9 +61,9 @@ QSize BlockGrid::minimumSizeHint() const {
QSize BlockGrid::sizeHint() const { QSize BlockGrid::sizeHint() const {
if (m_columns) { if (m_columns) {
const auto w = icon_width() * m_columns + g_icon_spacing * (1 + m_columns); const auto w = icon_size().width() * m_columns + g_icon_spacing * (1 + m_columns);
const unsigned int rows = size() / m_columns; const unsigned int rows = (m_rows ? m_rows : size() / m_columns);
const auto h = icon_height() * rows + g_icon_spacing * (rows + 1); const auto h = icon_size().height() * rows + g_icon_spacing * (rows + 1);
return {static_cast<int>(w), static_cast<int>(h)}; return {static_cast<int>(w), static_cast<int>(h)};
} }
@ -54,12 +72,23 @@ QSize BlockGrid::sizeHint() const {
} }
} }
unsigned int BlockGrid::icon_width() const { void BlockGrid::set_icon_size (const QSize& sz) {
return m_icons.empty() ? static_cast<unsigned int>(g_icon_spacing) : m_icons.front().size().width(); if (sz != m_icon_size) {
m_icon_size = sz;
m_empty_icon.reset();
if (m_icon_size.isValid()) {
m_empty_icon = std::make_unique<QPixmap>(m_icon_size);
m_empty_icon->fill(QColor(115, 115, 115, 255));
}
}
} }
unsigned int BlockGrid::icon_height() const { void BlockGrid::set_icon_size (int sz) {
return m_icons.empty() ? static_cast<unsigned int>(g_icon_spacing) : m_icons.front().size().height(); set_icon_size(QSize{sz, sz});
}
QSize BlockGrid::icon_size() const {
return m_icon_size.isValid() ? m_icon_size : QSize(g_icon_spacing, g_icon_spacing);
} }
void BlockGrid::push_back (AnimatedPixmap&& anim) { void BlockGrid::push_back (AnimatedPixmap&& anim) {
@ -70,6 +99,17 @@ std::size_t BlockGrid::size() const {
return m_icons.size(); return m_icons.size();
} }
unsigned int BlockGrid::rows() const {
if (m_rows) {
return m_rows;
}
else {
const auto widget_h = static_cast<unsigned int>(std::max(this->height(), g_icon_spacing));
const auto ico_spacing_uns = static_cast<unsigned int>(g_icon_spacing);
return (widget_h - ico_spacing_uns) / (icon_size().height() + ico_spacing_uns);
}
}
unsigned int BlockGrid::columns() const { unsigned int BlockGrid::columns() const {
if (m_columns) { if (m_columns) {
return m_columns; return m_columns;
@ -78,26 +118,29 @@ unsigned int BlockGrid::columns() const {
const auto widget_w = static_cast<unsigned int>(std::max(this->width(), g_icon_spacing)); const auto widget_w = static_cast<unsigned int>(std::max(this->width(), g_icon_spacing));
const auto ico_spacing_uns = static_cast<unsigned int>(g_icon_spacing); const auto ico_spacing_uns = static_cast<unsigned int>(g_icon_spacing);
return (widget_w - ico_spacing_uns) / (icon_width() + ico_spacing_uns); return (widget_w - ico_spacing_uns) / (icon_size().width() + ico_spacing_uns);
} }
} }
void BlockGrid::paintEvent (QPaintEvent* event) { void BlockGrid::paintEvent (QPaintEvent* event) {
QPainter painter(this); QPainter painter(this);
const int max_col = static_cast<int>(this->columns()); const int max_col = static_cast<int>(this->columns());
int x = 0;
int y = 0;
int count = 0; int count = 0;
for (auto& ico : m_icons) { for (auto& ico : m_icons) {
x = g_icon_spacing + (count % max_col) * (g_icon_spacing + ico.size().width()); auto point = g_icon_spacing + scalar_to_point(count, max_col) * (g_icon_spacing + to_qtint2(ico.size()));
y = g_icon_spacing + (count / max_col) * (g_icon_spacing + ico.size().height());
if (ico.frame_count()) { if (ico.frame_count()) {
painter.drawPixmap(x, y, ico.current_frame()); painter.drawPixmap(point.x(), point.y(), ico.current_frame());
} }
++count; ++count;
} }
const int total_squares = static_cast<int>(rows() * columns());
for (int z = count; z < total_squares && m_empty_icon; ++z) {
auto point = g_icon_spacing + scalar_to_point(z, max_col) * (g_icon_spacing + to_qtint2(icon_size()));
painter.drawPixmap(point.x(), point.y(), *m_empty_icon);
}
} }
void BlockGrid::advance_frame() { void BlockGrid::advance_frame() {

View file

@ -19,6 +19,7 @@
#include "../animated_pixmap.hpp" #include "../animated_pixmap.hpp"
#include <QWidget> #include <QWidget>
#include <QPixmap>
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -28,14 +29,15 @@ namespace duck::widget {
class BlockGrid : public QWidget { class BlockGrid : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit BlockGrid (QWidget* parent=nullptr, unsigned int columns=0, float fps=24.0f); explicit BlockGrid (QWidget* parent=nullptr, unsigned int rows=0, unsigned int columns=0, float fps=24.0f);
~BlockGrid() noexcept; ~BlockGrid() noexcept;
QSize minimumSizeHint() const override; QSize minimumSizeHint() const override;
QSize sizeHint() const override; QSize sizeHint() const override;
unsigned int icon_width() const; void set_icon_size (const QSize& sz);
unsigned int icon_height() const; void set_icon_size (int sz);
QSize icon_size() const;
void push_back (AnimatedPixmap&& anim); void push_back (AnimatedPixmap&& anim);
std::size_t size() const; std::size_t size() const;
@ -47,10 +49,14 @@ private slots:
void advance_frame(); void advance_frame();
private: private:
unsigned int rows() const;
unsigned int columns() const; unsigned int columns() const;
std::vector<AnimatedPixmap> m_icons; std::vector<AnimatedPixmap> m_icons;
QTimer* m_anim_timer; QTimer* m_anim_timer;
std::unique_ptr<QPixmap> m_empty_icon;
QSize m_icon_size;
unsigned int m_rows;
unsigned int m_columns; unsigned int m_columns;
}; };
} //namespace duck::widget } //namespace duck::widget

@ -0,0 +1 @@
Subproject commit 0a90a289a2c354c88130dbf04a4c15c696e0a9de