See desc for more.

- Add WAV playback back with 10 MiB as max limit.

- Some more Screenshot Menu checks.
This commit is contained in:
StackZ
2020-12-03 07:19:02 +01:00
parent 78d0dad604
commit 64977911e6
22 changed files with 457 additions and 168 deletions
+31
View File
@@ -28,6 +28,7 @@
#include "download.hpp"
#include "init.hpp"
#include "mainScreen.hpp"
#include "sound.hpp"
#include <dirent.h>
#include <unistd.h>
@@ -36,6 +37,8 @@ bool exiting = false, is3DSX = false, needUnloadFont = false;
C2D_SpriteSheet sprites;
int fadeAlpha = 0;
u32 old_time_limit;
std::unique_ptr<Sound> Music = nullptr;
bool dspfirmFound = false;
/*
Set, if 3DSX or CIA.
@@ -46,6 +49,32 @@ static void getCurrentUsage(){
is3DSX = (id != 0x0004000004391700);
}
/*
Init Music.
*/
static void InitMusic() {
if (access("sdmc:/3ds/dspfirm.cdc", F_OK) == 0) { // Ensure dspfirm dump exist.
if (access("sdmc:/3ds/Universal-Updater/music.wav", F_OK) == 0) { // Ensure music.wav exist.
dspfirmFound = true;
ndspInit();
Music = std::make_unique<Sound>("sdmc:/3ds/Universal-Updater/music.wav");
Music->play();
}
}
}
/*
Exit Music.
*/
static void ExitMusic() {
if (dspfirmFound) {
Music->stop();
Music = nullptr;
ndspExit();
}
}
/*
If button Position pressed -> Do something.
@@ -121,6 +150,7 @@ Result Init::Initialize() {
if (exiting) return -1; // In case the update was successful.
Gui::setScreen(std::make_unique<MainScreen>(), false, false);
InitMusic();
return 0;
}
@@ -172,6 +202,7 @@ Result Init::Exit() {
Gui::exit();
Gui::unloadSheet(sprites);
UnloadFont();
ExitMusic();
gfxExit();
cfguExit();
config->save();
+3 -2
View File
@@ -47,8 +47,9 @@ void Overlays::ShowCredits() {
Gui::DrawString(10, 70, 0.5f, TEXT_COLOR, "- dlbeer", 0, 0, font);
Gui::DrawString(10, 90, 0.5f, TEXT_COLOR, "- FlagBrew", 0, 0, font);
Gui::DrawString(10, 110, 0.5f, TEXT_COLOR, "- https://icons8.com/", 0, 0, font);
Gui::DrawString(10, 130, 0.5f, TEXT_COLOR, "- PabloMK7", 0, 0, font);
Gui::DrawString(10, 150, 0.5f, TEXT_COLOR, Lang::get("CONTRIBUTOR_TRANSLATORS"), 210, 0, font);
Gui::DrawString(10, 130, 0.5f, TEXT_COLOR, "- Ivandeve", 0, 0, font);
Gui::DrawString(10, 150, 0.5f, TEXT_COLOR, "- PabloMK7", 0, 0, font);
Gui::DrawString(10, 170, 0.5f, TEXT_COLOR, Lang::get("CONTRIBUTOR_TRANSLATORS"), 210, 0, font);
Gui::DrawString(10, 197, 0.5f, TEXT_COLOR, Lang::get("GITHUB"), 390, 0, font);
Gui::Draw_Rect(0, 215, 400, 25, BAR_COLOR);
+8 -12
View File
@@ -45,11 +45,9 @@ static const std::vector<Structs::ButtonPos> mainButtons = {
{ 10, 154, 300, 22 },
{ 10, 184, 300, 22 },
/* Add, Delete, Info.. */
{ 92, 215, 16, 16 },
{ 136, 215, 16, 16 },
{ 180, 215, 16, 16 },
{ 224, 215, 16, 16 },
{ 112, 215, 16, 16 }, // Delete.
{ 154, 215, 16, 16 }, // Update.
{ 200, 215, 16, 16 }, // Add.
{ 4, 0, 24, 24 } // Back.
};
@@ -265,7 +263,7 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
Gui::Draw_Rect(0, 0, 320, 25, ENTRY_BAR_COLOR);
Gui::Draw_Rect(0, 25, 320, 1, ENTRY_BAR_OUTL_COLOR);
GFX::DrawSprite(sprites_arrow_idx, mainButtons[10].x, mainButtons[10].y);
GFX::DrawSprite(sprites_arrow_idx, mainButtons[9].x, mainButtons[9].y);
Gui::DrawStringCentered(0, 2, 0.6, TEXT_COLOR, Lang::get("SELECT_UNISTORE_2"), 310, 0, font);
for(int i = 0; i < 6 && i < (int)info.size(); i++) {
@@ -280,7 +278,6 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
GFX::DrawSprite(sprites_delete_idx, mainButtons[6].x, mainButtons[6].y);
GFX::DrawSprite(sprites_update_idx, mainButtons[7].x, mainButtons[7].y);
GFX::DrawSprite(sprites_add_idx, mainButtons[8].x, mainButtons[8].y);
GFX::DrawSprite(sprites_qr_code_idx, mainButtons[9].x, mainButtons[9].y);
C3D_FrameEnd(0);
hidScanInput();
@@ -317,9 +314,9 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
else if (info[selection].Version < 3) Msg::waitMsg(Lang::get("UNISTORE_TOO_OLD"));
else if (info[selection].Version > _UNISTORE_VERSION) Msg::waitMsg(Lang::get("UNISTORE_TOO_NEW"));
else {
config->lastStore(info[selection].FileName);
store = std::make_unique<Store>(_STORE_PATH + info[selection].FileName, info[selection].FileName);
StoreUtils::ResetAll(store, meta, entries);
config->lastStore(info[selection].FileName);
StoreUtils::SortEntries(false, SortType::LAST_UPDATED, entries);
doOut = true;
}
@@ -339,9 +336,10 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
else if (info[i + sPos].Version < 3) Msg::waitMsg(Lang::get("UNISTORE_TOO_OLD"));
else if (info[i + sPos].Version > _UNISTORE_VERSION) Msg::waitMsg(Lang::get("UNISTORE_TOO_NEW"));
else {
config->lastStore(info[i + sPos].FileName);
store = std::make_unique<Store>(_STORE_PATH + info[i + sPos].FileName, info[i + sPos].FileName);
StoreUtils::ResetAll(store, meta, entries);
config->lastStore(info[i + sPos].FileName);
StoreUtils::SortEntries(false, SortType::LAST_UPDATED, entries);
doOut = true;
}
@@ -395,8 +393,6 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
}
/* Go out of the menu. */
if ((hidKeysDown() & KEY_B) || (hidKeysDown() & KEY_TOUCH && touching(touch, mainButtons[10]))) {
doOut = true;
}
if ((hidKeysDown() & KEY_B) || (hidKeysDown() & KEY_TOUCH && touching(touch, mainButtons[9]))) doOut = true;
}
}
+86 -73
View File
@@ -62,7 +62,11 @@ static const std::vector<Structs::ButtonPos> mainButtons = {
{ 10, 94, 300, 22 },
{ 10, 124, 300, 22 },
{ 10, 154, 300, 22 },
{ 10, 184, 300, 22 }
{ 10, 184, 300, 22 },
{ 5, 215, 24, 24 }, // QR Code / List.
{ 35, 215, 24, 24 }, // Keyboard.
{ 4, 0, 24, 24 } // Back.
};
extern bool touching(touchPosition touch, Structs::ButtonPos button);
@@ -84,6 +88,8 @@ QRCode::QRCode() {
quirc_resize(this->qrData, 400, 240);
if (checkWifiStatus()) this->stores = FetchStores(); // Fetching Stores here.
if (this->stores.size() > 0) this->displayList = true;
}
/*
@@ -140,39 +146,49 @@ void QRCode::drawThread() {
C2D_TargetClear(Top, TRANSPARENT);
C2D_TargetClear(Bottom, TRANSPARENT);
if (!this->displayInfo) {
if (!this->displayList) {
this->buffToImage(); // Fetch image.
Gui::ScreenDraw(Top);
C2D_DrawImageAt(this->image, 0, 0, 0.5, nullptr, 1.0f, 1.0f);
GFX::DrawBottom();
Gui::Draw_Rect(0, 0, 320, 25, ENTRY_BAR_COLOR);
Gui::Draw_Rect(0, 25, 320, 1, ENTRY_BAR_OUTL_COLOR);
} else {
GFX::DrawTop();
Gui::DrawStringCentered(0, 1, 0.7, TEXT_COLOR, Lang::get("STORE_INFO"), 390, 0, font);
Gui::DrawStringCentered(0, 30, 0.7f, TEXT_COLOR, this->stores[this->selectedStore].Title, 390, 0, font);
Gui::DrawStringCentered(0, 50, 0.6f, TEXT_COLOR, this->stores[this->selectedStore].Author, 380, 0, font);
if (this->stores[this->selectedStore].Description != "") {
/* "\n\n" breaks C2D_WordWrap, so check here. */
if (!(this->stores[this->selectedStore].Description.find("\n\n") != std::string::npos)) {
Gui::DrawStringCentered(0, 90, 0.5f, TEXT_COLOR, this->stores[this->selectedStore].Description, 380, 130, font, C2D_WordWrap);
if (this->stores.size() > 0) {
Gui::DrawStringCentered(0, 30, 0.7f, TEXT_COLOR, this->stores[this->selectedStore].Title, 390, 0, font);
Gui::DrawStringCentered(0, 50, 0.6f, TEXT_COLOR, this->stores[this->selectedStore].Author, 380, 0, font);
} else {
Gui::DrawStringCentered(0, 90, 0.5f, TEXT_COLOR, this->stores[this->selectedStore].Description, 380, 130, font);
if (this->stores[this->selectedStore].Description != "") {
/* "\n\n" breaks C2D_WordWrap, so check here. */
if (!(this->stores[this->selectedStore].Description.find("\n\n") != std::string::npos)) {
Gui::DrawStringCentered(0, 90, 0.5f, TEXT_COLOR, this->stores[this->selectedStore].Description, 380, 130, font, C2D_WordWrap);
} else {
Gui::DrawStringCentered(0, 90, 0.5f, TEXT_COLOR, this->stores[this->selectedStore].Description, 380, 130, font);
}
}
}
GFX::DrawBottom();
Gui::Draw_Rect(0, 0, 320, 25, ENTRY_BAR_COLOR);
Gui::Draw_Rect(0, 25, 320, 1, ENTRY_BAR_OUTL_COLOR);
Gui::DrawStringCentered(0, 2, 0.6, TEXT_COLOR, Lang::get("RECOMMENDED_UNISTORES"), 310, 0, font);
for(int i = 0; i < 6 && i < (int)this->stores.size(); i++) {
if (this->sPos + i == this->selectedStore) GFX::DrawBox(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, false);
Gui::DrawStringCentered(10 - 160 + (300 / 2), mainButtons[i].y + 4, 0.45f, TEXT_COLOR, this->stores[this->sPos + i].Title, 295, 0, font);
}
}
GFX::DrawBottom();
Gui::Draw_Rect(0, 0, 320, 25, ENTRY_BAR_COLOR);
Gui::Draw_Rect(0, 25, 320, 1, ENTRY_BAR_OUTL_COLOR);
Gui::DrawStringCentered(0, 2, 0.6, TEXT_COLOR, Lang::get("AVAILABLE_UNISTORES"), 310, 0, font);
for(int i = 0; i < 6 && i < (int)this->stores.size(); i++) {
if (this->sPos + i == this->selectedStore) GFX::DrawBox(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, false);
Gui::DrawStringCentered(10 - 160 + (300 / 2), mainButtons[i].y + 4, 0.45f, TEXT_COLOR, this->stores[this->sPos + i].Title, 295, 0, font);
}
GFX::DrawSprite((this->displayList ? sprites_qr_code_idx : sprites_list_idx), mainButtons[6].x, mainButtons[6].y);
if (this->displayList) GFX::DrawSprite(sprites_keyboard_idx, mainButtons[7].x, mainButtons[7].y);
GFX::DrawSprite(sprites_arrow_idx, mainButtons[8].x, mainButtons[8].y);
C3D_FrameEnd(0);
}
@@ -192,6 +208,7 @@ void QRCode::captureThread() {
CAMU_SetSize(SELECT_OUT1, SIZE_CTR_TOP_LCD, CONTEXT_A);
CAMU_SetOutputFormat(SELECT_OUT1, OUTPUT_RGB_565, CONTEXT_A);
CAMU_SetFrameRate(SELECT_OUT1, FRAME_RATE_30);
CAMU_SetNoiseFilter(SELECT_OUT1, true);
CAMU_SetAutoExposure(SELECT_OUT1, true);
CAMU_SetAutoWhiteBalance(SELECT_OUT1, true);
@@ -275,41 +292,44 @@ void captureHelper(void *arg) {
/*
Handle the capture.
std::vector<u8> &out: The Reference, where to output the decoded result.
*/
void QRCode::handler(std::vector<u8> &out) {
void QRCode::handler(std::string &result) {
hidScanInput();
touchPosition t;
hidTouchRead(&t);
u32 keyDown = hidKeysDown();
u32 keyRepeat = hidKeysDownRepeat();
if (keyDown & KEY_B) {
this->cancel = true;
if ((keyDown & KEY_B) || (keyDown & KEY_TOUCH && touching(t, mainButtons[8]))) {
result = "";
this->finished = true;
this->finish();
return;
}
if (this->displayInfo) {
if (this->timeout == 0) { // hidKeysDown() is pretty buggy, hence try to do it a timeout way.
if (keyDown & KEY_SELECT) {
this->timeout = 10;
keyDown = 0;
this->displayInfo = false;
/* Keyboard. */
if (keyDown & KEY_TOUCH && touching(t, mainButtons[7])) {
if (this->displayList) {
const std::string temp = Input::setkbdString(150, Lang::get("ENTER_URL"), { });
if (temp != "") {
result = temp;
this->finished = true;
this->finish();
return;
}
}
}
if (this->displayList) {
gspWaitForVBlank();
if ((keyDown & KEY_SELECT) || (keyDown & KEY_TOUCH && touching(t, mainButtons[6]))) {
keyDown = 0;
this->displayList = false;
}
} else {
if (this->stores.size() > 0) {
if (this->timeout == 0) {
if (keyDown & KEY_SELECT) {
this->timeout = 30;
keyDown = 0;
this->displayInfo = true;
}
}
if (keyRepeat & KEY_DOWN) {
if (this->selectedStore < (int)this->stores.size() - 1) this->selectedStore++;
else this->selectedStore = 0;
@@ -321,7 +341,8 @@ void QRCode::handler(std::vector<u8> &out) {
}
if (keyDown & KEY_A) {
this->FromList = true;
result = this->stores[this->selectedStore].URL;
this->finished = true;
this->finish();
return;
}
@@ -330,8 +351,8 @@ void QRCode::handler(std::vector<u8> &out) {
for (int i = 0; i < 6; i++) {
if (touching(t, mainButtons[i])) {
if (i + this->sPos < (int)this->stores.size()) {
this->selectedStore = i + this->sPos;
this->FromList = true;
result = this->stores[i + this->sPos].URL;
this->finished = true;
this->finish();
return;
}
@@ -340,8 +361,16 @@ void QRCode::handler(std::vector<u8> &out) {
}
}
} else {
if (this->stores.size() > 0) {
if ((keyDown & KEY_SELECT) || (keyDown & KEY_TOUCH && touching(t, mainButtons[6]))) {
keyDown = 0;
this->displayList = true;
}
}
if (!this->capturing) {
/* create camera draw thread. */
/* create camera capture thread. */
if (threadCreate((ThreadFunc)&captureHelper, this, 0x10000, 0x1A, 1, true) != NULL) this->capturing = true;
else {
this->finish();
@@ -372,50 +401,34 @@ void QRCode::handler(std::vector<u8> &out) {
if (!quirc_decode(&code, &scan_data)) {
this->finish();
out.resize(scan_data.payload_len);
std::copy(scan_data.payload, scan_data.payload + scan_data.payload_len, out.begin());
this->out.resize(scan_data.payload_len);
std::copy(scan_data.payload, scan_data.payload + scan_data.payload_len, this->out.begin());
/* From scanned stuff. */
if (this->out.empty()) result = "";
/* If Terminator, do -1. */
if (this->out.back() == '\0') result = std::string((char *)this->out.data(), this->out.size() - 1);
else result = std::string((char *)this->out.data(), this->out.size());
}
}
if (this->selectedStore < this->sPos) this->sPos = this->selectedStore;
else if (this->selectedStore > this->sPos + 6 - 1) this->sPos = this->selectedStore - 6 + 1;
}
if (this->timeout > 0) this->timeout--;
}
/*
The Store Add QR Code handle and such.
*/
std::string QR_Scanner::StoreHandle() {
std::vector<u8> data = { };
std::string result = "";
std::unique_ptr<QRCode> qrData = std::make_unique<QRCode>();
aptSetHomeAllowed(false); // Block the Home key.
threadCreate((ThreadFunc)&drawHelper, qrData.get(), 0x10000, 0x1A, 1, true);
while (!qrData->done()) qrData->handler(data); // Handle.
while (!qrData->done()) qrData->handler(result); // Handle.
aptSetHomeAllowed(true); // Re-Allow it.
/* Selected from list. */
if (qrData->FromList) {
return qrData->stores[qrData->selectedStore].URL;
}
/* False means Keyboard. */
if (!qrData->Mode()) {
const std::string out = Input::setkbdString(150, Lang::get("ENTER_URL"), { });
return out;
} else {
/* From scanned stuff. */
if (data.empty()) return "";
/* If Terminator, do -1. */
if (data.back() == '\0') return std::string((char *)data.data(), data.size() - 1);
else return std::string((char *)data.data(), data.size());
}
return "";
return result;
}
+4 -2
View File
@@ -107,7 +107,7 @@ MainScreen::MainScreen() {
void MainScreen::Draw(void) const {
if (this->storeMode == 5) {
/* Screenshot Menu. */
StoreUtils::DrawScreenshotMenu(this->Screenshot, this->screenshotIndex, this->screenshotFetch, this->sSize, this->screenshotName, this->zoom);
StoreUtils::DrawScreenshotMenu(this->Screenshot, this->screenshotIndex, this->screenshotFetch, this->sSize, this->screenshotName, this->zoom, this->canDisplay);
return;
}
@@ -180,13 +180,15 @@ void MainScreen::Logic(u32 hDown, u32 hHeld, touchPosition touch) {
if (this->screenshotIndex < this->sSize) {
if (this->sSize > 0) {
this->Screenshot = FetchScreenshot(this->entries[this->store->GetEntry()]->GetScreenshots()[this->screenshotIndex]);
if (this->Screenshot.tex) this->canDisplay = true;
else this->canDisplay = false;
}
}
this->screenshotFetch = false;
}
StoreUtils::ScreenshotMenu(this->Screenshot, this->screenshotIndex, this->screenshotFetch, this->storeMode, this->sSize, this->zoom);
StoreUtils::ScreenshotMenu(this->Screenshot, this->screenshotIndex, this->screenshotFetch, this->storeMode, this->sSize, this->zoom, this->canDisplay);
return;
}
+12 -5
View File
@@ -28,7 +28,9 @@
#include "structs.hpp"
extern bool touching(touchPosition touch, Structs::ButtonPos button);
static const Structs::ButtonPos btn = { 53, 215, 20, 20 };
static const Structs::ButtonPos btn = { 53, 215, 24, 24 };
static const Structs::ButtonPos sshot = { 83, 215, 24, 24 };
extern bool checkWifiStatus();
/*
Draw the Entry Info part.
@@ -61,7 +63,8 @@ void StoreUtils::DrawEntryInfo(const std::unique_ptr<Store> &store, const std::u
Gui::DrawString(61, 190, 0.45, TEXT_COLOR, Lang::get("LICENSE") + ": " + entry->GetLicense(), 240, 0, font);
GFX::DrawBox(btn.x, btn.y, btn.w, btn.h, false);
Gui::DrawString(btn.x + 3, btn.y, 0.6f, TEXT_COLOR, "", 0, 0, font);
GFX::DrawSprite(sprites_screenshot_idx, sshot.x, sshot.y);
Gui::DrawString(btn.x + 5, btn.y + 2, 0.6f, TEXT_COLOR, "", 0, 0, font);
}
}
@@ -74,12 +77,16 @@ void StoreUtils::DrawEntryInfo(const std::unique_ptr<Store> &store, const std::u
bool &showMark: Reference to showMark.. to show the mark menu.
bool &fetch: Reference to fetch, so we know, if we need to fetch, when accessing download list.
bool &sFetch: Reference to the screenshot fetch.
int &mode: Reference to the Store mode.
*/
void StoreUtils::EntryHandle(bool &showMark, bool &fetch, bool &sFetch, int &mode) {
if ((hDown & KEY_START) || (hDown & KEY_TOUCH && touching(touch, btn))) showMark = true;
if (hDown & KEY_SELECT) {
sFetch = true;
mode = 5;
if ((hDown & KEY_SELECT) || (hDown & KEY_TOUCH && touching(touch, sshot))) {
if (checkWifiStatus()) {
sFetch = true;
mode = 5;
}
}
}
+2 -2
View File
@@ -35,7 +35,7 @@ static const std::vector<Structs::ButtonPos> markBox = {
{ 196, 94, 52, 52 },
{ 258, 94, 52, 52 },
{ 53, 215, 20, 20 }
{ 53, 215, 24, 24 }
};
/*
@@ -68,7 +68,7 @@ void StoreUtils::DisplayMarkBox(int marks) {
Gui::DrawString(markBox[4].x + 15, markBox[4].y + 11, 0.9, TEXT_COLOR, "", 0, 0, font);
GFX::DrawBox(markBox[5].x, markBox[5].y, markBox[5].w, markBox[5].h, false);
Gui::DrawString(markBox[5].x + 3, markBox[5].y, 0.6f, TEXT_COLOR, "", 0, 0, font);
Gui::DrawString(markBox[5].x + 5, markBox[5].y + 2, 0.6f, TEXT_COLOR, "", 0, 0, font);
}
/*
+75 -51
View File
@@ -28,6 +28,7 @@
#include "structs.hpp"
extern bool touching(touchPosition touch, Structs::ButtonPos button);
extern bool checkWifiStatus();
/*
Draw the Screenshot menu.
@@ -38,56 +39,73 @@ extern bool touching(touchPosition touch, Structs::ButtonPos button);
const int screenshotSize: The screenshot amount.
const std::string &name: The name of the screenshot.
const int zoom: The zoom level, zoom out, 1x scale, or zoom in.
const bool canDisplay: If can display, or not.
*/
void StoreUtils::DrawScreenshotMenu(const C2D_Image &img, const int sIndex, const bool sFetch, const int screenshotSize, const std::string &name, const int zoom) {
void StoreUtils::DrawScreenshotMenu(const C2D_Image &img, const int sIndex, const bool sFetch, const int screenshotSize, const std::string &name, const int zoom, const bool canDisplay) {
Gui::ScreenDraw(Top);
Gui::Draw_Rect(0, 0, 400, 240, BG_COLOR);
if (screenshotSize > 0) {
float scale = 1.0f;
if (zoom == 0) {
scale = std::min(1.0f, std::min(400.0f / img.subtex->width, 240.0f / img.subtex->height));
if (img.tex) C2D_DrawImageAt(img, (400 - img.subtex->width * scale) / 2, (240 - img.subtex->height * scale) / 2, 0.5f, nullptr, scale, scale);
} else {
// Create new C2D_Image with smaller subtex
C2D_Image top = img;
if (img.subtex->height > 240)
top.subtex = new Tex3DS_SubTexture({img.subtex->width, (u16)(img.subtex->height / 2), img.subtex->left, img.subtex->top, img.subtex->right, 1.0f - (img.subtex->height / 2 / 512.0f)});
// If zoom == 2, then zoom in to fit the screen
if (zoom == 2)
scale = std::min(400.0f / top.subtex->width, 240.0f / top.subtex->height);
if (top.tex) C2D_DrawImageAt(top, (400 - top.subtex->width * scale) / 2, (240 - top.subtex->height * scale) / 2, 0.5f, nullptr, scale, scale);
// Only delete if new
if (top.subtex->height > 240)
delete top.subtex;
}
if (!canDisplay) {
GFX::DrawBottom();
/* Bottom. */
if (zoom > 0 && img.subtex->height * scale > 240) {
C2D_Image bottom = img;
bottom.subtex = new Tex3DS_SubTexture({img.subtex->width, (u16)(img.subtex->height / 2), img.subtex->left, img.subtex->bottom + (img.subtex->height / 2 / 512.0f), img.subtex->right, img.subtex->bottom});
if (bottom.tex) C2D_DrawImageAt(bottom, (320 - bottom.subtex->width * scale) / 2, (240 - bottom.subtex->height * scale) / 2, 0.5f, nullptr, scale, scale);
delete bottom.subtex;
if (screenshotSize > 0) { // if texture is nullptr AND screenshot size is larger than 0.
Gui::DrawStringCentered(0, 2, 0.6f, WHITE, Lang::get("SCREENSHOT_COULD_NOT_LOAD"), 310);
} else {
Gui::Draw_Rect(0, 215, 320, 25, BAR_COLOR);
Gui::Draw_Rect(0, 214, 320, 1, BAR_OUTL_COLOR);
Gui::DrawStringCentered(0, 220, 0.5f, TEXT_COLOR, Lang::get("SCREENSHOT_INSTRUCTIONS"), 310, 0, font);
char screenshots[0x100];
snprintf(screenshots, sizeof(screenshots), Lang::get("SCREENSHOT").c_str(), sIndex + 1, screenshotSize);
Gui::DrawStringCentered(0, 2, 0.6f, WHITE, screenshots, 310, 0, font);
Gui::DrawStringCentered(0, 40, 0.6f, WHITE, name, 310, 0, font);
Gui::DrawStringCentered(0, 2, 0.6f, WHITE, Lang::get("NO_SCREENSHOTS_AVAILABLE"), 310);
}
} else {
GFX::DrawBottom();
Gui::DrawStringCentered(0, 2, 0.6f, WHITE, Lang::get("NO_SCREENSHOTS_AVAILABLE"), 310);
return;
}
if (!sFetch) { // Only, if not fetch. This avoids a small flicker of the old screenshot on entries without screenshots.
if (screenshotSize > 0) {
float scale = 1.0f;
if (zoom == 0) {
scale = std::min(1.0f, std::min(400.0f / img.subtex->width, 240.0f / img.subtex->height));
if (img.tex) C2D_DrawImageAt(img, (400 - img.subtex->width * scale) / 2, (240 - img.subtex->height * scale) / 2, 0.5f, nullptr, scale, scale);
} else {
// Create new C2D_Image with smaller subtex
C2D_Image top = img;
if (img.subtex->height > 240)
top.subtex = new Tex3DS_SubTexture({img.subtex->width, (u16)(img.subtex->height / 2), img.subtex->left, img.subtex->top, img.subtex->right, 1.0f - (img.subtex->height / 2 / 512.0f)});
// If zoom == 2, then zoom in to fit the screen
if (zoom == 2)
scale = std::min(400.0f / top.subtex->width, 240.0f / top.subtex->height);
if (top.tex) C2D_DrawImageAt(top, (400 - top.subtex->width * scale) / 2, (240 - top.subtex->height * scale) / 2, 0.5f, nullptr, scale, scale);
// Only delete if new
if (top.subtex->height > 240)
delete top.subtex;
}
GFX::DrawBottom();
/* Bottom. */
if (zoom > 0 && img.subtex->height * scale > 240) {
C2D_Image bottom = img;
bottom.subtex = new Tex3DS_SubTexture({img.subtex->width, (u16)(img.subtex->height / 2), img.subtex->left, img.subtex->bottom + (img.subtex->height / 2 / 512.0f), img.subtex->right, img.subtex->bottom});
if (bottom.tex) C2D_DrawImageAt(bottom, (320 - bottom.subtex->width * scale) / 2, (240 - bottom.subtex->height * scale) / 2, 0.5f, nullptr, scale, scale);
delete bottom.subtex;
} else {
Gui::Draw_Rect(0, 215, 320, 25, BAR_COLOR);
Gui::Draw_Rect(0, 214, 320, 1, BAR_OUTL_COLOR);
Gui::DrawStringCentered(0, 220, 0.5f, TEXT_COLOR, Lang::get("SCREENSHOT_INSTRUCTIONS"), 310, 0, font);
char screenshots[0x100];
snprintf(screenshots, sizeof(screenshots), Lang::get("SCREENSHOT").c_str(), sIndex + 1, screenshotSize);
Gui::DrawStringCentered(0, 2, 0.6f, WHITE, screenshots, 310, 0, font);
Gui::DrawStringCentered(0, 40, 0.6f, WHITE, name, 310, 0, font);
}
} else {
GFX::DrawBottom();
Gui::DrawStringCentered(0, 2, 0.6f, WHITE, Lang::get("NO_SCREENSHOTS_AVAILABLE"), 310);
}
}
}
@@ -99,18 +117,22 @@ void StoreUtils::DrawScreenshotMenu(const C2D_Image &img, const int sIndex, cons
bool &sFetch: If fetching screenshots or not.
const int screenshotSize: The screenshot amount.
int &zoom: The zoom level, zoom out, 1x scale, or zoom in.
bool &canDisplay: If can display or not.
*/
void StoreUtils::ScreenshotMenu(C2D_Image &img, int &sIndex, bool &sFetch, int &storeMode, const int screenshotSize, int &zoom) {
void StoreUtils::ScreenshotMenu(C2D_Image &img, int &sIndex, bool &sFetch, int &storeMode, const int screenshotSize, int &zoom, bool &canDisplay) {
if (hDown & KEY_B) {
zoom = false;
canDisplay = false;
zoom = 0;
sIndex = 0;
storeMode = 0; // Go back to EntryInfo.
}
if (hDown & KEY_RIGHT) {
if (sIndex < screenshotSize - 1) {
sIndex++;
sFetch = true;
if ((hDown & KEY_RIGHT) || (hDown & KEY_R)) {
if (checkWifiStatus()) {
if (sIndex < screenshotSize - 1) {
sIndex++;
sFetch = true;
}
}
}
@@ -118,10 +140,12 @@ void StoreUtils::ScreenshotMenu(C2D_Image &img, int &sIndex, bool &sFetch, int &
if (hDown & KEY_UP && zoom < 2) zoom++;
if (hDown & KEY_LEFT) {
if (sIndex > 0) {
sIndex--;
sFetch = true;
if ((hDown & KEY_LEFT) || (hDown & KEY_L)) {
if (checkWifiStatus()) {
if (sIndex > 0) {
sIndex--;
sFetch = true;
}
}
}
}
+5 -3
View File
@@ -112,8 +112,10 @@ Config::Config() {
/* Let us create a new one. */
if (!this->json.contains("Version")) this->initialize();
if (!this->json.contains("Language")) this->sysLang();
else this->language(this->getString("Language"));
if (this->json.contains("LastStore")) this->lastStore(this->getString("LastStore"));
if (this->json.contains("List")) this->list(this->getBool("List"));
if (this->json.contains("AutoUpdate")) this->autoupdate(this->getBool("AutoUpdate"));
@@ -160,20 +162,20 @@ void Config::save() {
bool Config::getBool(const std::string &key) {
if (!this->json.contains(key)) return false;
return this->json.at(key).get_ref<const bool&>();
return this->json.at(key).get_ref<const bool &>();
}
void Config::setBool(const std::string &key, bool v) { this->json[key] = v; };
int Config::getInt(const std::string &key) {
if (!this->json.contains(key)) return 0;
return this->json.at(key).get_ref<const int64_t&>();
return this->json.at(key).get_ref<const int64_t &>();
}
void Config::setInt(const std::string &key, int v) { this->json[key] = v; };
std::string Config::getString(const std::string &key) {
if (!this->json.contains(key)) return "";
return this->json.at(key).get_ref<const std::string&>();
return this->json.at(key).get_ref<const std::string &>();
}
void Config::setString(const std::string &key, const std::string &v) { this->json[key] = v; };
+1 -1
View File
@@ -864,7 +864,7 @@ static StoreList fetch(const std::string &entry, nlohmann::json &js) {
Fetch Store list for available UniStores.
*/
std::vector<StoreList> FetchStores() {
Msg::DisplayMsg(Lang::get("FETCHING_AVAILABLE_UNISTORES"));
Msg::DisplayMsg(Lang::get("FETCHING_RECOMMENDED_UNISTORES"));
std::vector<StoreList> stores = { };
Result ret = 0;
+166
View File
@@ -0,0 +1,166 @@
/*
* This file is part of Universal-Updater
* Copyright (C) 2019-2020 Universal-Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "sound.hpp"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
/*
Reference: http://yannesposito.com/Scratch/en/blog/2010-10-14-Fun-with-wav/
*/
typedef struct _WavHeader {
char magic[4]; // "RIFF"
u32 totallength; // Total file length, minus 8.
char wavefmt[8]; // Should be "WAVEfmt ".
u32 format; // 16 for PCM format.
u16 pcm; // 1 for PCM format.
u16 channels; // Channels.
u32 frequency; // Sampling frequency.
u32 bytes_per_second;
u16 bytes_by_capture;
u16 bits_per_sample;
char data[4]; // "data".
u32 bytes_in_data;
} WavHeader;
static_assert(sizeof(WavHeader) == 44, "WavHeader size is not 44 bytes.");
#define _MAX_SIZE 10485760 // 10 MiB.
/*
Initialize the sound.
const std::string &path: Path to the file to play.
const int channel: The channel to use. 1 by default.
const bool toloop: If should loop or not. True by default.
*/
Sound::Sound(const std::string &path, const int channel, const bool toloop) {
ndspSetOutputMode(NDSP_OUTPUT_MONO);
ndspSetOutputCount(2); // Amount of buffers.
/* Reading wav file. */
FILE *file = fopen(path.c_str(), "rb");
if (!file) {
printf("Could not open the WAV file: %s.\n", path.c_str());
this->good = false;
return;
}
WavHeader wavHeader;
size_t read = fread(&wavHeader, 1, sizeof(wavHeader), file);
if (read != sizeof(wavHeader)) {
/* Short read. */
printf("WAV file header is too short: %s.\n", path.c_str());
fclose(file);
this->good = false;
return;
}
/* Verify the header. */
static const char RIFF_magic[4] = { 'R','I','F','F' };
if (memcmp(wavHeader.magic, RIFF_magic, sizeof(wavHeader.magic)) != 0) {
/* Incorrect magic number. */
printf("Wrong file format.\n");
fclose(file);
this->good = false;
return;
}
if (wavHeader.totallength == 0 ||
(wavHeader.channels != 1 && wavHeader.channels != 2) ||
(wavHeader.bits_per_sample != 8 && wavHeader.bits_per_sample != 16)) {
/* Unsupported WAV file. */
printf("Corrupted wav file.\n");
fclose(file);
this->good = false;
return;
}
/* Get the file size. */
fseek(file, 0, SEEK_END);
this->dataSize = ftell(file) - sizeof(wavHeader);
if (this->dataSize > _MAX_SIZE) {
fclose(file);
this->good = false;
return;
}
/* Allocating and reading samples. */
this->data = reinterpret_cast<u8 *>(linearAlloc(this->dataSize));
fseek(file, 44, SEEK_SET);
fread(this->data, 1, this->dataSize, file);
fclose(file);
//if (wavHeader.bits_per_sample == 16) this->dataSize /= 2; // Not sure.. if that is actually needed at all.
this->chnl = channel;
ndspChnReset(this->chnl);
ndspChnSetInterp(this->chnl, NDSP_INTERP_NONE);
ndspChnSetRate(this->chnl, float(wavHeader.frequency));
ndspChnSetFormat(this->chnl, ((wavHeader.bits_per_sample == 8) ? NDSP_FORMAT_MONO_PCM8 : NDSP_FORMAT_MONO_PCM16));
/* Create and play a wav buffer. */
memset(&this->waveBuf, 0, sizeof(this->waveBuf));
this->waveBuf.data_vaddr = reinterpret_cast<u32 *>(this->data);
this->waveBuf.nsamples = this->dataSize / (wavHeader.bits_per_sample >> 3);
this->waveBuf.looping = toloop;
this->waveBuf.status = NDSP_WBUF_FREE;
}
Sound::~Sound() {
if (this->good) {
this->waveBuf.data_vaddr = 0;
this->waveBuf.nsamples = 0;
this->waveBuf.looping = false;
this->waveBuf.status = 0;
ndspChnWaveBufClear(this->chnl);
if (this->data) linearFree(this->data);
}
}
/*
Plays the sound.
*/
void Sound::play() {
if (!this->data || !this->good) return;
DSP_FlushDataCache(this->data, this->dataSize);
ndspChnWaveBufAdd(this->chnl, &this->waveBuf);
}
/*
Stops the sound.
*/
void Sound::stop() {
if (!this->data || !this->good) return;
ndspChnWaveBufClear(this->chnl);
}