mirror of
https://github.com/LNH-team/pico-launcher.git
synced 2026-06-02 00:56:55 +02:00
Initial work on implementing support for cheats
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include "romBrowser/DisplayMode/RomBrowserDisplayModeFactory.h"
|
||||
#include "romBrowser/Theme/Material/MaterialThemeFileIconFactory.h"
|
||||
#include "romBrowser/views/NdsGameDetailsBottomSheetView.h"
|
||||
#include "romBrowser/views/cheats/CheatsBottomSheetView.h"
|
||||
#include "romBrowser/views/DisplaySettingsBottomSheetView.h"
|
||||
#include "bgm/AudioStreamPlayer.h"
|
||||
#include "bgm/BgmService.h"
|
||||
@@ -295,10 +296,15 @@ void App::HandleTrigger(RomBrowserStateTrigger trigger, RomBrowserState newState
|
||||
|
||||
void App::HandleShowGameInfoTrigger()
|
||||
{
|
||||
auto gameInfoDialog = std::make_unique<NdsGameDetailsBottomSheetView>(
|
||||
&_romBrowserController, &_theme->GetMaterialColorScheme(), _theme->GetFontRepository());
|
||||
gameInfoDialog->SetGraphics(_chipViewVram);
|
||||
_dialogPresenter.ShowDialog(std::move(gameInfoDialog));
|
||||
// auto gameInfoDialog = std::make_unique<NdsGameDetailsBottomSheetView>(
|
||||
// &_romBrowserController, &_theme->GetMaterialColorScheme(), _theme->GetFontRepository());
|
||||
// gameInfoDialog->SetGraphics(_chipViewVram);
|
||||
// _dialogPresenter.ShowDialog(std::move(gameInfoDialog));
|
||||
|
||||
auto cheatsViewModel = std::make_unique<CheatsViewModel>(_romBrowserController.GetTriggerFileInfo(), &_romBrowserController);
|
||||
auto cheatsDialog = std::make_unique<CheatsBottomSheetView>(
|
||||
std::move(cheatsViewModel), &_theme->GetMaterialColorScheme(), _theme->GetFontRepository(), &_focusManager);
|
||||
_dialogPresenter.ShowDialog(std::move(cheatsDialog));
|
||||
}
|
||||
|
||||
void App::HandleHideGameInfoTrigger()
|
||||
|
||||
28
arm9/source/cheats/Cheat.h
Normal file
28
arm9/source/cheats/Cheat.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "CheatTreeItem.h"
|
||||
|
||||
class Cheat : public CheatTreeItem
|
||||
{
|
||||
public:
|
||||
Cheat()
|
||||
: _cheatData(nullptr), _cheatDataLength(0) { }
|
||||
|
||||
Cheat(const char* name, const char* description, bool isCheatActive, const void* cheatData, u32 cheatDataLength)
|
||||
: CheatTreeItem(name, description), _isCheatActive(isCheatActive)
|
||||
, _cheatData(cheatData), _cheatDataLength(cheatDataLength) { }
|
||||
|
||||
bool GetIsCheatActive() const
|
||||
{
|
||||
return _isCheatActive;
|
||||
}
|
||||
|
||||
void SetIsCheatActive(bool isCheatActive)
|
||||
{
|
||||
_isCheatActive = isCheatActive;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _isCheatActive;
|
||||
const void* _cheatData;
|
||||
u32 _cheatDataLength;
|
||||
};
|
||||
81
arm9/source/cheats/CheatCategory.h
Normal file
81
arm9/source/cheats/CheatCategory.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "CheatTreeItem.h"
|
||||
#include "Cheat.h"
|
||||
|
||||
class CheatCategory : public CheatTreeItem
|
||||
{
|
||||
public:
|
||||
CheatCategory()
|
||||
: _isMaxOneCheatActive(false), _subCategories(nullptr), _numberOfSubCategories(0)
|
||||
, _cheats(nullptr), _numberOfCheats(0) { }
|
||||
|
||||
CheatCategory(const char* name, const char* description, bool isMaxOneCheatActive,
|
||||
CheatCategory* subCategories, u32 numberOfSubCategories, Cheat* cheats, u32 numberOfCheats)
|
||||
: CheatTreeItem(name, description), _isMaxOneCheatActive(isMaxOneCheatActive)
|
||||
, _subCategories(subCategories), _numberOfSubCategories(numberOfSubCategories)
|
||||
, _cheats(cheats), _numberOfCheats(numberOfCheats) { }
|
||||
|
||||
CheatCategory(CheatCategory& other) = delete;
|
||||
CheatCategory& operator=(CheatCategory& other) = delete;
|
||||
|
||||
CheatCategory(CheatCategory&& other)
|
||||
{
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
CheatCategory& operator=(CheatCategory&& other)
|
||||
{
|
||||
_name = other._name;
|
||||
other._name = nullptr;
|
||||
_description = other._description;
|
||||
other._description = nullptr;
|
||||
_isMaxOneCheatActive = other._isMaxOneCheatActive;
|
||||
other._isMaxOneCheatActive = false;
|
||||
_subCategories = other._subCategories;
|
||||
other._subCategories = nullptr;
|
||||
_numberOfSubCategories = other._numberOfSubCategories;
|
||||
other._numberOfSubCategories = 0;
|
||||
_cheats = other._cheats;
|
||||
other._cheats = nullptr;
|
||||
_numberOfCheats = other._numberOfCheats;
|
||||
other._numberOfCheats = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~CheatCategory()
|
||||
{
|
||||
if (_subCategories != nullptr)
|
||||
{
|
||||
free(_subCategories);
|
||||
}
|
||||
if (_cheats != nullptr)
|
||||
{
|
||||
free(_cheats);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetIsMaxOneCheatActive() const
|
||||
{
|
||||
return _isMaxOneCheatActive;
|
||||
}
|
||||
|
||||
const CheatCategory* GetSubCategories(u32& numberOfSubCategories) const
|
||||
{
|
||||
numberOfSubCategories = _numberOfSubCategories;
|
||||
return _subCategories;
|
||||
}
|
||||
|
||||
const Cheat* GetCheats(u32& numberOfCheats) const
|
||||
{
|
||||
numberOfCheats = _numberOfCheats;
|
||||
return _cheats;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _isMaxOneCheatActive;
|
||||
CheatCategory* _subCategories;
|
||||
u32 _numberOfSubCategories;
|
||||
Cheat* _cheats;
|
||||
u32 _numberOfCheats;
|
||||
};
|
||||
25
arm9/source/cheats/CheatTreeItem.h
Normal file
25
arm9/source/cheats/CheatTreeItem.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
class CheatTreeItem
|
||||
{
|
||||
public:
|
||||
const char* GetName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
const char* GetDescription() const
|
||||
{
|
||||
return _description;
|
||||
}
|
||||
|
||||
protected:
|
||||
const char* _name;
|
||||
const char* _description;
|
||||
|
||||
CheatTreeItem()
|
||||
: _name(nullptr), _description(nullptr) { }
|
||||
|
||||
CheatTreeItem(const char* name, const char* description)
|
||||
: _name(name), _description(description) { }
|
||||
};
|
||||
50
arm9/source/cheats/GameCheats.h
Normal file
50
arm9/source/cheats/GameCheats.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
#include "Cheat.h"
|
||||
#include "CheatCategory.h"
|
||||
|
||||
class GameCheats
|
||||
{
|
||||
public:
|
||||
GameCheats(std::unique_ptr<u8[]> cheatData, const char* gameName,
|
||||
CheatCategory* categories, u32 numberOfCategories, Cheat* cheats, u32 numberOfCheats)
|
||||
: _cheatData(std::move(cheatData)), _gameName(gameName)
|
||||
, _categories(categories), _numberOfCategories(numberOfCategories)
|
||||
, _cheats(cheats), _numberOfCheats(numberOfCheats) { }
|
||||
|
||||
~GameCheats()
|
||||
{
|
||||
if (_categories != nullptr)
|
||||
{
|
||||
free(_categories);
|
||||
}
|
||||
if (_cheats != nullptr)
|
||||
{
|
||||
free(_cheats);
|
||||
}
|
||||
}
|
||||
|
||||
const char* GetGameName() const
|
||||
{
|
||||
return _gameName;
|
||||
}
|
||||
|
||||
const CheatCategory* GetCheatCategories(u32& numberOfCategories) const
|
||||
{
|
||||
numberOfCategories = _numberOfCategories;
|
||||
return _categories;
|
||||
}
|
||||
|
||||
const Cheat* GetCheats(u32& numberOfCheats) const
|
||||
{
|
||||
numberOfCheats = _numberOfCheats;
|
||||
return _cheats;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<u8[]> _cheatData;
|
||||
const char* _gameName;
|
||||
CheatCategory* _categories;
|
||||
u32 _numberOfCategories;
|
||||
Cheat* _cheats;
|
||||
u32 _numberOfCheats;
|
||||
};
|
||||
13
arm9/source/cheats/ICheatRepository.h
Normal file
13
arm9/source/cheats/ICheatRepository.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "GameCheats.h"
|
||||
|
||||
class ICheatRepository
|
||||
{
|
||||
public:
|
||||
virtual ~ICheatRepository() { }
|
||||
|
||||
virtual std::unique_ptr<GameCheats> GetCheatsForGame(u32 gameCode, u32 headerCrc32) const = 0;
|
||||
|
||||
protected:
|
||||
ICheatRepository() { }
|
||||
};
|
||||
11
arm9/source/cheats/UsrCheatDat.h
Normal file
11
arm9/source/cheats/UsrCheatDat.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
struct usr_cheat_index_entry_t
|
||||
{
|
||||
u32 gameCode;
|
||||
u32 headerCrc32;
|
||||
u32 offset;
|
||||
u32 padding;
|
||||
};
|
||||
|
||||
static_assert(sizeof(usr_cheat_index_entry_t) == 16);
|
||||
174
arm9/source/cheats/UsrCheatRepository.cpp
Normal file
174
arm9/source/cheats/UsrCheatRepository.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
#include "common.h"
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
#include "UsrCheatRepository.h"
|
||||
|
||||
std::unique_ptr<GameCheats> UsrCheatRepository::GetCheatsForGame(u32 gameCode, u32 headerCrc32) const
|
||||
{
|
||||
auto index = FindIndex(gameCode, headerCrc32);
|
||||
if (index == nullptr)
|
||||
{
|
||||
LOG_DEBUG("Cheats not found for %c%c%c%c - 0x%X\n",
|
||||
gameCode & 0xFF, (gameCode >> 8) & 0xFF, (gameCode >> 16) & 0xFF, gameCode >> 24,
|
||||
headerCrc32);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto cheatData = std::make_unique_for_overwrite<u8[]>(index->padding); // padding was set to the size in UsrCheatRepositoryFactory
|
||||
if (_usrCheatFile->Seek(index->offset) != FR_OK)
|
||||
{
|
||||
LOG_ERROR("Failed to seek to cheat data\n");
|
||||
return nullptr;
|
||||
}
|
||||
if (!_usrCheatFile->ReadExact(cheatData.get(), index->padding))
|
||||
{
|
||||
LOG_ERROR("Failed to read cheat data\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u8* ptr = cheatData.get();
|
||||
|
||||
// game name
|
||||
const char* gameName = (const char*)ptr;
|
||||
ptr += strlen(gameName) + 1;
|
||||
|
||||
// padding
|
||||
ptr = (u8*)(((u32)ptr + 3) & ~3); // 32-bit align
|
||||
|
||||
// flags
|
||||
u32 flags = *(u32*)ptr;
|
||||
u32 totalNumberOfItems = flags & 0x0FFFFFFF;
|
||||
u32 gameActive = flags >> 28;
|
||||
ptr += 4;
|
||||
|
||||
// master codes
|
||||
ptr += 8 * 4;
|
||||
|
||||
auto categories = (CheatCategory*)malloc(totalNumberOfItems * sizeof(CheatCategory));
|
||||
u32 categoryCount = 0;
|
||||
|
||||
auto cheats = (Cheat*)malloc(totalNumberOfItems * sizeof(Cheat));
|
||||
u32 cheatCount = 0;
|
||||
|
||||
while (ptr < cheatData.get() + index->padding)
|
||||
{
|
||||
u32 itemFlags = *(u32*)ptr;
|
||||
bool isCategory = ((itemFlags >> 28) & 1) == 1;
|
||||
if (isCategory)
|
||||
{
|
||||
ParseCategory(categories[categoryCount], ptr);
|
||||
categoryCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseCheat(cheats[cheatCount], ptr);
|
||||
cheatCount++;
|
||||
}
|
||||
}
|
||||
|
||||
categories = (CheatCategory*)realloc(categories, categoryCount * sizeof(CheatCategory));
|
||||
cheats = (Cheat*)realloc(cheats, cheatCount * sizeof(Cheat));
|
||||
|
||||
return std::make_unique<GameCheats>(std::move(cheatData), gameName, categories, categoryCount, cheats, cheatCount);
|
||||
}
|
||||
|
||||
const usr_cheat_index_entry_t* UsrCheatRepository::FindIndex(u32 gameCode, u32 headerCrc32) const
|
||||
{
|
||||
if (_numberOfIndices != 0)
|
||||
{
|
||||
const auto index = std::lower_bound(_sortedIndices.get(), _sortedIndices.get() + _numberOfIndices, gameCode,
|
||||
[headerCrc32] (const usr_cheat_index_entry_t& entry, u32 value)
|
||||
{
|
||||
if (entry.gameCode != value)
|
||||
{
|
||||
return entry.gameCode < value;
|
||||
}
|
||||
|
||||
return entry.headerCrc32 < headerCrc32;
|
||||
});
|
||||
|
||||
if (index != _sortedIndices.get() + _numberOfIndices &&
|
||||
index->gameCode == gameCode &&
|
||||
index->headerCrc32 == headerCrc32)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void UsrCheatRepository::ParseCategory(CheatCategory& category, u8*& ptr) const
|
||||
{
|
||||
// flags
|
||||
u32 itemFlags = *(u32*)ptr;
|
||||
ptr += 4;
|
||||
u32 numberOfItems = itemFlags & 0x00FFFFFF;
|
||||
bool isMaxOneCheatActive = ((itemFlags >> 24) & 1) == 1;
|
||||
|
||||
// item name
|
||||
const char* itemName = (const char*)ptr;
|
||||
ptr += strlen(itemName) + 1;
|
||||
|
||||
// item description
|
||||
const char* itemDescription = (const char*)ptr;
|
||||
ptr += strlen(itemDescription) + 1;
|
||||
|
||||
// padding
|
||||
ptr = (u8*)(((u32)ptr + 3) & ~3); // 32-bit align
|
||||
|
||||
auto categories = (CheatCategory*)malloc(numberOfItems * sizeof(CheatCategory));
|
||||
u32 categoryCount = 0;
|
||||
|
||||
auto cheats = (Cheat*)malloc(numberOfItems * sizeof(Cheat));
|
||||
u32 cheatCount = 0;
|
||||
|
||||
for (u32 i = 0; i < numberOfItems; i++)
|
||||
{
|
||||
u32 itemFlags = *(u32*)ptr;
|
||||
bool isCategory = ((itemFlags >> 28) & 1) == 1;
|
||||
if (isCategory)
|
||||
{
|
||||
ParseCategory(categories[categoryCount], ptr);
|
||||
categoryCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseCheat(cheats[cheatCount], ptr);
|
||||
cheatCount++;
|
||||
}
|
||||
}
|
||||
|
||||
categories = (CheatCategory*)realloc(categories, categoryCount * sizeof(CheatCategory));
|
||||
cheats = (Cheat*)realloc(cheats, cheatCount * sizeof(Cheat));
|
||||
|
||||
category = CheatCategory(itemName, itemDescription, isMaxOneCheatActive, categories, categoryCount, cheats, cheatCount);
|
||||
}
|
||||
|
||||
void UsrCheatRepository::ParseCheat(Cheat& cheat, u8*& ptr) const
|
||||
{
|
||||
// flags
|
||||
u32 itemFlags = *(u32*)ptr;
|
||||
ptr += 4;
|
||||
bool isCheatActive = ((itemFlags >> 24) & 1) == 1;
|
||||
|
||||
// item name
|
||||
const char* itemName = (const char*)ptr;
|
||||
ptr += strlen(itemName) + 1;
|
||||
|
||||
// item description
|
||||
const char* itemDescription = (const char*)ptr;
|
||||
ptr += strlen(itemDescription) + 1;
|
||||
|
||||
// padding
|
||||
ptr = (u8*)(((u32)ptr + 3) & ~3); // 32-bit align
|
||||
|
||||
// number of code words
|
||||
u32 numberOfCodeWords = *(u32*)ptr;
|
||||
ptr += 4;
|
||||
|
||||
cheat = Cheat(itemName, itemDescription, isCheatActive, ptr, numberOfCodeWords * 4);
|
||||
|
||||
// code
|
||||
ptr += numberOfCodeWords * 4;
|
||||
}
|
||||
25
arm9/source/cheats/UsrCheatRepository.h
Normal file
25
arm9/source/cheats/UsrCheatRepository.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "fat/File.h"
|
||||
#include "ICheatRepository.h"
|
||||
#include "UsrCheatDat.h"
|
||||
|
||||
class UsrCheatRepository : public ICheatRepository
|
||||
{
|
||||
public:
|
||||
UsrCheatRepository(std::unique_ptr<File> usrCheatDatFile,
|
||||
std::unique_ptr<usr_cheat_index_entry_t[]> sortedIndices, u32 numberOfIndices)
|
||||
: _usrCheatFile(std::move(usrCheatDatFile))
|
||||
, _sortedIndices(std::move(sortedIndices)), _numberOfIndices(numberOfIndices) { }
|
||||
|
||||
std::unique_ptr<GameCheats> GetCheatsForGame(u32 gameCode, u32 headerCrc32) const override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<File> _usrCheatFile;
|
||||
std::unique_ptr<usr_cheat_index_entry_t[]> _sortedIndices;
|
||||
u32 _numberOfIndices;
|
||||
|
||||
const usr_cheat_index_entry_t* FindIndex(u32 gameCode, u32 headerCrc32) const;
|
||||
void ParseCategory(CheatCategory& category, u8*& ptr) const;
|
||||
void ParseCheat(Cheat& cheat, u8*& ptr) const;
|
||||
};
|
||||
87
arm9/source/cheats/UsrCheatRepositoryFactory.cpp
Normal file
87
arm9/source/cheats/UsrCheatRepositoryFactory.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "common.h"
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
#include "fat/File.h"
|
||||
#include "UsrCheatDat.h"
|
||||
#include "UsrCheatRepositoryFactory.h"
|
||||
|
||||
std::unique_ptr<UsrCheatRepository> UsrCheatRepositoryFactory::FromUsrCheatDat(const TCHAR* usrCheatDatPath)
|
||||
{
|
||||
auto file = std::make_unique<File>();
|
||||
if (file->Open(usrCheatDatPath, FA_READ | FA_WRITE) != FR_OK)
|
||||
{
|
||||
LOG_ERROR("Failed to open %s\n", usrCheatDatPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char header[12];
|
||||
if (!file->ReadExact(header, sizeof(header)))
|
||||
{
|
||||
LOG_ERROR("Failed to read usr cheat header\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (memcmp(header, "R4 CheatCode", sizeof(header)))
|
||||
{
|
||||
LOG_ERROR("Invalid usr cheat header\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Read index
|
||||
if (file->Seek(0x100) != FR_OK)
|
||||
{
|
||||
LOG_ERROR("Failed to seek to usr cheat index\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
usr_cheat_index_entry_t firstEntry;
|
||||
if (!file->ReadExact(&firstEntry, sizeof(firstEntry)))
|
||||
{
|
||||
LOG_ERROR("Failed to read first index\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u32 numberOfIndices = 0;
|
||||
if (firstEntry.offset != 0)
|
||||
{
|
||||
numberOfIndices = (firstEntry.offset - 0x100 - sizeof(usr_cheat_index_entry_t)) / sizeof(usr_cheat_index_entry_t);
|
||||
}
|
||||
|
||||
if (file->Seek(0x100) != FR_OK)
|
||||
{
|
||||
LOG_ERROR("Failed to seek to usr cheat index\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto indices = std::make_unique_for_overwrite<usr_cheat_index_entry_t[]>(numberOfIndices);
|
||||
if (!file->ReadExact(indices.get(), numberOfIndices * sizeof(usr_cheat_index_entry_t)))
|
||||
{
|
||||
LOG_ERROR("Failed to read first index\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Set padding field to the size of the cheat data
|
||||
if (numberOfIndices > 0)
|
||||
{
|
||||
for (u32 i = 0; i < numberOfIndices - 1; i++)
|
||||
{
|
||||
indices[i].padding = indices[i + 1].offset - indices[i].offset;
|
||||
}
|
||||
|
||||
indices[numberOfIndices - 1].padding = file->GetSize() - indices[numberOfIndices - 1].offset;
|
||||
}
|
||||
|
||||
// sort by gameCode, then by headerCrc32
|
||||
std::sort(indices.get(), indices.get() + numberOfIndices,
|
||||
[] (const usr_cheat_index_entry_t& a, const usr_cheat_index_entry_t& b)
|
||||
{
|
||||
if (a.gameCode != b.gameCode)
|
||||
{
|
||||
return a.gameCode < b.gameCode;
|
||||
}
|
||||
|
||||
return a.headerCrc32 < b.headerCrc32;
|
||||
});
|
||||
|
||||
return std::make_unique<UsrCheatRepository>(std::move(file), std::move(indices), numberOfIndices);
|
||||
}
|
||||
9
arm9/source/cheats/UsrCheatRepositoryFactory.h
Normal file
9
arm9/source/cheats/UsrCheatRepositoryFactory.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "UsrCheatRepository.h"
|
||||
|
||||
class UsrCheatRepositoryFactory
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<UsrCheatRepository> FromUsrCheatDat(const TCHAR* usrCheatDatPath);
|
||||
};
|
||||
@@ -8,6 +8,7 @@ class RomBrowserViewModel;
|
||||
class FileInfo;
|
||||
class TaskQueueBase;
|
||||
class ICoverRepository;
|
||||
class ICheatRepository;
|
||||
|
||||
class IRomBrowserController
|
||||
{
|
||||
@@ -17,7 +18,7 @@ public:
|
||||
virtual void NavigateUp() = 0;
|
||||
virtual void NavigateToPath(const TCHAR* name) = 0;
|
||||
virtual void LaunchFile(const FileInfo& fileInfo) = 0;
|
||||
virtual void ShowGameInfo() = 0;
|
||||
virtual void ShowGameInfo(const FileInfo& fileInfo) = 0;
|
||||
virtual void HideGameInfo() = 0;
|
||||
virtual void ShowDisplaySettings() = 0;
|
||||
virtual void HideDisplaySettings() = 0;
|
||||
@@ -33,11 +34,14 @@ public:
|
||||
virtual TaskQueueBase* GetIoTaskQueue() const = 0;
|
||||
virtual TaskQueueBase* GetBgTaskQueue() const = 0;
|
||||
virtual const ICoverRepository& GetCoverRepository() const = 0;
|
||||
virtual const ICheatRepository& GetCheatRepository() const = 0;
|
||||
|
||||
virtual const RomBrowserDisplaySettings& GetRomBrowserDisplaySettings() const = 0;
|
||||
|
||||
virtual void SetRomBrowserDisplaySettings(
|
||||
const RomBrowserDisplaySettings& romBrowserDisplaySettings) = 0;
|
||||
|
||||
virtual const FileInfo& GetTriggerFileInfo() const = 0;
|
||||
};
|
||||
|
||||
inline IRomBrowserController::~IRomBrowserController() { }
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "FileType/FileType.h"
|
||||
#include "SdFolderFactory.h"
|
||||
#include "services/settings/IAppSettingsService.h"
|
||||
#include "cheats/UsrCheatRepositoryFactory.h"
|
||||
#include "RomBrowserController.h"
|
||||
|
||||
RomBrowserController::RomBrowserController(
|
||||
@@ -23,14 +24,14 @@ void RomBrowserController::NavigateToPath(const TCHAR* name)
|
||||
|
||||
void RomBrowserController::LaunchFile(const FileInfo& fileInfo)
|
||||
{
|
||||
_launchFileInfo = FileInfo(fileInfo);
|
||||
_triggerFileInfo = FileInfo(fileInfo);
|
||||
_stateMachine.Fire(RomBrowserStateTrigger::Launch);
|
||||
}
|
||||
|
||||
void RomBrowserController::ShowGameInfo()
|
||||
void RomBrowserController::ShowGameInfo(const FileInfo& fileInfo)
|
||||
{
|
||||
// Currently disabled, as the game info panel is not complete
|
||||
// _stateMachine.Fire(RomBrowserStateTrigger::ShowGameInfo);
|
||||
_triggerFileInfo = FileInfo(fileInfo);
|
||||
_stateMachine.Fire(RomBrowserStateTrigger::ShowGameInfo);
|
||||
}
|
||||
|
||||
void RomBrowserController::HideGameInfo()
|
||||
@@ -140,6 +141,10 @@ void RomBrowserController::HandleNavigateTrigger()
|
||||
_coverRepository = std::make_unique<CoverRepository>();
|
||||
_coverRepository->Initialize();
|
||||
}
|
||||
if (!_cheatRepository)
|
||||
{
|
||||
_cheatRepository = UsrCheatRepositoryFactory().FromUsrCheatDat("/_pico/usrcheat.dat");
|
||||
}
|
||||
|
||||
u64 startTick = gTickCounter.GetValue();
|
||||
_navigateFileName = nullptr;
|
||||
@@ -182,7 +187,7 @@ void RomBrowserController::HandleLaunchTrigger()
|
||||
int idx = strlcat(_navigatePath, "/", sizeof(_navigatePath));
|
||||
if (_navigatePath[idx - 2] == '/')
|
||||
_navigatePath[idx - 1] = 0;
|
||||
strlcat(_navigatePath, _launchFileInfo.GetFileName(), sizeof(_navigatePath));
|
||||
strlcat(_navigatePath, _triggerFileInfo.GetFileName(), sizeof(_navigatePath));
|
||||
_appSettingsService->GetAppSettings().lastUsedFilePath = _navigatePath;
|
||||
_appSettingsService->Save();
|
||||
|
||||
@@ -190,7 +195,7 @@ void RomBrowserController::HandleLaunchTrigger()
|
||||
loadParams->savePath[0] = 0;
|
||||
loadParams->arguments[0] = 0;
|
||||
loadParams->argumentsLength = 0;
|
||||
if (_launchFileInfo.GetFileType()->TrySetLaunchParameters(loadParams, _navigatePath))
|
||||
if (_triggerFileInfo.GetFileType()->TrySetLaunchParameters(loadParams, _navigatePath))
|
||||
{
|
||||
gProcessManager.Goto<PicoLoaderProcess>();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "CoverRepository.h"
|
||||
#include "FileType/ExtensionFileTypeProvider.h"
|
||||
#include "services/settings/IAppSettingsService.h"
|
||||
#include "cheats/ICheatRepository.h"
|
||||
|
||||
class RomBrowserController : public IRomBrowserController
|
||||
{
|
||||
@@ -23,7 +24,7 @@ public:
|
||||
|
||||
void NavigateToPath(const TCHAR* name) override;
|
||||
void LaunchFile(const FileInfo& fileInfo) override;
|
||||
void ShowGameInfo() override;
|
||||
void ShowGameInfo(const FileInfo& fileInfo) override;
|
||||
void HideGameInfo() override;
|
||||
void ShowDisplaySettings() override;
|
||||
void HideDisplaySettings() override;
|
||||
@@ -39,6 +40,7 @@ public:
|
||||
TaskQueueBase* GetIoTaskQueue() const override { return _ioTaskQueue; }
|
||||
TaskQueueBase* GetBgTaskQueue() const override { return _bgTaskQueue; }
|
||||
const ICoverRepository& GetCoverRepository() const override { return *_coverRepository; }
|
||||
const ICheatRepository& GetCheatRepository() const override { return *_cheatRepository; }
|
||||
|
||||
void SetRomBrowserDisplaySettings(const RomBrowserDisplaySettings& romBrowserDisplaySettings) override;
|
||||
|
||||
@@ -47,6 +49,8 @@ public:
|
||||
return _appSettingsService->GetAppSettings().romBrowserDisplaySettings;
|
||||
}
|
||||
|
||||
virtual const FileInfo& GetTriggerFileInfo() const override { return _triggerFileInfo; }
|
||||
|
||||
private:
|
||||
IAppSettingsService* _appSettingsService;
|
||||
TaskQueueBase* _ioTaskQueue;
|
||||
@@ -58,11 +62,12 @@ private:
|
||||
RomBrowserStateMachine _stateMachine;
|
||||
TCHAR _navigatePath[256];
|
||||
TCHAR* _navigateFileName;
|
||||
FileInfo _launchFileInfo;
|
||||
FileInfo _triggerFileInfo;
|
||||
QueueTask<void> _navigateTask;
|
||||
bool _saveSettingsPending = false;
|
||||
std::unique_ptr<CoverRepository> _coverRepository;
|
||||
ExtensionFileTypeProvider _fileTypeProvider;
|
||||
std::unique_ptr<ICheatRepository> _cheatRepository;
|
||||
|
||||
void HandleTrigger();
|
||||
void HandleNavigateTrigger();
|
||||
|
||||
66
arm9/source/romBrowser/viewModels/CheatsViewModel.cpp
Normal file
66
arm9/source/romBrowser/viewModels/CheatsViewModel.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "common.h"
|
||||
#include "cheats/ICheatRepository.h"
|
||||
#include "fat/File.h"
|
||||
#include "CheatsViewModel.h"
|
||||
|
||||
#define CRCPOLY 0xEDB88320
|
||||
|
||||
static u32 crc32(const void* buffer, u32 length)
|
||||
{
|
||||
u32 crc = ~0u;
|
||||
const u8* p = (u8*)buffer;
|
||||
while (length--)
|
||||
{
|
||||
crc ^= *p++;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY : 0);
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
CheatsViewModel::CheatsViewModel(const FileInfo& romFileInfo, IRomBrowserController* romBrowserController)
|
||||
: _romFileInfo(romFileInfo), _romBrowserController(romBrowserController)
|
||||
{
|
||||
_loadCheatsTask = _romBrowserController->GetIoTaskQueue()->Enqueue([this] (const vu8& cancelRequested)
|
||||
{
|
||||
LOG_DEBUG("%s\n", _romFileInfo.GetFileName());
|
||||
auto file = std::make_unique<File>();
|
||||
file->Open(_romFileInfo.GetFastFileRef(), FA_READ);
|
||||
auto headerBuffer = std::make_unique_for_overwrite<u8[]>(512);
|
||||
if (!file->ReadExact(headerBuffer.get(), 512))
|
||||
{
|
||||
LOG_ERROR("Could not read rom header\n");
|
||||
return TaskResult<void>::Failed();
|
||||
}
|
||||
file->Close();
|
||||
|
||||
if (cancelRequested)
|
||||
{
|
||||
return TaskResult<void>::Canceled();
|
||||
}
|
||||
|
||||
u32 gameCode = *(u32*)(headerBuffer.get() + 0xC);
|
||||
u32 crc = crc32(headerBuffer.get(), 512);
|
||||
headerBuffer.reset();
|
||||
|
||||
if (cancelRequested)
|
||||
{
|
||||
return TaskResult<void>::Canceled();
|
||||
}
|
||||
|
||||
_cheats = _romBrowserController->GetCheatRepository().GetCheatsForGame(gameCode, crc);
|
||||
if (_cheats)
|
||||
{
|
||||
_state = State::DisplayCheats;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state = State::NoCheats;
|
||||
}
|
||||
|
||||
return TaskResult<void>::Completed();
|
||||
});
|
||||
}
|
||||
35
arm9/source/romBrowser/viewModels/CheatsViewModel.h
Normal file
35
arm9/source/romBrowser/viewModels/CheatsViewModel.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "core/task/TaskQueue.h"
|
||||
#include "cheats/GameCheats.h"
|
||||
#include "romBrowser/FileInfo.h"
|
||||
#include "romBrowser/IRomBrowserController.h"
|
||||
|
||||
/// @brief View model for the cheats screen.
|
||||
class CheatsViewModel
|
||||
{
|
||||
public:
|
||||
enum class State
|
||||
{
|
||||
Loading,
|
||||
NoCheats,
|
||||
DisplayCheats
|
||||
};
|
||||
|
||||
CheatsViewModel(const FileInfo& romFileInfo, IRomBrowserController* romBrowserController);
|
||||
|
||||
void Close()
|
||||
{
|
||||
_romBrowserController->HideGameInfo();
|
||||
}
|
||||
|
||||
State GetState() const { return _state; }
|
||||
const GameCheats* GetCheats() const { return _cheats.get(); }
|
||||
|
||||
private:
|
||||
FileInfo _romFileInfo;
|
||||
IRomBrowserController* _romBrowserController;
|
||||
QueueTask<void> _loadCheatsTask;
|
||||
std::unique_ptr<GameCheats> _cheats;
|
||||
State _state = State::Loading;
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "common.h"
|
||||
#include <algorithm>
|
||||
#include "romBrowser/FileType/Nds/NdsFileType.h"
|
||||
#include "RomBrowserViewModel.h"
|
||||
|
||||
RomBrowserViewModel::RomBrowserViewModel(IRomBrowserController* romBrowserController, const char* initialSelectedFileName)
|
||||
@@ -34,7 +35,8 @@ RomBrowserViewModel::RomBrowserViewModel(IRomBrowserController* romBrowserContro
|
||||
auto sortedFilteredFiles = sdFolder.FilterAndSort(filterSortParams, filteredCount);
|
||||
u64 endTick = gTickCounter.GetValue();
|
||||
LOG_DEBUG("Filter + sort took: %d us\n", (u32)TickCounter::TicksToMicroSeconds(endTick - startTick));
|
||||
_fileInfoManager = std::make_unique<FileInfoManager>(std::move(sortedFilteredFiles), filteredCount, _romBrowserController->GetCoverRepository());
|
||||
_fileInfoManager = std::make_unique<FileInfoManager>(std::move(sortedFilteredFiles),
|
||||
filteredCount, _romBrowserController->GetCoverRepository());
|
||||
_selectedItem = _fileInfoManager->GetItemIndex(initialSelectedFileName);
|
||||
}
|
||||
|
||||
@@ -59,7 +61,8 @@ void RomBrowserViewModel::NavigateUp()
|
||||
void RomBrowserViewModel::ShowGameInfo()
|
||||
{
|
||||
const auto& item = _fileInfoManager->GetItem(_selectedItem);
|
||||
if (item.GetFileType()->GetClassification() == FileTypeClassification::Folder)
|
||||
return;
|
||||
_romBrowserController->ShowGameInfo();
|
||||
if (item.GetFileType() == &NdsFileType::sInstance)
|
||||
{
|
||||
_romBrowserController->ShowGameInfo(item);
|
||||
}
|
||||
}
|
||||
47
arm9/source/romBrowser/views/cheats/CheatListItemView.cpp
Normal file
47
arm9/source/romBrowser/views/cheats/CheatListItemView.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "common.h"
|
||||
#include "themes/material/MaterialColorScheme.h"
|
||||
#include "themes/IFontRepository.h"
|
||||
#include "gui/palette/GradientPalette.h"
|
||||
#include "gui/GraphicsContext.h"
|
||||
#include "gui/OamBuilder.h"
|
||||
#include "CheatListItemView.h"
|
||||
|
||||
#define ICON_X 20
|
||||
#define ICON_Y 3
|
||||
|
||||
#define NAME_LABEL_X 40
|
||||
#define NAME_LABEL_Y 4
|
||||
|
||||
CheatListItemView::CheatListItemView(const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository)
|
||||
: _nameLabel(200, 16, 64, fontRepository->GetFont(FontType::Regular10))
|
||||
, _materialColorScheme(materialColorScheme)
|
||||
{
|
||||
_nameLabel.SetEllipsis(true);
|
||||
AddChildTail(&_nameLabel);
|
||||
}
|
||||
|
||||
void CheatListItemView::Update()
|
||||
{
|
||||
_nameLabel.SetPosition(NAME_LABEL_X, _position.y + NAME_LABEL_Y);
|
||||
ViewContainer::Update();
|
||||
}
|
||||
|
||||
void CheatListItemView::Draw(GraphicsContext& graphicsContext)
|
||||
{
|
||||
auto backColor = _materialColorScheme->GetColor(md::sys::color::surfaceContainerLow);
|
||||
_nameLabel.SetBackgroundColor(backColor);
|
||||
_nameLabel.SetForegroundColor(_materialColorScheme->onSurface);
|
||||
ViewContainer::Draw(graphicsContext);
|
||||
|
||||
if (graphicsContext.IsVisible(Rectangle(_position.x + ICON_X, _position.y + ICON_Y, 16, 16)))
|
||||
{
|
||||
u32 iconPaletteRow = graphicsContext.GetPaletteManager().AllocRow(
|
||||
GradientPalette(backColor, _materialColorScheme->primary),
|
||||
_position.y + ICON_Y, _position.y + ICON_Y + 16);
|
||||
auto iconOam = graphicsContext.GetOamManager().AllocOams(1);
|
||||
OamBuilder::OamWithSize<16, 16>(_position.x + ICON_X, _position.y + ICON_Y, _iconVramOffset >> 7)
|
||||
.WithPalette16(iconPaletteRow)
|
||||
.WithPriority(graphicsContext.GetPriority())
|
||||
.Build(iconOam[0]);
|
||||
}
|
||||
}
|
||||
35
arm9/source/romBrowser/views/cheats/CheatListItemView.h
Normal file
35
arm9/source/romBrowser/views/cheats/CheatListItemView.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include "gui/views/ViewContainer.h"
|
||||
#include "gui/views/Label2DView.h"
|
||||
|
||||
class MaterialColorScheme;
|
||||
class IFontRepository;
|
||||
|
||||
class CheatListItemView : public ViewContainer
|
||||
{
|
||||
public:
|
||||
CheatListItemView(const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository);
|
||||
|
||||
void Update() override;
|
||||
void Draw(GraphicsContext& graphicsContext) override;
|
||||
|
||||
Rectangle GetBounds() const override
|
||||
{
|
||||
return Rectangle(_position.x, _position.y, 256, 24);
|
||||
}
|
||||
|
||||
void SetName(const char* name)
|
||||
{
|
||||
_nameLabel.SetText(name);
|
||||
}
|
||||
|
||||
void SetIcon(u32 iconVramOffset)
|
||||
{
|
||||
_iconVramOffset = iconVramOffset;
|
||||
}
|
||||
|
||||
private:
|
||||
Label2DView _nameLabel;
|
||||
u32 _iconVramOffset = 0;
|
||||
const MaterialColorScheme* _materialColorScheme;
|
||||
};
|
||||
74
arm9/source/romBrowser/views/cheats/CheatsAdapter.h
Normal file
74
arm9/source/romBrowser/views/cheats/CheatsAdapter.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
#include "gui/views/RecyclerAdapter.h"
|
||||
#include "cheats/CheatCategory.h"
|
||||
#include "cheats/Cheat.h"
|
||||
#include "CheatListItemView.h"
|
||||
|
||||
class CheatsAdapter : public RecyclerAdapter
|
||||
{
|
||||
public:
|
||||
CheatsAdapter(const CheatCategory* categories, u32 numberOfCategories, const Cheat* cheats, u32 numberOfCheats,
|
||||
const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository,
|
||||
u32 folderIconVramOffset, u32 checkboxUncheckedIconVramOffset, u32 checkboxCheckedIconVramOffset)
|
||||
: _categories(categories), _numberOfCategories(numberOfCategories), _cheats(cheats), _numberOfCheats(numberOfCheats)
|
||||
, _materialColorScheme(materialColorScheme), _fontRepository(fontRepository)
|
||||
, _folderIconVramOffset(folderIconVramOffset)
|
||||
, _checkboxUncheckedIconVramOffset(checkboxUncheckedIconVramOffset)
|
||||
, _checkboxCheckedIconVramOffset(checkboxCheckedIconVramOffset) { }
|
||||
|
||||
u32 GetItemCount() const override
|
||||
{
|
||||
return _numberOfCategories + _numberOfCheats;
|
||||
}
|
||||
|
||||
void GetViewSize(int& width, int& height) const override
|
||||
{
|
||||
width = 256;
|
||||
height = 24;
|
||||
}
|
||||
|
||||
View* CreateView() const override
|
||||
{
|
||||
LOG_DEBUG("CheatsAdapter::CreateView\n");
|
||||
return new CheatListItemView(_materialColorScheme, _fontRepository);
|
||||
}
|
||||
|
||||
void DestroyView(View* view) const override
|
||||
{
|
||||
LOG_DEBUG("CheatsAdapter::DestroyView\n");
|
||||
delete (CheatListItemView*)view;
|
||||
}
|
||||
|
||||
void BindView(View* view, int index) const override
|
||||
{
|
||||
LOG_DEBUG("CheatsAdapter::BindView\n");
|
||||
auto listItemView = static_cast<CheatListItemView*>(view);
|
||||
if ((u32)index < _numberOfCategories)
|
||||
{
|
||||
listItemView->SetName(_categories[index].GetName());
|
||||
listItemView->SetIcon(_folderIconVramOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
index -= _numberOfCategories;
|
||||
listItemView->SetName(_cheats[index].GetName());
|
||||
listItemView->SetIcon(_cheats[index].GetIsCheatActive() ? _checkboxCheckedIconVramOffset : _checkboxUncheckedIconVramOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void ReleaseView(View* view, int index) const override
|
||||
{
|
||||
LOG_DEBUG("CheatsAdapter::ReleaseView\n");
|
||||
}
|
||||
|
||||
private:
|
||||
const CheatCategory* _categories;
|
||||
u32 _numberOfCategories;
|
||||
const Cheat* _cheats;
|
||||
u32 _numberOfCheats;
|
||||
const MaterialColorScheme* _materialColorScheme;
|
||||
const IFontRepository* _fontRepository;
|
||||
u32 _folderIconVramOffset;
|
||||
u32 _checkboxUncheckedIconVramOffset;
|
||||
u32 _checkboxCheckedIconVramOffset;
|
||||
};
|
||||
103
arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.cpp
Normal file
103
arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "common.h"
|
||||
#include "gui/GraphicsContext.h"
|
||||
#include "themes/material/MaterialColorScheme.h"
|
||||
#include "themes/IFontRepository.h"
|
||||
#include "gui/input/InputProvider.h"
|
||||
#include "gui/VramContext.h"
|
||||
#include "folderIcon.h"
|
||||
#include "checkboxChecked.h"
|
||||
#include "checkboxUnchecked.h"
|
||||
#include "CheatsBottomSheetView.h"
|
||||
|
||||
#define TITLE_LABEL_X 20
|
||||
#define TITLE_LABEL_Y 16
|
||||
|
||||
CheatsBottomSheetView::CheatsBottomSheetView(std::unique_ptr<CheatsViewModel> viewModel,
|
||||
const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository,
|
||||
FocusManager* focusManager)
|
||||
: _viewModel(std::move(viewModel))
|
||||
, _titleLabel(128, 16, 25, fontRepository->GetFont(FontType::Medium11))
|
||||
, _cheatListRecycler(0, 36, 256, 124, RecyclerView::Mode::VerticalList)
|
||||
, _materialColorScheme(materialColorScheme)
|
||||
, _fontRepository(fontRepository)
|
||||
, _focusManager(focusManager)
|
||||
{
|
||||
_titleLabel.SetText(u"Cheats");
|
||||
AddChildTail(&_titleLabel);
|
||||
AddChildTail(&_cheatListRecycler);
|
||||
}
|
||||
|
||||
void CheatsBottomSheetView::InitVram(const VramContext& vramContext)
|
||||
{
|
||||
BottomSheetView::InitVram(vramContext);
|
||||
|
||||
const auto objVramManager = vramContext.GetObjVramManager();
|
||||
if (objVramManager)
|
||||
{
|
||||
_folderIconVramOffset = objVramManager->Alloc(folderIconTilesLen);
|
||||
dma_ntrCopy32(3, folderIconTiles,
|
||||
objVramManager->GetVramAddress(_folderIconVramOffset), folderIconTilesLen);
|
||||
|
||||
_checkboxUncheckedIconVramOffset = objVramManager->Alloc(checkboxUncheckedTilesLen);
|
||||
dma_ntrCopy32(3, checkboxUncheckedTiles,
|
||||
objVramManager->GetVramAddress(_checkboxUncheckedIconVramOffset), checkboxUncheckedTilesLen);
|
||||
|
||||
_checkboxCheckedIconVramOffset = objVramManager->Alloc(checkboxCheckedTilesLen);
|
||||
dma_ntrCopy32(3, checkboxCheckedTiles,
|
||||
objVramManager->GetVramAddress(_checkboxCheckedIconVramOffset), checkboxCheckedTilesLen);
|
||||
}
|
||||
|
||||
_objVramManager = vramContext.GetObjVramManager();
|
||||
}
|
||||
|
||||
void CheatsBottomSheetView::Update()
|
||||
{
|
||||
_titleLabel.SetPosition(TITLE_LABEL_X, _position.y + TITLE_LABEL_Y);
|
||||
_cheatListRecycler.SetPosition(0, _position.y + 36);
|
||||
if (_viewModel->GetState() == CheatsViewModel::State::DisplayCheats)
|
||||
{
|
||||
if (_cheatsAdapter == nullptr)
|
||||
{
|
||||
LOG_DEBUG("Setting adapter\n");
|
||||
auto gameCheats = _viewModel->GetCheats();
|
||||
u32 numberOfCategories = 0;
|
||||
auto categories = gameCheats->GetCheatCategories(numberOfCategories);
|
||||
u32 numberOfCheats = 0;
|
||||
auto cheats = gameCheats->GetCheats(numberOfCheats);
|
||||
_cheatsAdapter = new CheatsAdapter(categories, numberOfCategories, cheats, numberOfCheats,
|
||||
_materialColorScheme, _fontRepository, _folderIconVramOffset,
|
||||
_checkboxUncheckedIconVramOffset, _checkboxCheckedIconVramOffset);
|
||||
_cheatListRecycler.SetAdapter(_cheatsAdapter);
|
||||
_cheatListRecycler.InitVram(VramContext(nullptr, _objVramManager, nullptr, nullptr));
|
||||
_cheatListRecycler.Focus(*_focusManager);
|
||||
LOG_DEBUG("Setting adapter done\n");
|
||||
}
|
||||
}
|
||||
BottomSheetView::Update();
|
||||
}
|
||||
|
||||
void CheatsBottomSheetView::Draw(GraphicsContext& graphicsContext)
|
||||
{
|
||||
graphicsContext.SetClipArea(GetBounds());
|
||||
u32 oldPrio = graphicsContext.SetPriority(1);
|
||||
{
|
||||
_titleLabel.SetBackgroundColor(_materialColorScheme->GetColor(md::sys::color::surfaceContainerLow));
|
||||
_titleLabel.SetForegroundColor(_materialColorScheme->onSurface);
|
||||
_titleLabel.Draw(graphicsContext);
|
||||
graphicsContext.SetClipArea(_cheatListRecycler.GetBounds());
|
||||
_cheatListRecycler.Draw(graphicsContext);
|
||||
// BottomSheetView::Draw(graphicsContext);
|
||||
}
|
||||
graphicsContext.SetPriority(oldPrio);
|
||||
graphicsContext.ResetClipArea();
|
||||
}
|
||||
|
||||
bool CheatsBottomSheetView::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager)
|
||||
{
|
||||
if (inputProvider.Triggered(InputKey::B))
|
||||
{
|
||||
_viewModel->Close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
42
arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.h
Normal file
42
arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "romBrowser/views/BottomSheetView.h"
|
||||
#include "gui/views/Label2DView.h"
|
||||
#include "gui/views/RecyclerView.h"
|
||||
#include "romBrowser/viewModels/CheatsViewModel.h"
|
||||
#include "CheatsAdapter.h"
|
||||
|
||||
class MaterialColorScheme;
|
||||
class IFontRepository;
|
||||
class IVramManager;
|
||||
|
||||
class CheatsBottomSheetView : public BottomSheetView
|
||||
{
|
||||
public:
|
||||
CheatsBottomSheetView(std::unique_ptr<CheatsViewModel> viewModel,
|
||||
const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository,
|
||||
FocusManager* focusManager);
|
||||
|
||||
void InitVram(const VramContext& vramContext) override;
|
||||
void Update() override;
|
||||
void Draw(GraphicsContext& graphicsContext) override;
|
||||
bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override;
|
||||
|
||||
void Focus(FocusManager& focusManager) override
|
||||
{
|
||||
_cheatListRecycler.Focus(focusManager);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<CheatsViewModel> _viewModel;
|
||||
Label2DView _titleLabel;
|
||||
RecyclerView _cheatListRecycler;
|
||||
CheatsAdapter* _cheatsAdapter = nullptr;
|
||||
const MaterialColorScheme* _materialColorScheme;
|
||||
const IFontRepository* _fontRepository;
|
||||
IVramManager* _objVramManager;
|
||||
FocusManager* _focusManager;
|
||||
u32 _folderIconVramOffset = 0;
|
||||
u32 _checkboxUncheckedIconVramOffset = 0;
|
||||
u32 _checkboxCheckedIconVramOffset = 0;
|
||||
};
|
||||
Reference in New Issue
Block a user