CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/Dialog/PSPDialog.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "Common/Data/Text/I18n.h"1819#include "Common/Serialize/Serializer.h"20#include "Common/Serialize/SerializeFuncs.h"21#include "Common/StringUtils.h"22#include "Core/Config.h"23#include "Core/System.h"24#include "Core/CoreTiming.h"25#include "Core/Dialog/PSPDialog.h"26#include "Core/HLE/sceCtrl.h"27#include "Core/HLE/scePower.h"28#include "Core/HLE/sceUtility.h"29#include "Core/MemMapHelpers.h"30#include "Core/Util/PPGeDraw.h"3132#define FADE_TIME 1.033const float FONT_SCALE = 0.55f;3435PSPDialog::PSPDialog(UtilityDialogType type) : dialogType_(type) {36}3738PSPDialog::~PSPDialog() {39}4041void PSPDialog::InitCommon() {42UpdateCommon();4344if (GetCommonParam() && GetCommonParam()->language != g_Config.GetPSPLanguage()) {45WARN_LOG(Log::sceUtility, "Game requested language %d, ignoring and using user language", GetCommonParam()->language);46}47}4849void PSPDialog::UpdateCommon() {50okButtonImg = ImageID("I_CIRCLE");51cancelButtonImg = ImageID("I_CROSS");52okButtonFlag = CTRL_CIRCLE;53cancelButtonFlag = CTRL_CROSS;54if (GetCommonParam() && GetCommonParam()->buttonSwap == 1) {55okButtonImg = ImageID("I_CROSS");56cancelButtonImg = ImageID("I_CIRCLE");57okButtonFlag = CTRL_CROSS;58cancelButtonFlag = CTRL_CIRCLE;59}60}6162PSPDialog::DialogStatus PSPDialog::GetStatus() {63if (pendingStatusTicks != 0 && CoreTiming::GetTicks() >= pendingStatusTicks) {64bool changeAllowed = true;65if (pendingStatus == SCE_UTILITY_STATUS_NONE && status == SCE_UTILITY_STATUS_SHUTDOWN) {66FinishVolatile();67} else if (pendingStatus == SCE_UTILITY_STATUS_RUNNING && status == SCE_UTILITY_STATUS_INITIALIZE) {68if (!volatileLocked_) {69volatileLocked_ = KernelVolatileMemLock(0, 0, 0) == 0;70changeAllowed = volatileLocked_;71}72}73if (changeAllowed) {74status = pendingStatus;75pendingStatusTicks = 0;76}77}7879PSPDialog::DialogStatus retval = status;80if (UseAutoStatus()) {81if (status == SCE_UTILITY_STATUS_SHUTDOWN)82status = SCE_UTILITY_STATUS_NONE;83if (status == SCE_UTILITY_STATUS_INITIALIZE)84status = SCE_UTILITY_STATUS_RUNNING;85}86return retval;87}8889void PSPDialog::ChangeStatus(DialogStatus newStatus, int delayUs) {90if (delayUs <= 0) {91if (newStatus == SCE_UTILITY_STATUS_NONE && status == SCE_UTILITY_STATUS_SHUTDOWN) {92FinishVolatile();93} else if (newStatus == SCE_UTILITY_STATUS_RUNNING && status == SCE_UTILITY_STATUS_INITIALIZE) {94if (!volatileLocked_) {95// TODO: Should probably make the status pending instead?96volatileLocked_ = KernelVolatileMemLock(0, 0, 0) == 0;97}98}99status = newStatus;100pendingStatus = newStatus;101pendingStatusTicks = 0;102} else {103pendingStatus = newStatus;104pendingStatusTicks = CoreTiming::GetTicks() + usToCycles(delayUs);105}106}107108void PSPDialog::FinishVolatile() {109if (!volatileLocked_)110return;111112if (KernelVolatileMemUnlock(0) == 0) {113volatileLocked_ = false;114// Simulate modifications to volatile memory.115Memory::Memset(PSP_GetVolatileMemoryStart(), 0, PSP_GetVolatileMemoryEnd() - PSP_GetVolatileMemoryStart());116}117}118119int PSPDialog::FinishInit() {120if (ReadStatus() != SCE_UTILITY_STATUS_INITIALIZE)121return -1;122// The thread already locked.123volatileLocked_ = true;124ChangeStatus(SCE_UTILITY_STATUS_RUNNING, 0);125return 0;126}127128int PSPDialog::FinishShutdown() {129if (ReadStatus() != SCE_UTILITY_STATUS_SHUTDOWN)130return -1;131ChangeStatus(SCE_UTILITY_STATUS_NONE, 0);132return 0;133}134135void PSPDialog::ChangeStatusInit(int delayUs) {136ChangeStatus(SCE_UTILITY_STATUS_INITIALIZE, 0);137138auto params = GetCommonParam();139if (params)140UtilityDialogInitialize(DialogType(), delayUs, params->accessThread);141else142ChangeStatus(SCE_UTILITY_STATUS_RUNNING, delayUs);143}144145void PSPDialog::ChangeStatusShutdown(int delayUs) {146// If we're doing shutdown right away and skipped start, we don't run the dialog thread.147bool skipDialogShutdown = status == SCE_UTILITY_STATUS_NONE && pendingStatus == SCE_UTILITY_STATUS_NONE;148ChangeStatus(SCE_UTILITY_STATUS_SHUTDOWN, 0);149150auto params = GetCommonParam();151if (params && !skipDialogShutdown)152UtilityDialogShutdown(DialogType(), delayUs, params->accessThread);153else154ChangeStatus(SCE_UTILITY_STATUS_NONE, delayUs);155}156157void PSPDialog::StartDraw()158{159PPGeBegin();160PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0x20000000));161}162163void PSPDialog::EndDraw()164{165PPGeEnd();166}167168int PSPDialog::Shutdown(bool force)169{170if (force) {171ChangeStatus(SCE_UTILITY_STATUS_NONE, 0);172} else {173ChangeStatus(SCE_UTILITY_STATUS_SHUTDOWN, 0);174}175return 0;176}177178void PSPDialog::StartFade(bool fadeIn_)179{180isFading = true;181fadeTimer = 0;182fadeIn = fadeIn_;183}184185void PSPDialog::UpdateFade(int animSpeed) {186if (isFading) {187fadeTimer += 1.0f/30.0f * animSpeed; // Probably need a more real value of delta time188if (fadeTimer < FADE_TIME) {189if (fadeIn)190fadeValue = (u32) (fadeTimer / FADE_TIME * 255);191else192fadeValue = 255 - (u32) (fadeTimer / FADE_TIME * 255);193} else {194fadeValue = (fadeIn ? 255 : 0);195isFading = false;196if (!fadeIn) {197FinishFadeOut();198}199}200}201}202203void PSPDialog::FinishFadeOut() {204ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0);205}206207u32 PSPDialog::CalcFadedColor(u32 inColor) const {208u32 alpha = inColor >> 24;209alpha = alpha * fadeValue / 255;210return (inColor & 0x00FFFFFF) | (alpha << 24);211}212213void PSPDialog::DoState(PointerWrap &p) {214auto s = p.Section("PSPDialog", 1, 3);215if (!s)216return;217218Do(p, status);219Do(p, lastButtons);220Do(p, buttons);221Do(p, fadeTimer);222Do(p, isFading);223Do(p, fadeIn);224Do(p, fadeValue);225226// I don't think we should save these two... Let's just ignore them for now for compat.227int okButtonImg = 0;228Do(p, okButtonImg);229int cancelButtonImg = 0;230Do(p, cancelButtonImg);231232Do(p, okButtonFlag);233Do(p, cancelButtonFlag);234235if (s >= 2) {236Do(p, pendingStatus);237Do(p, pendingStatusTicks);238} else {239pendingStatusTicks = 0;240}241242if (s >= 3) {243Do(p, volatileLocked_);244} else {245volatileLocked_ = false;246}247}248249pspUtilityDialogCommon *PSPDialog::GetCommonParam()250{251// FIXME252return 0;253}254255void PSPDialog::UpdateButtons()256{257lastButtons = __CtrlPeekButtons();258buttons = __CtrlReadLatch();259}260261bool PSPDialog::IsButtonPressed(int checkButton)262{263return !isFading && (buttons & checkButton);264}265266bool PSPDialog::IsButtonHeld(int checkButton, int &framesHeld, int framesHeldThreshold, int framesHeldRepeatRate)267{268bool btnWasHeldLastFrame = (lastButtons & checkButton) && (__CtrlPeekButtons() & checkButton);269if (!isFading && btnWasHeldLastFrame) {270framesHeld++;271}272else {273framesHeld = 0;274return false;275}276277// It's considered held for dialog purposes after 30 frames (~0.5 seconds),278// and set to repeat every 10 frames, by default.279if (framesHeld >= framesHeldThreshold && ((framesHeld % framesHeldRepeatRate) == 0))280return true;281282return false;283}284285PPGeStyle PSPDialog::FadedStyle(PPGeAlign align, float scale) {286PPGeStyle textStyle;287textStyle.align = align;288textStyle.scale = scale;289textStyle.color = CalcFadedColor(textStyle.color);290textStyle.hasShadow = true;291textStyle.shadowColor = CalcFadedColor(textStyle.shadowColor);292return textStyle;293}294295PPGeImageStyle PSPDialog::FadedImageStyle() {296PPGeImageStyle style;297style.color = CalcFadedColor(style.color);298return style;299}300301void PSPDialog::DisplayButtons(int flags, std::string_view caption) {302bool useCaption = false;303char safeCaption[65] = {0};304if (!caption.empty()) {305useCaption = true;306truncate_cpy(safeCaption, sizeof(safeCaption), caption);307}308309PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_LEFT, FONT_SCALE);310311auto di = GetI18NCategory(I18NCat::DIALOG);312float x1 = 183.5f, x2 = 261.5f;313if (GetCommonParam()->buttonSwap == 1) {314x1 = 261.5f;315x2 = 183.5f;316}317if (flags & DS_BUTTON_OK) {318std::string_view text = useCaption ? safeCaption : di->T("Enter");319PPGeDrawImage(okButtonImg, x2, 256, 11.5f, 11.5f, textStyle);320PPGeDrawText(text, x2 + 14.5f, 252, textStyle);321}322if (flags & DS_BUTTON_CANCEL) {323std::string_view text = useCaption ? safeCaption : di->T("Back");324PPGeDrawImage(cancelButtonImg, x1, 256, 11.5f, 11.5f, textStyle);325PPGeDrawText(text, x1 + 14.5f, 252, textStyle);326}327}328329int PSPDialog::GetConfirmButton() {330if (PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm) {331return CTRL_CIRCLE;332}333return g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE;334}335336int PSPDialog::GetCancelButton() {337if (PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm) {338return CTRL_CROSS;339}340return g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CIRCLE : CTRL_CROSS;341}342343344