mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-12 09:48:37 +12:00
Improve Save Manager (#2951)
* Add the save icons to the save data entry and manager. * Simplify code slightly since I have an else now so no need for == false * Move the icon to the top of the list because it looks better. Remove redundant settitle. * Fix size. It's a bit forced but there wasn't any better way as far as I could see on stack overflow. Also, add an error dialog if you have no entries. Simplify the logic slightly for the selected since with the no data case handled, I can make more assumptions about the return value. * save_data_utility: fix dialog sizes * CELL_OK * Retcon dialog to instead be error in log. * Dangle92 and I had some fun. Everything should be good now. * In dangle's code he disabled the icon, in mine I hide it if there is nothing. Having both isn't needed. Yay merges resulting in doing stupid things. * Fix leek * Default size to zero for sanity. Shared pointer is fine handling null (tested with disgaea and renaming icon file) * Simplifying. Thanks for review and advice all
This commit is contained in:
parent
e8ba5876ce
commit
ab595d2b95
3 changed files with 74 additions and 45 deletions
|
@ -141,11 +141,16 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
|
||||||
save_entry2.atime = entry.atime;
|
save_entry2.atime = entry.atime;
|
||||||
save_entry2.mtime = entry.mtime;
|
save_entry2.mtime = entry.mtime;
|
||||||
save_entry2.ctime = entry.ctime;
|
save_entry2.ctime = entry.ctime;
|
||||||
//save_entry2.iconBuf = NULL; // TODO: Here should be the PNG buffer
|
if (fs::is_file(base_dir + entry.name + "/ICON0.PNG"))
|
||||||
//save_entry2.iconBufSize = 0; // TODO: Size of the PNG file
|
{
|
||||||
|
fs::file icon = fs::file(base_dir + entry.name + "/ICON0.PNG");
|
||||||
|
u32 iconSize = icon.size();
|
||||||
|
std::vector<uchar> iconData;
|
||||||
|
icon.read(iconData, iconSize);
|
||||||
|
save_entry2.iconBuf = iconData;
|
||||||
|
}
|
||||||
save_entry2.isNew = false;
|
save_entry2.isNew = false;
|
||||||
|
save_entries.emplace_back(save_entry2);
|
||||||
save_entries.push_back(save_entry2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -210,6 +215,13 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
|
||||||
return CELL_SAVEDATA_ERROR_CBRESULT;
|
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
|
// Clean save data list
|
||||||
save_entries.erase(std::remove_if(save_entries.begin(), save_entries.end(), [&listSet](const SaveDataEntry& entry) -> bool
|
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<bool> dlg_result(false);
|
atomic_t<bool> dlg_result(false);
|
||||||
bool hasNewData = (bool) listSet->newData; // Are we saving?
|
|
||||||
|
|
||||||
|
|
||||||
Emu.CallAfter([&]()
|
Emu.CallAfter([&]()
|
||||||
{
|
{
|
||||||
|
@ -309,28 +320,18 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
|
||||||
thread_ctrl::wait_for(1000);
|
thread_ctrl::wait_for(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UI returns -1 for new save games
|
||||||
if (selected == -1)
|
if (selected == -1)
|
||||||
{
|
{
|
||||||
if (hasNewData)
|
save_entry.dirName = listSet->newData->dirName.get_ptr();
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel selected in UI
|
// Cancel selected in UI
|
||||||
else if (selected == -2)
|
if (selected == -2)
|
||||||
{
|
{
|
||||||
return CELL_CANCEL;
|
return CELL_CANCEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) || (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM))
|
|
||||||
{
|
|
||||||
return CELL_OK;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (funcFixed)
|
if (funcFixed)
|
||||||
|
|
|
@ -282,8 +282,7 @@ struct SaveDataEntry
|
||||||
s64 atime;
|
s64 atime;
|
||||||
s64 mtime;
|
s64 mtime;
|
||||||
s64 ctime;
|
s64 ctime;
|
||||||
//void* iconBuf;
|
std::vector<uchar> iconBuf;
|
||||||
//u32 iconBufSize;
|
|
||||||
bool isNew;
|
bool isNew;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "save_data_utility.h"
|
#include "save_data_utility.h"
|
||||||
|
|
||||||
inline QString qstr(const std::string& _in) { return QString::fromUtf8(_in.data(), _in.size()); }
|
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)
|
: QDialog(parent), m_entry(save)
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Save Data Information"));
|
setWindowTitle(tr("Save Data Information"));
|
||||||
setMinimumSize(QSize(400, 300));
|
|
||||||
|
|
||||||
// Table
|
// Table
|
||||||
m_list = new QTableWidget(this);
|
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->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->setSelectionBehavior(QAbstractItemView::SelectRows); // enable to only select whole rows instead of items
|
||||||
m_list->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
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);
|
vbox_main->setAlignment(Qt::AlignCenter);
|
||||||
setLayout(vbox_main);
|
setLayout(vbox_main);
|
||||||
|
|
||||||
// resize to minimum view size
|
|
||||||
resize(minimumSize().expandedTo(sizeHint()));
|
|
||||||
|
|
||||||
UpdateData();
|
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.
|
//This is intended to write the information of save data to QTableView.
|
||||||
void save_data_info_dialog::UpdateData()
|
void save_data_info_dialog::UpdateData()
|
||||||
{
|
{
|
||||||
m_list->clearContents();
|
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.
|
//Maybe there should be more details of save data.
|
||||||
m_list->setItem(0, 0, new QTableWidgetItem(tr("User ID")));
|
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, 0, new QTableWidgetItem(tr("Detail")));
|
||||||
m_list->setItem(3, 1, new QTableWidgetItem(qstr(m_entry.details)));
|
m_list->setItem(3, 1, new QTableWidgetItem(qstr(m_entry.details)));
|
||||||
|
|
||||||
m_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
QImage img;
|
||||||
m_list->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
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.
|
//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<SaveDataEntry>& entries, s32 focusedEntry, bool is_saving, QWidget* parent)
|
save_data_list_dialog::save_data_list_dialog(const std::vector<SaveDataEntry>& entries, s32 focusedEntry, bool is_saving, QWidget* parent)
|
||||||
: QDialog(parent), m_save_entries(entries), m_selectedEntry(-1), selectedEntryLabel(nullptr)
|
: 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));
|
setMinimumSize(QSize(400, 400));
|
||||||
|
|
||||||
// Table
|
// Table
|
||||||
m_list = new QTableWidget(this);
|
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->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->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
|
||||||
m_list->setSelectionBehavior(QAbstractItemView::SelectRows);
|
m_list->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
@ -84,18 +101,18 @@ save_data_list_dialog::save_data_list_dialog(const std::vector<SaveDataEntry>& e
|
||||||
|
|
||||||
// Button Layout
|
// Button Layout
|
||||||
QHBoxLayout* hbox_action = new QHBoxLayout();
|
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);
|
if (entries.size() > 0)
|
||||||
hbox_action->addWidget(push_select);
|
{ // If there are no entries, don't add the selection widget or the selection label to the UI.
|
||||||
setWindowTitle(tr("Save Data Chooser"));
|
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);
|
selectedEntryLabel = new QLabel(this);
|
||||||
UpdateSelectionLabel();
|
UpdateSelectionLabel();
|
||||||
|
}
|
||||||
|
|
||||||
if (is_saving)
|
if (is_saving)
|
||||||
{
|
{
|
||||||
|
@ -108,6 +125,9 @@ save_data_list_dialog::save_data_list_dialog(const std::vector<SaveDataEntry>& e
|
||||||
}
|
}
|
||||||
|
|
||||||
hbox_action->addStretch();
|
hbox_action->addStretch();
|
||||||
|
|
||||||
|
QPushButton *push_cancel = new QPushButton(tr("&Cancel"), this);
|
||||||
|
push_cancel->setAutoDefault(false);
|
||||||
hbox_action->addWidget(push_cancel);
|
hbox_action->addWidget(push_cancel);
|
||||||
|
|
||||||
// events
|
// events
|
||||||
|
@ -120,7 +140,7 @@ save_data_list_dialog::save_data_list_dialog(const std::vector<SaveDataEntry>& e
|
||||||
|
|
||||||
// TODO: Unstub functions inside of this context menu so it makes sense to show this menu
|
// 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, &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);
|
OnSort(col);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -141,6 +161,7 @@ save_data_list_dialog::save_data_list_dialog(const std::vector<SaveDataEntry>& e
|
||||||
m_list->setCurrentCell(focusedEntry, 0);
|
m_list->setCurrentCell(focusedEntry, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void save_data_list_dialog::UpdateSelectionLabel()
|
void save_data_list_dialog::UpdateSelectionLabel()
|
||||||
{
|
{
|
||||||
if (selectedEntryLabel != nullptr)
|
if (selectedEntryLabel != nullptr)
|
||||||
|
@ -279,8 +300,6 @@ void save_data_list_dialog::UpdateList(void)
|
||||||
{
|
{
|
||||||
m_list->clearContents();
|
m_list->clearContents();
|
||||||
m_list->setRowCount(m_save_entries.size());
|
m_list->setRowCount(m_save_entries.size());
|
||||||
m_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
|
||||||
m_list->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
|
||||||
|
|
||||||
int row = 0;
|
int row = 0;
|
||||||
for (SaveDataEntry entry: m_save_entries)
|
for (SaveDataEntry entry: m_save_entries)
|
||||||
|
@ -293,4 +312,14 @@ void save_data_list_dialog::UpdateList(void)
|
||||||
|
|
||||||
++row;
|
++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));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue