Initial commit

This commit is contained in:
Gericom
2025-11-22 17:21:45 +01:00
commit 5d6f67c612
517 changed files with 63025 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
#include "common.h"
#include <string.h>
#include "core/StringUtil.h"
#include "FileType/NullFileTypeProvider.h"
#include "FileType/BmpFileCover.h"
#include "FileType/InternalFileInfo.h"
#include "SdFolderFactory.h"
#include "CoverRepository.h"
void CoverRepository::Initialize()
{
NullFileTypeProvider fileTypeProvider;
_ndsCoversFolder = SdFolderFactory(&fileTypeProvider).CreateFromPath("/_pico/covers/nds");
if (_ndsCoversFolder)
{
_ndsCoversFolder->SortByNameInPlace();
}
_gbaCoversFolder = SdFolderFactory(&fileTypeProvider).CreateFromPath("/_pico/covers/gba");
if (_gbaCoversFolder)
{
_gbaCoversFolder->SortByNameInPlace();
}
_userCoversFolder = SdFolderFactory(&fileTypeProvider).CreateFromPath("/_pico/covers/user");
if (_userCoversFolder)
{
_userCoversFolder->SortByNameInPlace();
}
}
FileCover* CoverRepository::GetCoverForFile(const FileInfo& fileInfo, const InternalFileInfo* internalFileInfo) const
{
char nameBuffer[256];
const auto& fileType = fileInfo.GetFileType();
if (fileType->GetClassification() != FileTypeClassification::Folder)
{
const FileInfo* coverFile = nullptr;
// Try to get a cover based on the filename in the user folder
if (_userCoversFolder)
{
u32 length = StringUtil::Copy(nameBuffer, fileInfo.GetFileName(), sizeof(nameBuffer) - 5);
nameBuffer[length + 0] = '.';
nameBuffer[length + 1] = 'b';
nameBuffer[length + 2] = 'm';
nameBuffer[length + 3] = 'p';
nameBuffer[length + 4] = 0;
coverFile = _userCoversFolder->BinarySearch(nameBuffer);
}
// Try to get a cover based on an internal game code
if (!coverFile && internalFileInfo)
{
const auto* coverFolder = GetCoverFolder(fileType->GetShortName());
if (coverFolder)
{
const char* gameCode = internalFileInfo->GetGameCode();
if (gameCode)
{
u32 length = StringUtil::Copy(nameBuffer, gameCode, sizeof(nameBuffer) - 5);
nameBuffer[length + 0] = '.';
nameBuffer[length + 1] = 'b';
nameBuffer[length + 2] = 'm';
nameBuffer[length + 3] = 'p';
nameBuffer[length + 4] = 0;
}
coverFile = coverFolder->BinarySearch(nameBuffer);
}
}
if (coverFile)
{
return new BmpFileCover(coverFile->GetFastFileRef());
}
if (!coverFile && internalFileInfo)
{
auto cover = internalFileInfo->CreateGameCover();
if (cover)
{
return cover;
}
}
}
return fileType->CreateFileCover(fileInfo.GetFileName());
}
const SdFolder* CoverRepository::GetCoverFolder(const char* coverFolderName) const
{
if (!strcmp(coverFolderName, "nds"))
{
return _ndsCoversFolder.get();
}
else if (!strcmp(coverFolderName, "gba"))
{
return _gbaCoversFolder.get();
}
else
{
return nullptr;
}
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include "ICoverRepository.h"
#include "SdFolder.h"
class CoverRepository : public ICoverRepository
{
public:
void Initialize() override;
FileCover* GetCoverForFile(
const FileInfo& fileInfo, const InternalFileInfo* internalFileInfo) const override;
private:
std::unique_ptr<SdFolder> _ndsCoversFolder;
std::unique_ptr<SdFolder> _gbaCoversFolder;
std::unique_ptr<SdFolder> _userCoversFolder;
const SdFolder* GetCoverFolder(const char* coverFolderName) const;
};

View File

@@ -0,0 +1,85 @@
#include "common.h"
#include "../FileInfoManager.h"
#include "core/task/TaskQueue.h"
#include "../views/BannerListItemView.h"
#include "../Theme/IRomBrowserViewFactory.h"
#include "BannerListFileRecyclerAdapter.h"
void BannerListFileRecyclerAdapter::GetViewSize(int& width, int& height) const
{
width = 203;
height = 44;
}
View* BannerListFileRecyclerAdapter::CreateView() const
{
return _romBrowserViewFactory->CreateBannerListItemView(_vblankTextureLoader);
}
void BannerListFileRecyclerAdapter::DestroyView(View* view) const
{
delete static_cast<BannerListItemView*>(view);
}
void BannerListFileRecyclerAdapter::BindView(View* view, int index) const
{
auto listItemView = static_cast<BannerListItemView*>(view);
listItemView->SetGraphics(_bannerListItemViewGraphics);
FileRecyclerAdapter::BindView(view, index);
}
TaskResult<void> BannerListFileRecyclerAdapter::BindView(View* view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const
{
auto listItemView = static_cast<BannerListItemView*>(view);
const auto& fileInfo = _fileInfoManager->GetItem(index);
bool fileNameAsTitle = true;
if (internalFileInfo)
{
const char16_t* gameTitle = internalFileInfo->GetGameTitle();
if (gameTitle)
{
listItemView->SetGameTitle(gameTitle);
fileNameAsTitle = false;
}
}
listItemView->SetFileName(fileInfo.GetFileName(), fileNameAsTitle);
auto icon = internalFileInfo ? internalFileInfo->CreateGameIcon() : nullptr;
if (!icon)
{
icon = fileInfo.GetFileType()->CreateFileIcon("", _themeFileIconFactory);
}
if (icon != nullptr)
{
if (cancelRequested)
{
icon.reset();
_fileInfoManager->ReleaseFileInfo(index);
return TaskResult<void>::Canceled();
}
icon->SetAnimFrame(_iconFrameCounter);
listItemView->SetIcon(std::move(icon));
listItemView->UploadIconGraphics();
if (cancelRequested)
{
listItemView->SetIcon(nullptr);
_fileInfoManager->ReleaseFileInfo(index);
return TaskResult<void>::Canceled();
}
}
return TaskResult<void>::Completed();
}
void BannerListFileRecyclerAdapter::ReleaseView(View* view, int index) const
{
LOG_DEBUG("Releasing %d\n", index);
auto listItemView = static_cast<BannerListItemView*>(view);
listItemView->SetIcon(nullptr);
listItemView->SetGameTitle(u"");
_fileInfoManager->ReleaseFileInfo(index);
}
void BannerListFileRecyclerAdapter::InitVram(const VramContext& vramContext)
{
_bannerListItemViewGraphics = _romBrowserViewFactory->UploadBannerListItemViewGraphics(vramContext);
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include "../FileRecyclerAdapter.h"
#include "../views/BannerListItemView.h"
class TaskQueueBase;
class IRomBrowserViewFactory;
class BannerListFileRecyclerAdapter : public FileRecyclerAdapter
{
public:
BannerListFileRecyclerAdapter(FileInfoManager* fileInfoManager,
TaskQueueBase* taskQueue, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory,
VBlankTextureLoader* vblankTextureLoader)
: FileRecyclerAdapter(fileInfoManager, taskQueue, themeFileIconFactory)
, _romBrowserViewFactory(romBrowserViewFactory)
, _vblankTextureLoader(vblankTextureLoader) { }
void GetViewSize(int& width, int& height) const override;
View* CreateView() const override;
void DestroyView(View* view) const override;
void BindView(View* view, int index) const override;
void ReleaseView(View* view, int index) const override;
void InitVram(const VramContext& vramContext) override;
private:
const IRomBrowserViewFactory* _romBrowserViewFactory;
BannerListItemView::VramToken _bannerListItemViewGraphics;
VBlankTextureLoader* _vblankTextureLoader;
TaskResult<void> BindView(View* view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override;
};

View File

@@ -0,0 +1,59 @@
#include "common.h"
#include "../FileInfoManager.h"
#include "core/task/TaskQueue.h"
#include "../views/CoverView.h"
#include "../Theme/IRomBrowserViewFactory.h"
#include "../FileType/UnknownFileCover.h"
#include "romBrowser/ICoverRepository.h"
#include "CoverFlowFileRecyclerAdapter.h"
void CoverFlowFileRecyclerAdapter::GetViewSize(int& width, int& height) const
{
width = 44;
height = 44;
}
View* CoverFlowFileRecyclerAdapter::CreateView() const
{
return new CoverView(_vblankTextureLoader);
}
void CoverFlowFileRecyclerAdapter::DestroyView(View* view) const
{
auto coverView = static_cast<CoverView*>(view);
delete coverView;
}
TaskResult<void> CoverFlowFileRecyclerAdapter::BindView(View* view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const
{
auto coverView = static_cast<CoverView*>(view);
auto cover = _fileInfoManager->GetFileCover(index);
if (cancelRequested)
{
_fileInfoManager->ReleaseFileInfo(index);
return TaskResult<void>::Canceled();
}
coverView->SetCover(std::move(cover));
coverView->UploadCoverGraphics();
if (cancelRequested)
{
coverView->ClearCover();
_fileInfoManager->ReleaseFileInfo(index);
return TaskResult<void>::Canceled();
}
return TaskResult<void>::Completed();
}
void CoverFlowFileRecyclerAdapter::ReleaseView(View* view, int index) const
{
LOG_DEBUG("Releasing %d\n", index);
auto coverView = static_cast<CoverView*>(view);
coverView->ClearCover();
_fileInfoManager->ReleaseFileInfo(index);
}
void CoverFlowFileRecyclerAdapter::InitVram(const VramContext& vramContext)
{
// _iconGridItemViewGraphics = _romBrowserViewFactory->UploadIconGridItemViewGraphics(vramManager);
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include "../FileRecyclerAdapter.h"
class IRomBrowserViewFactory;
class VBlankTextureLoader;
class ICoverRepository;
class CoverFlowFileRecyclerAdapter : public FileRecyclerAdapter
{
public:
CoverFlowFileRecyclerAdapter(FileInfoManager* fileInfoManager,
TaskQueueBase* taskQueue, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory,
VBlankTextureLoader* vblankTextureLoader,
const ICoverRepository* coverRepository)
: FileRecyclerAdapter(fileInfoManager, taskQueue, themeFileIconFactory)
, _romBrowserViewFactory(romBrowserViewFactory)
, _vblankTextureLoader(vblankTextureLoader)
, _coverRepository(coverRepository) { }
void GetViewSize(int& width, int& height) const override;
View* CreateView() const override;
void DestroyView(View* view) const override;
void ReleaseView(View* view, int index) const override;
void InitVram(const VramContext& vramContext) override;
private:
const IRomBrowserViewFactory* _romBrowserViewFactory;
VBlankTextureLoader* _vblankTextureLoader;
const ICoverRepository* _coverRepository;
TaskResult<void> BindView(View* view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override;
};

View File

@@ -0,0 +1,73 @@
#include "common.h"
#include "../FileInfoManager.h"
#include "core/task/TaskQueue.h"
#include "../views/IconGridItemView.h"
#include "../Theme/IRomBrowserViewFactory.h"
#include "IconGridFileRecyclerAdapter.h"
void IconGridFileRecyclerAdapter::GetViewSize(int& width, int& height) const
{
width = 44;
height = 44;
}
View* IconGridFileRecyclerAdapter::CreateView() const
{
return _romBrowserViewFactory->CreateIconGridItemView();
}
void IconGridFileRecyclerAdapter::DestroyView(View* view) const
{
delete static_cast<IconGridItemView*>(view);
}
void IconGridFileRecyclerAdapter::BindView(View* view, int index) const
{
auto iconGridItemView = static_cast<IconGridItemView*>(view);
iconGridItemView->SetGraphics(_iconGridItemViewGraphics);
FileRecyclerAdapter::BindView(view, index);
}
TaskResult<void> IconGridFileRecyclerAdapter::BindView(View* view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const
{
auto iconGridItemView = static_cast<IconGridItemView*>(view);
auto icon = internalFileInfo ? internalFileInfo->CreateGameIcon() : nullptr;
if (!icon)
{
const auto& fileInfo = _fileInfoManager->GetItem(index);
icon = fileInfo.GetFileType()->CreateFileIcon(fileInfo.GetFileName(), _themeFileIconFactory);
}
if (icon != nullptr)
{
if (cancelRequested)
{
icon.reset();
_fileInfoManager->ReleaseFileInfo(index);
return TaskResult<void>::Canceled();
}
icon->SetAnimFrame(_iconFrameCounter);
iconGridItemView->SetIcon(std::move(icon));
iconGridItemView->UploadIconGraphics();
if (cancelRequested)
{
iconGridItemView->SetIcon(nullptr);
_fileInfoManager->ReleaseFileInfo(index);
return TaskResult<void>::Canceled();
}
}
return TaskResult<void>::Completed();
}
void IconGridFileRecyclerAdapter::ReleaseView(View* view, int index) const
{
LOG_DEBUG("Releasing %d\n", index);
auto iconGridItemView = static_cast<IconGridItemView*>(view);
iconGridItemView->SetIcon(nullptr);
_fileInfoManager->ReleaseFileInfo(index);
}
void IconGridFileRecyclerAdapter::InitVram(const VramContext& vramContext)
{
_iconGridItemViewGraphics = _romBrowserViewFactory->UploadIconGridItemViewGraphics(vramContext);
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "../FileRecyclerAdapter.h"
#include "../views/IconGridItemView.h"
class IRomBrowserViewFactory;
class IconGridFileRecyclerAdapter : public FileRecyclerAdapter
{
public:
IconGridFileRecyclerAdapter(FileInfoManager* fileInfoManager,
TaskQueueBase* taskQueue, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory)
: FileRecyclerAdapter(fileInfoManager, taskQueue, themeFileIconFactory)
, _romBrowserViewFactory(romBrowserViewFactory) { }
void GetViewSize(int& width, int& height) const override;
View* CreateView() const override;
void DestroyView(View* view) const override;
void BindView(View* view, int index) const override;
void ReleaseView(View* view, int index) const override;
void InitVram(const VramContext& vramContext) override;
private:
const IRomBrowserViewFactory* _romBrowserViewFactory;
IconGridItemView::VramToken _iconGridItemViewGraphics;
TaskResult<void> BindView(View* view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override;
};

View File

@@ -0,0 +1,4 @@
#include "common.h"
#include "RomBrowserBannerListDisplayMode.h"
const RomBrowserBannerListDisplayMode RomBrowserBannerListDisplayMode::sInstance;

View File

@@ -0,0 +1,39 @@
#pragma once
#include "gui/views/RecyclerView.h"
#include "RomBrowserDisplayMode.h"
#include "BannerListFileRecyclerAdapter.h"
class RomBrowserBannerListDisplayMode : public RomBrowserDisplayMode
{
public:
static const RomBrowserBannerListDisplayMode sInstance;
bool IsVertical() const override { return true; }
std::unique_ptr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
int startButtonCount, int endButtonCount) const override
{
return romBrowserViewFactory->CreateAppBarView(0, 0,
AppBarView::Orientation::Vertical, startButtonCount, endButtonCount);
}
std::unique_ptr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
{
auto recyclerView = std::make_unique<RecyclerView>(42, 0, 256 - 42, 192, RecyclerView::Mode::VerticalList);
recyclerView->SetPadding(0, 3);
recyclerView->SetItemSpacing(0, 3);
return recyclerView;
}
FileRecyclerAdapter* CreateRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const override
{
return new BannerListFileRecyclerAdapter(
&viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(), themeFileIconFactory,
romBrowserViewFactory, vblankTextureLoader);
}
private:
constexpr RomBrowserBannerListDisplayMode() { }
};

View File

@@ -0,0 +1,23 @@
#pragma once
#include <memory>
#include "../views/AppBarView.h"
#include "gui/views/RecyclerViewBase.h"
#include "../FileRecyclerAdapter.h"
#include "../viewModels/RomBrowserViewModel.h"
#include "../Theme/IRomBrowserViewFactory.h"
class VBlankTextureLoader;
class ICoverRepository;
class RomBrowserDisplayMode
{
public:
virtual bool IsVertical() const = 0;
virtual bool ShowCoverOnTopScreen() const { return true; }
virtual std::unique_ptr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
int startButtonCount, int endButtonCount) const = 0;
virtual std::unique_ptr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const = 0;
virtual FileRecyclerAdapter* CreateRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const = 0;
};

View File

@@ -0,0 +1,34 @@
#include "common.h"
#include "RomBrowserHorizontalIconGridDisplayMode.h"
#include "RomBrowserVerticalIconGridDisplayMode.h"
#include "RomBrowserBannerListDisplayMode.h"
#include "RomBrowserHorizontalCoverFlowDisplayMode.h"
#include "RomBrowserDisplayModeFactory.h"
const RomBrowserDisplayMode* RomBrowserDisplayModeFactory::GetRomBrowserDisplayMode(
RomBrowserLayout romBrowserDisplayMode) const
{
switch (romBrowserDisplayMode)
{
case RomBrowserLayout::HorizontalIconGrid:
{
return &RomBrowserHorizontalIconGridDisplayMode::sInstance;
}
case RomBrowserLayout::VerticalIconGrid:
{
return &RomBrowserVerticalIconGridDisplayMode::sInstance;
}
case RomBrowserLayout::BannerList:
{
return &RomBrowserBannerListDisplayMode::sInstance;
}
case RomBrowserLayout::CoverFlow:
{
return &RomBrowserHorizontalCoverFlowDisplayMode::sInstance;
}
default:
{
return nullptr;
}
}
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "services/settings/RomBrowserLayout.h"
#include "RomBrowserDisplayMode.h"
class RomBrowserDisplayModeFactory
{
public:
const RomBrowserDisplayMode* GetRomBrowserDisplayMode(
RomBrowserLayout romBrowserDisplayMode) const;
};

View File

@@ -0,0 +1,4 @@
#include "common.h"
#include "RomBrowserHorizontalCoverFlowDisplayMode.h"
const RomBrowserHorizontalCoverFlowDisplayMode RomBrowserHorizontalCoverFlowDisplayMode::sInstance;

View File

@@ -0,0 +1,34 @@
#pragma once
#include "RomBrowserDisplayMode.h"
class RomBrowserHorizontalCoverFlowDisplayMode : public RomBrowserDisplayMode
{
public:
static const RomBrowserHorizontalCoverFlowDisplayMode sInstance;
bool IsVertical() const override { return false; }
bool ShowCoverOnTopScreen() const override { return false; }
std::unique_ptr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
int startButtonCount, int endButtonCount) const override
{
return romBrowserViewFactory->CreateAppBarView(0, 0,
AppBarView::Orientation::Horizontal, startButtonCount, endButtonCount);
}
std::unique_ptr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
{
return romBrowserViewFactory->CreateCoverFlowRecyclerView();
}
FileRecyclerAdapter* CreateRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const override
{
return romBrowserViewFactory->CreateCoverFlowRecyclerAdapter(
viewModel, themeFileIconFactory, vblankTextureLoader);
}
private:
constexpr RomBrowserHorizontalCoverFlowDisplayMode() { }
};

View File

@@ -0,0 +1,4 @@
#include "common.h"
#include "RomBrowserHorizontalIconGridDisplayMode.h"
const RomBrowserHorizontalIconGridDisplayMode RomBrowserHorizontalIconGridDisplayMode::sInstance;

View File

@@ -0,0 +1,39 @@
#pragma once
#include "gui/views/RecyclerView.h"
#include "RomBrowserDisplayMode.h"
#include "IconGridFileRecyclerAdapter.h"
class RomBrowserHorizontalIconGridDisplayMode : public RomBrowserDisplayMode
{
public:
static const RomBrowserHorizontalIconGridDisplayMode sInstance;
bool IsVertical() const override { return false; }
std::unique_ptr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
int startButtonCount, int endButtonCount) const override
{
return romBrowserViewFactory->CreateAppBarView(0, 0,
AppBarView::Orientation::Horizontal, startButtonCount, endButtonCount);
}
std::unique_ptr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
{
auto recyclerView = std::make_unique<RecyclerView>(0, 42, 256, 192 - 42, RecyclerView::Mode::HorizontalGrid);
recyclerView->SetPadding(10, 0);
recyclerView->SetItemSpacing(4, 4);
return recyclerView;
}
FileRecyclerAdapter* CreateRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const override
{
return new IconGridFileRecyclerAdapter(
&viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(),
themeFileIconFactory, romBrowserViewFactory);
}
private:
constexpr RomBrowserHorizontalIconGridDisplayMode() { }
};

View File

@@ -0,0 +1,4 @@
#include "common.h"
#include "RomBrowserVerticalIconGridDisplayMode.h"
const RomBrowserVerticalIconGridDisplayMode RomBrowserVerticalIconGridDisplayMode::sInstance;

View File

@@ -0,0 +1,39 @@
#pragma once
#include "gui/views/RecyclerView.h"
#include "RomBrowserDisplayMode.h"
#include "IconGridFileRecyclerAdapter.h"
class RomBrowserVerticalIconGridDisplayMode : public RomBrowserDisplayMode
{
public:
static const RomBrowserVerticalIconGridDisplayMode sInstance;
bool IsVertical() const override { return true; }
std::unique_ptr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
int startButtonCount, int endButtonCount) const override
{
return romBrowserViewFactory->CreateAppBarView(0, 0,
AppBarView::Orientation::Vertical, startButtonCount, endButtonCount);
}
std::unique_ptr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
{
auto recyclerView = std::make_unique<RecyclerView>(42, 0, 256 - 42, 192, RecyclerView::Mode::VerticalGrid);
recyclerView->SetPadding(0, 3);
recyclerView->SetItemSpacing(9, 3);
return recyclerView;
}
FileRecyclerAdapter* CreateRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const override
{
return new IconGridFileRecyclerAdapter(
&viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(),
themeFileIconFactory, romBrowserViewFactory);
}
private:
constexpr RomBrowserVerticalIconGridDisplayMode() { }
};

View File

@@ -0,0 +1,20 @@
#include "common.h"
#include <string.h>
#include "core/StringUtil.h"
#include "FileInfo.h"
FileInfo::FileInfo(const FileInfo& fileInfo)
: _type(fileInfo._type), _fastFileRef(fileInfo._fastFileRef)
{
u32 bufferLength = strlen(fileInfo.GetFileName()) + 1;
_name = std::make_unique_for_overwrite<TCHAR[]>(bufferLength);
StringUtil::Copy(_name.get(), fileInfo.GetFileName(), bufferLength);
}
FileInfo::FileInfo(const TCHAR* fileName, const FileType* type, const FastFileRef& fastFileRef)
: _type(type), _fastFileRef(fastFileRef)
{
u32 bufferLength = strlen(fileName) + 1;
_name = std::make_unique_for_overwrite<TCHAR[]>(bufferLength);
StringUtil::Copy(_name.get(), fileName, bufferLength);
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include "fat/ff.h"
#include "fat/FastFileRef.h"
#include "FileType/FileType.h"
class InternalFileInfo;
class FileInfo
{
public:
FileInfo() { }
FileInfo(const FileInfo& fileInfo);
FileInfo(const TCHAR* fileName, const FileType* type, const FastFileRef& fastFileRef);
FileInfo &operator=(FileInfo&& rhs)
{
if (this != &rhs)
{
_name = std::move(rhs._name);
_type = rhs._type;
_fastFileRef = rhs._fastFileRef;
}
return *this;
}
const TCHAR* GetFileName() const { return _name.get(); }
const FileType* GetFileType() const { return _type; }
u32 GetFileSize() const { return _fastFileRef.GetFileSize(); }
InternalFileInfo* CreateInternalFileInfo() const
{
return _type->CreateInternalFileInfo(_fastFileRef);
}
const FastFileRef& GetFastFileRef() const { return _fastFileRef; }
private:
std::unique_ptr<TCHAR[]> _name;
const FileType* _type;
FastFileRef _fastFileRef;
};

View File

@@ -0,0 +1,32 @@
#include "common.h"
#include <string.h>
#include "FileInfoManager.h"
FileInfoManager::FileInfoManager(std::unique_ptr<const FileInfo*[]> items, u32 itemCount, const ICoverRepository& coverRepository)
: _items(std::move(items)), _itemCount(itemCount)
, _extraFileInfo(std::make_unique<ExtraFileInfo[]>(itemCount))
, _coverRepository(coverRepository) { }
FileInfoManager::~FileInfoManager()
{
for (u32 i = 0; i < _itemCount; i++)
{
ReleaseFileInfo(i);
}
}
int FileInfoManager::GetItemIndex(const char* fileName)
{
if (fileName == nullptr)
{
return -1;
}
for (u32 i = 0; i < _itemCount; i++)
{
if (strcmp(fileName, _items[i]->GetFileName()) == 0)
{
return i;
}
}
return -1;
}

View File

@@ -0,0 +1,70 @@
#pragma once
#include "common.h"
#include <memory>
#include "FileInfo.h"
#include "FileType/FileCover.h"
#include "ICoverRepository.h"
#include "core/SharedPtr.h"
#include "FileType/InternalFileInfo.h"
class FileInfoManager
{
public:
FileInfoManager(std::unique_ptr<const FileInfo*[]> items, u32 itemCount, const ICoverRepository& coverRepository);
~FileInfoManager();
const InternalFileInfo* GetInternalFileInfo(int index)
{
return _extraFileInfo[index].internalFileInfo;
}
SharedPtr<FileCover> GetFileCover(int index)
{
return _extraFileInfo[index].fileCover;
}
void LoadFileInfo(int index)
{
auto internalFileInfo = GetInternalFileInfo(index);
if (!internalFileInfo)
{
internalFileInfo = _items[index]->CreateInternalFileInfo();
}
if (!_extraFileInfo[index].fileCover.IsValid())
{
_extraFileInfo[index].fileCover = SharedPtr(_coverRepository.GetCoverForFile(*_items[index], internalFileInfo));
}
_extraFileInfo[index].internalFileInfo = internalFileInfo;
}
void ReleaseFileInfo(int index)
{
auto internalFileInfo = GetInternalFileInfo(index);
if (internalFileInfo)
{
delete internalFileInfo;
_extraFileInfo[index].internalFileInfo = nullptr;
}
_extraFileInfo[index].fileCover.Reset();
}
int GetItemIndex(const char* fileName);
const FileInfo& GetItem(int index) const { return *_items[index]; }
u32 GetItemCount() const { return _itemCount; }
private:
struct ExtraFileInfo
{
const InternalFileInfo* internalFileInfo;
SharedPtr<FileCover> fileCover;
};
std::unique_ptr<const FileInfo*[]> _items;
u32 _itemCount;
std::unique_ptr<ExtraFileInfo[]> _extraFileInfo;
const ICoverRepository& _coverRepository;
};

View File

@@ -0,0 +1,26 @@
#include "common.h"
#include "core/task/TaskQueue.h"
#include "FileInfoManager.h"
#include "FileRecyclerAdapter.h"
u32 FileRecyclerAdapter::GetItemCount() const
{
return _fileInfoManager->GetItemCount();
}
void FileRecyclerAdapter::BindView(View* view, int index) const
{
LOG_DEBUG("Binding %d\n", index);
_taskQueue->Enqueue([=, this] (const vu8& cancelRequested)
{
LOG_DEBUG("Started task to load %d\n", index);
_fileInfoManager->LoadFileInfo(index);
auto internalFileInfo = _fileInfoManager->GetInternalFileInfo(index);
if (cancelRequested)
{
_fileInfoManager->ReleaseFileInfo(index);
return TaskResult<void>::Canceled();
}
return BindView(view, index, internalFileInfo, cancelRequested);
});
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include "core/task/TaskQueue.h"
#include "gui/views/RecyclerAdapter.h"
class FileInfoManager;
class IVramManager;
class InternalFileInfo;
class IThemeFileIconFactory;
class VramContext;
class FileRecyclerAdapter : public RecyclerAdapter
{
public:
u32 GetItemCount() const override;
void BindView(View* view, int index) const override;
void SetIconFrameCounter(u32 iconFrameCounter)
{
_iconFrameCounter = iconFrameCounter;
}
virtual void InitVram(const VramContext& vramContext) { }
protected:
FileInfoManager* _fileInfoManager;
TaskQueueBase* _taskQueue;
u32 _iconFrameCounter;
const IThemeFileIconFactory* _themeFileIconFactory;
FileRecyclerAdapter(FileInfoManager* fileInfoManager, TaskQueueBase* taskQueue,
const IThemeFileIconFactory* themeFileIconFactory)
: _fileInfoManager(fileInfoManager), _taskQueue(taskQueue)
, _iconFrameCounter(0), _themeFileIconFactory(themeFileIconFactory) { }
virtual TaskResult<void> BindView(View* view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const = 0;
};

View File

@@ -0,0 +1,48 @@
#include "common.h"
#include <string.h>
#include <nds/arm9/cache.h>
#include <memory>
#include <libtwl/dma/dmaNitro.h>
#include "fat/File.h"
#include "core/math/ColorConverter.h"
#include "BmpFileCover.h"
BmpFileCover::BmpFileCover(const FastFileRef& coverFileRef)
{
const auto file = std::make_unique<File>();
file->Open(coverFileRef, FA_READ);
if (!file->ReadExact(_coverBuffer, 0x436))
return;
u32 dataOffset = _coverBuffer[0xA] | (_coverBuffer[0xB] << 8) | (_coverBuffer[0xC] << 16) | (_coverBuffer[0xD] << 24);
u8* paletteData32 = &_coverBuffer[0x36];
for (u32 i = 0; i < 256; i++)
{
u32 b = *paletteData32++;
u32 g = *paletteData32++;
u32 r = *paletteData32++;
paletteData32++;
_palette[i] = ColorConverter::ToXBGR555(Rgb<5, 5, 5>(Rgb<8, 8, 8>(r, g, b)));
}
if (file->Seek(dataOffset) != FR_OK ||
!file->ReadExact(_coverBuffer, sizeof(_coverBuffer)))
return;
file->Close();
DC_FlushRange(_coverBuffer, sizeof(_coverBuffer));
DC_FlushRange(_palette, sizeof(_palette));
}
void BmpFileCover::Upload2DCoverBitmap(void* destination) const
{
cover_bitmapToTiledCopy(_coverBuffer, destination);
}
void BmpFileCover::Upload2DCoverPalette(void* destination) const
{
dma_ntrCopy32(3, _palette, destination, sizeof(_palette));
}

View File

@@ -0,0 +1,27 @@
#pragma once
#include "FileCover.h"
#include "fat/FastFileRef.h"
/// @brief Class representing a BMP file cover.
class alignas(32) BmpFileCover : public FileCover
{
public:
explicit BmpFileCover(const FastFileRef& coverFileRef);
VBlankTextureLoadRequest CreateTextureLoadRequest() const override
{
return VBlankTextureLoadRequest(
_coverBuffer, 128 * 96, _texVramOffset,
_palette, sizeof(_palette), _plttVramOffset,
nullptr, nullptr);
}
void Upload2DCoverBitmap(void* destination) const override;
void Upload2DCoverPalette(void* destination) const override;
bool IsActualCover() const override { return true; }
private:
u8 _coverBuffer[128 * 96] alignas(32);
u16 _palette[256] alignas(32);
};

View File

@@ -0,0 +1,61 @@
#pragma once
#include "FileType.h"
#include "services/settings/FileAssociation.h"
#include "../Theme/IThemeFileIconFactory.h"
/// @brief Class representing a custom (user provided) file type.
class CustomFileType : public FileType
{
public:
CustomFileType()
: FileType(nullptr, FileTypeClassification::Unknown) { }
explicit CustomFileType(const FileAssociation* fileAssociation)
: CustomFileType(fileAssociation, nullptr) { }
CustomFileType(const FileAssociation* fileAssociation, const FileType* baseFileType)
: FileType(
baseFileType != nullptr ? baseFileType->GetShortName() : fileAssociation->extension.GetString(),
baseFileType != nullptr ? baseFileType->GetClassification() : FileTypeClassification::Misc)
, _fileAssociation(fileAssociation), _baseFileType(baseFileType) { }
std::unique_ptr<FileIcon> CreateFileIcon(const TCHAR* fileName,
const IThemeFileIconFactory* themeFileIconFactory) const override
{
return _baseFileType != nullptr
? _baseFileType->CreateFileIcon(fileName, themeFileIconFactory)
: themeFileIconFactory->CreateGenericFileIcon(fileName);
}
FileCover* CreateFileCover(const TCHAR* fileName) const override
{
return _baseFileType != nullptr
? _baseFileType->CreateFileCover(fileName)
: FileType::CreateFileCover(fileName);
};
bool HasInternalFileInfo() const override
{
return _baseFileType != nullptr
&& _baseFileType->HasInternalFileInfo();
}
InternalFileInfo* CreateInternalFileInfo(const FastFileRef& fastFileRef) const override
{
return _baseFileType != nullptr
? _baseFileType->CreateInternalFileInfo(fastFileRef)
: nullptr;
}
bool TrySetLaunchParameters(pload_params_t* launchParameters, const char* filePath) const override
{
StringUtil::Copy(launchParameters->romPath, _fileAssociation->applicationPath, sizeof(launchParameters->romPath));
u32 length = StringUtil::Copy(launchParameters->arguments, filePath, sizeof(launchParameters->arguments));
launchParameters->argumentsLength = length + 1;
return true;
}
private:
const FileAssociation* _fileAssociation;
const FileType* _baseFileType = nullptr;
};

View File

@@ -0,0 +1,58 @@
#include "common.h"
#include <string.h>
#include "UnknownFileType.h"
#include "Nds/NdsFileType.h"
#include "Gba/GbaFileType.h"
#include "ExtensionFileTypeProvider.h"
static bool isNdsExtension(const char* extension)
{
return !strcasecmp(extension, "nds")
|| !strcasecmp(extension, "srl")
|| !strcasecmp(extension, "dsi");
}
static bool isGbaExtension(const char* extension)
{
return !strcasecmp(extension, "gba")
|| !strcasecmp(extension, "agb");
}
ExtensionFileTypeProvider::ExtensionFileTypeProvider(const AppSettings& appSettings)
: _appSettings(appSettings)
{
_customFileTypes = std::make_unique_for_overwrite<CustomFileType[]>(appSettings.numberOfFileAssociations);
for (u32 i = 0; i < appSettings.numberOfFileAssociations; i++)
{
const FileType* baseFileType = nullptr;
if (isGbaExtension(appSettings.fileAssociations[i].extension))
{
baseFileType = &GbaFileType::sInstance;
}
_customFileTypes[i] = CustomFileType(&appSettings.fileAssociations[i], baseFileType);
}
}
const FileType* ExtensionFileTypeProvider::GetFileType(const TCHAR* path) const
{
const char* extension = strrchr(path, '.');
if (extension)
{
extension++; // skip over dot
if (isNdsExtension(extension))
{
return &NdsFileType::sInstance;
}
for (u32 i = 0; i < _appSettings.numberOfFileAssociations; i++)
{
if (!strcasecmp(extension, _customFileTypes[i].GetShortName()))
{
return &_customFileTypes[i];
}
}
}
return &UnknownFileType::sInstance;
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include <memory>
#include "IFileTypeProvider.h"
#include "services/settings/AppSettings.h"
#include "CustomFileType.h"
/// @brief Implementation of \see IFileTypeProvider that uses extensions to identify file types.
class ExtensionFileTypeProvider : public IFileTypeProvider
{
public:
explicit ExtensionFileTypeProvider(const AppSettings& appSettings);
const FileType* GetFileType(const TCHAR* path) const override;
private:
const AppSettings& _appSettings;
std::unique_ptr<CustomFileType[]> _customFileTypes;
};

View File

@@ -0,0 +1,46 @@
#pragma once
#include "gui/VBlankTextureLoadRequest.h"
extern "C" void cover_bitmapToTiledCopy(const void* bitmap, void* vram);
#define COVER_WIDTH 106
#define COVER_HEIGHT 96
/// @brief Abstract base class for a file cover.
class FileCover
{
public:
virtual ~FileCover() = 0;
/// @brief Sets the texture and texture palette offsets of this cover after it has been loaded to vram.
/// @param texVramOffset The texture vram offset.
/// @param plttVramOffset The texture palette vram offset.
void SetTexVramOffset(u32 texVramOffset, u32 plttVramOffset)
{
_texVramOffset = texVramOffset;
_plttVramOffset = plttVramOffset;
}
/// @brief Creates a texture load request to load this cover.
/// @return The constructed texture load request.
virtual VBlankTextureLoadRequest CreateTextureLoadRequest() const = 0;
/// @brief Uploads the 8bpp bitmap graphics of this cover to BG vram.
/// @param destination The address to load to.
virtual void Upload2DCoverBitmap(void* destination) const = 0;
/// @brief Uploads the 256 color palette of this cover to palette ram.
/// @param destination The address to load to.
virtual void Upload2DCoverPalette(void* destination) const = 0;
/// @brief Returns whether this cover is an actual cover graphic of the file.
/// @return True when this cover is an actual cover graphic of the file,
/// or false when the graphic is a (generic) placeholder.
virtual bool IsActualCover() const = 0;
protected:
u32 _texVramOffset = 0;
u32 _plttVramOffset = 0;
};
inline FileCover::~FileCover() { }

View File

@@ -0,0 +1,32 @@
.section ".itcm", "ax"
.arm
// r0 = bitmap
// r1 = vram
.global cover_bitmapToTiledCopy
.type cover_bitmapToTiledCopy, %function
cover_bitmapToTiledCopy:
push {r4-r9}
mov r12, #12
1:
sub r12, r12, #(14 << 16)
2:
ldrd r2, [r0], #128
ldrd r4, [r0], #128
ldrd r6, [r0], #128
ldrd r8, [r0], #128
stmia r1!, {r2-r9}
ldrd r2, [r0], #128
ldrd r4, [r0], #128
ldrd r6, [r0], #128
ldrd r8, [r0]
stmia r1!, {r2-r9}
sub r0, r0, #(7 * 128 - 8)
adds r12, r12, #(1 << 16)
bmi 2b
add r0, r0, #(128 * 8 - (14 * 8))
subs r12, r12, #1
bne 1b
pop {r4-r9}
bx lr

View File

@@ -0,0 +1,58 @@
#pragma once
#include "core/math/Point.h"
#include "core/math/Rgb.h"
class PaletteManager;
class GraphicsContext;
#define FILE_ICON_VRAM_SIZE 4096
/// @brief Abstract base class representing a file icon.
class FileIcon
{
public:
virtual ~FileIcon() = 0;
/// @brief Uploads the graphics of this icon to the specified \p vram address.
/// @param vram The vram address to load the graphics to.
virtual void UploadGraphics(vu16* vram) const = 0;
/// @brief Updates this icon.
virtual void Update() { }
/// @brief Draws this file icon.
/// @param graphicsContext The graphics context to use.
/// @param backgroundColor The color on which the icon is drawn.
virtual void Draw(GraphicsContext& graphicsContext, const Rgb<8, 8, 8>& backgroundColor) = 0;
/// @brief Sets the OBJ vram offset of this icon.
/// @param offset The OBJ vram offset.
void SetObjVramOffset(u32 offset) { _vramOffset = offset; }
/// @brief Sets the icon animation frame.
/// @param frame The animation frame.
void SetAnimFrame(u32 frame)
{
_frame = frame;
}
/// @brief Sets the position where this icon will be drawn.
/// @param position The position where this icon will be drawn.
void SetPosition(const Point& position) { _position = position; }
/// @brief Sets the position where this icon will be drawn.
/// @param x The X position where this icon will be drawn.
/// @param y The Y position where this icon will be drawn.
void SetPosition(int x, int y)
{
_position.x = x;
_position.y = y;
}
protected:
u32 _vramOffset = 0;
u32 _frame = 0;
Point _position;
};
inline FileIcon::~FileIcon() { }

View File

@@ -0,0 +1,75 @@
#pragma once
#include <memory>
#include "fat/ff.h"
#include "fat/FastFileRef.h"
#include "FileTypeClassification.h"
#include "FileIcon.h"
#include "FileCover.h"
#include "UnknownFileCover.h"
#include "picoLoaderBootstrap.h"
class FileInfo;
class InternalFileInfo;
class IThemeFileIconFactory;
class ICoverRepository;
/// @brief Abstract base class representing a file type.
class FileType
{
public:
virtual ~FileType() = 0;
/// @brief Returns the short name for this file type.
/// @return The short name for this file type.
constexpr const char* GetShortName() const { return _shortName; }
/// @brief Returns the classification for this file type.
/// @return The classification for this file type.
constexpr FileTypeClassification GetClassification() const { return _classification; }
/// @brief Creates a generic file icon for a file of this file type.
/// @param fileName The name of the file.
/// @param themeFileIconFactory The theme file icon factory to use.
/// @return The constructed file icon, or \c nullptr when no file icon for this file type is available.
virtual std::unique_ptr<FileIcon> CreateFileIcon(const TCHAR* fileName,
const IThemeFileIconFactory* themeFileIconFactory) const
{
return nullptr;
};
/// @brief Creates a generic file cover for a file of this file type.
/// @param fileName The name of the file.
/// @return The constructed file cover.
virtual FileCover* CreateFileCover(const TCHAR* fileName) const
{
return new UnknownFileCover();
};
/// @brief Returns if this file format has internal file info or not.
/// @return \c true if this file format has internal file info, or \c false otherwise.
virtual bool HasInternalFileInfo() const { return false; }
/// @brief Reads the internal file info of the file specified by \p fastFileRef.
/// @param fastFileRef The file to get the internal file info of.
/// @return The internal file info of the specified file when successful, or \c nullptr otherwise.
virtual InternalFileInfo* CreateInternalFileInfo(const FastFileRef& fastFileRef) const { return nullptr; }
/// @brief Tries to set the launch parameters to launch a file of this file type at the specified \p filePath.
/// @param launchParameters The launch parameters to set.
/// @param filePath The file that is going to be launched.
/// @return \c true when the launch parameters were set successfully, or \c false otherwise.
virtual bool TrySetLaunchParameters(pload_params_t* launchParameters, const char* filePath) const
{
return false;
}
protected:
constexpr FileType(const char* shortName, FileTypeClassification classification)
: _shortName(shortName), _classification(classification) { }
private:
const char* _shortName;
FileTypeClassification _classification;
};
inline FileType::~FileType() { }

View File

@@ -0,0 +1,12 @@
#pragma once
enum class FileTypeClassification
{
Unknown,
Folder,
Misc,
Game,
Music,
Picture,
Video
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "../StaticFileCover.h"
#include "folderCover.h"
/// @brief Generic cover for a folder.
class FolderFileCover : public StaticFileCover
{
public:
FolderFileCover()
: StaticFileCover(folderCoverBitmap, folderCoverPal) { }
};

View File

@@ -0,0 +1,4 @@
#include "common.h"
#include "FolderFileType.h"
const FolderFileType FolderFileType::sInstance;

View File

@@ -0,0 +1,27 @@
#pragma once
#include <memory>
#include "../FileType.h"
#include "../../Theme/IThemeFileIconFactory.h"
#include "FolderFileCover.h"
/// @brief File type that represents a folder.
class FolderFileType : public FileType
{
public:
static const FolderFileType sInstance;
std::unique_ptr<FileIcon> CreateFileIcon(const TCHAR* fileName,
const IThemeFileIconFactory* themeFileIconFactory) const override
{
return themeFileIconFactory->CreateFolderIcon(fileName);
}
FileCover* CreateFileCover(const TCHAR* fileName) const override
{
return new FolderFileCover();
};
private:
constexpr FolderFileType()
: FileType("folder", FileTypeClassification::Folder) { }
};

View File

@@ -0,0 +1,4 @@
#include "common.h"
#include "GbaFileType.h"
const GbaFileType GbaFileType::sInstance;

View File

@@ -0,0 +1,29 @@
#pragma once
#include "../FileType.h"
#include "GbaInternalFileInfo.h"
#include "core/StringUtil.h"
#include "../../Theme/IThemeFileIconFactory.h"
/// @brief File type for gba roms.
class GbaFileType : public FileType
{
public:
static const GbaFileType sInstance;
std::unique_ptr<FileIcon> CreateFileIcon(const TCHAR* fileName,
const IThemeFileIconFactory* themeFileIconFactory) const override
{
return themeFileIconFactory->CreateGenericFileIcon(fileName);
}
bool HasInternalFileInfo() const override { return true; }
InternalFileInfo* CreateInternalFileInfo(const FastFileRef& fastFileRef) const override
{
return new GbaInternalFileInfo(fastFileRef);
}
private:
constexpr GbaFileType()
: FileType("gba", FileTypeClassification::Game) { }
};

View File

@@ -0,0 +1,20 @@
#include "common.h"
#include <string.h>
#include <nds/arm9/cache.h>
#include "fat/File.h"
#include "GbaInternalFileInfo.h"
GbaInternalFileInfo::GbaInternalFileInfo(const FastFileRef& fastFileRef)
{
memset(_gameCode, 0, sizeof(_gameCode));
const auto file = std::make_unique<File>();
file->Open(fastFileRef, FA_READ);
if (file->Seek(0xAC) != FR_OK)
return;
u32 bytesRead;
if (file->Read(_gameCode, 4, bytesRead) != FR_OK)
return;
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include "../InternalFileInfo.h"
#include "fat/FastFileRef.h"
/// @brief Internal file info for gba roms.
class alignas(32) GbaInternalFileInfo : public InternalFileInfo
{
public:
explicit GbaInternalFileInfo(const FastFileRef& fastFileRef);
constexpr const char* GetGameCode() const override { return _gameCode; }
private:
char _gameCode[5];
};

View File

@@ -0,0 +1,13 @@
#pragma once
class FileType;
/// @brief Interface for getting a file type based on a file path.
class IFileTypeProvider
{
public:
virtual ~IFileTypeProvider() = 0;
virtual const FileType* GetFileType(const TCHAR* path) const = 0;
};
inline IFileTypeProvider::~IFileTypeProvider() { }

View File

@@ -0,0 +1,29 @@
#pragma once
#include <memory>
#include "FileIcon.h"
#include "FileCover.h"
/// @brief Abstract base class representing internal file information.
class InternalFileInfo
{
public:
virtual ~InternalFileInfo() = 0;
/// @brief Returns the game code of the file.
/// @return A pointer to the game code if available, or \c nullptr otherwise.
virtual const char* GetGameCode() const { return nullptr; }
/// @brief Returns the game title of the file.
/// @return A pointer to the game title if available, or \c nullptr otherwise.
virtual const char16_t* GetGameTitle() const { return nullptr; }
/// @brief Creates an icon based on the internal file information.
/// @return A unique pointer to the created icon when successful, or \c nullptr otherwise.
virtual std::unique_ptr<FileIcon> CreateGameIcon() const { return nullptr; }
/// @brief Creates a cover based on the internal file information.
/// @return A unique pointer to the created cover when successful, or \c nullptr otherwise.
virtual FileCover* CreateGameCover() const { return nullptr; }
};
inline InternalFileInfo::~InternalFileInfo() { }

View File

@@ -0,0 +1,142 @@
#include "common.h"
#include <libtwl/math/mathDiv.h>
#include <libtwl/dma/dmaNitro.h>
#include "gui/PaletteManager.h"
#include "gui/OamManager.h"
#include "gui/OamBuilder.h"
#include "gui/GraphicsContext.h"
#include "gui/palette/DirectPalette.h"
#include "NdsFileIcon.h"
NdsFileIcon::NdsFileIcon(const nds_banner_t* banner)
: _banner(banner), _animTokenIdx(0), _lastAnimToken(0)
, _animLength(0), _loop(false)
{
_animated = _banner->header.version >= NDS_BANNER_VERSION_103
&& _banner->animation.animTokens[0].duration != 0;
if (_animated)
{
_lastAnimToken = NDS_BANNER_ANIM_TOKEN_COUNT - 1;
int length = 0;
_loop = true;
for (int i = 0; i < NDS_BANNER_ANIM_TOKEN_COUNT; i++)
{
_tokenStartTimes[i] = length;
const auto& token = _banner->animation.animTokens[i];
if (token.duration == NDS_BANNER_ANIM_DURATION_CONTROL_FRAME)
{
_loop = token.control != NDS_BANNER_ANIM_CONTROL_STOP;
_lastAnimToken = i - 1;
break;
}
else
length += token.duration;
}
_animLength = length;
_tokenStartTimes[NDS_BANNER_ANIM_TOKEN_COUNT] = _animLength;
}
}
void NdsFileIcon::UploadGraphics(vu16* vram) const
{
if (_animated)
dma_ntrCopy32(3, _banner->animation.iconGfx, vram, sizeof(_banner->animation.iconGfx));
else
dma_ntrCopy32(3, _banner->iconGfx, vram, sizeof(_banner->iconGfx));
}
void NdsFileIcon::Update()
{
if (!_animated)
return;
_frame %= _animLength;
if ((!_loop && _frame >= _animLength) || _lastAnimToken == 0)
{
_animTokenIdx = _lastAnimToken;
}
else
{
u32 start = 0;
u32 end = _lastAnimToken;
while (start <= end)
{
const u32 mid = (start + end) >> 1;
u32 midTime = _tokenStartTimes[mid];
if (midTime <= _frame && _frame < _tokenStartTimes[mid + 1])
{
start = mid;
break;
}
else if (_frame < midTime)
end = mid - 1;
else
start = mid + 1;
}
_animTokenIdx = start;
}
if (++_frame == _animLength)
_frame = 0;
// if (++_durationCounter < _banner->animation.animTokens[_animTokenIdx].duration)
// return;
// _durationCounter = 0;
// if (++_animTokenIdx >= NDS_BANNER_ANIM_TOKEN_COUNT)
// {
// _animTokenIdx = 0;
// return;
// }
// if (_banner->animation.animTokens[_animTokenIdx].duration == NDS_BANNER_ANIM_DURATION_CONTROL_FRAME)
// {
// switch (_banner->animation.animTokens[_animTokenIdx].control)
// {
// case NDS_BANNER_ANIM_CONTROL_LOOP:
// _animTokenIdx = 0;
// break;
// case NDS_BANNER_ANIM_CONTROL_STOP:
// _animTokenIdx--;
// break;
// }
// }
}
void NdsFileIcon::Draw(GraphicsContext& graphicsContext, const Rgb<8, 8, 8>& backgroundColor)
{
if (!graphicsContext.IsVisible(Rectangle(_position, 32, 32)))
return;
const u16* palette = _animated
? _banner->animation.iconPltt[_banner->animation.animTokens[_animTokenIdx].plttIdx]
: _banner->iconPltt;
u32 paletteRowIdx = graphicsContext.GetPaletteManager().AllocRow(
DirectPalette(palette), _position.y, _position.y + 32);
u32 vramOffset = _vramOffset;
if (_animated)
vramOffset += _banner->animation.animTokens[_animTokenIdx].gfxIdx * 512;
auto builder = OamBuilder::OamWithSize<32, 32>(
_position, vramOffset >> 7)
.WithPalette16(paletteRowIdx)
.WithPriority(graphicsContext.GetPriority());
if (_animated)
{
builder
.WithHFlip(_banner->animation.animTokens[_animTokenIdx].hFlip)
.WithVFlip(_banner->animation.animTokens[_animTokenIdx].vFlip);
}
gfx_oam_entry_t* oam = graphicsContext.GetOamManager().AllocOams(1);
builder.Build(oam[0]);
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include "../FileIcon.h"
#include "ndsBanner.h"
/// @brief Icon of a nds rom.
class NdsFileIcon : public FileIcon
{
public:
explicit NdsFileIcon(const nds_banner_t* banner);
void UploadGraphics(vu16* vram) const override;
void Update() override;
void Draw(GraphicsContext& graphicsContext, const Rgb<8, 8, 8>& backgroundColor) override;
private:
const nds_banner_t* _banner;
bool _animated;
int _animTokenIdx;
// int _durationCounter;
u32 _lastAnimToken;
u32 _animLength;
u16 _tokenStartTimes[65];
bool _loop;
};

View File

@@ -0,0 +1,4 @@
#include "common.h"
#include "NdsFileType.h"
const NdsFileType NdsFileType::sInstance;

View File

@@ -0,0 +1,36 @@
#pragma once
#include "../FileType.h"
#include "NdsInternalFileInfo.h"
#include "core/StringUtil.h"
#include "../../Theme/IThemeFileIconFactory.h"
/// @brief File type for nds roms.
class NdsFileType : public FileType
{
public:
static const NdsFileType sInstance;
std::unique_ptr<FileIcon> CreateFileIcon(const TCHAR* fileName,
const IThemeFileIconFactory* themeFileIconFactory) const override
{
return themeFileIconFactory->CreateNdsFileIcon(fileName);
}
bool HasInternalFileInfo() const override { return true; }
InternalFileInfo* CreateInternalFileInfo(const FastFileRef& fastFileRef) const override
{
return new NdsInternalFileInfo(fastFileRef);
}
bool TrySetLaunchParameters(pload_params_t* launchParameters, const char* filePath) const override
{
StringUtil::Copy(launchParameters->romPath, filePath, sizeof(launchParameters->romPath));
return true;
}
private:
constexpr NdsFileType()
: FileType("nds", FileTypeClassification::Game) { }
};

View File

@@ -0,0 +1,53 @@
#include "common.h"
#include <string.h>
#include <nds/arm9/cache.h>
#include "fat/File.h"
#include "romBrowser/ICoverRepository.h"
#include "NdsInternalFileInfo.h"
NdsInternalFileInfo::NdsInternalFileInfo(const FastFileRef& fastFileRef)
{
const auto file = std::make_unique<File>();
_hasBanner = false;
memset(_gameCode, 0, sizeof(_gameCode));
file->Open(fastFileRef, FA_READ);
if (file->Seek(0xC) != FR_OK)
return;
u32 bytesRead;
if (file->Read(_gameCode, 4, bytesRead) != FR_OK)
return;
if (file->Seek(0x68) != FR_OK)
return;
u32 bannerOffset;
if (file->Read(&bannerOffset, 4, bytesRead) != FR_OK)
return;
if (bannerOffset == 0)
return;
if (file->Seek(bannerOffset) != FR_OK)
return;
if (file->Read(&_banner, 0xA00, bytesRead) != FR_OK)
return;
if (_banner.header.version >= NDS_BANNER_VERSION_103)
{
if (file->Read(((u8*)&_banner) + 0xA00, 0x19C0, bytesRead) != FR_OK)
return;
}
_hasBanner = true;
DC_FlushRange(&_banner, sizeof(_banner));
}
const char16_t* NdsInternalFileInfo::GetGameTitle() const
{
if (!_hasBanner)
return nullptr;
return _banner.title[NDS_BANNER_TITLE_LANGUAGE_ENGLISH];
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include "../InternalFileInfo.h"
#include "ndsBanner.h"
#include "NdsFileIcon.h"
#include "fat/FastFileRef.h"
/// @brief Internal file info for nds roms.
class alignas(32) NdsInternalFileInfo : public InternalFileInfo
{
public:
explicit NdsInternalFileInfo(const FastFileRef& fastFileRef);
constexpr const char* GetGameCode() const override { return _gameCode; }
const char16_t* GetGameTitle() const override;
std::unique_ptr<FileIcon> CreateGameIcon() const override
{
if (!_hasBanner)
return nullptr;
return std::make_unique<NdsFileIcon>(&_banner);
}
const nds_banner_t& GetBanner() const { return _banner; }
private:
nds_banner_t _banner alignas(32);
bool _hasBanner;
char _gameCode[5];
};

View File

@@ -0,0 +1,66 @@
#pragma once
#define NDS_BANNER_VERSION_1 0x0001
#define NDS_BANNER_VERSION_2 0x0002
#define NDS_BANNER_VERSION_3 0x0003
#define NDS_BANNER_VERSION_103 0x0103
typedef struct
{
u16 version;
u16 version1Crc;
u16 version2Crc;
u16 version3Crc;
u16 version103AnimCrc;
u8 reserved[0x16];
} nds_banner_header_t;
#define NDS_BANNER_ANIM_DURATION_CONTROL_FRAME 0
#define NDS_BANNER_ANIM_CONTROL_LOOP 0
#define NDS_BANNER_ANIM_CONTROL_STOP 1
#define NDS_BANNER_TITLE_LANGUAGE_JAPANESE 0
#define NDS_BANNER_TITLE_LANGUAGE_ENGLISH 1
#define NDS_BANNER_TITLE_LANGUAGE_FRENCH 2
#define NDS_BANNER_TITLE_LANGUAGE_GERMAN 3
#define NDS_BANNER_TITLE_LANGUAGE_ITALIAN 4
#define NDS_BANNER_TITLE_LANGUAGE_SPANISH 5
#define NDS_BANNER_TITLE_LANGUAGE_CHINESE 6
#define NDS_BANNER_TITLE_LANGUAGE_KOREAN 7
typedef struct
{
u8 duration;
union
{
struct
{
u8 gfxIdx : 3;
u8 plttIdx : 3;
u8 hFlip : 1;
u8 vFlip : 1;
};
u8 control;
};
} nds_banner_anim_token_t;
#define NDS_BANNER_ANIM_TOKEN_COUNT 64
typedef struct
{
u8 iconGfx[8][0x200];
u16 iconPltt[8][16];
nds_banner_anim_token_t animTokens[NDS_BANNER_ANIM_TOKEN_COUNT];
} nds_banner_anim_t;
typedef struct
{
nds_banner_header_t header;
u8 iconGfx[0x200];
u16 iconPltt[16];
char16_t title[16][128];
nds_banner_anim_t animation;
} nds_banner_t;
static_assert(sizeof(nds_banner_t) == 0x23C0, "Invalid size for nds_banner_t");

View File

@@ -0,0 +1,13 @@
#pragma once
#include "IFileTypeProvider.h"
#include "UnknownFileType.h"
/// @brief Dummy implementation of \see IFileTypeProvider that always returns \see UnknownFileType.
class NullFileTypeProvider : public IFileTypeProvider
{
public:
const FileType* GetFileType(const TCHAR* path) const override
{
return &UnknownFileType::sInstance;
}
};

View File

@@ -0,0 +1,34 @@
#pragma once
#include "FileCover.h"
#include <libtwl/dma/dmaNitro.h>
class StaticFileCover : public FileCover
{
public:
StaticFileCover(const void* bitmapData, const void* paletteData)
: _bitmapData(bitmapData), _paletteData(paletteData) { }
VBlankTextureLoadRequest CreateTextureLoadRequest() const override
{
return VBlankTextureLoadRequest(
_bitmapData, 128 * 96, _texVramOffset,
_paletteData, 512, _plttVramOffset,
nullptr, nullptr);
}
void Upload2DCoverBitmap(void* destination) const override
{
cover_bitmapToTiledCopy(_bitmapData, destination);
}
void Upload2DCoverPalette(void* destination) const override
{
dma_ntrCopy32(3, _paletteData, destination, 512);
}
bool IsActualCover() const override { return false; }
private:
const void* _bitmapData;
const void* _paletteData;
};

View File

@@ -0,0 +1,33 @@
#include "common.h"
#include <libtwl/dma/dmaNitro.h>
#include "gui/PaletteManager.h"
#include "gui/OamManager.h"
#include "gui/OamBuilder.h"
#include "gui/GraphicsContext.h"
#include "gui/palette/DirectPalette.h"
#include "StaticIcon.h"
void StaticIcon::UploadGraphics(vu16* vram) const
{
dma_ntrCopy32(3, _tileData, vram, 512);
}
void StaticIcon::Update()
{
}
void StaticIcon::Draw(GraphicsContext& graphicsContext, const Rgb<8, 8, 8>& backgroundColor)
{
if (!graphicsContext.IsVisible(Rectangle(_position, 32, 32)))
return;
u32 paletteRowIdx = graphicsContext.GetPaletteManager().AllocRow(
DirectPalette(_paletteData), _position.y, _position.y + 32);
gfx_oam_entry_t* oam = graphicsContext.GetOamManager().AllocOams(1);
OamBuilder::OamWithSize<32, 32>(_position, _vramOffset >> 7)
.WithPalette16(paletteRowIdx)
.WithPriority(graphicsContext.GetPriority())
.Build(oam[0]);
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include "FileIcon.h"
class StaticIcon : public FileIcon
{
public:
StaticIcon(const u8* tileData, const u16* paletteData)
: _tileData(tileData), _paletteData(paletteData) { }
void UploadGraphics(vu16* vram) const override;
void Update() override;
void Draw(GraphicsContext& graphicsContext, const Rgb<8, 8, 8>& backgroundColor) override;
private:
const u8* _tileData;
const u16* _paletteData;
u32 _vramOffset;
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "unknownCover.h"
#include "StaticFileCover.h"
/// @brief Fallback question mark cover.
class UnknownFileCover : public StaticFileCover
{
public:
UnknownFileCover()
: StaticFileCover(unknownCoverBitmap, unknownCoverPal) { }
};

View File

@@ -0,0 +1,4 @@
#include "common.h"
#include "UnknownFileType.h"
const UnknownFileType UnknownFileType::sInstance;

View File

@@ -0,0 +1,12 @@
#pragma once
#include "FileType.h"
class UnknownFileType : public FileType
{
public:
static const UnknownFileType sInstance;
private:
constexpr UnknownFileType()
: FileType("other", FileTypeClassification::Unknown) { }
};

View File

@@ -0,0 +1,17 @@
#pragma once
#include "FileType/FileCover.h"
class FileInfo;
class InternalFileInfo;
class ICoverRepository
{
public:
virtual ~ICoverRepository() = 0;
virtual void Initialize() = 0;
virtual FileCover* GetCoverForFile(
const FileInfo& fileInfo, const InternalFileInfo* internalFileInfo) const = 0;
};
inline ICoverRepository::~ICoverRepository() { }

View File

@@ -0,0 +1,43 @@
#pragma once
#include "core/SharedPtr.h"
#include "services/settings/AppSettings.h"
class SdFolder;
class RomBrowserStateMachine;
class RomBrowserViewModel;
class FileInfo;
class TaskQueueBase;
class ICoverRepository;
class IRomBrowserController
{
public:
virtual ~IRomBrowserController() = 0;
virtual void NavigateUp() = 0;
virtual void NavigateToPath(const TCHAR* name) = 0;
virtual void LaunchFile(const FileInfo& fileInfo) = 0;
virtual void ShowGameInfo() = 0;
virtual void HideGameInfo() = 0;
virtual void ShowDisplaySettings() = 0;
virtual void HideDisplaySettings() = 0;
virtual void Update() = 0;
virtual const SdFolder& GetSdFolder() const = 0;
virtual const RomBrowserStateMachine& GetStateMachine() const = 0;
virtual const SharedPtr<RomBrowserViewModel>& GetRomBrowserViewModel() = 0;
virtual TaskQueueBase* GetIoTaskQueue() const = 0;
virtual TaskQueueBase* GetBgTaskQueue() const = 0;
virtual const ICoverRepository& GetCoverRepository() const = 0;
virtual const RomBrowserDisplaySettings& GetRomBrowserDisplaySettings() const = 0;
virtual void SetRomBrowserDisplaySettings(
const RomBrowserDisplaySettings& romBrowserDisplaySettings) = 0;
};
inline IRomBrowserController::~IRomBrowserController() { }

View File

@@ -0,0 +1,209 @@
#include "common.h"
#include <array>
#include "picoLoaderBootstrap.h"
#include "PicoLoaderProcess.h"
#include "FileType/ExtensionFileTypeProvider.h"
#include "FileType/FileType.h"
#include "SdFolderFactory.h"
#include "services/settings/IAppSettingsService.h"
#include "RomBrowserController.h"
RomBrowserController::RomBrowserController(
IAppSettingsService* appSettingsService, TaskQueueBase* ioTaskQueue,
TaskQueueBase* bgTaskQueue)
: _appSettingsService(appSettingsService)
, _ioTaskQueue(ioTaskQueue), _bgTaskQueue(bgTaskQueue)
, _fileTypeProvider(appSettingsService->GetAppSettings()) { }
void RomBrowserController::NavigateToPath(const TCHAR* name)
{
StringUtil::Copy(_navigatePath, name, sizeof(_navigatePath) / sizeof(_navigatePath[0]));
_stateMachine.Fire(RomBrowserStateTrigger::Navigate);
}
void RomBrowserController::LaunchFile(const FileInfo& fileInfo)
{
_launchFileInfo = FileInfo(fileInfo);
_stateMachine.Fire(RomBrowserStateTrigger::Launch);
}
void RomBrowserController::ShowGameInfo()
{
// Currently disabled, as the game info panel is not complete
// _stateMachine.Fire(RomBrowserStateTrigger::ShowGameInfo);
}
void RomBrowserController::HideGameInfo()
{
_stateMachine.Fire(RomBrowserStateTrigger::HideGameInfo);
}
void RomBrowserController::ShowDisplaySettings()
{
_stateMachine.Fire(RomBrowserStateTrigger::ShowDisplaySettings);
}
void RomBrowserController::HideDisplaySettings()
{
if (_saveSettingsPending)
{
_saveSettingsPending = false;
_ioTaskQueue->Enqueue([this] (const vu8& cancelRequested)
{
_appSettingsService->Save();
return TaskResult<void>::Completed();
});
}
_stateMachine.Fire(RomBrowserStateTrigger::HideDisplaySettings);
}
void RomBrowserController::SetRomBrowserDisplaySettings(
const RomBrowserDisplaySettings& romBrowserDisplaySettings)
{
_appSettingsService->GetAppSettings().romBrowserDisplaySettings = romBrowserDisplaySettings;
_saveSettingsPending = true;
_stateMachine.Fire(RomBrowserStateTrigger::ChangeDisplayMode);
}
void RomBrowserController::Update()
{
_stateMachine.Update();
if (_stateMachine.HasStateChanged())
{
HandleTrigger();
}
switch (_stateMachine.GetCurrentState())
{
case RomBrowserState::Start:
{
LOG_DEBUG("RomBrowserState::Start\n");
const auto& lastUsed = _appSettingsService->GetAppSettings().lastUsedFilePath;
if (strlen(lastUsed.GetString()) != 0)
{
NavigateToPath(lastUsed.GetString());
}
else
{
NavigateToPath("/");
}
break;
}
case RomBrowserState::LoadingFolder:
{
if (_navigateTask.GetTask().IsCompletedSuccessfully())
{
_navigateTask.Dispose();
_stateMachine.Fire(RomBrowserStateTrigger::FolderLoadDone);
}
break;
}
case RomBrowserState::Launching:
default:
{
break;
}
}
}
void RomBrowserController::HandleTrigger()
{
switch (_stateMachine.GetLastTrigger())
{
case RomBrowserStateTrigger::Navigate:
HandleNavigateTrigger();
break;
case RomBrowserStateTrigger::FolderLoadDone:
HandleFolderLoadDoneTrigger();
break;
case RomBrowserStateTrigger::Launch:
HandleLaunchTrigger();
break;
case RomBrowserStateTrigger::ChangeDisplayMode:
HandleChangeDisplayModeTrigger();
break;
default:
break;
}
}
void RomBrowserController::HandleNavigateTrigger()
{
LOG_DEBUG("RomBrowserStateTrigger::Navigate\n");
_navigateTask = _ioTaskQueue->Enqueue([this] (const vu8& cancelRequested)
{
if (!_coverRepository)
{
_coverRepository = std::make_unique<CoverRepository>();
_coverRepository->Initialize();
}
u64 startTick = gTickCounter.GetValue();
_navigateFileName = nullptr;
if (strcmp(_navigatePath, "/") != 0) // can't f_stat on root dir
{
FILINFO fileInfo;
if (f_stat(_navigatePath, &fileInfo) != FR_OK)
{
StringUtil::Copy(_navigatePath, "/", sizeof(_navigatePath) / sizeof(_navigatePath[0]));
}
else if (!(fileInfo.fattrib & AM_DIR))
{
_navigateFileName = strrchr(_navigatePath, '/') + 1;
_navigateFileName[-1] = 0;
}
}
f_chdir(_navigatePath);
SdFolderFactory sdFolderFactory { &_fileTypeProvider };
_newSdFolder = sdFolderFactory.CreateFromPath(".");
u64 endTick = gTickCounter.GetValue();
LOG_DEBUG("Loading files in folder took: %d us\n", (u32)TickCounter::TicksToMicroSeconds(endTick - startTick));
return TaskResult<void>::Completed();
});
}
void RomBrowserController::HandleFolderLoadDoneTrigger()
{
LOG_DEBUG("RomBrowserStateTrigger::FolderLoadDone\n");
_romBrowserViewModel.Reset();
_sdFolder = std::move(_newSdFolder);
_romBrowserViewModel = SharedPtr(new RomBrowserViewModel(this, _navigateFileName));
}
void RomBrowserController::HandleLaunchTrigger()
{
LOG_DEBUG("RomBrowserStateTrigger::Launch\n");
_ioTaskQueue->Enqueue([this] (const vu8& cancelRequested)
{
f_getcwd(_navigatePath, sizeof(_navigatePath) / sizeof(_navigatePath[0]));
int idx = strlcat(_navigatePath, "/", sizeof(_navigatePath));
if (_navigatePath[idx - 2] == '/')
_navigatePath[idx - 1] = 0;
strlcat(_navigatePath, _launchFileInfo.GetFileName(), sizeof(_navigatePath));
_appSettingsService->GetAppSettings().lastUsedFilePath = _navigatePath;
_appSettingsService->Save();
auto loadParams = pload_getLoadParams();
loadParams->savePath[0] = 0;
loadParams->arguments[0] = 0;
loadParams->argumentsLength = 0;
if (_launchFileInfo.GetFileType()->TrySetLaunchParameters(loadParams, _navigatePath))
{
gProcessManager.Goto<PicoLoaderProcess>();
}
else
{
LOG_FATAL("Failed to set launch parameters.\n");
}
return TaskResult<void>::Completed();
});
}
void RomBrowserController::HandleChangeDisplayModeTrigger()
{
LOG_DEBUG("RomBrowserStateTrigger::ChangeDisplayMode\n");
_romBrowserViewModel = SharedPtr(new RomBrowserViewModel(this));
}

View File

@@ -0,0 +1,72 @@
#pragma once
#include <memory>
#include "core/SharedPtr.h"
#include "SdFolder.h"
#include "viewModels/RomBrowserViewModel.h"
#include "RomBrowserStateMachine.h"
#include "core/task/TaskQueue.h"
#include "IRomBrowserController.h"
#include "CoverRepository.h"
#include "FileType/ExtensionFileTypeProvider.h"
#include "services/settings/IAppSettingsService.h"
class RomBrowserController : public IRomBrowserController
{
public:
RomBrowserController(IAppSettingsService* appSettingsService,
TaskQueueBase* ioTaskQueue, TaskQueueBase* bgTaskQueue);
void NavigateUp() override
{
NavigateToPath("..");
}
void NavigateToPath(const TCHAR* name) override;
void LaunchFile(const FileInfo& fileInfo) override;
void ShowGameInfo() override;
void HideGameInfo() override;
void ShowDisplaySettings() override;
void HideDisplaySettings() override;
void Update() override;
const SdFolder& GetSdFolder() const override { return *_sdFolder; }
const RomBrowserStateMachine& GetStateMachine() const override { return _stateMachine; }
const SharedPtr<RomBrowserViewModel>& GetRomBrowserViewModel() override { return _romBrowserViewModel; }
TaskQueueBase* GetIoTaskQueue() const override { return _ioTaskQueue; }
TaskQueueBase* GetBgTaskQueue() const override { return _bgTaskQueue; }
const ICoverRepository& GetCoverRepository() const override { return *_coverRepository; }
void SetRomBrowserDisplaySettings(const RomBrowserDisplaySettings& romBrowserDisplaySettings) override;
const RomBrowserDisplaySettings& GetRomBrowserDisplaySettings() const override
{
return _appSettingsService->GetAppSettings().romBrowserDisplaySettings;
}
private:
IAppSettingsService* _appSettingsService;
TaskQueueBase* _ioTaskQueue;
TaskQueueBase* _bgTaskQueue;
std::unique_ptr<SdFolder> _sdFolder;
SharedPtr<RomBrowserViewModel> _romBrowserViewModel;
std::unique_ptr<SdFolder> _newSdFolder;
RomBrowserStateMachine _stateMachine;
TCHAR _navigatePath[256];
TCHAR* _navigateFileName;
FileInfo _launchFileInfo;
QueueTask<void> _navigateTask;
bool _saveSettingsPending = false;
std::unique_ptr<CoverRepository> _coverRepository;
ExtensionFileTypeProvider _fileTypeProvider;
void HandleTrigger();
void HandleNavigateTrigger();
void HandleFolderLoadDoneTrigger();
void HandleLaunchTrigger();
void HandleChangeDisplayModeTrigger();
};

View File

@@ -0,0 +1,11 @@
#pragma once
enum class RomBrowserState
{
Start,
Browser,
GameInfo,
LoadingFolder,
Launching,
DisplaySettings
};

View File

@@ -0,0 +1,58 @@
#include "common.h"
#include "StateMachineTriggerChecker.h"
#include "RomBrowserStateMachine.h"
void RomBrowserStateMachine::Fire(RomBrowserStateTrigger trigger)
{
LOG_DEBUG("Fire %d\n", trigger);
_newTrigger = trigger;
}
bool RomBrowserStateMachine::FireDirect(RomBrowserStateTrigger trigger)
{
LOG_DEBUG("FireDirect %d\n", trigger);
RomBrowserState newState;
if (StateMachineTriggerChecker(_curState, trigger)
.In(RomBrowserState::Start)
.Trigger(RomBrowserStateTrigger::Navigate).GoesTo(RomBrowserState::LoadingFolder)
.In(RomBrowserState::Browser)
.Trigger(RomBrowserStateTrigger::ChangeDisplayMode).GoesTo(RomBrowserState::Browser)
.Trigger(RomBrowserStateTrigger::Navigate).GoesTo(RomBrowserState::LoadingFolder)
.Trigger(RomBrowserStateTrigger::ShowGameInfo).GoesTo(RomBrowserState::GameInfo)
.Trigger(RomBrowserStateTrigger::Launch).GoesTo(RomBrowserState::Launching)
.Trigger(RomBrowserStateTrigger::ShowDisplaySettings).GoesTo(RomBrowserState::DisplaySettings)
.In(RomBrowserState::GameInfo)
.Trigger(RomBrowserStateTrigger::HideGameInfo).GoesTo(RomBrowserState::Browser)
.In(RomBrowserState::LoadingFolder)
.Trigger(RomBrowserStateTrigger::FolderLoadDone).GoesTo(RomBrowserState::Browser)
.In(RomBrowserState::DisplaySettings)
.Trigger(RomBrowserStateTrigger::ChangeDisplayMode).GoesTo(RomBrowserState::DisplaySettings)
.Trigger(RomBrowserStateTrigger::HideDisplaySettings).GoesTo(RomBrowserState::Browser)
.Check(newState))
{
_prevState = _curState;
_curState = newState;
_lastTrigger = trigger;
return true;
}
return false;
}
void RomBrowserStateMachine::Update()
{
_stateChanged = false;
if (_newTrigger == RomBrowserStateTrigger::None)
return;
if (!FireDirect(_newTrigger))
{
LOG_ERROR("Trigger %d invalid in state %d\n", _newTrigger, _curState);
}
else
{
_stateChanged = true;
}
_newTrigger = RomBrowserStateTrigger::None;
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include "RomBrowserState.h"
#include "RomBrowserStateTrigger.h"
class RomBrowserStateMachine
{
public:
void Fire(RomBrowserStateTrigger trigger);
void Update();
constexpr RomBrowserState GetPreviousState() const { return _prevState; }
constexpr RomBrowserStateTrigger GetLastTrigger() const { return _lastTrigger; }
constexpr RomBrowserState GetCurrentState() const { return _curState; }
constexpr bool HasStateChanged() const { return _stateChanged; }
private:
RomBrowserStateTrigger _lastTrigger = RomBrowserStateTrigger::None;
RomBrowserState _prevState = RomBrowserState::Start;
RomBrowserState _curState = RomBrowserState::Start;
RomBrowserStateTrigger _newTrigger = RomBrowserStateTrigger::None;
bool _stateChanged = false;
bool FireDirect(RomBrowserStateTrigger trigger);
};

View File

@@ -0,0 +1,14 @@
#pragma once
enum class RomBrowserStateTrigger
{
None,
Navigate,
ChangeDisplayMode,
ShowGameInfo,
HideGameInfo,
FolderLoadDone,
Launch,
ShowDisplaySettings,
HideDisplaySettings
};

View File

@@ -0,0 +1,111 @@
#include "common.h"
#include <string.h>
#include <algorithm>
#include "SdFolder.h"
SdFolder::SdFolder(FileInfo** files, int fileCount)
: _files(files), _fileCount(fileCount) { }
SdFolder::~SdFolder()
{
for (int i = 0; i < _fileCount; i++)
delete _files[i];
free(_files);
}
std::unique_ptr<const FileInfo*[]> SdFolder::FilterAndSort(
const SdFolderFilterSortParams& filterSortParams, int& resultCount) const
{
auto sortedFilteredFiles = std::make_unique<const FileInfo*[]>(_fileCount);
int filteredCount = 0;
for (int i = 0; i < _fileCount; i++)
{
const FileInfo* file = _files[i];
auto classification = file->GetFileType()->GetClassification();
if (classification != FileTypeClassification::Unknown)
{
sortedFilteredFiles[filteredCount++] = file;
}
}
std::sort(sortedFilteredFiles.get(), sortedFilteredFiles.get() + filteredCount,
[filterSortParams] (const FileInfo*& a, const FileInfo*& b)
{
bool result = true;
if (CompareClassification(a, b, result))
return result;
auto sortType = filterSortParams.sortType;
auto sortDirection = filterSortParams.sortDirection;
if (a->GetFileType()->GetClassification() == FileTypeClassification::Folder &&
b->GetFileType()->GetClassification() == FileTypeClassification::Folder)
{
if (sortType != SdFolderSortType::Name)
{
sortType = SdFolderSortType::Name;
sortDirection = SdFolderSortDirection::Ascending;
}
}
switch (sortType)
{
case SdFolderSortType::Name:
default:
{
result = CompareName(a, b);
break;
}
}
return sortDirection == SdFolderSortDirection::Ascending ? result : !result;
});
resultCount = filteredCount;
return sortedFilteredFiles;
}
bool SdFolder::CompareClassification(const FileInfo* a, const FileInfo* b, bool& result)
{
auto aClassification = a->GetFileType()->GetClassification();
auto bClassification = b->GetFileType()->GetClassification();
if (aClassification == bClassification)
return false;
if (aClassification == FileTypeClassification::Folder)
{
result = true;
return true;
}
else if (bClassification == FileTypeClassification::Folder)
{
result = false;
return true;
}
return false;
}
bool SdFolder::CompareName(const FileInfo* a, const FileInfo* b)
{
return strcasecmp(a->GetFileName(), b->GetFileName()) < 0;
}
void SdFolder::SortByNameInPlace()
{
std::sort(_files, _files + _fileCount, CompareName);
}
const FileInfo* SdFolder::BinarySearch(const char* fileName) const
{
if (_fileCount != 0)
{
const auto file = std::lower_bound(_files, _files + _fileCount, fileName,
[] (const FileInfo* entry, const char* value)
{
return strcasecmp(entry->GetFileName(), value) < 0;
});
if (file != _files + _fileCount && !strcasecmp((*file)->GetFileName(), fileName))
{
return *file;
}
}
return nullptr;
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include <memory>
#include "FileInfo.h"
#include "SdFolderFilterSortParams.h"
/// @brief Class representing the contents of a folder on the sd card.
class SdFolder
{
FileInfo** _files;
int _fileCount;
static bool CompareClassification(const FileInfo* a, const FileInfo* b, bool& result);
static bool CompareName(const FileInfo* a, const FileInfo* b);
public:
/// @brief Creates an SdFolder from the given files. The ownership of both the array
/// and the FileInfo structs it points to will be taken over.
/// @param files The array of files.
/// @param fileCount The number of files in the array.
SdFolder(FileInfo** files, int fileCount);
/// @brief Destructs the folder, together with the FileInfo structs.
~SdFolder();
/// @brief Filters and sorts the files in this folder using the given filterSortParams.
/// @param filterSortParams The filter and sort parameters.
/// @param resultCount Will contain the number of results.
/// @return A unique pointer to an array of FileInfo pointers containing the results.
std::unique_ptr<const FileInfo*[]> FilterAndSort(
const SdFolderFilterSortParams& filterSortParams, int& resultCount) const;
void SortByNameInPlace();
const FileInfo* BinarySearch(const char* fileName) const;
/// @brief Gets a pointer to an array with all files in the folder.
/// @return A pointer to an array with all files in the folder.
const FileInfo* const* GetFiles() const { return _files; }
/// @brief Gets the total number of files in the folder.
/// @return The total number of files.
int GetFileCount() const { return _fileCount; }
};

View File

@@ -0,0 +1,39 @@
#include "common.h"
#include <vector>
#include "fat/Directory.h"
#include "FileInfo.h"
#include "FileType/Folder/FolderFileType.h"
#include "SdFolderFactory.h"
std::unique_ptr<SdFolder> SdFolderFactory::CreateFromPath(const char* path) const
{
Directory directory;
if (directory.Open(path) != FR_OK)
return nullptr;
int count = 0;
int bufferSize = 8;
auto fileInfos = (FileInfo**)malloc(sizeof(FileInfo*) * bufferSize);
auto sdFileInfo = std::make_unique<FILINFO>();
while (true)
{
if (directory.Read(sdFileInfo.get()) != FR_OK)
return nullptr;
if (sdFileInfo->fname[0] == 0)
break;
if (count >= bufferSize)
{
bufferSize *= 2;
fileInfos = (FileInfo**)realloc(fileInfos, sizeof(FileInfo*) * bufferSize);
}
auto fileType = sdFileInfo->fattrib & AM_DIR
? &FolderFileType::sInstance
: _fileTypeProvider->GetFileType(sdFileInfo->fname);
fileInfos[count++] = new FileInfo(sdFileInfo->fname, fileType,
FastFileRef(directory.GetFatFsDirectory(), sdFileInfo.get()));
}
return std::make_unique<SdFolder>(fileInfos, count);
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include <memory>
#include "SdFolder.h"
#include "FileType/IFileTypeProvider.h"
class SdFolderFactory
{
public:
SdFolderFactory(const IFileTypeProvider* fileTypeProvider)
: _fileTypeProvider(fileTypeProvider) { }
std::unique_ptr<SdFolder> CreateFromPath(const char* path) const;
private:
const IFileTypeProvider* _fileTypeProvider;
};

View File

@@ -0,0 +1,15 @@
#pragma once
#include "SdFolderSortType.h"
#include "SdFolderSortDirection.h"
class SdFolderFilterSortParams
{
public:
SdFolderSortType sortType = SdFolderSortType::Name;
SdFolderSortDirection sortDirection = SdFolderSortDirection::Ascending;
SdFolderFilterSortParams() { }
SdFolderFilterSortParams(SdFolderSortType sortType, SdFolderSortDirection sortDirection)
: sortType(sortType), sortDirection(sortDirection) { }
};

View File

@@ -0,0 +1,7 @@
#pragma once
enum class SdFolderSortDirection
{
Ascending,
Descending
};

View File

@@ -0,0 +1,7 @@
#pragma once
enum class SdFolderSortType
{
Name,
LastModified
};

View File

@@ -0,0 +1,70 @@
#pragma once
/// @brief Helper class for specifying state machine state transitions in an intuitive way.
/// @tparam TState The state enum type.
/// @tparam TTrigger The trigger enum type.
template <typename TState, typename TTrigger>
class StateMachineTriggerChecker
{
const TState _fromState;
const TTrigger _trigger;
bool _isValid;
TState _newState;
TState _from;
TTrigger _fromTrigger;
public:
/// @brief Constructs a StateMachineTriggerChecker for a state machine
/// that is currently in state fromState and received the given trigger.
/// @param fromState The current state of the state machine.
/// @param trigger The received trigger.
explicit constexpr StateMachineTriggerChecker(TState fromState, TTrigger trigger)
: _fromState(fromState), _trigger(trigger), _isValid(false), _newState(fromState) { }
/// @brief Specifies the start of a state transition. Multiple triggers can be
/// specified for a given from state.
/// @param from The start state of the following trigger definitions.
/// @return this
constexpr StateMachineTriggerChecker& In(TState from)
{
if (!_isValid)
_from = from;
return *this;
}
/// @brief Specifies the trigger for a state transition. Should be used
/// after In has been used at least once.
/// @param trigger The trigger of the state transition.
/// @return this
constexpr StateMachineTriggerChecker& Trigger(TTrigger trigger)
{
if (!_isValid)
_fromTrigger = trigger;
return *this;
}
/// @brief Specifies the end state for a state transition. Should be used
/// after every Trigger.
/// @param to The end state of the state transition.
/// @return this
constexpr StateMachineTriggerChecker& GoesTo(TState to)
{
if (!_isValid && _fromState == _from && _trigger == _fromTrigger)
{
_isValid = true;
_newState = to;
}
return *this;
}
/// @brief Ends the state transition definitions and returns
/// the check result.
/// @param newState The new state for the state machine.
/// @return true if the received trigger was valid for the
/// state of the state machine, or false otherwise.
constexpr bool Check(TState& newState) const
{
newState = _newState;
return _isValid;
}
};

View File

@@ -0,0 +1,40 @@
#pragma once
#include <memory>
#include "../views/IconGridItemView.h"
#include "../views/BannerListItemView.h"
#include "../views/AppBarView.h"
#include "../views/BannerView.h"
#include "gui/views/RecyclerViewBase.h"
class VramContext;
class VBlankTextureLoader;
class RomBrowserViewModel;
class IThemeFileIconFactory;
class FileRecyclerAdapter;
class IRomBrowserViewFactory
{
public:
virtual ~IRomBrowserViewFactory() = 0;
virtual IconGridItemView* CreateIconGridItemView() const = 0;
virtual IconGridItemView::VramToken UploadIconGridItemViewGraphics(
const VramContext& vramContext) const { return IconGridItemView::VramToken(0); }
virtual BannerListItemView* CreateBannerListItemView(VBlankTextureLoader* vblankTextureLoader) const = 0;
virtual BannerListItemView::VramToken UploadBannerListItemViewGraphics(
const VramContext& vramContext) const { return BannerListItemView::VramToken(0); }
virtual std::unique_ptr<AppBarView> CreateAppBarView(int x, int y, AppBarView::Orientation orientation,
int startButtonCount, int endButtonCount) const = 0;
virtual std::unique_ptr<BannerView> CreateFileInfoView() const = 0;
virtual std::unique_ptr<RecyclerViewBase> CreateCoverFlowRecyclerView() const = 0;
virtual FileRecyclerAdapter* CreateCoverFlowRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
VBlankTextureLoader* vblankTextureLoader) const = 0;
};
inline IRomBrowserViewFactory::~IRomBrowserViewFactory() { }

View File

@@ -0,0 +1,14 @@
#pragma once
class FileIcon;
class IThemeFileIconFactory
{
public:
virtual ~IThemeFileIconFactory() = 0;
virtual std::unique_ptr<FileIcon> CreateFolderIcon(const TCHAR* name) const = 0;
virtual std::unique_ptr<FileIcon> CreateGenericFileIcon(const TCHAR* name) const = 0;
virtual std::unique_ptr<FileIcon> CreateNdsFileIcon(const TCHAR* name) const = 0;
};
inline IThemeFileIconFactory::~IThemeFileIconFactory() { }

View File

@@ -0,0 +1,227 @@
#include "common.h"
#include <string.h>
#include <algorithm>
#include <libtwl/mem/memVram.h>
#include "gui/Gx.h"
#include "gui/GraphicsContext.h"
#include "gui/materialDesign.h"
#include "gui/VramContext.h"
#include "themes/material/MaterialColorScheme.h"
#include "romBrowser/FileType/FileCover.h"
#include "core/math/SinTable.h"
#include "carouselMask.h"
#include "CarouselRecyclerView.h"
#define COVER_SPACING 4
#define Y_OFFSET 56
#define CORNER_RADIUS 18
#define SELECTED_COVER_WIDTH COVER_WIDTH
#define SELECTED_COVER_X 46
#define NEXT_COVER_WIDTH 54
#define NEXT_COVER_X (SELECTED_COVER_X + SELECTED_COVER_WIDTH + COVER_SPACING)
#define SMALL_COVER_WIDTH 36
#define HORIZONTAL_PADDING 6
u32 CarouselRecyclerView::sMaskTextureVramOffset;
void CarouselRecyclerView::UploadGraphics(const VramContext& vramContext)
{
const auto textureVramManager = vramContext.GetTexVramManager();
if (textureVramManager)
{
sMaskTextureVramOffset = textureVramManager->Alloc(carouselMaskBitmapLen);
dma_ntrCopy32(3, carouselMaskBitmap, textureVramManager->GetVramAddress(sMaskTextureVramOffset), carouselMaskBitmapLen);
}
}
void CarouselRecyclerView::Update()
{
if (_itemCount == 0)
{
return;
}
int rangeStartIndex = GetSelectedItem() - 4;
int rangeEndIndex = GetSelectedItem() + 1 + 4;
rangeStartIndex = std::clamp(rangeStartIndex, 0, (int)_itemCount - 1);
rangeEndIndex = std::clamp(rangeEndIndex, 0, (int)_itemCount);
if (_curRangeStart != rangeStartIndex || _curRangeLength != rangeEndIndex - rangeStartIndex)
{
LOG_DEBUG("range: %d - %d\n", rangeStartIndex, rangeEndIndex - 1);
if (_curRangeLength != 0)
{
if (_curRangeStart < rangeStartIndex)
ReleaseRange(_curRangeStart, rangeStartIndex);
if (rangeEndIndex < _curRangeStart + _curRangeLength)
ReleaseRange(rangeEndIndex, _curRangeStart + _curRangeLength);
}
BindRange(rangeStartIndex, rangeEndIndex);
_curRangeStart = rangeStartIndex;
_curRangeLength = rangeEndIndex - rangeStartIndex;
}
for (u32 i = _viewPoolFreeCount; i < _viewPool.size(); i++)
{
_viewPoolEx[i].xPositionAnimator.Update();
_viewPoolEx[i].widthAnimator.Update();
_viewPool[i].view->Update();
}
}
void CarouselRecyclerView::Draw(GraphicsContext& graphicsContext)
{
for (u32 i = _viewPoolFreeCount; i < _viewPool.size(); i++)
{
fix32<12> x = (_viewPoolEx[i].xPositionAnimator.GetValue() + 0.5).Int();
fix32<12> width = (_viewPoolEx[i].widthAnimator.GetValue() + 0.5).Int();
fix32<12> left = x;
if (left < HORIZONTAL_PADDING)
{
left = HORIZONTAL_PADDING;
}
fix32<12> right = x + width;
if (right > (256 - HORIZONTAL_PADDING))
{
right = 256 - HORIZONTAL_PADDING;
}
if (left != right)
{
graphicsContext.SetPolygonId(i);
Gx::MtxIdentity();
Gx::MtxTranslate(0, 0, fix32<12>(-5 - std::abs(GetSelectedItem() - _viewPool[i].itemIdx)) / 64);
RenderCoverMask(graphicsContext, left, right);
// Render cover
_viewPool[i].view->SetPosition((x - ((COVER_WIDTH - width) / 2) + 0.5).Int(), Y_OFFSET);
_viewPool[i].view->Draw(graphicsContext);
RenderRoundedCorners(graphicsContext, x, width);
}
}
Gx::MtxIdentity();
}
void CarouselRecyclerView::RenderCoverMask(GraphicsContext& graphicsContext, fix32<12> left, fix32<12> right) const
{
Gx::PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGON_MODE_MODULATE, GX_DISPLAY_MODE_FRONT,
false, false, false, GX_DEPTH_FUNC_LESS, false, 31, 0);
Gx::TexImageParam((128 * 1024) >> 3, false, false, false, false, GX_TEXSIZE_8,
GX_TEXSIZE_8, GX_TEXFMT_PLTT16, false, GX_TEXGEN_NONE);
graphicsContext.GetRgb6Palette()->ApplyColor(Rgb<6, 6, 6>(_materialColorScheme->surfaceBright));
Gx::TexCoord(0, 0);
Gx::Begin(GX_PRIMITIVE_QUAD);
{
REG_GX_VTX_16 = GX_VTX_PACK((left / 64).GetRawValue(), Y_OFFSET << 3);
REG_GX_VTX_16 = 0;
REG_GX_VTX_XY = GX_VTX_PACK((left / 64).GetRawValue(), (Y_OFFSET + COVER_HEIGHT) << 3);
REG_GX_VTX_XY = GX_VTX_PACK((right / 64).GetRawValue(), (Y_OFFSET + COVER_HEIGHT) << 3);
REG_GX_VTX_XY = GX_VTX_PACK((right / 64).GetRawValue(), Y_OFFSET << 3);
}
Gx::End();
}
void CarouselRecyclerView::RenderRoundedCorners(GraphicsContext& graphicsContext, fix32<12> x, fix32<12> width) const
{
Gx::PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGON_MODE_MODULATE, GX_DISPLAY_MODE_FRONT,
false, false, false, GX_DEPTH_FUNC_EQUAL, false, 31, 0);
Gx::TexImageParam(sMaskTextureVramOffset >> 3, true, true, true, true, GX_TEXSIZE_32,
GX_TEXSIZE_32, GX_TEXFMT_A5I3, false, GX_TEXGEN_NONE);
graphicsContext.GetRgb6Palette()->ApplyColor(Rgb<6, 6, 6>(_materialColorScheme->inverseOnSurface));
Gx::Begin(GX_PRIMITIVE_QUAD);
// top-left
Gx::TexCoord(0, 0);
REG_GX_VTX_16 = GX_VTX_PACK((x / 64).GetRawValue(), Y_OFFSET << 3);
REG_GX_VTX_16 = 0;
Gx::TexCoord(0, CORNER_RADIUS);
REG_GX_VTX_XY = GX_VTX_PACK((x / 64).GetRawValue(), (Y_OFFSET + CORNER_RADIUS) << 3);
Gx::TexCoord(CORNER_RADIUS, CORNER_RADIUS);
REG_GX_VTX_XY = GX_VTX_PACK(((x + CORNER_RADIUS) / 64).GetRawValue(), (Y_OFFSET + CORNER_RADIUS) << 3);
Gx::TexCoord(CORNER_RADIUS, 0);
REG_GX_VTX_XY = GX_VTX_PACK(((x + CORNER_RADIUS) / 64).GetRawValue(), Y_OFFSET << 3);
// top-right
Gx::TexCoord(-CORNER_RADIUS, 0);
REG_GX_VTX_16 = GX_VTX_PACK(((x + width - CORNER_RADIUS) / 64).GetRawValue(), Y_OFFSET << 3);
REG_GX_VTX_16 = 0;
Gx::TexCoord(-CORNER_RADIUS, CORNER_RADIUS);
REG_GX_VTX_XY = GX_VTX_PACK(((x + width - CORNER_RADIUS) / 64).GetRawValue(), (Y_OFFSET + CORNER_RADIUS) << 3);
Gx::TexCoord(0, CORNER_RADIUS);
REG_GX_VTX_XY = GX_VTX_PACK(((x + width) / 64).GetRawValue(), (Y_OFFSET + CORNER_RADIUS) << 3);
Gx::TexCoord(0, 0);
REG_GX_VTX_XY = GX_VTX_PACK(((x + width) / 64).GetRawValue(), Y_OFFSET << 3);
// bottom-left
Gx::TexCoord(0, -CORNER_RADIUS);
REG_GX_VTX_16 = GX_VTX_PACK((x / 64).GetRawValue(), (Y_OFFSET + COVER_HEIGHT - CORNER_RADIUS) << 3);
REG_GX_VTX_16 = 0;
Gx::TexCoord(0, 0);
REG_GX_VTX_XY = GX_VTX_PACK((x / 64).GetRawValue(), (Y_OFFSET + COVER_HEIGHT) << 3);
Gx::TexCoord(CORNER_RADIUS, 0);
REG_GX_VTX_XY = GX_VTX_PACK(((x + CORNER_RADIUS) / 64).GetRawValue(), (Y_OFFSET + COVER_HEIGHT) << 3);
Gx::TexCoord(CORNER_RADIUS, -CORNER_RADIUS);
REG_GX_VTX_XY = GX_VTX_PACK(((x + CORNER_RADIUS) / 64).GetRawValue(), (Y_OFFSET + COVER_HEIGHT - CORNER_RADIUS) << 3);
// bottom-right
Gx::TexCoord(-CORNER_RADIUS, -CORNER_RADIUS);
REG_GX_VTX_16 = GX_VTX_PACK(((x + width - CORNER_RADIUS) / 64).GetRawValue(), (Y_OFFSET + COVER_HEIGHT - CORNER_RADIUS) << 3);
REG_GX_VTX_16 = 0;
Gx::TexCoord(-CORNER_RADIUS, 0);
REG_GX_VTX_XY = GX_VTX_PACK(((x + width - CORNER_RADIUS) / 64).GetRawValue(), (Y_OFFSET + COVER_HEIGHT) << 3);
Gx::TexCoord(0, 0);
REG_GX_VTX_XY = GX_VTX_PACK(((x + width) / 64).GetRawValue(), (Y_OFFSET + COVER_HEIGHT) << 3);
Gx::TexCoord(0, -CORNER_RADIUS);
REG_GX_VTX_XY = GX_VTX_PACK(((x + width) / 64).GetRawValue(), (Y_OFFSET + COVER_HEIGHT - CORNER_RADIUS) << 3);
Gx::End();
}
void CarouselRecyclerView::UpdateItemPosition(int viewPoolIndex, bool initial)
{
ViewPoolEntry* item = &_viewPool[viewPoolIndex];
ViewPoolEntryEx* itemEx = &_viewPoolEx[viewPoolIndex];
int selectedIndex = GetSelectedItem();
if (selectedIndex == -1)
{
selectedIndex = 0;
}
int itemIndex = item->itemIdx;
fix32<12> x;
fix32<12> width;
if (itemIndex < selectedIndex)
{
x = SELECTED_COVER_X + (SMALL_COVER_WIDTH + COVER_SPACING) * (itemIndex - selectedIndex);
width = SMALL_COVER_WIDTH;
}
else if (itemIndex == selectedIndex + 1)
{
x = NEXT_COVER_X;
width = NEXT_COVER_WIDTH;
}
else if (itemIndex > selectedIndex + 1)
{
x = NEXT_COVER_X + NEXT_COVER_WIDTH + COVER_SPACING
+ (SMALL_COVER_WIDTH + COVER_SPACING) * (itemIndex - selectedIndex - 2);
width = SMALL_COVER_WIDTH;
}
else
{
x = SELECTED_COVER_X;
width = SELECTED_COVER_WIDTH;
}
if (initial)
{
itemEx->xPositionAnimator = Animator(x);
itemEx->widthAnimator = Animator(width);
}
else
{
itemEx->xPositionAnimator.Goto(x, md::sys::motion::duration::medium4, &md::sys::motion::easing::standard);
itemEx->widthAnimator.Goto(width, md::sys::motion::duration::medium4, &md::sys::motion::easing::standard);
}
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include <array>
#include "romBrowser/views/CoverFlowRecyclerViewBase.h"
#include "animation/Animator.h"
class MaterialColorScheme;
class CarouselRecyclerView : public CoverFlowRecyclerViewBase
{
public:
explicit CarouselRecyclerView(const MaterialColorScheme* materialColorScheme)
: _materialColorScheme(materialColorScheme) { }
static void UploadGraphics(const VramContext& vramContext);
void Update() override;
void Draw(GraphicsContext &graphicsContext) override;
private:
struct ViewPoolEntryEx
{
Animator<fix32<12>> xPositionAnimator;
Animator<fix32<12>> widthAnimator;
};
std::array<ViewPoolEntryEx, 10> _viewPoolEx;
const MaterialColorScheme* _materialColorScheme;
static u32 sMaskTextureVramOffset;
void RenderCoverMask(GraphicsContext& graphicsContext, fix32<12> left, fix32<12> right) const;
void RenderRoundedCorners(GraphicsContext& graphicsContext, fix32<12> x, fix32<12> width) const;
void UpdateItemPosition(int viewPoolIndex, bool initial) override;
void SwapViewPoolEntry(int indexA, int indexB) override
{
CoverFlowRecyclerViewBase::SwapViewPoolEntry(indexA, indexB);
std::swap(_viewPoolEx[indexA], _viewPoolEx[indexB]);
}
};

View File

@@ -0,0 +1,32 @@
#include "common.h"
#include "gui/VramContext.h"
#include "romBrowser/views/IconButton2DView.h"
#include "MaterialAppBarView.h"
MaterialAppBarView::MaterialAppBarView(int x, int y, Orientation orientation,
int startButtonCount, int endButtonCount, const MaterialColorScheme* materialColorScheme)
: AppBarView(x, y, orientation, startButtonCount, endButtonCount, materialColorScheme)
{
for (int i = 0; i < _startButtonCount + _endButtonCount; i++)
{
_buttons[i] = new IconButton2DView(
IconButtonView::Type::Standard,
IconButtonView::State::NoToggle,
md::sys::color::inverseOnSurface,
materialColorScheme);
AddChildTail(_buttons[i]);
}
}
void MaterialAppBarView::InitVram(const VramContext& vramContext)
{
const auto objVramManager = vramContext.GetObjVramManager();
if (objVramManager)
{
auto iconButtonVramToken = IconButton2DView::UploadGraphics(*objVramManager);
for (int i = 0; i < _startButtonCount + _endButtonCount; i++)
{
static_cast<IconButton2DView*>(_buttons[i])->SetGraphics(iconButtonVramToken);
}
}
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "../../views/AppBarView.h"
class MaterialAppBarView : public AppBarView
{
public:
MaterialAppBarView(int x, int y, Orientation orientation,
int startButtonCount, int endButtonCount, const MaterialColorScheme* materialColorScheme);
void InitVram(const VramContext& vramContext) override;
};

View File

@@ -0,0 +1,147 @@
#include "common.h"
#include <libtwl/gfx/gfx.h>
#include "gui/PaletteManager.h"
#include "gui/OamManager.h"
#include "gui/OamBuilder.h"
#include "gui/IVramManager.h"
#include "gui/VramContext.h"
#include "gui/GraphicsContext.h"
#include "core/math/ColorConverter.h"
#include "core/math/RgbMixer.h"
#include "themes/material/MaterialColorScheme.h"
#include "themes/IFontRepository.h"
#include "bannerListItemBg0.h"
#include "bannerListItemBg1.h"
#include "bannerListItemBg2.h"
#include "gui/palette/GradientPalette.h"
#include "gui/palette/DirectPalette.h"
#include "gui/views/Label2DView.h"
#include "MaterialBannerListItemView.h"
MaterialBannerListItemView::MaterialBannerListItemView(const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository)
: BannerListItemView(
std::make_unique<Label2DView>(160, 16, 50, fontRepository->GetFont(FontType::Medium10)),
std::make_unique<Label2DView>(160, 16, 50, fontRepository->GetFont(FontType::Regular10)),
std::make_unique<Label2DView>(160, 16, 50, fontRepository->GetFont(FontType::Regular10)))
, _materialColorScheme(materialColorScheme) { }
void MaterialBannerListItemView::Draw(GraphicsContext& graphicsContext)
{
if (!graphicsContext.IsVisible(Rectangle(_position.x - 2, _position.y - 2, 207, 48)))
return;
auto backColor = _materialColorScheme->inverseOnSurface;
auto frontColor = _isFocused
? _materialColorScheme->mainIconBg
: _materialColorScheme->surfaceBright;
u16 bgPltt[16];
for (int i = 0; i < 16; i++)
{
auto blendFactors = ColorConverter::FromXBGR555(bannerListItemBg0Pal[i]);
auto palColor = Rgb<8, 8, 8>(
(backColor.r * blendFactors.r + frontColor.r * blendFactors.g + 16) / 31,
(backColor.g * blendFactors.r + frontColor.g * blendFactors.g + 16) / 31,
(backColor.b * blendFactors.r + frontColor.b * blendFactors.g + 16) / 31);
palColor = palColor.Clamped();
bgPltt[i] = ColorConverter::ToGBGR565(palColor);
}
u32 bgPaletteRow = graphicsContext.GetPaletteManager().AllocRow(
DirectPalette(bgPltt), _position.y - 2, _position.y - 2 + 48);
gfx_oam_entry_t* oam = graphicsContext.GetOamManager().AllocOams(4);
OamBuilder::OamWithSize<64, 64>(
_position.x - 2,
_position.y - 2, _bgVramOffset >> 7)
.WithPalette16(bgPaletteRow)
.WithPriority(graphicsContext.GetPriority())
.Build(oam[0]);
OamBuilder::OamWithSize<64, 64>(
_position.x - 2 + 64,
_position.y - 2, (_bgVramOffset + bannerListItemBg0TilesLen) >> 7)
.WithPalette16(bgPaletteRow)
.WithPriority(graphicsContext.GetPriority())
.Build(oam[1]);
OamBuilder::OamWithSize<64, 64>(
_position.x - 2 + 64 + 64,
_position.y - 2, (_bgVramOffset + bannerListItemBg0TilesLen) >> 7)
.WithPalette16(bgPaletteRow)
.WithPriority(graphicsContext.GetPriority())
.Build(oam[2]);
OamBuilder::OamWithSize<32, 64>(
_position.x - 2 + 64 + 64 + 64,
_position.y - 2, (_bgVramOffset + bannerListItemBg0TilesLen + bannerListItemBg1TilesLen) >> 7)
.WithPalette16(bgPaletteRow)
.WithPriority(graphicsContext.GetPriority())
.Build(oam[3]);
if (_isFocused)
{
_firstLine->SetBackgroundColor(frontColor);
_firstLine->SetForegroundColor(_materialColorScheme->onSecondaryContainer);
_secondLine->SetBackgroundColor(frontColor);
_secondLine->SetForegroundColor(_materialColorScheme->onSecondaryContainer);
_thirdLine->SetBackgroundColor(frontColor);
_thirdLine->SetForegroundColor(_materialColorScheme->onSecondaryContainer);
}
else
{
_firstLine->SetForegroundColor(_materialColorScheme->onSurface);
_firstLine->SetBackgroundColor(_materialColorScheme->surfaceBright);
_secondLine->SetForegroundColor(_materialColorScheme->onSurfaceVariant);
_secondLine->SetBackgroundColor(_materialColorScheme->surfaceBright);
_thirdLine->SetForegroundColor(_materialColorScheme->onSurfaceVariant);
_thirdLine->SetBackgroundColor(_materialColorScheme->surfaceBright);
}
if (_lines == 1)
{
_firstLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 14);
}
else if (_lines == 2)
{
_firstLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 8);
_secondLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 20);
}
else
{
_firstLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 2);
_secondLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 14);
_thirdLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 26);
}
if (_lines >= 1)
_firstLine->Draw(graphicsContext);
if (_lines >= 2)
_secondLine->Draw(graphicsContext);
if (_lines >= 3)
_thirdLine->Draw(graphicsContext);
if (_icon)
{
_icon->SetObjVramOffset(_iconVramOffset);
_icon->SetPosition(6 + _position.x, 6 + _position.y);
_icon->Draw(graphicsContext, frontColor);
}
}
BannerListItemView::VramToken MaterialBannerListItemView::UploadGraphics(const VramContext& vramContext)
{
const auto objVramManager = vramContext.GetObjVramManager();
u32 vramOffset = 0;
if (objVramManager)
{
vramOffset = objVramManager->Alloc(
bannerListItemBg0TilesLen + bannerListItemBg1TilesLen + bannerListItemBg2TilesLen);
dma_ntrCopy32(3, bannerListItemBg0Tiles,
objVramManager->GetVramAddress(vramOffset),
bannerListItemBg0TilesLen);
dma_ntrCopy32(3, bannerListItemBg1Tiles,
objVramManager->GetVramAddress(vramOffset + bannerListItemBg0TilesLen),
bannerListItemBg1TilesLen);
dma_ntrCopy32(3, bannerListItemBg2Tiles,
objVramManager->GetVramAddress(vramOffset + bannerListItemBg0TilesLen + bannerListItemBg1TilesLen),
bannerListItemBg2TilesLen);
}
return BannerListItemView::VramToken(vramOffset);
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include "gui/views/LabelView.h"
#include "../../views/BannerListItemView.h"
class MaterialColorScheme;
class IFontRepository;
class MaterialBannerListItemView : public BannerListItemView
{
public:
MaterialBannerListItemView(const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository);
void Draw(GraphicsContext& graphicsContext) override;
Rectangle GetBounds() const override
{
return Rectangle(_position, 203, 44);
}
void SetGraphics(const VramToken& vramToken) override
{
_bgVramOffset = vramToken.GetVramOffset();
}
static VramToken UploadGraphics(const VramContext& vramContext);
private:
const MaterialColorScheme* _materialColorScheme;
u32 _bgVramOffset;
};

View File

@@ -0,0 +1,54 @@
#include "common.h"
#include "romBrowser/FileInfoManager.h"
#include "core/task/TaskQueue.h"
#include "MaterialCoverView.h"
#include "romBrowser/Theme/IRomBrowserViewFactory.h"
#include "romBrowser/FileType/UnknownFileCover.h"
#include "romBrowser/ICoverRepository.h"
#include "MaterialCoverFlowFileRecyclerAdapter.h"
void MaterialCoverFlowFileRecyclerAdapter::GetViewSize(int& width, int& height) const
{
width = COVER_WIDTH;
height = COVER_HEIGHT;
}
View* MaterialCoverFlowFileRecyclerAdapter::CreateView() const
{
return new MaterialCoverView(_vblankTextureLoader);
}
void MaterialCoverFlowFileRecyclerAdapter::DestroyView(View* view) const
{
auto coverView = static_cast<MaterialCoverView*>(view);
delete coverView;
}
TaskResult<void> MaterialCoverFlowFileRecyclerAdapter::BindView(View* view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const
{
auto coverView = static_cast<MaterialCoverView*>(view);
auto cover = _fileInfoManager->GetFileCover(index);
if (cancelRequested)
{
_fileInfoManager->ReleaseFileInfo(index);
return TaskResult<void>::Canceled();
}
coverView->SetCover(std::move(cover));
coverView->UploadCoverGraphics();
if (cancelRequested)
{
coverView->ClearCover();
_fileInfoManager->ReleaseFileInfo(index);
return TaskResult<void>::Canceled();
}
return TaskResult<void>::Completed();
}
void MaterialCoverFlowFileRecyclerAdapter::ReleaseView(View* view, int index) const
{
LOG_DEBUG("Releasing %d\n", index);
auto coverView = static_cast<MaterialCoverView*>(view);
coverView->ClearCover();
_fileInfoManager->ReleaseFileInfo(index);
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include "romBrowser/FileRecyclerAdapter.h"
class IRomBrowserViewFactory;
class VBlankTextureLoader;
class ICoverRepository;
class MaterialCoverFlowFileRecyclerAdapter : public FileRecyclerAdapter
{
public:
MaterialCoverFlowFileRecyclerAdapter(FileInfoManager* fileInfoManager,
TaskQueueBase* taskQueue, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory,
VBlankTextureLoader* vblankTextureLoader,
const ICoverRepository* coverRepository)
: FileRecyclerAdapter(fileInfoManager, taskQueue, themeFileIconFactory)
, _romBrowserViewFactory(romBrowserViewFactory)
, _vblankTextureLoader(vblankTextureLoader)
, _coverRepository(coverRepository) { }
void GetViewSize(int& width, int& height) const override;
View* CreateView() const override;
void DestroyView(View* view) const override;
void ReleaseView(View* view, int index) const override;
private:
const IRomBrowserViewFactory* _romBrowserViewFactory;
VBlankTextureLoader* _vblankTextureLoader;
const ICoverRepository* _coverRepository;
TaskResult<void> BindView(View* view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override;
};

View File

@@ -0,0 +1,56 @@
#include "common.h"
#include "core/math/SinTable.h"
#include "gui/VramContext.h"
#include "gui/Gx.h"
#include "gui/materialDesign.h"
#include "gui/GraphicsContext.h"
#include "MaterialCoverView.h"
void MaterialCoverView::InitVram(const VramContext& vramContext)
{
const auto texVramManager = vramContext.GetTexVramManager();
const auto texPlttVramManager = vramContext.GetTexPlttVramManager();
if (texVramManager && texPlttVramManager)
{
_texVramOffset = texVramManager->Alloc(128 * 96);
_plttVramOffset = texPlttVramManager->Alloc(256 * 2);
}
}
void MaterialCoverView::Draw(GraphicsContext& graphicsContext)
{
if (_cover.IsValid() && _textureLoadRequest.GetState() == VBlankTextureLoadRequestState::LoadComplete)
{
Gx::TexImageParam(_texVramOffset >> 3, false, true, false, true, GX_TEXSIZE_128,
GX_TEXSIZE_128, GX_TEXFMT_PLTT256, false, GX_TEXGEN_NONE);
Gx::TexPlttBase(_plttVramOffset >> 4);
u32 polygonId = graphicsContext.GetPolygonId();
Gx::PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGON_MODE_MODULATE, GX_DISPLAY_MODE_FRONT,
false, false, false, GX_DEPTH_FUNC_EQUAL, false, 31, polygonId);
Gx::Color(31, 31, 31);
Gx::Begin(GX_PRIMITIVE_QUAD);
Gx::TexCoord(0, -COVER_HEIGHT);
REG_GX_VTX_16 = GX_VTX_PACK(_position.x << 6, _position.y << 3);
REG_GX_VTX_16 = 0;
Gx::TexCoord(0, 0);
REG_GX_VTX_XY = GX_VTX_PACK(_position.x << 6, (_position.y + COVER_HEIGHT) << 3);
Gx::TexCoord(COVER_WIDTH, 0);
REG_GX_VTX_XY = GX_VTX_PACK((_position.x + COVER_WIDTH) << 6, (_position.y + COVER_HEIGHT) << 3);
Gx::TexCoord(COVER_WIDTH, -COVER_HEIGHT);
REG_GX_VTX_XY = GX_VTX_PACK((_position.x + COVER_WIDTH) << 6, _position.y << 3);
Gx::End();
}
}
void MaterialCoverView::UploadCoverGraphics()
{
if (_cover.IsValid())
{
_cover->SetTexVramOffset(_texVramOffset, _plttVramOffset);
_vblankTextureLoader->CancelLoad(_textureLoadRequest);
_textureLoadRequest = _cover->CreateTextureLoadRequest();
_vblankTextureLoader->RequestLoad(_textureLoadRequest);
}
}

View File

@@ -0,0 +1,54 @@
#pragma once
#include <memory>
#include "core/SharedPtr.h"
#include "gui/views/View.h"
#include "romBrowser/FileType/FileCover.h"
#include "gui/VBlankTextureLoader.h"
class MaterialCoverView : public View
{
public:
explicit MaterialCoverView(VBlankTextureLoader* vblankTextureLoader)
: _vblankTextureLoader(vblankTextureLoader) { }
~MaterialCoverView() override
{
_vblankTextureLoader->CancelLoad(_textureLoadRequest);
}
void InitVram(const VramContext& vramContext) override;
void Draw(GraphicsContext& graphicsContext) override;
Rectangle GetBounds() const override
{
return Rectangle(_position.x - (COVER_WIDTH / 2), _position.y - (COVER_HEIGHT / 2), COVER_WIDTH, COVER_HEIGHT);
}
void SetCover(SharedPtr<FileCover> cover)
{
if (_cover.IsValid())
{
_vblankTextureLoader->CancelLoad(_textureLoadRequest);
}
_cover = std::move(cover);
}
void ClearCover()
{
if (_cover.IsValid())
{
_vblankTextureLoader->CancelLoad(_textureLoadRequest);
}
_cover.Reset();
}
void UploadCoverGraphics();
private:
VBlankTextureLoader* _vblankTextureLoader;
SharedPtr<FileCover> _cover;
VBlankTextureLoadRequest _textureLoadRequest;
u32 _texVramOffset = 0;
u32 _plttVramOffset = 0;
};

View File

@@ -0,0 +1,66 @@
#include "common.h"
#include "gui/GraphicsContext.h"
#include "gui/PaletteManager.h"
#include "gui/font/nitroFont2.h"
#include "core/math/RgbMixer.h"
#include "gui/OamBuilder.h"
#include "largeFolderIcon.h"
#include "gui/palette/GradientPalette.h"
#include "themes/IFontRepository.h"
#include "MaterialFileIcon.h"
MaterialFileIcon::MaterialFileIcon(const TCHAR* name, const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository)
: _materialColorScheme(materialColorScheme), _fontRepository(fontRepository)
{
int i;
for (i = 0; i < 3; i++)
{
TCHAR c = name[i];
if (c == 0)
break;
_displayName[i] = c;
}
_displayName[i] = 0;
}
void MaterialFileIcon::UploadGraphics(vu16* vram) const
{
dma_ntrCopy32(3, GetIconTiles(), vram, 32 * 32 / 2);
auto font = _fontRepository->GetFont(FontType::Medium11);
u8 tileBuffer[32 * 16 / 2];
memset(tileBuffer, 0, sizeof(tileBuffer));
u32 textWidth, textHeight;
nft2_measureString(font, _displayName, textWidth, textHeight);
nft2_string_render_params_t renderParams;
renderParams.x = ((int)32 - (int)textWidth) / 2;
renderParams.y = 0;
renderParams.width = 32;
renderParams.height = 16;
renderParams.a5i3 = false;
nft2_renderString(font, _displayName, tileBuffer, 32, &renderParams);
memcpy((u8*)vram + largeFolderIconTilesLen, tileBuffer, sizeof(tileBuffer));
}
void MaterialFileIcon::Draw(GraphicsContext& graphicsContext, const Rgb<8, 8, 8>& backgroundColor)
{
auto iconColor = GetIconColor();
auto nameColor = GetTextColor();
auto oams = graphicsContext.GetOamManager().AllocOams(2);
u32 iconPaletteRow = graphicsContext.GetPaletteManager().AllocRow(
GradientPalette(backgroundColor, iconColor), _position.y, _position.y + 32);
OamBuilder::OamWithSize<32, 32>(_position.x, _position.y, _vramOffset >> 7)
.WithPalette16(iconPaletteRow)
.WithPriority(graphicsContext.GetPriority())
.Build(oams[1]);
u32 namePaletteRow = graphicsContext.GetPaletteManager().AllocRow(
GradientPalette(iconColor, nameColor), _position.y, _position.y + 32);
OamBuilder::OamWithSize<32, 16>(_position.x, _position.y + GetTextYOffset(), (_vramOffset + largeFolderIconTilesLen) >> 7)
.WithPalette16(namePaletteRow)
.WithPriority(graphicsContext.GetPriority())
.Build(oams[0]);
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include "../../FileType/FileIcon.h"
#include "core/math/Rgb.h"
class MaterialColorScheme;
class IFontRepository;
class MaterialFileIcon : public FileIcon
{
public:
MaterialFileIcon(const TCHAR* name, const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository);
void UploadGraphics(vu16* vram) const override;
void Draw(GraphicsContext& graphicsContext, const Rgb<8, 8, 8>& backgroundColor) override;
protected:
const MaterialColorScheme* _materialColorScheme;
const IFontRepository* _fontRepository;
virtual const void* GetIconTiles() const = 0;
virtual Rgb<8, 8, 8> GetIconColor() const = 0;
virtual Rgb<8, 8, 8> GetTextColor() const = 0;
virtual int GetTextYOffset() const = 0;
private:
char16_t _displayName[4];
};

View File

@@ -0,0 +1,84 @@
#include "common.h"
#include "gui/GraphicsContext.h"
#include "gui/OamBuilder.h"
#include "gui/IVramManager.h"
#include "gui/VramContext.h"
#include "core/math/RgbMixer.h"
#include "core/math/ColorConverter.h"
#include "iconCell.h"
#include "gui/palette/GradientPalette.h"
#include "themes/material/MaterialColorScheme.h"
#include "themes/IFontRepository.h"
#include "MaterialFileInfoCardView.h"
MaterialFileInfoCardView::MaterialFileInfoCardView(const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository)
: _firstLine(176, 16, 50, fontRepository->GetFont(FontType::Medium11))
, _secondLine(176, 16, 50, fontRepository->GetFont(FontType::Regular10))
, _thirdLine(176, 16, 50, fontRepository->GetFont(FontType::Regular10))
, _filenameLabelView(220, 16, 200, fontRepository->GetFont(FontType::Medium7_5))
, _materialColorScheme(materialColorScheme)
{
AddChildTail(&_firstLine);
AddChildTail(&_secondLine);
AddChildTail(&_thirdLine);
_filenameLabelView.SetEllipsis(true);
AddChildTail(&_filenameLabelView);
}
void MaterialFileInfoCardView::InitVram(const VramContext& vramContext)
{
BannerView::InitVram(vramContext);
const auto objVramManager = vramContext.GetObjVramManager();
if (objVramManager)
{
_iconCellVramOffset = objVramManager->Alloc(iconCellTilesLen);
dma_ntrCopy32(3, iconCellTiles, objVramManager->GetVramAddress(_iconCellVramOffset), iconCellTilesLen);
}
}
void MaterialFileInfoCardView::Update()
{
BannerView::Update();
_firstLine.SetPosition(_position.x + 70, _position.y + 130 - 8);
_secondLine.SetPosition(_position.x + 70, _position.y + 145 - 8);
_thirdLine.SetPosition(_position.x + 70, _position.y + 159 - 8);
_filenameLabelView.SetPosition(_position.x + 18, _position.y + 168);
if (_icon)
{
_icon->SetPosition(_position.x + 24, _position.y + 136 - 8);
_icon->Update();
}
}
void MaterialFileInfoCardView::Draw(GraphicsContext& graphicsContext)
{
_firstLine.SetBackgroundColor(_materialColorScheme->secondaryContainer);
_firstLine.SetForegroundColor(_materialColorScheme->onSecondaryContainer);
_secondLine.SetBackgroundColor(_materialColorScheme->secondaryContainer);
_secondLine.SetForegroundColor(_materialColorScheme->onSecondaryContainer);
_thirdLine.SetBackgroundColor(_materialColorScheme->secondaryContainer);
_thirdLine.SetForegroundColor(_materialColorScheme->onSecondaryContainer);
_filenameLabelView.SetBackgroundColor(_materialColorScheme->secondaryContainer);
_filenameLabelView.SetForegroundColor(_materialColorScheme->onSurfaceVariant);
BannerView::Draw(graphicsContext);
const auto& bgColor = _materialColorScheme->secondaryContainer;
const auto& fgColor = _materialColorScheme->mainIconBg;
u32 iconCellPlttRow = graphicsContext.GetPaletteManager().AllocRow(
GradientPalette(bgColor, fgColor));
gfx_oam_entry_t* oam = graphicsContext.GetOamManager().AllocOams(1);
OamBuilder::OamWithSize<64, 64>(_position.x + 18, _position.y + 130 - 8, _iconCellVramOffset >> 7)
.WithPalette16(iconCellPlttRow)
.WithPriority(3)
.Build(oam[0]);
if (_icon)
{
_icon->SetObjVramOffset(_iconVramOffset);
_icon->Draw(graphicsContext, fgColor);
}
}

View File

@@ -0,0 +1,75 @@
#pragma once
#include "core/task/TaskQueue.h"
#include "gui/views/Label2DView.h"
#include "../../views/BannerView.h"
class FileIcon;
class MaterialColorScheme;
class IFontRepository;
class MaterialFileInfoCardView : public BannerView
{
public:
MaterialFileInfoCardView(const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository);
void InitVram(const VramContext& vramContext) override;
void Update() override;
void Draw(GraphicsContext& graphicsContext) override;
void SetFirstLineAsync(TaskQueueBase* taskQueue, const char* firstLine, bool ellipsis) override
{
_firstLine.SetEllipsis(ellipsis);
if (taskQueue)
_firstLine.SetTextAsync(taskQueue, firstLine);
else
_firstLine.SetText(firstLine);
}
void SetFirstLineAsync(TaskQueueBase* taskQueue, const char16_t* firstLine, u32 length, bool ellipsis) override
{
_firstLine.SetEllipsis(ellipsis);
if (taskQueue)
_firstLine.SetTextAsync(taskQueue, firstLine, length);
else
_firstLine.SetText(firstLine, length);
}
void SetSecondLineAsync(TaskQueueBase* taskQueue, const char16_t* secondLine, u32 length) override
{
if (taskQueue)
_secondLine.SetTextAsync(taskQueue, secondLine, length);
else
_secondLine.SetText(secondLine, length);
}
void SetThirdLineAsync(TaskQueueBase* taskQueue, const char16_t* thirdLine, u32 length) override
{
if (taskQueue)
_thirdLine.SetTextAsync(taskQueue, thirdLine, length);
else
_thirdLine.SetText(thirdLine, length);
}
void SetFileNameAsync(TaskQueueBase* taskQueue, const TCHAR* fileName, bool useAsTitle) override
{
BannerView::SetFileNameAsync(taskQueue, fileName, useAsTitle);
if (taskQueue)
_filenameLabelView.SetTextAsync(taskQueue, fileName);
else
_filenameLabelView.SetText(fileName);
}
Rectangle GetBounds() const override
{
return Rectangle(_position, 236, 60);
}
private:
Label2DView _firstLine;
Label2DView _secondLine;
Label2DView _thirdLine;
Label2DView _filenameLabelView;
u32 _iconCellVramOffset;
const MaterialColorScheme* _materialColorScheme;
};

View File

@@ -0,0 +1,30 @@
#pragma once
#include "MaterialFileIcon.h"
#include "largeFolderIcon.h"
#include "themes/material/MaterialColorScheme.h"
class MaterialFolderIcon : public MaterialFileIcon
{
public:
MaterialFolderIcon(const TCHAR* name, const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository)
: MaterialFileIcon(name, materialColorScheme, fontRepository) { }
protected:
const void* GetIconTiles() const override
{
return largeFolderIconTiles;
}
Rgb<8, 8, 8> GetIconColor() const override
{
return _materialColorScheme->tertiaryContainer;
}
Rgb<8, 8, 8> GetTextColor() const override
{
return _materialColorScheme->onTertiaryContainer;
}
int GetTextYOffset() const override { return 10; }
};

View File

@@ -0,0 +1,30 @@
#pragma once
#include "MaterialFileIcon.h"
#include "largeFileIcon.h"
#include "themes/material/MaterialColorScheme.h"
class MaterialGenericFileIcon : public MaterialFileIcon
{
public:
MaterialGenericFileIcon(const TCHAR* name, const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository)
: MaterialFileIcon(name, materialColorScheme, fontRepository) { }
protected:
const void* GetIconTiles() const override
{
return largeFileIconTiles;
}
Rgb<8, 8, 8> GetIconColor() const override
{
return _materialColorScheme->tertiary;
}
Rgb<8, 8, 8> GetTextColor() const override
{
return _materialColorScheme->onTertiary;
}
int GetTextYOffset() const override { return 8; }
};

View File

@@ -0,0 +1,67 @@
#include "common.h"
#include <libtwl/gfx/gfx.h>
#include "gui/PaletteManager.h"
#include "gui/OamManager.h"
#include "gui/OamBuilder.h"
#include "gui/IVramManager.h"
#include "gui/VramContext.h"
#include "gui/GraphicsContext.h"
#include "iconCell2.h"
#include "iconCell3.h"
#include "core/math/ColorConverter.h"
#include "core/math/RgbMixer.h"
#include "themes/material/MaterialColorScheme.h"
#include "gui/palette/DirectPalette.h"
#include "MaterialIconGridItemView.h"
void MaterialIconGridItemView::Draw(GraphicsContext& graphicsContext)
{
if (!graphicsContext.IsVisible(Rectangle(_position.x - 2, _position.y - 2, 48, 48)))
return;
auto backColor = _materialColorScheme->inverseOnSurface;
auto frontColor = _isFocused
? _materialColorScheme->mainIconBg
: _materialColorScheme->surfaceBright;
u16 selectedIconCellPltt[16];
for (int i = 0; i < 16; i++)
{
auto blendFactors = ColorConverter::FromXBGR555(iconCell3Pal[i]);
auto palColor = Rgb<8, 8, 8>(
(backColor.r * blendFactors.r + frontColor.r * blendFactors.g + 16) / 31,
(backColor.g * blendFactors.r + frontColor.g * blendFactors.g + 16) / 31,
(backColor.b * blendFactors.r + frontColor.b * blendFactors.g + 16) / 31);
palColor = palColor.Clamped();
selectedIconCellPltt[i] = ColorConverter::ToGBGR565(palColor);
}
u32 cellPaletteRow = graphicsContext.GetPaletteManager().AllocRow(
DirectPalette(selectedIconCellPltt), _position.y - 2, _position.y - 2 + 48);
gfx_oam_entry_t* oam = graphicsContext.GetOamManager().AllocOams(1);
OamBuilder::OamWithSize<64, 64>(
_position.x - 2,
_position.y - 2, _bgVramOffset >> 7)
.WithPalette16(cellPaletteRow)
.WithPriority(graphicsContext.GetPriority())
.Build(oam[0]);
if (_icon)
{
_icon->SetObjVramOffset(_iconVramOffset);
_icon->SetPosition(6 + _position.x, 6 + _position.y);
_icon->Draw(graphicsContext, frontColor);
}
}
MaterialIconGridItemView::VramToken MaterialIconGridItemView::UploadGraphics(const VramContext& vramContext)
{
const auto objVramManager = vramContext.GetObjVramManager();
u32 vramOffset = 0;
if (objVramManager)
{
vramOffset = objVramManager->Alloc(iconCell3TilesLen);
dma_ntrCopy32(3, iconCell3Tiles, objVramManager->GetVramAddress(vramOffset), iconCell3TilesLen);
}
return MaterialIconGridItemView::VramToken(vramOffset);
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include "../../views/IconGridItemView.h"
class MaterialColorScheme;
class MaterialIconGridItemView : public IconGridItemView
{
public:
explicit MaterialIconGridItemView(const MaterialColorScheme* materialColorScheme)
: _materialColorScheme(materialColorScheme) { }
void Draw(GraphicsContext& graphicsContext) override;
Rectangle GetBounds() const override
{
return Rectangle(_position, 44, 44);
}
void SetGraphics(const VramToken& vramToken) override
{
_bgVramOffset = vramToken.GetVramOffset();
}
static VramToken UploadGraphics(const VramContext& vramContext);
private:
const MaterialColorScheme* _materialColorScheme;
u32 _bgVramOffset;
};

View File

@@ -0,0 +1,30 @@
#pragma once
#include "MaterialFileIcon.h"
#include "largeDSCardIcon.h"
#include "themes/material/MaterialColorScheme.h"
class MaterialNdsFileIcon : public MaterialFileIcon
{
public:
MaterialNdsFileIcon(const TCHAR* name, const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository)
: MaterialFileIcon(name, materialColorScheme, fontRepository) { }
protected:
const void* GetIconTiles() const override
{
return largeDSCardIconTiles;
}
Rgb<8, 8, 8> GetIconColor() const override
{
return _materialColorScheme->tertiary;
}
Rgb<8, 8, 8> GetTextColor() const override
{
return _materialColorScheme->onTertiary;
}
int GetTextYOffset() const override { return 3; }
};

View File

@@ -0,0 +1,71 @@
#pragma once
#include "MaterialIconGridItemView.h"
#include "MaterialBannerListItemView.h"
#include "MaterialFileInfoCardView.h"
#include "../IRomBrowserViewFactory.h"
#include "romBrowser/viewModels/RomBrowserViewModel.h"
#include "CarouselRecyclerView.h"
#include "MaterialCoverFlowFileRecyclerAdapter.h"
#include "MaterialAppBarView.h"
class MaterialColorScheme;
class IFontRepository;
class MaterialRomBrowserViewFactory : public IRomBrowserViewFactory
{
public:
MaterialRomBrowserViewFactory(const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository)
: _materialColorScheme(materialColorScheme), _fontRepository(fontRepository) { }
IconGridItemView* CreateIconGridItemView() const override
{
return new MaterialIconGridItemView(_materialColorScheme);
}
IconGridItemView::VramToken UploadIconGridItemViewGraphics(
const VramContext& vramContext) const override
{
return MaterialIconGridItemView::UploadGraphics(vramContext);
}
BannerListItemView* CreateBannerListItemView(VBlankTextureLoader* vblankTextureLoader) const override
{
return new MaterialBannerListItemView(_materialColorScheme, _fontRepository);
}
BannerListItemView::VramToken UploadBannerListItemViewGraphics(
const VramContext& vramContext) const override
{
return MaterialBannerListItemView::UploadGraphics(vramContext);
}
std::unique_ptr<AppBarView> CreateAppBarView(int x, int y, AppBarView::Orientation orientation,
int startButtonCount, int endButtonCount) const override
{
return std::make_unique<MaterialAppBarView>(x, y, orientation, startButtonCount, endButtonCount, _materialColorScheme);
}
std::unique_ptr<BannerView> CreateFileInfoView() const override
{
return std::make_unique<MaterialFileInfoCardView>(_materialColorScheme, _fontRepository);
}
std::unique_ptr<RecyclerViewBase> CreateCoverFlowRecyclerView() const override
{
return std::make_unique<CarouselRecyclerView>(_materialColorScheme);
}
FileRecyclerAdapter* CreateCoverFlowRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
VBlankTextureLoader* vblankTextureLoader) const override
{
return new MaterialCoverFlowFileRecyclerAdapter(
&viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(),
themeFileIconFactory, this, vblankTextureLoader, &viewModel->GetCoverRepository());
}
private:
const MaterialColorScheme* _materialColorScheme;
const IFontRepository* _fontRepository;
};

View File

@@ -0,0 +1,35 @@
#pragma once
#include "../IThemeFileIconFactory.h"
#include "MaterialFolderIcon.h"
#include "MaterialGenericFileIcon.h"
#include "MaterialNdsFileIcon.h"
class MaterialColorScheme;
class IFontRepository;
class MaterialThemeFileIconFactory : public IThemeFileIconFactory
{
public:
explicit MaterialThemeFileIconFactory(const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository)
: _materialColorScheme(materialColorScheme), _fontRepository(fontRepository) { }
std::unique_ptr<FileIcon> CreateFolderIcon(const TCHAR* name) const override
{
return std::make_unique<MaterialFolderIcon>(name, _materialColorScheme, _fontRepository);
}
std::unique_ptr<FileIcon> CreateGenericFileIcon(const TCHAR* name) const override
{
return std::make_unique<MaterialGenericFileIcon>(name, _materialColorScheme, _fontRepository);
}
std::unique_ptr<FileIcon> CreateNdsFileIcon(const TCHAR* name) const override
{
return std::make_unique<MaterialNdsFileIcon>(name, _materialColorScheme, _fontRepository);
}
private:
const MaterialColorScheme* _materialColorScheme;
const IFontRepository* _fontRepository;
};

View File

@@ -0,0 +1,60 @@
#include "common.h"
#include "gui/Gx.h"
#include "gui/VramContext.h"
#include "romBrowser/views/IconButton3DView.h"
#include "CustomAppBarView.h"
#define BLOCK_VTX_PACK(x, y, z) (((x)&0x3FF) | ((((y) >> 3) & 0x3FF) << 10) | ((z) << 20))
CustomAppBarView::CustomAppBarView(int x, int y, Orientation orientation,
int startButtonCount, int endButtonCount, const MaterialColorScheme* materialColorScheme,
u32 scrimTexVramOffset, u32 scrimPlttVramOffset)
: AppBarView(x, y, orientation, startButtonCount, endButtonCount, materialColorScheme)
, _scrimTexVramOffset(scrimTexVramOffset), _scrimPlttVramOffset(scrimPlttVramOffset)
{
for (int i = 0; i < _startButtonCount + _endButtonCount; i++)
{
_buttons[i] = new IconButton3DView(
IconButtonView::Type::Tonal,
IconButtonView::State::NoToggle,
md::sys::color::inverseOnSurface,
materialColorScheme);
AddChildTail(_buttons[i]);
}
}
void CustomAppBarView::Draw(GraphicsContext& graphicsContext)
{
Gx::MtxIdentity();
Gx::PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGON_MODE_MODULATE, GX_DISPLAY_MODE_FRONT,
false, false, false, GX_DEPTH_FUNC_LESS, false, 31, 63);
Gx::Color(0);
Gx::TexImageParam(_scrimTexVramOffset >> 3, true, false, false, false, GX_TEXSIZE_8,
GX_TEXSIZE_64, GX_TEXFMT_A5I3, false, GX_TEXGEN_NONE);
Gx::TexPlttBase(_scrimPlttVramOffset >> 4);
Gx::Begin(GX_PRIMITIVE_QUAD);
if (GetOrientation() == Orientation::Horizontal)
{
Gx::TexCoord(0, 0);
Gx::Vtx16(0, 0, -1.0 / 64);
Gx::TexCoord(0, 42);
Gx::Vtx16(0, 42.0 / 512.0, -1.0 / 64);
Gx::TexCoord(256, 42);
Gx::Vtx16(256.0 / 64, 42.0 / 512.0, -1.0 / 64);
Gx::TexCoord(256, 0);
Gx::Vtx16(256.0 / 64, 0, -1.0 / 64);
}
else
{
Gx::TexCoord(0, 0);
Gx::Vtx16(0, 192.0 / 512, -1.0 / 64);
Gx::TexCoord(0, 42);
Gx::Vtx16(42.0 / 64, 192.0 / 512, -1.0 / 64);
Gx::TexCoord(192, 42);
Gx::Vtx16(42.0 / 64, 0, -1.0 / 64);
Gx::TexCoord(192, 0);
Gx::Vtx16(0, 0, -1.0 / 64);
Gx::End();
}
AppBarView::Draw(graphicsContext);
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include "../../views/AppBarView.h"
class CustomAppBarView : public AppBarView
{
public:
CustomAppBarView(int x, int y, Orientation orientation,
int startButtonCount, int endButtonCount, const MaterialColorScheme* materialColorScheme,
u32 scrimTexVramOffset, u32 scrimPlttVramOffset);
void Draw(GraphicsContext& graphicsContext) override;
private:
u32 _scrimTexVramOffset = 0;
u32 _scrimPlttVramOffset = 0;
};

View File

@@ -0,0 +1,124 @@
#include "common.h"
#include <libtwl/gfx/gfx.h>
#include "core/math/Rgb.h"
#include "gui/PaletteManager.h"
#include "gui/OamManager.h"
#include "gui/Gx.h"
#include "gui/OamBuilder.h"
#include "gui/IVramManager.h"
#include "gui/VramContext.h"
#include "gui/GraphicsContext.h"
#include "core/math/ColorConverter.h"
#include "core/math/RgbMixer.h"
#include "themes/material/MaterialColorScheme.h"
#include "themes/IFontRepository.h"
#include "bannerListItemBg0.h"
#include "bannerListItemBg1.h"
#include "bannerListItemBg2.h"
#include "gui/palette/GradientPalette.h"
#include "gui/palette/DirectPalette.h"
#include "gui/views/Label3DView.h"
#include "CustomBannerListItemView.h"
#define X_OFFSET (-3)
#define Y_OFFSET (-2)
#define Z_OFFSET 300
#define WIDTH 209
#define HEIGHT 49
#define LINE_WIDTH 160
#define LINE_HEIGHT 16
#define MAX_LINE_STRING_LENGTH 50
CustomBannerListItemView::CustomBannerListItemView(const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository, u32 texVramOffset, u32 plttVramOffset,
u32 selectedTexVramOffset, u32 selectedPlttVramOffset, VBlankTextureLoader* vblankTextureLoader)
: BannerListItemView(
std::make_unique<Label3DView>(LINE_WIDTH, LINE_HEIGHT, MAX_LINE_STRING_LENGTH,
fontRepository->GetFont(FontType::Medium10), vblankTextureLoader),
std::make_unique<Label3DView>(LINE_WIDTH, LINE_HEIGHT, MAX_LINE_STRING_LENGTH,
fontRepository->GetFont(FontType::Regular10), vblankTextureLoader),
std::make_unique<Label3DView>(LINE_WIDTH, LINE_HEIGHT, MAX_LINE_STRING_LENGTH,
fontRepository->GetFont(FontType::Regular10), vblankTextureLoader))
, _materialColorScheme(materialColorScheme)
, _texVramOffset(texVramOffset)
, _plttVramOffset(plttVramOffset)
, _selectedTexVramOffset(selectedTexVramOffset)
, _selectedPlttVramOffset(selectedPlttVramOffset) { }
void CustomBannerListItemView::Draw(GraphicsContext& graphicsContext)
{
if (!graphicsContext.IsVisible(Rectangle(_position.x + X_OFFSET, _position.y + Y_OFFSET, WIDTH, HEIGHT)))
{
return;
}
auto backgroundColor = Rgb<8, 8, 8>(200, 200, 200);
Gx::MtxIdentity();
Gx::PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGON_MODE_MODULATE, GX_DISPLAY_MODE_FRONT,
false, false, false, GX_DEPTH_FUNC_LESS, false, 31, 0);
Gx::Color(0x7FFF);
u32 tex = _isFocused ? _selectedTexVramOffset : _texVramOffset;
u32 pltt = _isFocused ? _selectedPlttVramOffset : _plttVramOffset;
Gx::TexImageParam(tex >> 3, false, false, false, false, GX_TEXSIZE_256,
GX_TEXSIZE_64, GX_TEXFMT_A3I5, false, GX_TEXGEN_NONE);
Gx::TexPlttBase(pltt >> 4);
Gx::Begin(GX_PRIMITIVE_QUAD);
Gx::TexCoord(0, 0);
REG_GX_VTX_16 = GX_VTX_PACK((_position.x + X_OFFSET) << 6, (_position.y + Y_OFFSET) << 3);
REG_GX_VTX_16 = (Z_OFFSET) << 6;
Gx::TexCoord(0, HEIGHT);
REG_GX_VTX_16 = GX_VTX_PACK((_position.x + X_OFFSET) << 6, (_position.y + Y_OFFSET + HEIGHT) << 3);
REG_GX_VTX_16 = (Z_OFFSET) << 6;
Gx::TexCoord(WIDTH, HEIGHT);
REG_GX_VTX_16 = GX_VTX_PACK((_position.x + X_OFFSET + WIDTH) << 6, (_position.y + Y_OFFSET + HEIGHT) << 3);
REG_GX_VTX_16 = (Z_OFFSET) << 6;
Gx::TexCoord(WIDTH, 0);
REG_GX_VTX_16 = GX_VTX_PACK((_position.x + X_OFFSET + WIDTH) << 6, (_position.y + Y_OFFSET) << 3);
REG_GX_VTX_16 = (Z_OFFSET) << 6;
Gx::End();
graphicsContext.SetPolygonId(1);
_firstLine->SetForegroundColor(Rgb<8, 8, 8>(30, 30, 30));
_secondLine->SetForegroundColor(Rgb<8, 8, 8>(30, 30, 30));
_thirdLine->SetForegroundColor(Rgb<8, 8, 8>(30, 30, 30));
if (_lines == 1)
{
_firstLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 14);
}
else if (_lines == 2)
{
_firstLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 8);
_secondLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 20);
}
else
{
_firstLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 2);
_secondLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 14);
_thirdLine->SetPosition(_position.x + 6 + 32 + 6, _position.y + 26);
}
if (_lines >= 1)
{
_firstLine->Draw(graphicsContext);
}
if (_lines >= 2)
{
_secondLine->Draw(graphicsContext);
}
if (_lines >= 3)
{
_thirdLine->Draw(graphicsContext);
}
if (_icon)
{
_icon->SetObjVramOffset(_iconVramOffset);
_icon->SetPosition(6 + _position.x, 6 + _position.y);
_icon->Draw(graphicsContext, backgroundColor);
}
}

Some files were not shown because too many files have changed in this diff Show More