feat(texturepackPage): icon column
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
parent
9913080a82
commit
d384d991fa
@ -23,6 +23,8 @@
|
||||
#include <QMap>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "MTPixmapCache.h"
|
||||
|
||||
#include "minecraft/mod/tasks/LocalTexturePackParseTask.h"
|
||||
|
||||
void TexturePack::setDescription(QString new_description)
|
||||
@ -32,34 +34,41 @@ void TexturePack::setDescription(QString new_description)
|
||||
m_description = new_description;
|
||||
}
|
||||
|
||||
void TexturePack::setImage(QImage new_image)
|
||||
void TexturePack::setImage(QImage new_image) const
|
||||
{
|
||||
QMutexLocker locker(&m_data_lock);
|
||||
|
||||
Q_ASSERT(!new_image.isNull());
|
||||
|
||||
if (m_pack_image_cache_key.key.isValid())
|
||||
QPixmapCache::remove(m_pack_image_cache_key.key);
|
||||
PixmapCache::remove(m_pack_image_cache_key.key);
|
||||
|
||||
m_pack_image_cache_key.key = QPixmapCache::insert(QPixmap::fromImage(new_image));
|
||||
// scale the image to avoid flooding the pixmapcache
|
||||
auto pixmap = QPixmap::fromImage(new_image.scaled(QSize(128, 128), Qt::AspectRatioMode::KeepAspectRatioByExpanding));
|
||||
|
||||
m_pack_image_cache_key.key = PixmapCache::insert(pixmap);
|
||||
m_pack_image_cache_key.was_ever_used = true;
|
||||
}
|
||||
|
||||
QPixmap TexturePack::image(QSize size)
|
||||
QPixmap TexturePack::image(QSize size, Qt::AspectRatioMode mode) const
|
||||
{
|
||||
QPixmap cached_image;
|
||||
if (QPixmapCache::find(m_pack_image_cache_key.key, &cached_image)) {
|
||||
if (PixmapCache::find(m_pack_image_cache_key.key, &cached_image)) {
|
||||
if (size.isNull())
|
||||
return cached_image;
|
||||
return cached_image.scaled(size);
|
||||
return cached_image.scaled(size, mode);
|
||||
}
|
||||
|
||||
// No valid image we can get
|
||||
if (!m_pack_image_cache_key.was_ever_used)
|
||||
if (!m_pack_image_cache_key.was_ever_used) {
|
||||
return {};
|
||||
} else {
|
||||
qDebug() << "Texture Pack" << name() << "Had it's image evicted from the cache. reloading...";
|
||||
PixmapCache::markCacheMissByEviciton();
|
||||
}
|
||||
|
||||
// Imaged got evicted from the cache. Re-process it and retry.
|
||||
TexturePackUtils::process(*this);
|
||||
TexturePackUtils::processPackPNG(*this);
|
||||
return image(size);
|
||||
}
|
||||
|
||||
|
@ -40,13 +40,13 @@ class TexturePack : public Resource {
|
||||
[[nodiscard]] QString description() const { return m_description; }
|
||||
|
||||
/** Gets the image of the texture pack, converted to a QPixmap for drawing, and scaled to size. */
|
||||
[[nodiscard]] QPixmap image(QSize size);
|
||||
[[nodiscard]] QPixmap image(QSize size, Qt::AspectRatioMode mode = Qt::AspectRatioMode::IgnoreAspectRatio) const;
|
||||
|
||||
/** Thread-safe. */
|
||||
void setDescription(QString new_description);
|
||||
|
||||
/** Thread-safe. */
|
||||
void setImage(QImage new_image);
|
||||
void setImage(QImage new_image) const;
|
||||
|
||||
bool valid() const override;
|
||||
|
||||
@ -65,5 +65,5 @@ class TexturePack : public Resource {
|
||||
struct {
|
||||
QPixmapCache::Key key;
|
||||
bool was_ever_used = false;
|
||||
} m_pack_image_cache_key;
|
||||
} mutable m_pack_image_cache_key;
|
||||
};
|
||||
|
@ -33,6 +33,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include "TexturePackFolderModel.h"
|
||||
|
||||
@ -41,7 +44,9 @@
|
||||
|
||||
TexturePackFolderModel::TexturePackFolderModel(const QString& dir, std::shared_ptr<const BaseInstance> instance)
|
||||
: ResourceFolderModel(QDir(dir), instance)
|
||||
{}
|
||||
{
|
||||
m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::DATE, SortType::NAME };
|
||||
}
|
||||
|
||||
Task* TexturePackFolderModel::createUpdateTask()
|
||||
{
|
||||
@ -52,3 +57,98 @@ Task* TexturePackFolderModel::createParseTask(Resource& resource)
|
||||
{
|
||||
return new LocalTexturePackParseTask(m_next_resolution_ticket, static_cast<TexturePack&>(resource));
|
||||
}
|
||||
|
||||
|
||||
QVariant TexturePackFolderModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (!validateIndex(index))
|
||||
return {};
|
||||
|
||||
int row = index.row();
|
||||
int column = index.column();
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (column) {
|
||||
case NameColumn:
|
||||
return m_resources[row]->name();
|
||||
case DateColumn:
|
||||
return m_resources[row]->dateTimeChanged();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
case Qt::ToolTipRole:
|
||||
if (column == NameColumn) {
|
||||
if (at(row)->isSymLinkUnder(instDirPath())) {
|
||||
return m_resources[row]->internal_id() +
|
||||
tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original."
|
||||
"\nCanonical Path: %1")
|
||||
.arg(at(row)->fileinfo().canonicalFilePath());;
|
||||
}
|
||||
if (at(row)->isMoreThanOneHardLink()) {
|
||||
return m_resources[row]->internal_id() +
|
||||
tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original.");
|
||||
}
|
||||
}
|
||||
|
||||
return m_resources[row]->internal_id();
|
||||
case Qt::DecorationRole: {
|
||||
if (column == NameColumn && (at(row)->isSymLinkUnder(instDirPath()) || at(row)->isMoreThanOneHardLink()))
|
||||
return APPLICATION->getThemedIcon("status-yellow");
|
||||
if (column == ImageColumn) {
|
||||
return at(row)->image(QSize(64, 64), Qt::AspectRatioMode::KeepAspectRatioByExpanding);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
case Qt::CheckStateRole:
|
||||
switch (column) {
|
||||
case ActiveColumn:
|
||||
return m_resources[row]->enabled() ? Qt::Checked : Qt::Unchecked;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
QVariant TexturePackFolderModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (section) {
|
||||
case NameColumn:
|
||||
return tr("Name");
|
||||
case DateColumn:
|
||||
return tr("Last modified");
|
||||
case ImageColumn:
|
||||
return tr("Image");
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
case Qt::ToolTipRole: {
|
||||
switch (section) {
|
||||
case ActiveColumn:
|
||||
//: Here, resource is a generic term for external resources, like Mods, Resource Packs, Shader Packs, etc.
|
||||
return tr("Is the resource enabled?");
|
||||
case NameColumn:
|
||||
//: Here, resource is a generic term for external resources, like Mods, Resource Packs, Shader Packs, etc.
|
||||
return tr("The name of the resource.");
|
||||
case DateColumn:
|
||||
//: Here, resource is a generic term for external resources, like Mods, Resource Packs, Shader Packs, etc.
|
||||
return tr("The date and time this resource was last changed (or added).");
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
int TexturePackFolderModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : NUM_COLUMNS;
|
||||
}
|
@ -38,12 +38,32 @@
|
||||
|
||||
#include "ResourceFolderModel.h"
|
||||
|
||||
#include "TexturePack.h"
|
||||
|
||||
class TexturePackFolderModel : public ResourceFolderModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
enum Columns
|
||||
{
|
||||
ActiveColumn = 0,
|
||||
NameColumn,
|
||||
DateColumn,
|
||||
ImageColumn,
|
||||
NUM_COLUMNS
|
||||
};
|
||||
|
||||
explicit TexturePackFolderModel(const QString &dir, std::shared_ptr<const BaseInstance> instance);
|
||||
|
||||
[[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
[[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
[[nodiscard]] int columnCount(const QModelIndex &parent) const override;
|
||||
|
||||
[[nodiscard]] Task* createUpdateTask() override;
|
||||
[[nodiscard]] Task* createParseTask(Resource&) override;
|
||||
|
||||
RESOURCE_HELPERS(TexturePack)
|
||||
};
|
||||
|
@ -131,6 +131,7 @@ bool processZIP(TexturePack& pack, ProcessingLevel level)
|
||||
bool packPNG_result = TexturePackUtils::processPackPNG(pack, std::move(data));
|
||||
|
||||
file.close();
|
||||
zip.close();
|
||||
if (!packPNG_result) {
|
||||
return false;
|
||||
}
|
||||
@ -147,7 +148,7 @@ bool processPackTXT(TexturePack& pack, QByteArray&& raw_data)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool processPackPNG(TexturePack& pack, QByteArray&& raw_data)
|
||||
bool processPackPNG(const TexturePack& pack, QByteArray&& raw_data)
|
||||
{
|
||||
auto img = QImage::fromData(raw_data);
|
||||
if (!img.isNull()) {
|
||||
@ -159,6 +160,70 @@ bool processPackPNG(TexturePack& pack, QByteArray&& raw_data)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool processPackPNG(const TexturePack& pack)
|
||||
{
|
||||
auto png_invalid = [&pack]() {
|
||||
qWarning() << "Texture pack at" << pack.fileinfo().filePath() << "does not have a valid pack.png";
|
||||
return false;
|
||||
};
|
||||
|
||||
switch (pack.type()) {
|
||||
case ResourceType::FOLDER:
|
||||
{
|
||||
QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png"));
|
||||
if (image_file_info.exists() && image_file_info.isFile()) {
|
||||
QFile pack_png_file(image_file_info.filePath());
|
||||
if (!pack_png_file.open(QIODevice::ReadOnly))
|
||||
return png_invalid(); // can't open pack.png file
|
||||
|
||||
auto data = pack_png_file.readAll();
|
||||
|
||||
bool pack_png_result = TexturePackUtils::processPackPNG(pack, std::move(data));
|
||||
|
||||
pack_png_file.close();
|
||||
if (!pack_png_result) {
|
||||
return png_invalid(); // pack.png invalid
|
||||
}
|
||||
} else {
|
||||
return png_invalid(); // pack.png does not exists or is not a valid file.
|
||||
}
|
||||
}
|
||||
case ResourceType::ZIPFILE:
|
||||
{
|
||||
Q_ASSERT(pack.type() == ResourceType::ZIPFILE);
|
||||
|
||||
QuaZip zip(pack.fileinfo().filePath());
|
||||
if (!zip.open(QuaZip::mdUnzip))
|
||||
return false; // can't open zip file
|
||||
|
||||
QuaZipFile file(&zip);
|
||||
if (zip.setCurrentFile("pack.png")) {
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qCritical() << "Failed to open file in zip.";
|
||||
zip.close();
|
||||
return png_invalid();
|
||||
}
|
||||
|
||||
auto data = file.readAll();
|
||||
|
||||
bool pack_png_result = TexturePackUtils::processPackPNG(pack, std::move(data));
|
||||
|
||||
file.close();
|
||||
if (!pack_png_result) {
|
||||
zip.close();
|
||||
return png_invalid(); // pack.png invalid
|
||||
}
|
||||
} else {
|
||||
zip.close();
|
||||
return png_invalid(); // could not set pack.mcmeta as current file.
|
||||
}
|
||||
}
|
||||
default:
|
||||
qWarning() << "Invalid type for resource pack parse task!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool validate(QFileInfo file)
|
||||
{
|
||||
TexturePack rp{ file };
|
||||
|
@ -36,7 +36,10 @@ bool processZIP(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full
|
||||
bool processFolder(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full);
|
||||
|
||||
bool processPackTXT(TexturePack& pack, QByteArray&& raw_data);
|
||||
bool processPackPNG(TexturePack& pack, QByteArray&& raw_data);
|
||||
bool processPackPNG(const TexturePack& pack, QByteArray&& raw_data);
|
||||
|
||||
/// processes ONLY the pack.png (rest of the pack may be invalid)
|
||||
bool processPackPNG(const TexturePack& pack);
|
||||
|
||||
/** Checks whether a file is valid as a texture pack or not. */
|
||||
bool validate(QFileInfo file);
|
||||
|
Loading…
Reference in New Issue
Block a user