mirror of
https://github.com/wiiu-env/launchiine.git
synced 2024-11-25 19:17:00 +01:00
- Actually displaying installed title now
- Try to clean up the async stuff when the vector gets bigger
This commit is contained in:
parent
4c4fbcfb2e
commit
d97d5ed325
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
|||||||
*.rpx
|
*.rpx
|
||||||
build/
|
build/
|
||||||
src/resources/filelist.h
|
src/resources/filelist.h
|
||||||
|
*.save-failed
|
||||||
|
1
Makefile
1
Makefile
@ -21,6 +21,7 @@ TARGET := $(notdir $(CURDIR))
|
|||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := src \
|
SOURCES := src \
|
||||||
src/fs \
|
src/fs \
|
||||||
|
src/game \
|
||||||
src/gui \
|
src/gui \
|
||||||
src/menu \
|
src/menu \
|
||||||
src/resources \
|
src/resources \
|
||||||
|
BIN
data/images/noGameIcon.png
Normal file
BIN
data/images/noGameIcon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.1 KiB |
@ -6,6 +6,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LAUNCHIINE_VERSION "v0.1"
|
#define LAUNCHIINE_VERSION "v0.1"
|
||||||
|
#define META_PATH "/meta"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
202
src/game/GameList.cpp
Normal file
202
src/game/GameList.cpp
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#include <string.h>
|
||||||
|
#include <coreinit/mcp.h>
|
||||||
|
#include <nn/acp/nn_acp_types.h>
|
||||||
|
#include <coreinit/cache.h>
|
||||||
|
|
||||||
|
#include "utils/AsyncExecutor.h"
|
||||||
|
#include "GameList.h"
|
||||||
|
#include "common/common.h"
|
||||||
|
|
||||||
|
#include "fs/DirList.h"
|
||||||
|
#include "fs/FSUtils.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "utils/StringTools.h"
|
||||||
|
|
||||||
|
void GameList::clear() {
|
||||||
|
for (auto const& x : fullGameList) {
|
||||||
|
if(x != NULL) {
|
||||||
|
if(x->imageData != NULL) {
|
||||||
|
DEBUG_FUNCTION_LINE("Delete the image data\n");
|
||||||
|
delete x->imageData;
|
||||||
|
x->imageData = NULL;
|
||||||
|
}
|
||||||
|
delete x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gameFilter.clear();
|
||||||
|
fullGameList.clear();
|
||||||
|
filteredList.clear();
|
||||||
|
//! Clear memory of the vector completely
|
||||||
|
std::vector<gameInfo *>().swap(filteredList);
|
||||||
|
std::vector<gameInfo*>().swap(fullGameList);
|
||||||
|
titleListChanged(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gameInfo * GameList::getGameInfo(uint64_t titleId) const {
|
||||||
|
for (uint32_t i = 0; i < filteredList.size(); ++i) {
|
||||||
|
if(titleId == filteredList[i]->titleId)
|
||||||
|
return filteredList[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int ACPGetTitleMetaXml(uint64_t titleid, ACPMetaXml*);
|
||||||
|
int32_t GameList::readGameList() {
|
||||||
|
// Clear list
|
||||||
|
for (auto const& x : fullGameList) {
|
||||||
|
delete x;
|
||||||
|
}
|
||||||
|
|
||||||
|
fullGameList.clear();
|
||||||
|
//! Clear memory of the vector completely
|
||||||
|
std::vector<gameInfo*>().swap(fullGameList);
|
||||||
|
|
||||||
|
int32_t cnt = 0;
|
||||||
|
|
||||||
|
MCPError mcp = MCP_Open();
|
||||||
|
if (mcp < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCPError titleCount = MCP_TitleCount(mcp);
|
||||||
|
if (titleCount < 0) {
|
||||||
|
MCP_Close(mcp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<struct MCPTitleListType> titles(titleCount);
|
||||||
|
uint32_t realTitleCount;
|
||||||
|
|
||||||
|
MCPError err = MCP_TitleList(mcp, &realTitleCount, titles.data(), titles.size() * sizeof(decltype(titles)::value_type));
|
||||||
|
if (err < 0) {
|
||||||
|
MCP_Close(mcp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (realTitleCount != titles.size()) {
|
||||||
|
titles.resize(realTitleCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto title_candidate : titles) {
|
||||||
|
if(true || (title_candidate.titleId & 0xFFFFFFFF00000000L) == 0x0005000000000000L) {
|
||||||
|
gameInfo* newGameInfo = new gameInfo;
|
||||||
|
newGameInfo->titleId = title_candidate.titleId;
|
||||||
|
newGameInfo->gamePath = title_candidate.path;
|
||||||
|
newGameInfo->name = "<unknown>";
|
||||||
|
newGameInfo->imageData = NULL;
|
||||||
|
DCFlushRange(newGameInfo, sizeof(gameInfo));
|
||||||
|
fullGameList.push_back(newGameInfo);
|
||||||
|
titleAdded(newGameInfo);
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameList::loadIcons() {
|
||||||
|
for (int i = 0; i < this->size(); i++) {
|
||||||
|
gameInfo * newHeader = this->at(i);
|
||||||
|
|
||||||
|
ACPMetaXml* meta = (ACPMetaXml*)calloc(1, 0x4000); //TODO fix wut
|
||||||
|
if(meta) {
|
||||||
|
auto acp = ACPGetTitleMetaXml(newHeader->titleId, meta);
|
||||||
|
if(acp >= 0) {
|
||||||
|
newHeader->name = meta->shortname_en;
|
||||||
|
}
|
||||||
|
free(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newHeader->imageData == NULL) {
|
||||||
|
std::string filepath = "fs:" + newHeader->gamePath + META_PATH + "/iconTex.tga";
|
||||||
|
uint8_t *buffer = NULL;
|
||||||
|
uint32_t bufferSize = 0;
|
||||||
|
int iResult = FSUtils::LoadFileToMem(filepath.c_str(), &buffer, &bufferSize);
|
||||||
|
|
||||||
|
if(iResult > 0) {
|
||||||
|
GuiImageData * imageData = new GuiImageData(buffer, bufferSize, GX2_TEX_CLAMP_MODE_MIRROR);
|
||||||
|
if(imageData) {
|
||||||
|
newHeader->imageData = imageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! free original image buffer which is converted to texture now and not needed anymore
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DCFlushRange(newHeader, sizeof(gameInfo));
|
||||||
|
titleUpdated(newHeader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameList::internalFilterList(std::vector<gameInfo*> &fullList) {
|
||||||
|
for (uint32_t i = 0; i < fullList.size(); ++i) {
|
||||||
|
gameInfo *header = fullList[i];
|
||||||
|
|
||||||
|
//! TODO: do filtering as needed
|
||||||
|
|
||||||
|
filteredList.push_back(header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t GameList::filterList(const char * filter) {
|
||||||
|
if(filter) {
|
||||||
|
gameFilter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fullGameList.size() == 0) {
|
||||||
|
readGameList();
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredList.clear();
|
||||||
|
|
||||||
|
// Filter current game list if selected
|
||||||
|
internalFilterList(fullGameList);
|
||||||
|
|
||||||
|
sortList();
|
||||||
|
|
||||||
|
titleListChanged(this);
|
||||||
|
|
||||||
|
AsyncExecutor::execute([&] { loadIcons();});
|
||||||
|
|
||||||
|
return filteredList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameList::internalLoadUnfiltered(std::vector<gameInfo*> & fullList) {
|
||||||
|
for (uint32_t i = 0; i < fullList.size(); ++i) {
|
||||||
|
gameInfo *header = fullList[i];
|
||||||
|
|
||||||
|
filteredList.push_back(header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t GameList::loadUnfiltered() {
|
||||||
|
if(fullGameList.size() == 0) {
|
||||||
|
readGameList();
|
||||||
|
}
|
||||||
|
|
||||||
|
gameFilter.clear();
|
||||||
|
filteredList.clear();
|
||||||
|
|
||||||
|
// Filter current game list if selected
|
||||||
|
internalLoadUnfiltered(fullGameList);
|
||||||
|
|
||||||
|
sortList();
|
||||||
|
|
||||||
|
AsyncExecutor::execute([&] { loadIcons();});
|
||||||
|
|
||||||
|
titleListChanged(this);
|
||||||
|
|
||||||
|
return filteredList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameList::sortList() {
|
||||||
|
std::sort(filteredList.begin(), filteredList.end(), nameSortCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameList::nameSortCallback(const gameInfo *a, const gameInfo *b) {
|
||||||
|
return (strcasecmp(((gameInfo *) a)->name.c_str(), ((gameInfo *) b)->name.c_str()) < 0);
|
||||||
|
}
|
||||||
|
|
102
src/game/GameList.h
Normal file
102
src/game/GameList.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#ifndef GAME_LIST_H_
|
||||||
|
#define GAME_LIST_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <coreinit/mcp.h>
|
||||||
|
#include <gui/sigslot.h>
|
||||||
|
#include <gui/GuiImageData.h>
|
||||||
|
|
||||||
|
typedef struct _gameInfo {
|
||||||
|
uint64_t titleId;
|
||||||
|
std::string name;
|
||||||
|
std::string gamePath;
|
||||||
|
GuiImageData * imageData;
|
||||||
|
} gameInfo;
|
||||||
|
|
||||||
|
class GameList {
|
||||||
|
public:
|
||||||
|
GameList() : selectedGame(0) { };
|
||||||
|
~GameList() { clear(); };
|
||||||
|
|
||||||
|
int32_t size() const {
|
||||||
|
return filteredList.size();
|
||||||
|
}
|
||||||
|
int32_t gameCount() const {
|
||||||
|
return fullGameList.size();
|
||||||
|
}
|
||||||
|
int32_t filterList(const char * gameFilter = NULL);
|
||||||
|
int32_t loadUnfiltered();
|
||||||
|
|
||||||
|
gameInfo * at(int32_t i) const {
|
||||||
|
return operator[](i);
|
||||||
|
}
|
||||||
|
gameInfo * operator[](int32_t i) const {
|
||||||
|
if (i < 0 || i >= (int32_t) filteredList.size())
|
||||||
|
return NULL;
|
||||||
|
return filteredList[i];
|
||||||
|
}
|
||||||
|
gameInfo * getGameInfo(uint64_t titleId) const;
|
||||||
|
|
||||||
|
const char * getCurrentFilter() const {
|
||||||
|
return gameFilter.c_str();
|
||||||
|
}
|
||||||
|
void sortList();
|
||||||
|
void clear();
|
||||||
|
bool operator!() const {
|
||||||
|
return (fullGameList.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Gamelist scrolling operators
|
||||||
|
int32_t operator+=(int32_t i) {
|
||||||
|
return (selectedGame = (selectedGame+i) % filteredList.size());
|
||||||
|
}
|
||||||
|
int32_t operator-=(int32_t i) {
|
||||||
|
return (selectedGame = (selectedGame-i+filteredList.size()) % filteredList.size());
|
||||||
|
}
|
||||||
|
int32_t operator++() {
|
||||||
|
return (selectedGame = (selectedGame+1) % filteredList.size());
|
||||||
|
}
|
||||||
|
int32_t operator--() {
|
||||||
|
return (selectedGame = (selectedGame-1+filteredList.size()) % filteredList.size());
|
||||||
|
}
|
||||||
|
int32_t operator++(int32_t i) {
|
||||||
|
return operator++();
|
||||||
|
}
|
||||||
|
int32_t operator--(int32_t i) {
|
||||||
|
return operator--();
|
||||||
|
}
|
||||||
|
gameInfo * GetCurrentSelected() const {
|
||||||
|
return operator[](selectedGame);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<gameInfo *> & getfilteredList(void) {
|
||||||
|
return filteredList;
|
||||||
|
}
|
||||||
|
std::vector<gameInfo *> & getFullGameList(void) {
|
||||||
|
return fullGameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
sigslot::signal1<GameList *> titleListChanged;
|
||||||
|
sigslot::signal1<gameInfo *> titleUpdated;
|
||||||
|
sigslot::signal1<gameInfo *> titleAdded;
|
||||||
|
protected:
|
||||||
|
|
||||||
|
int32_t readGameList();
|
||||||
|
|
||||||
|
void internalFilterList(std::vector<gameInfo*> & fullList);
|
||||||
|
void internalLoadUnfiltered(std::vector<gameInfo*> & fullList);
|
||||||
|
|
||||||
|
void loadIcons();
|
||||||
|
|
||||||
|
static bool nameSortCallback(const gameInfo *a, const gameInfo *b);
|
||||||
|
|
||||||
|
static GameList *gameListInstance;
|
||||||
|
|
||||||
|
std::string gameFilter;
|
||||||
|
int32_t selectedGame;
|
||||||
|
std::vector<gameInfo *> filteredList;
|
||||||
|
std::vector<gameInfo *> fullGameList;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -16,31 +16,155 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include <gui/GuiIconGrid.h>
|
#include <gui/GuiIconGrid.h>
|
||||||
#include <gui/GuiController.h>
|
#include <gui/GuiController.h>
|
||||||
|
#include <coreinit/cache.h>
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include <gui/video/CVideo.h>
|
#include <gui/video/CVideo.h>
|
||||||
|
#include "utils/logger.h"
|
||||||
|
|
||||||
GuiIconGrid::GuiIconGrid(int32_t w, int32_t h, int32_t GameIndex)
|
GuiIconGrid::GuiIconGrid(int32_t w, int32_t h, uint64_t GameIndex)
|
||||||
: GuiTitleBrowser(w, h, GameIndex),
|
: GuiTitleBrowser(w, h, GameIndex),
|
||||||
particleBgImage(w, h, 50, 60.0f, 90.0f, 0.6f, 1.0f) {
|
particleBgImage(w, h, 50, 60.0f, 90.0f, 0.6f, 1.0f)
|
||||||
|
, touchTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::VPAD_TOUCH)
|
||||||
|
, wpadTouchTrigger(GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5, GuiTrigger::BUTTON_A)
|
||||||
|
, noIcon(Resources::GetFile("noGameIcon.png"), Resources::GetFileSize("noGameIcon.png"), GX2_TEX_CLAMP_MODE_MIRROR) {
|
||||||
append(&particleBgImage);
|
append(&particleBgImage);
|
||||||
|
selectedGame = GameIndex;
|
||||||
|
listOffset = selectedGame / (MAX_COLS * MAX_ROWS);
|
||||||
|
targetLeftPosition = -listOffset * getWidth();
|
||||||
|
currentLeftPosition = targetLeftPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
GuiIconGrid::~GuiIconGrid() {
|
GuiIconGrid::~GuiIconGrid() {
|
||||||
|
containerMutex.lock();
|
||||||
|
for (auto const& x : gameInfoContainers) {
|
||||||
|
remove(x.second->button);
|
||||||
|
delete x.second;
|
||||||
|
}
|
||||||
|
gameInfoContainers.clear();
|
||||||
|
containerMutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiIconGrid::setSelectedGame(int32_t idx) {
|
void GuiIconGrid::setSelectedGame(uint64_t idx) {
|
||||||
this->selectedGame = idx;
|
this->selectedGame = idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t GuiIconGrid::getSelectedGame(void) {
|
uint64_t GuiIconGrid::getSelectedGame(void) {
|
||||||
return selectedGame;
|
return selectedGame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GuiIconGrid::OnGameTitleListUpdated(GameList * gameList) {
|
||||||
|
containerMutex.lock();
|
||||||
|
for(int32_t i = 0; i < gameList->size(); i++) {
|
||||||
|
gameInfo * info = gameList->at(i);
|
||||||
|
GameInfoContainer * container = NULL;
|
||||||
|
|
||||||
|
for (auto const& x : gameInfoContainers) {
|
||||||
|
if(info->titleId == x.first) {
|
||||||
|
container = x.second;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(container == NULL) {
|
||||||
|
OnGameTitleAdded(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
containerMutex.unlock();
|
||||||
|
bUpdatePositions = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiIconGrid::OnLaunchClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) {
|
||||||
|
//! do not auto launch when wiimote is pointing to screen and presses A
|
||||||
|
//if((trigger == &buttonATrigger) && (controller->chan & (GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5)) && controller->data.validPointer) {
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
DEBUG_FUNCTION_LINE("Tried to launch %s (%016llX)\n", gameInfoContainers[getSelectedGame()]->info->name.c_str(),getSelectedGame());
|
||||||
|
gameLaunchClicked(this, getSelectedGame());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GuiIconGrid::OnGameButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) {
|
||||||
|
containerMutex.lock();
|
||||||
|
for (auto const& x : gameInfoContainers) {
|
||||||
|
if(x.second->button == button) {
|
||||||
|
if(selectedGame == (x.second->info->titleId)) {
|
||||||
|
if(gameLaunchTimer < 30)
|
||||||
|
OnLaunchClick(button, controller, trigger);
|
||||||
|
} else {
|
||||||
|
setSelectedGame(x.second->info->titleId);
|
||||||
|
gameSelectionChanged(this, selectedGame);
|
||||||
|
}
|
||||||
|
gameLaunchTimer = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
containerMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiIconGrid::OnGameTitleAdded(gameInfo * info) {
|
||||||
|
DEBUG_FUNCTION_LINE("Adding %016llX\n", info->titleId);
|
||||||
|
GuiImage * image = new GuiImage(&noIcon);
|
||||||
|
GuiButton * button = new GuiButton(noIcon.getWidth(), noIcon.getHeight());
|
||||||
|
button->setImage(image);
|
||||||
|
button->setPosition(0, 0);
|
||||||
|
button->setEffectGrow();
|
||||||
|
button->setTrigger(&touchTrigger);
|
||||||
|
button->setTrigger(&wpadTouchTrigger);
|
||||||
|
button->setSoundClick(buttonClickSound);
|
||||||
|
//button->setClickable( (idx < gameList->size()) );
|
||||||
|
//button->setSelectable( (idx < gameList->size()) );
|
||||||
|
button->clicked.connect(this, &GuiIconGrid::OnGameButtonClick);
|
||||||
|
|
||||||
|
GameInfoContainer * container = new GameInfoContainer(button, image, info);
|
||||||
|
containerMutex.lock();
|
||||||
|
gameInfoContainers[info->titleId] = container;
|
||||||
|
containerMutex.unlock();
|
||||||
|
this->append(button);
|
||||||
|
|
||||||
|
bUpdatePositions = true;
|
||||||
|
}
|
||||||
|
void GuiIconGrid::OnGameTitleUpdated(gameInfo * info) {
|
||||||
|
DEBUG_FUNCTION_LINE("Updating infos of %016llX\n", info->titleId);
|
||||||
|
GameInfoContainer * container = NULL;
|
||||||
|
containerMutex.lock();
|
||||||
|
for (auto const& x : gameInfoContainers) {
|
||||||
|
if(info->titleId == x.first) {
|
||||||
|
container = x.second;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(container != NULL) {
|
||||||
|
container->updateImageData();
|
||||||
|
}
|
||||||
|
containerMutex.unlock();
|
||||||
|
bUpdatePositions = true;
|
||||||
|
}
|
||||||
|
|
||||||
void GuiIconGrid::process() {
|
void GuiIconGrid::process() {
|
||||||
|
if(currentLeftPosition < targetLeftPosition) {
|
||||||
|
currentLeftPosition += 35;
|
||||||
|
|
||||||
|
if(currentLeftPosition > targetLeftPosition)
|
||||||
|
currentLeftPosition = targetLeftPosition;
|
||||||
|
|
||||||
|
bUpdatePositions = true;
|
||||||
|
} else if(currentLeftPosition > targetLeftPosition) {
|
||||||
|
currentLeftPosition -= 35;
|
||||||
|
|
||||||
|
if(currentLeftPosition < targetLeftPosition)
|
||||||
|
currentLeftPosition = targetLeftPosition;
|
||||||
|
|
||||||
|
bUpdatePositions = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bUpdatePositions) {
|
||||||
|
bUpdatePositions = false;
|
||||||
|
updateButtonPositions();
|
||||||
|
}
|
||||||
|
gameLaunchTimer++;
|
||||||
|
|
||||||
GuiFrame::process();
|
GuiFrame::process();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,6 +172,37 @@ void GuiIconGrid::update(GuiController * c) {
|
|||||||
GuiFrame::update(c);
|
GuiFrame::update(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiIconGrid::draw(CVideo *pVideo) {
|
void GuiIconGrid::updateButtonPositions() {
|
||||||
GuiFrame::draw(pVideo);
|
int32_t col = 0, row = 0, listOff = 0;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
containerMutex.lock();
|
||||||
|
for (auto const& x : gameInfoContainers) {
|
||||||
|
|
||||||
|
listOff = i / (MAX_COLS * MAX_ROWS);
|
||||||
|
|
||||||
|
float posX = currentLeftPosition + listOff * width + ( col * (noIcon.getWidth() + noIcon.getWidth() * 0.5f) - (MAX_COLS * 0.5f - 0.5f) * (noIcon.getWidth() + noIcon.getWidth() * 0.5f) );
|
||||||
|
float posY = -row * (noIcon.getHeight() + noIcon.getHeight() * 0.5f) + (MAX_ROWS * 0.5f - 0.5f) * (noIcon.getHeight() + noIcon.getHeight() * 0.5f) + 30.0f;
|
||||||
|
|
||||||
|
if(x.second->button != NULL) {
|
||||||
|
x.second->button->setPosition(posX, posY);
|
||||||
|
}
|
||||||
|
|
||||||
|
col++;
|
||||||
|
if(col >= MAX_COLS) {
|
||||||
|
col = 0;
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
if(row >= MAX_ROWS)
|
||||||
|
row = 0;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
containerMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiIconGrid::draw(CVideo *pVideo) {
|
||||||
|
containerMutex.lock();
|
||||||
|
GuiFrame::draw(pVideo);
|
||||||
|
containerMutex.unlock();
|
||||||
}
|
}
|
||||||
|
@ -19,25 +19,77 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include "gui/GuiTitleBrowser.h"
|
#include "gui/GuiTitleBrowser.h"
|
||||||
#include <gui/GuiParticleImage.h>
|
#include <gui/GuiParticleImage.h>
|
||||||
|
#include "utils/AsyncExecutor.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
|
||||||
class GuiIconGrid : public GuiTitleBrowser, public sigslot::has_slots<> {
|
class GuiIconGrid : public GuiTitleBrowser, public sigslot::has_slots<> {
|
||||||
public:
|
public:
|
||||||
GuiIconGrid(int32_t w, int32_t h, int32_t GameIndex);
|
GuiIconGrid(int32_t w, int32_t h, uint64_t selectedTitleId);
|
||||||
virtual ~GuiIconGrid();
|
virtual ~GuiIconGrid();
|
||||||
|
|
||||||
void setSelectedGame(int32_t idx);
|
void setSelectedGame(uint64_t idx);
|
||||||
int32_t getSelectedGame(void);
|
uint64_t getSelectedGame(void);
|
||||||
|
|
||||||
void update(GuiController * t);
|
void update(GuiController * t);
|
||||||
void draw(CVideo *pVideo);
|
void draw(CVideo *pVideo);
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
|
void OnGameTitleListUpdated(GameList * list);
|
||||||
|
void OnAddGameTitle(gameInfo * info);
|
||||||
|
void OnGameTitleUpdated(gameInfo * info);
|
||||||
|
void OnGameTitleAdded(gameInfo * info);
|
||||||
private:
|
private:
|
||||||
static const int32_t MAX_ROWS = 3;
|
static const int32_t MAX_ROWS = 3;
|
||||||
static const int32_t MAX_COLS = 5;
|
static const int32_t MAX_COLS = 5;
|
||||||
|
|
||||||
GuiSound *buttonClickSound;
|
GuiSound *buttonClickSound;
|
||||||
|
|
||||||
int32_t selectedGame = 0;
|
|
||||||
|
|
||||||
GuiParticleImage particleBgImage;
|
GuiParticleImage particleBgImage;
|
||||||
|
|
||||||
|
GuiTrigger touchTrigger;
|
||||||
|
GuiTrigger wpadTouchTrigger;
|
||||||
|
|
||||||
|
GuiImageData noIcon;
|
||||||
|
|
||||||
|
void OnLaunchClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger);
|
||||||
|
void OnGameButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger);
|
||||||
|
void updateButtonPositions();
|
||||||
|
|
||||||
|
int32_t listOffset;
|
||||||
|
uint64_t selectedGame;
|
||||||
|
int32_t currentLeftPosition;
|
||||||
|
int32_t targetLeftPosition;
|
||||||
|
uint32_t gameLaunchTimer;
|
||||||
|
bool bUpdatePositions = false;
|
||||||
|
|
||||||
|
class GameInfoContainer {
|
||||||
|
public:
|
||||||
|
GameInfoContainer(GuiButton* button, GuiImage * image, gameInfo * info) {
|
||||||
|
this->image = image;
|
||||||
|
this->info = info;
|
||||||
|
this->button = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
~GameInfoContainer() {
|
||||||
|
if(button != NULL) {
|
||||||
|
AsyncExecutor::pushForDelete(button);
|
||||||
|
}
|
||||||
|
if(image != NULL) {
|
||||||
|
AsyncExecutor::pushForDelete(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateImageData() {
|
||||||
|
if(image != NULL && info != NULL && info->imageData != NULL) {
|
||||||
|
image->setImageData(info->imageData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiImage * image;
|
||||||
|
gameInfo * info;
|
||||||
|
GuiButton * button;
|
||||||
|
};
|
||||||
|
|
||||||
|
CMutex containerMutex;
|
||||||
|
std::map<uint64_t, GameInfoContainer *> gameInfoContainers;
|
||||||
};
|
};
|
||||||
|
@ -2,15 +2,20 @@
|
|||||||
|
|
||||||
#include <gui/Gui.h>
|
#include <gui/Gui.h>
|
||||||
#include <gui/sigslot.h>
|
#include <gui/sigslot.h>
|
||||||
|
#include "game/GameList.h"
|
||||||
|
|
||||||
class GuiTitleBrowser : public GuiFrame {
|
class GuiTitleBrowser : public GuiFrame {
|
||||||
public:
|
public:
|
||||||
GuiTitleBrowser(int32_t w, int32_t h, int32_t GameIndex) : GuiFrame(w, h) {}
|
GuiTitleBrowser(int32_t w, int32_t h, uint64_t GameIndex) : GuiFrame(w, h) {}
|
||||||
virtual ~GuiTitleBrowser() {}
|
virtual ~GuiTitleBrowser() {}
|
||||||
|
|
||||||
virtual void setSelectedGame(int32_t idx) = 0;
|
virtual void setSelectedGame(uint64_t idx) = 0;
|
||||||
virtual int32_t getSelectedGame(void) = 0;
|
virtual uint64_t getSelectedGame(void) = 0;
|
||||||
|
|
||||||
sigslot::signal2<GuiTitleBrowser *, int32_t> gameLaunchClicked;
|
virtual void OnGameTitleListUpdated(GameList * list) = 0;
|
||||||
sigslot::signal2<GuiTitleBrowser *, int32_t> gameSelectionChanged;
|
virtual void OnGameTitleUpdated(gameInfo * info) = 0;
|
||||||
|
virtual void OnGameTitleAdded(gameInfo * info) = 0;
|
||||||
|
|
||||||
|
sigslot::signal2<GuiTitleBrowser *, uint64_t> gameLaunchClicked;
|
||||||
|
sigslot::signal2<GuiTitleBrowser *, uint64_t> gameSelectionChanged;
|
||||||
};
|
};
|
||||||
|
@ -40,9 +40,15 @@ MainWindow::MainWindow(int32_t w, int32_t h)
|
|||||||
pointerValid[i] = false;
|
pointerValid[i] = false;
|
||||||
}
|
}
|
||||||
SetupMainView();
|
SetupMainView();
|
||||||
|
gameList.titleListChanged.connect(this, &MainWindow::OnGameTitleListChanged);
|
||||||
|
gameList.titleUpdated.connect(this, &MainWindow::OnGameTitleUpdated);
|
||||||
|
gameList.titleAdded.connect(this, &MainWindow::OnGameTitleAdded);
|
||||||
|
AsyncExecutor::execute([&] {gameList.loadUnfiltered();});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow() {
|
MainWindow::~MainWindow() {
|
||||||
|
gameList.titleListChanged.disconnect(this);
|
||||||
while(!tvElements.empty()) {
|
while(!tvElements.empty()) {
|
||||||
delete tvElements[0];
|
delete tvElements[0];
|
||||||
remove(tvElements[0]);
|
remove(tvElements[0]);
|
||||||
@ -103,6 +109,31 @@ void MainWindow::process() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::OnGameTitleListChanged(GameList * list) {
|
||||||
|
currentTvFrame->OnGameTitleListUpdated(list);
|
||||||
|
if(currentTvFrame != currentDrcFrame) {
|
||||||
|
currentDrcFrame->OnGameTitleListUpdated(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::OnGameTitleUpdated(gameInfo * info) {
|
||||||
|
currentTvFrame->OnGameTitleUpdated(info);
|
||||||
|
if(currentTvFrame != currentDrcFrame) {
|
||||||
|
currentDrcFrame->OnGameTitleUpdated(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::OnGameTitleAdded(gameInfo * info) {
|
||||||
|
DEBUG_FUNCTION_LINE("%08X\n", info);
|
||||||
|
if(info == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentTvFrame->OnGameTitleAdded(info);
|
||||||
|
if(currentTvFrame != currentDrcFrame) {
|
||||||
|
currentDrcFrame->OnGameTitleAdded(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::update(GuiController *controller) {
|
void MainWindow::update(GuiController *controller) {
|
||||||
//! dont read behind the initial elements in case one was added
|
//! dont read behind the initial elements in case one was added
|
||||||
//uint32_t tvSize = tvElements.size();
|
//uint32_t tvSize = tvElements.size();
|
||||||
@ -179,6 +210,7 @@ void MainWindow::SetupMainView() {
|
|||||||
currentTvFrame->setEffect(EFFECT_FADE, 10, 255);
|
currentTvFrame->setEffect(EFFECT_FADE, 10, 255);
|
||||||
currentTvFrame->setState(GuiElement::STATE_DISABLED);
|
currentTvFrame->setState(GuiElement::STATE_DISABLED);
|
||||||
currentTvFrame->effectFinished.connect(this, &MainWindow::OnOpenEffectFinish);
|
currentTvFrame->effectFinished.connect(this, &MainWindow::OnOpenEffectFinish);
|
||||||
|
|
||||||
appendTv(currentTvFrame);
|
appendTv(currentTvFrame);
|
||||||
|
|
||||||
currentDrcFrame = new GuiIconGrid(width, height,0);
|
currentDrcFrame = new GuiIconGrid(width, height,0);
|
||||||
@ -186,7 +218,6 @@ void MainWindow::SetupMainView() {
|
|||||||
currentDrcFrame->setState(GuiElement::STATE_DISABLED);
|
currentDrcFrame->setState(GuiElement::STATE_DISABLED);
|
||||||
currentDrcFrame->effectFinished.connect(this, &MainWindow::OnOpenEffectFinish);
|
currentDrcFrame->effectFinished.connect(this, &MainWindow::OnOpenEffectFinish);
|
||||||
|
|
||||||
|
|
||||||
if(currentTvFrame != currentDrcFrame) {
|
if(currentTvFrame != currentDrcFrame) {
|
||||||
currentDrcFrame->setEffect(EFFECT_FADE, 10, 255);
|
currentDrcFrame->setEffect(EFFECT_FADE, 10, 255);
|
||||||
currentDrcFrame->setState(GuiElement::STATE_DISABLED);
|
currentDrcFrame->setState(GuiElement::STATE_DISABLED);
|
||||||
@ -292,7 +323,7 @@ void MainWindow::OnSettingsButtonClicked(GuiElement *element){
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::OnGameSelectionChange(GuiTitleBrowser *element, int32_t selectedIdx) {
|
void MainWindow::OnGameSelectionChange(GuiTitleBrowser *element, uint64_t selectedIdx) {
|
||||||
if(!currentDrcFrame || !currentTvFrame)
|
if(!currentDrcFrame || !currentTvFrame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -303,6 +334,6 @@ void MainWindow::OnGameSelectionChange(GuiTitleBrowser *element, int32_t selecte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::OnGameLaunch(GuiTitleBrowser *element, int32_t selectedIdx) {
|
void MainWindow::OnGameLaunch(GuiTitleBrowser *element, uint64_t selectedIdx) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <gui/Gui.h>
|
#include <gui/Gui.h>
|
||||||
|
#include "game/GameList.h"
|
||||||
#include "system/CMutex.h"
|
#include "system/CMutex.h"
|
||||||
#include "gui/GuiTitleBrowser.h"
|
#include "gui/GuiTitleBrowser.h"
|
||||||
#include "MainDrcButtonsFrame.h"
|
#include "MainDrcButtonsFrame.h"
|
||||||
@ -116,13 +117,17 @@ private:
|
|||||||
void OnOpenEffectFinish(GuiElement *element);
|
void OnOpenEffectFinish(GuiElement *element);
|
||||||
void OnCloseEffectFinish(GuiElement *element);
|
void OnCloseEffectFinish(GuiElement *element);
|
||||||
|
|
||||||
void OnGameLaunch(GuiTitleBrowser *element, int32_t gameIdx);
|
void OnGameLaunch(GuiTitleBrowser *element, uint64_t gameIdx);
|
||||||
void OnGameSelectionChange(GuiTitleBrowser *element, int32_t selectedIdx);
|
void OnGameSelectionChange(GuiTitleBrowser *element, uint64_t selectedIdx);
|
||||||
|
|
||||||
void OnSettingsButtonClicked(GuiElement *element);
|
void OnSettingsButtonClicked(GuiElement *element);
|
||||||
void OnLayoutSwitchClicked(GuiElement *element);
|
void OnLayoutSwitchClicked(GuiElement *element);
|
||||||
void OnLayoutSwitchEffectFinish(GuiElement *element);
|
void OnLayoutSwitchEffectFinish(GuiElement *element);
|
||||||
|
|
||||||
|
void OnGameTitleListChanged(GameList * list);
|
||||||
|
void OnGameTitleUpdated(gameInfo * info);
|
||||||
|
void OnGameTitleAdded(gameInfo * info);
|
||||||
|
|
||||||
int32_t width, height;
|
int32_t width, height;
|
||||||
std::vector<GuiElement *> drcElements;
|
std::vector<GuiElement *> drcElements;
|
||||||
std::vector<GuiElement *> tvElements;
|
std::vector<GuiElement *> tvElements;
|
||||||
@ -138,6 +143,8 @@ private:
|
|||||||
GuiImage *pointerImg[4];
|
GuiImage *pointerImg[4];
|
||||||
bool pointerValid[4];
|
bool pointerValid[4];
|
||||||
|
|
||||||
|
GameList gameList;
|
||||||
|
|
||||||
CMutex guiMutex;
|
CMutex guiMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,5 +11,10 @@ void AsyncExecutor::execute(std::function<void()> func) {
|
|||||||
if(!instance) {
|
if(!instance) {
|
||||||
instance = new AsyncExecutor();
|
instance = new AsyncExecutor();
|
||||||
}
|
}
|
||||||
instance->elements.push_back(std::async(std::launch::async,func));
|
instance->elements.push(std::async(std::launch::async,func));
|
||||||
|
if(instance->elements.size() >= 25){
|
||||||
|
//DEBUG_FUNCTION_LINE("Wait on queue %d\n",instance->elements.size());
|
||||||
|
instance->elements.front().get();
|
||||||
|
instance->elements.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <queue>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <gui/GuiElement.h>
|
#include <gui/GuiElement.h>
|
||||||
|
|
||||||
@ -22,5 +22,5 @@ private:
|
|||||||
AsyncExecutor() {}
|
AsyncExecutor() {}
|
||||||
~AsyncExecutor() {}
|
~AsyncExecutor() {}
|
||||||
|
|
||||||
std::vector<std::future<void>> elements;
|
std::queue<std::future<void>> elements;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user