/**************************************************************************** * ProgressWindow * USB Loader GX 2009 * * ProgressWindow.cpp ***************************************************************************/ #include #include #include #include #include #include #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 (progressbarImg->GetWidth() * progressPercent * Settings.WSFactor) - progressbarImg->GetWidth(), 0, static_cast (progressbarImg->GetWidth() * progressPercent * Settings.WSFactor) - progressbarImg->GetWidth(), 0, 0, 0); else progressbarImg->SetSkew(0, 0, static_cast (progressbarImg->GetWidth() * progressPercent) - progressbarImg->GetWidth(), 0, static_cast (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); }