mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-08 12:35:08 +01:00
a66a30a771
*added support to control screen pointer with gc pad or classic controller. you are always able to control as long as the corresponding wii control does not point to the screen (e.g. wiimote 1 not pointing to screen -> gcpad/classic controller 1 can control pointer 1). a speed factor is added to the gui option. need feedback about a proper default value, currently 15% (only tested gc pad on dolphin-emu) *fix reinit of cheatcount on download of new file *moved installation window to be on top of main window *added game installation cancel *added nand extract cancel *added back extract of save feature for a real nand channels *added auto position of progress window messages in vertical direction depending of how many are used at the same time
521 lines
14 KiB
C++
521 lines
14 KiB
C++
/****************************************************************************
|
|
* ProgressWindow
|
|
* USB Loader GX 2009
|
|
*
|
|
* ProgressWindow.cpp
|
|
***************************************************************************/
|
|
#include <gccore.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "menu/menus.h"
|
|
#include "sys.h"
|
|
#include "language/gettext.h"
|
|
#include "GUI/gui.h"
|
|
#include "prompts/ProgressWindow.h"
|
|
#include "usbloader/wbfs.h"
|
|
#include "usbloader/utils.h"
|
|
#include "themes/CTheme.h"
|
|
#include "utils/timer.h"
|
|
|
|
extern float gamesize;
|
|
extern int install_abort_signal;
|
|
|
|
/*** Variables used only in this file ***/
|
|
static lwp_t progressthread = LWP_THREAD_NULL;
|
|
static mutex_t ProgressMutex = LWP_MUTEX_NULL;
|
|
static bool CancelEnabled = false;
|
|
static bool progressCanceled = false;
|
|
static char progressTitle[75];
|
|
static char progressMsg1[75];
|
|
static char progressMsg2[75];
|
|
static Timer ProgressTimer;
|
|
static int showProgress = 0;
|
|
static s64 progressDone = -1;
|
|
static s64 progressTotal = -1;
|
|
static bool showTime = false;
|
|
static bool showSize = false;
|
|
static bool changed = true;
|
|
static bool changedMessages = true;
|
|
|
|
/****************************************************************************
|
|
* StartProgress
|
|
***************************************************************************/
|
|
extern "C" void StartProgress(const char * title, const char * msg1, const char * msg2, bool swSize, bool swTime)
|
|
{
|
|
if(title)
|
|
strncpy(progressTitle, title, sizeof(progressTitle)-1);
|
|
else
|
|
progressTitle[0] = '\0';
|
|
|
|
if(msg1)
|
|
strncpy(progressMsg1, msg1, sizeof(progressMsg1)-1);
|
|
else
|
|
progressMsg1[0] = '\0';
|
|
|
|
if(msg2)
|
|
strncpy(progressMsg2, msg2, sizeof(progressMsg2)-1);
|
|
else
|
|
progressMsg2[0] = '\0';
|
|
|
|
progressCanceled = false;
|
|
showSize = swSize;
|
|
showTime = swTime;
|
|
showProgress = 1;
|
|
ProgressTimer.reset();
|
|
|
|
LWP_ResumeThread(progressthread);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* ShowProgress
|
|
*
|
|
* Callbackfunction for updating the progress values
|
|
* Use this function as standard callback
|
|
***************************************************************************/
|
|
extern "C" void ShowProgress(s64 done, s64 total)
|
|
{
|
|
LWP_MutexLock(ProgressMutex);
|
|
progressDone = done;
|
|
progressTotal = total;
|
|
if(!done)
|
|
{
|
|
ProgressTimer.reset();
|
|
LWP_ResumeThread(progressthread);
|
|
showProgress = 1;
|
|
}
|
|
changed = true;
|
|
LWP_MutexUnlock(ProgressMutex);
|
|
}
|
|
|
|
void ShowProgress(const char *msg2, s64 done, s64 total)
|
|
{
|
|
if (done > total)
|
|
done = total;
|
|
|
|
LWP_MutexLock(ProgressMutex);
|
|
|
|
if(total >= 0)
|
|
{
|
|
progressDone = done;
|
|
progressTotal = total;
|
|
}
|
|
|
|
if(msg2)
|
|
strncpy(progressMsg2, msg2, sizeof(progressMsg2)-1);
|
|
else
|
|
progressMsg2[0] = '\0';
|
|
|
|
if(!done)
|
|
{
|
|
ProgressTimer.reset();
|
|
LWP_ResumeThread(progressthread);
|
|
showProgress = 1;
|
|
}
|
|
|
|
changedMessages = true;
|
|
changed = true;
|
|
|
|
LWP_MutexUnlock(ProgressMutex);
|
|
}
|
|
|
|
void ShowProgress(const char *title, const char *msg1, const char *msg2, s64 done, s64 total, bool swSize, bool swTime)
|
|
{
|
|
if (done > total)
|
|
done = total;
|
|
|
|
LWP_MutexLock(ProgressMutex);
|
|
|
|
if(total >= 0)
|
|
{
|
|
progressDone = done;
|
|
progressTotal = total;
|
|
}
|
|
|
|
if(title)
|
|
strncpy(progressTitle, title, sizeof(progressTitle)-1);
|
|
else
|
|
progressTitle[0] = '\0';
|
|
|
|
if(msg1)
|
|
strncpy(progressMsg1, msg1, sizeof(progressMsg1)-1);
|
|
else
|
|
progressMsg1[0] = '\0';
|
|
|
|
if(msg2)
|
|
strncpy(progressMsg2, msg2, sizeof(progressMsg2)-1);
|
|
else
|
|
progressMsg2[0] = '\0';
|
|
|
|
showSize = swSize;
|
|
showTime = swTime;
|
|
|
|
if(!done)
|
|
{
|
|
ProgressTimer.reset();
|
|
LWP_ResumeThread(progressthread);
|
|
showProgress = 1;
|
|
}
|
|
|
|
changedMessages = true;
|
|
changed = true;
|
|
|
|
LWP_MutexUnlock(ProgressMutex);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* ProgressStop
|
|
***************************************************************************/
|
|
extern "C" void ProgressStop()
|
|
{
|
|
progressCanceled = false;
|
|
showProgress = 0;
|
|
progressTitle[0] = 0;
|
|
progressMsg1[0] = 0;
|
|
progressMsg2[0] = 0;
|
|
progressDone = -1;
|
|
progressTotal = -1;
|
|
showTime = false;
|
|
showSize = false;
|
|
|
|
// wait for thread to finish
|
|
while (!LWP_ThreadIsSuspended(progressthread))
|
|
usleep(100);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* ProgressCancelEnable
|
|
*
|
|
* Enable/disable the progress cancel button
|
|
***************************************************************************/
|
|
extern "C" void ProgressCancelEnable(bool enable)
|
|
{
|
|
CancelEnabled = enable;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* ProgressCanceled
|
|
***************************************************************************/
|
|
extern "C" bool ProgressCanceled()
|
|
{
|
|
return progressCanceled;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* UpdateProgressValues
|
|
***************************************************************************/
|
|
static void UpdateProgressValues(GuiImage *progressbarImg, GuiText *prTxt, GuiText *timeTxt, GuiText *speedTxt, GuiText *sizeTxt)
|
|
{
|
|
if(!changed)
|
|
return;
|
|
|
|
LWP_MutexLock(ProgressMutex);
|
|
changed = false;
|
|
changedMessages = false;
|
|
s64 done = progressDone;
|
|
s64 total = progressTotal;
|
|
u32 speed = 0;
|
|
|
|
if(gamesize > 0.0f)
|
|
{
|
|
done = (s64) ((float) done / (float) total * gamesize);
|
|
total = (s64) gamesize;
|
|
|
|
if(progressCanceled)
|
|
install_abort_signal = 1;
|
|
}
|
|
|
|
//Calculate speed in KB/s
|
|
if (ProgressTimer.elapsed() > 0.0f)
|
|
speed = (u32) (done/ProgressTimer.elapsed());
|
|
|
|
LWP_MutexUnlock(ProgressMutex);
|
|
|
|
u32 TimeLeft = 0, h = 0, m = 0, s = 0;
|
|
if(speed > 0)
|
|
TimeLeft = (total-done)/speed;
|
|
|
|
if(TimeLeft > 0)
|
|
{
|
|
h = TimeLeft / 3600;
|
|
m = (TimeLeft / 60) % 60;
|
|
s = TimeLeft % 60;
|
|
}
|
|
|
|
float progressPercent = 100.0 * done / total;
|
|
|
|
prTxt->SetTextf("%.2f", progressPercent);
|
|
|
|
if (Settings.widescreen && Settings.wsprompt)
|
|
progressbarImg->SetSkew(0, 0, static_cast<int> (progressbarImg->GetWidth() * progressPercent * Settings.WSFactor)
|
|
- progressbarImg->GetWidth(), 0, static_cast<int> (progressbarImg->GetWidth() * progressPercent
|
|
* Settings.WSFactor) - progressbarImg->GetWidth(), 0, 0, 0);
|
|
else
|
|
progressbarImg->SetSkew(0, 0, static_cast<int> (progressbarImg->GetWidth() * progressPercent)
|
|
- progressbarImg->GetWidth(), 0, static_cast<int> (progressbarImg->GetWidth() * progressPercent)
|
|
- progressbarImg->GetWidth(), 0, 0, 0);
|
|
|
|
if (showTime == true)
|
|
{
|
|
timeTxt->SetTextf("%s %d:%02d:%02d", tr( "Time left:" ), h, m, s);
|
|
}
|
|
|
|
if (showSize == true)
|
|
{
|
|
if (total < MB_SIZE)
|
|
sizeTxt->SetTextf("%0.2fKB/%0.2fKB", done / KB_SIZE, total / KB_SIZE);
|
|
else if (total > MB_SIZE && total < GB_SIZE)
|
|
sizeTxt->SetTextf("%0.2fMB/%0.2fMB", done / MB_SIZE, total / MB_SIZE);
|
|
else
|
|
sizeTxt->SetTextf("%0.2fGB/%0.2fGB", done / GB_SIZE, total / GB_SIZE);
|
|
|
|
speedTxt->SetTextf("%dKB/s", (int) (speed/KB_SIZE));
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* ProgressWindow
|
|
*
|
|
* Opens a window, which displays progress to the user. Can either display a
|
|
* progress bar showing % completion, or a throbber that only shows that an
|
|
* action is in progress.
|
|
***************************************************************************/
|
|
static void ProgressWindow(const char *title, const char *msg1, const char *msg2)
|
|
{
|
|
progressCanceled = false;
|
|
|
|
usleep(500000); // wait to see if progress flag changes soon
|
|
if (!showProgress) return;
|
|
|
|
int PosY;
|
|
|
|
//if(msg2 != 0)
|
|
// PosY = 40;
|
|
//else
|
|
PosY = 20;
|
|
|
|
GuiWindow promptWindow(472, 320);
|
|
promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);
|
|
promptWindow.SetPosition(0, -10);
|
|
|
|
GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png"));
|
|
GuiImageData dialogBox(Resources::GetFile("dialogue_box.png"), Resources::GetFileSize("dialogue_box.png"));
|
|
|
|
GuiTrigger trigA;
|
|
trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
|
|
|
|
GuiImage dialogBoxImg(&dialogBox);
|
|
if (Settings.wsprompt)
|
|
{
|
|
dialogBoxImg.SetWidescreen(Settings.widescreen);
|
|
}
|
|
|
|
GuiImageData progressbarOutline(Resources::GetFile("progressbar_outline.png"), Resources::GetFileSize("progressbar_outline.png"));
|
|
|
|
GuiImage progressbarOutlineImg(&progressbarOutline);
|
|
if (Settings.wsprompt)
|
|
{
|
|
progressbarOutlineImg.SetWidescreen(Settings.widescreen);
|
|
}
|
|
progressbarOutlineImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
|
progressbarOutlineImg.SetPosition(35, PosY);
|
|
|
|
GuiImageData progressbarEmpty(Resources::GetFile("progressbar_empty.png"), Resources::GetFileSize("button_dialogue_box.png"));
|
|
GuiImage progressbarEmptyImg(&progressbarEmpty);
|
|
progressbarEmptyImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
|
progressbarEmptyImg.SetPosition(35, PosY);
|
|
progressbarEmptyImg.SetTileHorizontal(100);
|
|
|
|
GuiImageData progressbar(Resources::GetFile("progressbar.png"), Resources::GetFileSize("progressbar.png"));
|
|
GuiImage progressbarImg(&progressbar);
|
|
progressbarImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
|
progressbarImg.SetPosition(35, PosY);
|
|
|
|
GuiText titleTxt(title, 26, thColor("r=0 g=0 b=0 a=255 - prompt windows text color"));
|
|
titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
|
titleTxt.SetPosition(0, 50);
|
|
|
|
GuiText msg1Txt(msg1, 22, thColor("r=0 g=0 b=0 a=255 - prompt windows text color"));
|
|
msg1Txt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
|
msg1Txt.SetPosition(0, 90);
|
|
msg1Txt.SetMaxWidth(430, DOTTED);
|
|
|
|
GuiText msg2Txt(msg2, 22, thColor("r=0 g=0 b=0 a=255 - prompt windows text color"));
|
|
msg2Txt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
|
msg2Txt.SetPosition(0, 125);
|
|
msg2Txt.SetMaxWidth(430, DOTTED);
|
|
|
|
GuiText prsTxt("%", 22, thColor("r=0 g=0 b=0 a=255 - prompt windows text color"));
|
|
prsTxt.SetAlignment(ALIGN_RIGHT, ALIGN_MIDDLE);
|
|
prsTxt.SetPosition(-178, PosY);
|
|
|
|
GuiText timeTxt((char*) NULL, 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color"));
|
|
timeTxt.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
|
|
timeTxt.SetPosition(280, -50);
|
|
|
|
GuiText sizeTxt((char*) NULL, 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color"));
|
|
sizeTxt.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
|
|
sizeTxt.SetPosition(50, -50);
|
|
|
|
GuiText speedTxt((char*) NULL, 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color"));
|
|
speedTxt.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
|
|
speedTxt.SetPosition(50, -74);
|
|
|
|
GuiText prTxt((char*) NULL, 22, thColor("r=0 g=0 b=0 a=255 - prompt windows text color"));
|
|
prTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
|
prTxt.SetPosition(210, PosY);
|
|
|
|
if ((Settings.wsprompt) && (Settings.widescreen)) /////////////adjust for widescreen
|
|
{
|
|
progressbarOutlineImg.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);
|
|
progressbarOutlineImg.SetPosition(0, PosY);
|
|
progressbarEmptyImg.SetPosition(80, PosY);
|
|
progressbarEmptyImg.SetTileHorizontal(78);
|
|
progressbarImg.SetPosition(80, PosY);
|
|
msg1Txt.SetMaxWidth(380, DOTTED);
|
|
msg2Txt.SetMaxWidth(380, DOTTED);
|
|
|
|
timeTxt.SetPosition(250, -50);
|
|
timeTxt.SetFontSize(20);
|
|
speedTxt.SetPosition(90, -74);
|
|
speedTxt.SetFontSize(20);
|
|
sizeTxt.SetPosition(90, -50);
|
|
sizeTxt.SetFontSize(20);
|
|
}
|
|
|
|
GuiText cancelTxt(tr( "Cancel" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color"));
|
|
GuiImage cancelImg(&btnOutline);
|
|
const float cancelScale = 0.8f;
|
|
cancelImg.SetScale(cancelScale);
|
|
cancelTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
|
cancelTxt.SetPosition(cancelImg.GetWidth()/2*cancelScale-cancelTxt.GetTextWidth()/2, 0);
|
|
if (Settings.wsprompt)
|
|
{
|
|
cancelTxt.SetWidescreen(Settings.widescreen);
|
|
cancelImg.SetWidescreen(Settings.widescreen);
|
|
}
|
|
|
|
GuiButton cancelBtn(&cancelImg, &cancelImg, ALIGN_LEFT, ALIGN_MIDDLE, 0, 0, &trigA, btnSoundOver, btnSoundClick2, 1);
|
|
cancelBtn.SetLabel(&cancelTxt);
|
|
cancelBtn.SetState(STATE_SELECTED);
|
|
cancelBtn.SetPosition(dialogBoxImg.GetWidth()/2-cancelImg.GetWidth()/2*cancelScale, PosY + 45);
|
|
|
|
promptWindow.Append(&dialogBoxImg);
|
|
promptWindow.Append(&progressbarEmptyImg);
|
|
promptWindow.Append(&progressbarImg);
|
|
promptWindow.Append(&progressbarOutlineImg);
|
|
promptWindow.Append(&prTxt);
|
|
promptWindow.Append(&prsTxt);
|
|
if (title) promptWindow.Append(&titleTxt);
|
|
promptWindow.Append(&msg1Txt);
|
|
promptWindow.Append(&msg2Txt);
|
|
if (showTime) promptWindow.Append(&timeTxt);
|
|
if (showSize)
|
|
{
|
|
promptWindow.Append(&sizeTxt);
|
|
promptWindow.Append(&speedTxt);
|
|
}
|
|
if(CancelEnabled)
|
|
promptWindow.Append(&cancelBtn);
|
|
|
|
HaltGui();
|
|
promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50);
|
|
mainWindow->SetState(STATE_DISABLED);
|
|
mainWindow->Append(&promptWindow);
|
|
ResumeGui();
|
|
|
|
while (promptWindow.GetEffect() > 0) usleep(100);
|
|
|
|
while (showProgress)
|
|
{
|
|
usleep(50000);
|
|
|
|
if (shutdown)
|
|
Sys_Shutdown();
|
|
if (reset)
|
|
Sys_Reboot();
|
|
|
|
if (changed)
|
|
{
|
|
if (changedMessages)
|
|
{
|
|
titleTxt.SetText(progressTitle);
|
|
msg1Txt.SetText(progressMsg1);
|
|
msg2Txt.SetText(progressMsg2);
|
|
|
|
if(progressMsg1[0] != '\0' && progressMsg2[0] == '\0') {
|
|
msg1Txt.SetPosition(0, 120);
|
|
}
|
|
else if(progressMsg2[0] != '\0' && progressMsg1[0] == '\0') {
|
|
msg2Txt.SetPosition(0, 120);
|
|
}
|
|
else {
|
|
msg1Txt.SetPosition(0, 90);
|
|
msg2Txt.SetPosition(0, 125);
|
|
}
|
|
}
|
|
UpdateProgressValues(&progressbarImg, &prTxt, &timeTxt, &speedTxt, &sizeTxt);
|
|
}
|
|
|
|
if(cancelBtn.GetState() == STATE_CLICKED)
|
|
{
|
|
progressCanceled = true;
|
|
cancelBtn.ResetState();
|
|
}
|
|
}
|
|
|
|
promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50);
|
|
while (promptWindow.GetEffect() > 0) usleep(100);
|
|
|
|
HaltGui();
|
|
mainWindow->Remove(&promptWindow);
|
|
mainWindow->SetState(STATE_DEFAULT);
|
|
ResumeGui();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* ProgressThread
|
|
***************************************************************************/
|
|
static void * ProgressThread(void *arg)
|
|
{
|
|
while (1)
|
|
{
|
|
if (!showProgress) LWP_SuspendThread(progressthread);
|
|
|
|
ProgressWindow(progressTitle, progressMsg1, progressMsg2);
|
|
usleep(100);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* InitProgressThread
|
|
*
|
|
* Startup Progressthread in idle prio
|
|
***************************************************************************/
|
|
void InitProgressThread()
|
|
{
|
|
LWP_MutexInit(&ProgressMutex, true);
|
|
LWP_CreateThread(&progressthread, ProgressThread, NULL, NULL, 16384, 70);
|
|
|
|
memset(progressTitle, 0, sizeof(progressTitle));
|
|
memset(progressMsg1, 0, sizeof(progressMsg1));
|
|
memset(progressMsg2, 0, sizeof(progressMsg2));
|
|
}
|
|
|
|
/****************************************************************************
|
|
* ExitProgressThread
|
|
*
|
|
* Shutdown Progressthread
|
|
***************************************************************************/
|
|
void ExitProgressThread()
|
|
{
|
|
LWP_JoinThread(progressthread, NULL);
|
|
progressthread = LWP_THREAD_NULL;
|
|
LWP_MutexUnlock(ProgressMutex);
|
|
LWP_MutexDestroy(ProgressMutex);
|
|
}
|