UI: Asynchronously update size and dates on sort.
This means items shift and jump into place, but it also means we don't hang even for large savedata collections.
This commit is contained in:
parent
8c937f45f7
commit
09ca16361c
2 changed files with 68 additions and 34 deletions
|
@ -138,32 +138,49 @@ private:
|
||||||
|
|
||||||
class SortedLinearLayout : public UI::LinearLayoutList {
|
class SortedLinearLayout : public UI::LinearLayoutList {
|
||||||
public:
|
public:
|
||||||
typedef std::function<bool(View *, View *)> CompareFunc;
|
typedef std::function<void(View *)> PrepFunc;
|
||||||
typedef std::function<bool()> DoneFunc;
|
typedef std::function<bool(const View *, const View *)> CompareFunc;
|
||||||
|
|
||||||
SortedLinearLayout(UI::Orientation orientation, UI::LayoutParams *layoutParams = nullptr)
|
SortedLinearLayout(UI::Orientation orientation, UI::LayoutParams *layoutParams = nullptr)
|
||||||
: UI::LinearLayoutList(orientation, layoutParams) {
|
: UI::LinearLayoutList(orientation, layoutParams) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetCompare(CompareFunc lessFunc, DoneFunc doneFunc) {
|
void SetCompare(const PrepFunc &prepFunc, const CompareFunc &lessFunc) {
|
||||||
|
prepIndex_ = 0;
|
||||||
|
prepFunc_ = prepFunc;
|
||||||
lessFunc_ = lessFunc;
|
lessFunc_ = lessFunc;
|
||||||
doneFunc_ = doneFunc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update() override;
|
void Update() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
size_t prepIndex_ = 0;
|
||||||
|
PrepFunc prepFunc_;
|
||||||
CompareFunc lessFunc_;
|
CompareFunc lessFunc_;
|
||||||
DoneFunc doneFunc_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void SortedLinearLayout::Update() {
|
void SortedLinearLayout::Update() {
|
||||||
|
if (prepFunc_) {
|
||||||
|
// Try to avoid dropping more than a frame, prefer items shift.
|
||||||
|
constexpr double ALLOWED_TIME = 0.95 / 60.0;
|
||||||
|
double start_time = time_now_d();
|
||||||
|
for (; prepIndex_ < views_.size(); ++prepIndex_) {
|
||||||
|
prepFunc_(views_[prepIndex_]);
|
||||||
|
if (time_now_d() > start_time + ALLOWED_TIME) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (lessFunc_) {
|
if (lessFunc_) {
|
||||||
|
// We may sort several times while calculating.
|
||||||
std::stable_sort(views_.begin(), views_.end(), lessFunc_);
|
std::stable_sort(views_.begin(), views_.end(), lessFunc_);
|
||||||
}
|
}
|
||||||
if (doneFunc_ && doneFunc_()) {
|
// We're done if we got through all items.
|
||||||
|
if (prepIndex_ >= views_.size()) {
|
||||||
|
prepFunc_ = PrepFunc();
|
||||||
lessFunc_ = CompareFunc();
|
lessFunc_ = CompareFunc();
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::LinearLayout::Update();
|
UI::LinearLayout::Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,8 +201,15 @@ public:
|
||||||
|
|
||||||
const Path &GamePath() const { return savePath_; }
|
const Path &GamePath() const { return savePath_; }
|
||||||
|
|
||||||
uint64_t GetTotalSize();
|
uint64_t GetTotalSize() const {
|
||||||
int64_t GetDateSeconds();
|
return totalSize_;
|
||||||
|
}
|
||||||
|
int64_t GetDateSeconds() const {
|
||||||
|
return dateSeconds_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateTotalSize();
|
||||||
|
void UpdateDateSeconds();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateText(const std::shared_ptr<GameInfo> &ginfo);
|
void UpdateText(const std::shared_ptr<GameInfo> &ginfo);
|
||||||
|
@ -199,9 +223,9 @@ private:
|
||||||
bool hasDateSeconds_ = false;
|
bool hasDateSeconds_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint64_t SavedataButton::GetTotalSize() {
|
void SavedataButton::UpdateTotalSize() {
|
||||||
if (hasTotalSize_)
|
if (hasTotalSize_)
|
||||||
return totalSize_;
|
return;
|
||||||
|
|
||||||
File::FileInfo info;
|
File::FileInfo info;
|
||||||
if (File::GetFileInfo(savePath_, &info)) {
|
if (File::GetFileInfo(savePath_, &info)) {
|
||||||
|
@ -211,12 +235,11 @@ uint64_t SavedataButton::GetTotalSize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
hasTotalSize_ = true;
|
hasTotalSize_ = true;
|
||||||
return totalSize_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t SavedataButton::GetDateSeconds() {
|
void SavedataButton::UpdateDateSeconds() {
|
||||||
if (hasDateSeconds_)
|
if (hasDateSeconds_)
|
||||||
return dateSeconds_;
|
return;
|
||||||
|
|
||||||
File::FileInfo info;
|
File::FileInfo info;
|
||||||
if (File::GetFileInfo(savePath_, &info)) {
|
if (File::GetFileInfo(savePath_, &info)) {
|
||||||
|
@ -227,7 +250,6 @@ int64_t SavedataButton::GetDateSeconds() {
|
||||||
}
|
}
|
||||||
|
|
||||||
hasDateSeconds_ = true;
|
hasDateSeconds_ = true;
|
||||||
return dateSeconds_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::EventReturn SavedataPopupScreen::OnDeleteButtonClick(UI::EventParams &e) {
|
UI::EventReturn SavedataPopupScreen::OnDeleteButtonClick(UI::EventParams &e) {
|
||||||
|
@ -446,25 +468,34 @@ void SavedataBrowser::SetSortOption(SavedataSortOption opt) {
|
||||||
if (gameList_) {
|
if (gameList_) {
|
||||||
SortedLinearLayout *gl = static_cast<SortedLinearLayout *>(gameList_);
|
SortedLinearLayout *gl = static_cast<SortedLinearLayout *>(gameList_);
|
||||||
if (sortOption_ == SavedataSortOption::FILENAME) {
|
if (sortOption_ == SavedataSortOption::FILENAME) {
|
||||||
gl->SetCompare(&ByFilename, &SortDone);
|
gl->SetCompare(&PrepFilename, &ByFilename);
|
||||||
} else if (sortOption_ == SavedataSortOption::SIZE) {
|
} else if (sortOption_ == SavedataSortOption::SIZE) {
|
||||||
gl->SetCompare(&BySize, &SortDone);
|
gl->SetCompare(&PrepSize, &BySize);
|
||||||
} else if (sortOption_ == SavedataSortOption::DATE) {
|
} else if (sortOption_ == SavedataSortOption::DATE) {
|
||||||
gl->SetCompare(&ByDate, &SortDone);
|
gl->SetCompare(&PrepDate, &ByDate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SavedataBrowser::ByFilename(UI::View *v1, UI::View *v2) {
|
void SavedataBrowser::PrepFilename(UI::View *v) {
|
||||||
SavedataButton *b1 = static_cast<SavedataButton *>(v1);
|
// Nothing needed.
|
||||||
SavedataButton *b2 = static_cast<SavedataButton *>(v2);
|
}
|
||||||
|
|
||||||
|
bool SavedataBrowser::ByFilename(const UI::View *v1, const UI::View *v2) {
|
||||||
|
const SavedataButton *b1 = static_cast<const SavedataButton *>(v1);
|
||||||
|
const SavedataButton *b2 = static_cast<const SavedataButton *>(v2);
|
||||||
|
|
||||||
return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0;
|
return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SavedataBrowser::BySize(UI::View *v1, UI::View *v2) {
|
void SavedataBrowser::PrepSize(UI::View *v) {
|
||||||
SavedataButton *b1 = static_cast<SavedataButton *>(v1);
|
SavedataButton *b = static_cast<SavedataButton *>(v);
|
||||||
SavedataButton *b2 = static_cast<SavedataButton *>(v2);
|
b->UpdateTotalSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SavedataBrowser::BySize(const UI::View *v1, const UI::View *v2) {
|
||||||
|
const SavedataButton *b1 = static_cast<const SavedataButton *>(v1);
|
||||||
|
const SavedataButton *b2 = static_cast<const SavedataButton *>(v2);
|
||||||
const uint64_t size1 = b1->GetTotalSize();
|
const uint64_t size1 = b1->GetTotalSize();
|
||||||
const uint64_t size2 = b2->GetTotalSize();
|
const uint64_t size2 = b2->GetTotalSize();
|
||||||
|
|
||||||
|
@ -475,9 +506,14 @@ bool SavedataBrowser::BySize(UI::View *v1, UI::View *v2) {
|
||||||
return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0;
|
return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SavedataBrowser::ByDate(UI::View *v1, UI::View *v2) {
|
void SavedataBrowser::PrepDate(UI::View *v) {
|
||||||
SavedataButton *b1 = static_cast<SavedataButton *>(v1);
|
SavedataButton *b = static_cast<SavedataButton *>(v);
|
||||||
SavedataButton *b2 = static_cast<SavedataButton *>(v2);
|
b->UpdateDateSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SavedataBrowser::ByDate(const UI::View *v1, const UI::View *v2) {
|
||||||
|
const SavedataButton *b1 = static_cast<const SavedataButton *>(v1);
|
||||||
|
const SavedataButton *b2 = static_cast<const SavedataButton *>(v2);
|
||||||
const int64_t time1 = b1->GetDateSeconds();
|
const int64_t time1 = b1->GetDateSeconds();
|
||||||
const int64_t time2 = b2->GetDateSeconds();
|
const int64_t time2 = b2->GetDateSeconds();
|
||||||
|
|
||||||
|
@ -488,10 +524,6 @@ bool SavedataBrowser::ByDate(UI::View *v1, UI::View *v2) {
|
||||||
return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0;
|
return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SavedataBrowser::SortDone() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavedataBrowser::Refresh() {
|
void SavedataBrowser::Refresh() {
|
||||||
using namespace UI;
|
using namespace UI;
|
||||||
|
|
||||||
|
|
|
@ -46,10 +46,12 @@ public:
|
||||||
UI::Event OnChoice;
|
UI::Event OnChoice;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool ByFilename(UI::View *, UI::View *);
|
static void PrepFilename(UI::View *);
|
||||||
static bool BySize(UI::View *, UI::View *);
|
static void PrepSize(UI::View *);
|
||||||
static bool ByDate(UI::View *, UI::View *);
|
static void PrepDate(UI::View *);
|
||||||
static bool SortDone();
|
static bool ByFilename(const UI::View *, const UI::View *);
|
||||||
|
static bool BySize(const UI::View *, const UI::View *);
|
||||||
|
static bool ByDate(const UI::View *, const UI::View *);
|
||||||
|
|
||||||
void Refresh();
|
void Refresh();
|
||||||
UI::EventReturn SavedataButtonClick(UI::EventParams &e);
|
UI::EventReturn SavedataButtonClick(UI::EventParams &e);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue