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
commit 64977911e6
22 changed files with 450 additions and 161 deletions

View file

@ -49,4 +49,5 @@ To build Universal-Updater from source, you will need to setup devkitARM with li
- [dlbeer](https://github.com/dlbeer) - Original developer of [quirc](https://github.com/dlbeer/quirc)
- [FlagBrew](https://github.com/FlagBrew): Original QR Code Scanner code
- [Icons8](https://icons8.com/): Icon Designer
- [lvandeve](https://github.com/lvandeve): For [LodePNG](https://github.com/lvandeve/lodepng)
- [PabloMK7](https://github.com/mariohackandglitch): Download Code Improvements

View file

@ -7,8 +7,11 @@ sprites/checked.png
sprites/delete.png
sprites/download.png
sprites/info.png
sprites/keyboard.png
sprites/list.png
sprites/noIcon.png
sprites/qr_code.png
sprites/screenshot.png
sprites/search.png
sprites/settings.png
sprites/shortcut.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

BIN
assets/gfx/sprites/list.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 387 B

After

Width:  |  Height:  |  Size: 377 B

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

View file

@ -67,16 +67,10 @@ public:
void drawThread();
void captureThread();
void handler(std::vector<u8>& out);
void handler(std::string &result);
bool done() const { return this->finished; };
bool cancelled() const { return this->cancel; };
bool Mode() const { return this->mode; };
void Info(bool v) { this->displayInfo = v; };
int selectedStore = 0, sPos = 0;
std::vector<StoreList> stores = { };
bool FromList = false;
uint8_t timeout = 30;
void List(bool v) { this->displayList = v; };
private:
void buffToImage();
void finish();
@ -90,9 +84,10 @@ private:
std::atomic<bool> finished = false;
bool capturing = false;
bool cancel = false;
bool mode = true; // True -> Camera, False -> URL.
bool displayInfo = false;
bool displayList = false;
int selectedStore = 0, sPos = 0;
std::vector<StoreList> stores = { };
std::vector<u8> out;
};
/*

View file

@ -55,7 +55,7 @@ private:
std::vector<std::string> dwnldList, dwnldSizes;
bool initialized = false, fetchDown = false, showMarks = false, showSettings = false,
ascending = false, updateFilter = false, screenshotFetch = false;
ascending = false, updateFilter = false, screenshotFetch = false, canDisplay = false;
int storeMode = 0, marks = 0, markIndex = 0, sPage = 0, lMode = 0, sSelection = 0,
lastMode = 0, smallDelay = 0, sPos = 0, screenshotIndex = 0, sSize = 0, zoom = 0;

View file

@ -71,8 +71,8 @@ namespace StoreUtils {
void DrawCredits();
/* Screenshot menu. */
void DrawScreenshotMenu(const C2D_Image &img, const int sIndex, const bool sFetch, const int screenshotSize, const std::string &name, const int zoom);
void ScreenshotMenu(C2D_Image &img, int &sIndex, bool &sFetch, int &storeMode, const int screenshotSize, int &zoom);
void DrawScreenshotMenu(const C2D_Image &img, const int sIndex, const bool sFetch, const int screenshotSize, const std::string &name, const int zoom, const bool canDisplay);
void ScreenshotMenu(C2D_Image &img, int &sIndex, bool &sFetch, int &storeMode, const int screenshotSize, int &zoom, bool &canDisplay);
/* Settings. */
void DrawSettings(int page, int selection, int sPos);

47
include/utils/sound.hpp Normal file
View file

@ -0,0 +1,47 @@
/*
* 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.
*/
#ifndef _UNIVERSAL_UPDATER_SOUND_HPP
#define _UNIVERSAL_UPDATER_SOUND_HPP
#include <3ds.h>
#include <string>
class Sound {
public:
Sound(const std::string &path, const int channel = 1, const bool toloop = true);
~Sound();
void play();
void stop();
private:
u32 dataSize;
bool good = true;
ndspWaveBuf waveBuf;
u8 *data = nullptr;
int chnl;
};
#endif

View file

@ -9,7 +9,6 @@
"AUTO_UPDATE_UU": "Auto-update Universal-Updater",
"AUTO_UPDATE_UU_DESC": "When enabled, Universal-Updater will check for updates every time it's opened.",
"AVAILABLE_DOWNLOADS": "Available Downloads",
"AVAILABLE_UNISTORES": "Available UniStores",
"BOOT_TITLE": "Would you like to boot this title?",
"CATEGORY": "Category",
"CHANGE_3DSX_PATH": "Change 3DSX path",
@ -57,8 +56,8 @@
"ENTRIES": "Entries",
"EXECUTE_ENTRY": "Would you like to execute this entry?",
"EXIT_APP": "Exit Universal-Updater",
"FETCHING_AVAILABLE_UNISTORES": "Fetching available UniStores...",
"FETCHING_METADATA": "Fetching old metadata...",
"FETCHING_RECOMMENDED_UNISTORES": "Fetching recommended UniStores...",
"FILE_EXTRACTED": "file extracted.",
"FILE_SLASH": "Seems like a '/' is included, which is not supported.\nPlease change 'file' to filename only.",
"FILES_EXTRACTED": "files extracted.",
@ -84,8 +83,10 @@
"NO_LICENSE": "No License",
"NO_SCREENSHOTS_AVAILABLE": "No Screenshots available",
"NOT_IMPLEMENTED": "Not Implemented Yet",
"RECOMMENDED_UNISTORES": "Recommended UniStores",
"REVISION": "Revision",
"SCREENSHOT": "Screenshot %d / %d",
"SCREENSHOT_COULD_NOT_LOAD": "Screenshot could not be loaded.",
"SCREENSHOT_INSTRUCTIONS": "Press  to change and  to zoom",
"SEARCH_FILTERS": "Search and Filters",
"SELECT_DIR": "Select a directory",

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();

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);

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;
}
}

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,14 +146,20 @@ 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);
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);
@ -165,14 +177,18 @@ void QRCode::drawThread() {
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);
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::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;
}
}
}
} else {
if (this->displayList) {
gspWaitForVBlank();
if ((keyDown & KEY_SELECT) || (keyDown & KEY_TOUCH && touching(t, mainButtons[6]))) {
keyDown = 0;
this->displayList = false;
}
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;
}

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;
}

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) {
if ((hDown & KEY_SELECT) || (hDown & KEY_TOUCH && touching(touch, sshot))) {
if (checkWifiStatus()) {
sFetch = true;
mode = 5;
}
}
}

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);
}
/*

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,16 +39,32 @@ 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 (!canDisplay) {
GFX::DrawBottom();
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::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;
@ -89,6 +106,7 @@ void StoreUtils::DrawScreenshotMenu(const C2D_Image &img, const int sIndex, cons
GFX::DrawBottom();
Gui::DrawStringCentered(0, 2, 0.6f, WHITE, Lang::get("NO_SCREENSHOTS_AVAILABLE"), 310);
}
}
}
/*
@ -99,29 +117,35 @@ 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 ((hDown & KEY_RIGHT) || (hDown & KEY_R)) {
if (checkWifiStatus()) {
if (sIndex < screenshotSize - 1) {
sIndex++;
sFetch = true;
}
}
}
if (hDown & KEY_DOWN && zoom > 0) zoom--;
if (hDown & KEY_UP && zoom < 2) zoom++;
if (hDown & KEY_LEFT) {
if ((hDown & KEY_LEFT) || (hDown & KEY_L)) {
if (checkWifiStatus()) {
if (sIndex > 0) {
sIndex--;
sFetch = true;
}
}
}
}

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; };

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
source/utils/sound.cpp Normal file
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);
}