diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index abbf473f42..4d2f57948a 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -141,11 +141,16 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, save_entry2.atime = entry.atime; save_entry2.mtime = entry.mtime; save_entry2.ctime = entry.ctime; - //save_entry2.iconBuf = NULL; // TODO: Here should be the PNG buffer - //save_entry2.iconBufSize = 0; // TODO: Size of the PNG file + if (fs::is_file(base_dir + entry.name + "/ICON0.PNG")) + { + fs::file icon = fs::file(base_dir + entry.name + "/ICON0.PNG"); + u32 iconSize = icon.size(); + std::vector iconData; + icon.read(iconData, iconSize); + save_entry2.iconBuf = iconData; + } save_entry2.isNew = false; - - save_entries.push_back(save_entry2); + save_entries.emplace_back(save_entry2); } break; @@ -210,6 +215,13 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, return CELL_SAVEDATA_ERROR_CBRESULT; } + // if the callback has returned ok, lets return OK. + // typically used at game launch when no list is actually required. + if ((result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) || (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)) + { + return CELL_OK; + } + // Clean save data list save_entries.erase(std::remove_if(save_entries.begin(), save_entries.end(), [&listSet](const SaveDataEntry& entry) -> bool { @@ -293,10 +305,9 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, } } - // Display Save Data List but do so asynchronously in the GUI thread. For, qTimers only work using main UI thread. + // Display Save Data List but do so asynchronously in the GUI thread. + bool hasNewData = (bool)listSet->newData; // newData atomic_t dlg_result(false); - bool hasNewData = (bool) listSet->newData; // Are we saving? - Emu.CallAfter([&]() { @@ -309,28 +320,18 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, thread_ctrl::wait_for(1000); } + // UI returns -1 for new save games if (selected == -1) { - if (hasNewData) - { - save_entry.dirName = listSet->newData->dirName.get_ptr(); - } - else - { - // This happens if someone tries to load but there is no data selected. Some games will throw errors (Akiba) if cell_ok is returned - return CELL_CANCEL; - } + save_entry.dirName = listSet->newData->dirName.get_ptr(); } + // Cancel selected in UI - else if (selected == -2) + if (selected == -2) { return CELL_CANCEL; } - if ((result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) || (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)) - { - return CELL_OK; - } } if (funcFixed) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.h b/rpcs3/Emu/Cell/Modules/cellSaveData.h index 289c1e9dc5..d10e0d68f9 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.h +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.h @@ -282,8 +282,7 @@ struct SaveDataEntry s64 atime; s64 mtime; s64 ctime; - //void* iconBuf; - //u32 iconBufSize; + std::vector iconBuf; bool isNew; }; diff --git a/rpcs3/rpcs3qt/save_data_utility.cpp b/rpcs3/rpcs3qt/save_data_utility.cpp index a1336cbdb6..c132ff9235 100644 --- a/rpcs3/rpcs3qt/save_data_utility.cpp +++ b/rpcs3/rpcs3qt/save_data_utility.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "save_data_utility.h" inline QString qstr(const std::string& _in) { return QString::fromUtf8(_in.data(), _in.size()); } @@ -9,10 +9,10 @@ save_data_info_dialog::save_data_info_dialog(const SaveDataEntry& save, QWidget* : QDialog(parent), m_entry(save) { setWindowTitle(tr("Save Data Information")); - setMinimumSize(QSize(400, 300)); // Table m_list = new QTableWidget(this); + //m_list->setItemDelegate(new table_item_delegate(this)); // to get rid of item selection rectangles include "table_item_delegate.h" m_list->setSelectionBehavior(QAbstractItemView::SelectRows); // enable to only select whole rows instead of items m_list->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -35,17 +35,26 @@ save_data_info_dialog::save_data_info_dialog(const SaveDataEntry& save, QWidget* vbox_main->setAlignment(Qt::AlignCenter); setLayout(vbox_main); - // resize to minimum view size - resize(minimumSize().expandedTo(sizeHint())); - UpdateData(); + + m_list->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); + m_list->verticalHeader()->resizeSections(QHeaderView::ResizeToContents); + + QSize tableSize = QSize( + m_list->verticalHeader()->width() + m_list->horizontalHeader()->length() + m_list->frameWidth() * 2, + m_list->horizontalHeader()->height() + m_list->verticalHeader()->length() + m_list->frameWidth() * 2); + + // no minimum size needed because we always have same table size and row count + resize(sizeHint() - m_list->sizeHint() + tableSize); + } //This is intended to write the information of save data to QTableView. void save_data_info_dialog::UpdateData() { m_list->clearContents(); - m_list->setRowCount(4); // set this to nr of members in struct + int num_entries = 4; // set this to number of members in struct + m_list->setRowCount(num_entries); //Maybe there should be more details of save data. m_list->setItem(0, 0, new QTableWidgetItem(tr("User ID"))); @@ -60,8 +69,15 @@ void save_data_info_dialog::UpdateData() m_list->setItem(3, 0, new QTableWidgetItem(tr("Detail"))); m_list->setItem(3, 1, new QTableWidgetItem(qstr(m_entry.details))); - m_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - m_list->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + QImage img; + if (m_entry.iconBuf.size() > 0 && img.loadFromData((uchar*) &m_entry.iconBuf[0], m_entry.iconBuf.size(), "PNG")) + { + m_list->insertRow(0); + QTableWidgetItem* img_item = new QTableWidgetItem(); + img_item->setData(Qt::DecorationRole, QPixmap::fromImage(img)); + m_list->setItem(0, 0, new QTableWidgetItem(tr("Icon"))); + m_list->setItem(0, 1, img_item); + } } //Show up the savedata list, either to choose one to save/load or to manage saves. @@ -69,11 +85,12 @@ void save_data_info_dialog::UpdateData() save_data_list_dialog::save_data_list_dialog(const std::vector& entries, s32 focusedEntry, bool is_saving, QWidget* parent) : QDialog(parent), m_save_entries(entries), m_selectedEntry(-1), selectedEntryLabel(nullptr) { - setWindowTitle(tr("Save Data Utility")); + setWindowTitle(tr("Save Data Interface")); setMinimumSize(QSize(400, 400)); // Table m_list = new QTableWidget(this); + //m_list->setItemDelegate(new table_item_delegate(this)); // to get rid of cell selection rectangles include "table_item_delegate.h" m_list->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); m_list->setSelectionBehavior(QAbstractItemView::SelectRows); @@ -84,18 +101,18 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e // Button Layout QHBoxLayout* hbox_action = new QHBoxLayout(); - QPushButton *push_cancel = new QPushButton(tr("&Cancel"), this); - push_cancel->setAutoDefault(false); - QPushButton *push_select = new QPushButton(tr("&Select Entry"), this); - push_select->setAutoDefault(true); - push_select->setDefault(true); - connect(push_select, &QAbstractButton::clicked, this, &save_data_list_dialog::accept); - hbox_action->addWidget(push_select); - setWindowTitle(tr("Save Data Chooser")); + if (entries.size() > 0) + { // If there are no entries, don't add the selection widget or the selection label to the UI. + QPushButton *push_select = new QPushButton(tr("&Select Entry"), this); + connect(push_select, &QAbstractButton::clicked, this, &save_data_list_dialog::accept); + push_select->setAutoDefault(true); + push_select->setDefault(true); + hbox_action->addWidget(push_select); - selectedEntryLabel = new QLabel(this); - UpdateSelectionLabel(); + selectedEntryLabel = new QLabel(this); + UpdateSelectionLabel(); + } if (is_saving) { @@ -108,6 +125,9 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e } hbox_action->addStretch(); + + QPushButton *push_cancel = new QPushButton(tr("&Cancel"), this); + push_cancel->setAutoDefault(false); hbox_action->addWidget(push_cancel); // events @@ -120,7 +140,7 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e // TODO: Unstub functions inside of this context menu so it makes sense to show this menu //connect(m_list, &QTableWidget::customContextMenuRequested, this, &save_data_list_dialog::ShowContextMenu); - connect(m_list->horizontalHeader(), &QHeaderView::sectionClicked, [=](int col){ + connect(m_list->horizontalHeader(), &QHeaderView::sectionClicked, [=](int col) { OnSort(col); }); @@ -141,6 +161,7 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e m_list->setCurrentCell(focusedEntry, 0); } + void save_data_list_dialog::UpdateSelectionLabel() { if (selectedEntryLabel != nullptr) @@ -279,8 +300,6 @@ void save_data_list_dialog::UpdateList(void) { m_list->clearContents(); m_list->setRowCount(m_save_entries.size()); - m_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - m_list->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); int row = 0; for (SaveDataEntry entry: m_save_entries) @@ -293,4 +312,14 @@ void save_data_list_dialog::UpdateList(void) ++row; } + + m_list->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); + m_list->verticalHeader()->resizeSections(QHeaderView::ResizeToContents); + + QSize tableSize = QSize( + m_list->verticalHeader()->width() + m_list->horizontalHeader()->length() + m_list->frameWidth() * 2, + m_list->horizontalHeader()->height() + m_list->verticalHeader()->length() + m_list->frameWidth() * 2); + + resize(minimumSize().expandedTo(sizeHint() - m_list->sizeHint() + tableSize)); + }