usbloadergx/source/prompts/ProgressWindow.cpp
strtoul a66a30a771 *removed buggy focus system completely (it was never working correct)
*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
2011-12-28 16:27:30 +00:00

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