mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-10 21:16:24 +02:00
Implement the new MemStick screen experience (rough cut)
This commit is contained in:
1 parent
acc0884569
commit
357293cd9f
4 files changed
+218
-37
No files matched your search
@@ -803,6 +803,69 @@ void Button::Draw(UIContext &dc) {
|
||||
}
|
||||
}
|
||||
|
||||
void RadioButton::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
w = 0.0f;
|
||||
h = 0.0f;
|
||||
|
||||
if (!text_.empty()) {
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), &w, &h);
|
||||
}
|
||||
|
||||
// Add some internal padding to not look totally ugly
|
||||
w += paddingW_ * 3.0f + radioRadius_ * 2.0f;
|
||||
h = std::max(h, radioRadius_ * 2) + paddingH_ * 2;
|
||||
}
|
||||
|
||||
std::string RadioButton::DescribeText() const {
|
||||
auto u = GetI18NCategory("UI Elements");
|
||||
return ReplaceAll(u->T("%1 radio button"), "%1", text_);
|
||||
}
|
||||
|
||||
void RadioButton::Click() {
|
||||
Clickable::Click();
|
||||
UI::PlayUISound(UI::UISound::CONFIRM);
|
||||
*value_ = thisButtonValue_;
|
||||
}
|
||||
|
||||
void RadioButton::Draw(UIContext &dc) {
|
||||
Style style = dc.theme->buttonStyle;
|
||||
|
||||
bool checked = *value_ == thisButtonValue_;
|
||||
|
||||
if (HasFocus()) style = dc.theme->buttonFocusedStyle;
|
||||
if (down_) style = dc.theme->buttonDownStyle;
|
||||
if (!IsEnabled()) style = dc.theme->buttonDisabledStyle;
|
||||
|
||||
DrawBG(dc, style);
|
||||
|
||||
dc.Flush();
|
||||
dc.BeginNoTex();
|
||||
dc.Draw()->Circle(bounds_.x + paddingW_ + radioRadius_, bounds_.centerY(), radioRadius_, 2.5f, 36, 0, style.fgColor, 1.0f);
|
||||
if (checked) {
|
||||
dc.Draw()->FillCircle(bounds_.x + paddingW_ + radioRadius_, bounds_.centerY(), radioInnerRadius_, 36, style.fgColor);
|
||||
}
|
||||
dc.Flush();
|
||||
dc.Begin();
|
||||
|
||||
float tw, th;
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), &tw, &th);
|
||||
|
||||
if (tw > bounds_.w) {
|
||||
dc.PushScissor(bounds_);
|
||||
}
|
||||
|
||||
dc.SetFontStyle(dc.theme->uiFont);
|
||||
|
||||
if (!text_.empty()) {
|
||||
float textX = bounds_.x + paddingW_ * 2.0f + radioRadius_ * 2.0f;
|
||||
dc.DrawText(text_.c_str(), textX, bounds_.centerY(), style.fgColor, ALIGN_LEFT | ALIGN_VCENTER);
|
||||
}
|
||||
|
||||
if (tw > bounds_.w) {
|
||||
dc.PopScissor();
|
||||
}
|
||||
}
|
||||
|
||||
void ImageView::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
dc.Draw()->GetAtlas()->measureImage(atlasImage_, &w, &h);
|
||||
// TODO: involve sizemode
|
||||
|
||||
+22
-2
@@ -522,6 +522,8 @@ protected:
|
||||
bool down_ = false;
|
||||
};
|
||||
|
||||
// TODO: Very similar to Choice, should probably merge them.
|
||||
// Right now more flexible image support though.
|
||||
class Button : public Clickable {
|
||||
public:
|
||||
Button(const std::string &text, LayoutParams *layoutParams = 0)
|
||||
@@ -544,12 +546,10 @@ public:
|
||||
void SetIgnoreText(bool ignore) {
|
||||
ignoreText_ = ignore;
|
||||
}
|
||||
|
||||
// Needed an extra small button...
|
||||
void SetScale(float f) {
|
||||
scale_ = f;
|
||||
}
|
||||
|
||||
private:
|
||||
Style style_;
|
||||
std::string text_;
|
||||
@@ -560,6 +560,26 @@ private:
|
||||
bool ignoreText_ = false;
|
||||
};
|
||||
|
||||
class RadioButton : public Clickable {
|
||||
public:
|
||||
RadioButton(int *value, int thisButtonValue, const std::string &text, LayoutParams *layoutParams = 0)
|
||||
: Clickable(layoutParams), value_(value), thisButtonValue_(thisButtonValue), text_(text) {}
|
||||
void Click() override;
|
||||
void Draw(UIContext &dc) override;
|
||||
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
|
||||
std::string DescribeText() const override;
|
||||
|
||||
private:
|
||||
int *value_;
|
||||
int thisButtonValue_;
|
||||
std::string text_;
|
||||
const float paddingW_ = 8;
|
||||
const float paddingH_ = 4;
|
||||
|
||||
const float radioRadius_ = 16.0f;
|
||||
const float radioInnerRadius_ = 8.0f;
|
||||
};
|
||||
|
||||
class Slider : public Clickable {
|
||||
public:
|
||||
Slider(int *value, int minValue, int maxValue, LayoutParams *layoutParams = 0)
|
||||
|
||||
+113
-31
@@ -102,6 +102,36 @@ static std::string FormatSpaceString(int64_t space) {
|
||||
|
||||
MemStickScreen::MemStickScreen(bool initialSetup)
|
||||
: initialSetup_(initialSetup) {
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
// Let's only offer the browse-for-folder choice on Android 10 or later.
|
||||
// Earlier versions often don't really have working folder browsers.
|
||||
storageBrowserWorking_ = System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 29;
|
||||
#else
|
||||
// For testing UI only
|
||||
storageBrowserWorking_ = true;
|
||||
#endif
|
||||
|
||||
if (initialSetup_) {
|
||||
// Preselect current choice.
|
||||
if (System_GetPropertyBool(SYSPROP_ANDROID_SCOPED_STORAGE)) {
|
||||
choice_ = CHOICE_BROWSE_FOLDER;
|
||||
} else {
|
||||
WARN_LOG(SYSTEM, "Scoped storage not enabled - shouldn't be in MemStickScreen at initial setup");
|
||||
choice_ = CHOICE_STORAGE_ROOT;
|
||||
// Shouldn't really be here in initial setup.
|
||||
}
|
||||
} else {
|
||||
// Detect the current choice, so it's preselected in the UI.
|
||||
if (g_Config.memStickDirectory == Path(g_extFilesDir)) {
|
||||
choice_ = CHOICE_PRIVATE_DIRECTORY;
|
||||
} else if (g_Config.memStickDirectory == Path(g_externalDir)) {
|
||||
choice_ = CHOICE_STORAGE_ROOT;
|
||||
} else if (storageBrowserWorking_) {
|
||||
choice_ = CHOICE_BROWSE_FOLDER;
|
||||
} else {
|
||||
choice_ = CHOICE_SET_MANUAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MemStickScreen::CreateViews() {
|
||||
@@ -138,43 +168,72 @@ void MemStickScreen::CreateViews() {
|
||||
// TODO: Gonna need a scroll view.
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
if (!System_GetPropertyBool(SYSPROP_ANDROID_SCOPED_STORAGE)) {
|
||||
leftColumn->Add(new Button(iz->T("Use PSP folder at root of storage")))->OnClick.Handle(this, &MemStickScreen::OnUseStorageRoot);
|
||||
leftColumn->Add(new TextView(iz->T("DataWillStay", "Data will stay even if you uninstall PPSSPP.")))->SetBullet(true);
|
||||
leftColumn->Add(new TextView(iz->T("DataCanBeShared", "Data can be shared between PPSSPP regular/Gold.")))->SetBullet(true);
|
||||
leftColumn->Add(new TextView(iz->T("EasyUSBAccess", "Easy USB access")))->SetBullet(true);
|
||||
leftColumn->Add(new RadioButton(&choice_, CHOICE_STORAGE_ROOT, iz->T("Use PSP folder at root of storage")))->OnClick.Handle(this, &MemStickScreen::OnChoiceClick);
|
||||
}
|
||||
|
||||
// Let's only offer the browse-for-folder choice on Android 10 or later.
|
||||
// Earlier versions often don't really have working folder browsers.
|
||||
bool storageBrowserWorking = System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 29;
|
||||
#else
|
||||
// For testing UI only
|
||||
bool storageBrowserWorking = true;
|
||||
#endif
|
||||
|
||||
if (storageBrowserWorking) {
|
||||
leftColumn->Add(new Button(iz->T("Create or Choose a PSP folder"), ImageID("I_FOLDER_OPEN")))->OnClick.Handle(this, &MemStickScreen::OnBrowse);
|
||||
leftColumn->Add(new TextView(iz->T("DataWillStay", "Data will stay even if you uninstall PPSSPP.")))->SetBullet(true);
|
||||
leftColumn->Add(new TextView(iz->T("DataCanBeShared", "Data can be shared between PPSSPP regular/Gold.")))->SetBullet(true);
|
||||
leftColumn->Add(new TextView(iz->T("EasyUSBAccess", "Easy USB access")))->SetBullet(true);
|
||||
if (storageBrowserWorking_) {
|
||||
//ImageID("I_FOLDER_OPEN")
|
||||
leftColumn->Add(new RadioButton(&choice_, CHOICE_BROWSE_FOLDER, iz->T("Create or Choose a PSP folder")))->OnClick.Handle(this, &MemStickScreen::OnChoiceClick);
|
||||
// TODO: Show current folder here if we have one set.
|
||||
} else {
|
||||
leftColumn->Add(new Button(iz->T("Manually specify PSP folder")))->OnClick.Handle(this, &MemStickScreen::OnSetFolderManually);
|
||||
leftColumn->Add(new RadioButton(&choice_, CHOICE_SET_MANUAL, iz->T("Manually specify PSP folder")))->OnClick.Handle(this, &MemStickScreen::OnChoiceClick);
|
||||
leftColumn->Add(new TextView(iz->T("DataWillStay", "Data will stay even if you uninstall PPSSPP.")))->SetBullet(true);
|
||||
leftColumn->Add(new TextView(iz->T("DataCanBeShared", "Data can be shared between PPSSPP regular/Gold.")))->SetBullet(true);
|
||||
// TODO: Show current folder here if we have one set.
|
||||
}
|
||||
if (!g_Config.memStickDirectory.empty()) {
|
||||
leftColumn->Add(new TextView(StringFromFormat(" %s: %s", iz->T("Current PSP Data Folder"), g_Config.memStickDirectory.ToVisualString().c_str()), ALIGN_LEFT, false));
|
||||
}
|
||||
|
||||
leftColumn->Add(new Button(iz->T("Skip for now - use App Private Directory"), ImageID("I_WARNING")))->OnClick.Handle(this, &MemStickScreen::OnUseInternalStorage);
|
||||
// Consider https://www.compart.com/en/unicode/U+26A0 (unicode warning sign?)? or a graphic?
|
||||
leftColumn->Add(new TextView(iz->T("DataWillBeLostOnUninstall", "Warning! Data will be lost when you uninstall PPSSPP!")))->SetBullet(true);
|
||||
leftColumn->Add(new TextView(iz->T("DataCannotBeShared", "Data CANNOT be shared between PPSSPP regular/Gold!")))->SetBullet(true);
|
||||
#if GOLD
|
||||
leftColumn->Add(new TextView(iz->T("USBAccessThroughGold", "USB access through Android/data/org.ppsspp.ppssppgold/files")))->SetBullet(true);
|
||||
#else
|
||||
leftColumn->Add(new TextView(iz->T("USBAccessThrough", "USB access through Android/data/org.ppsspp.ppsspp/files")))->SetBullet(true);
|
||||
#endif
|
||||
leftColumn->Add(new RadioButton(&choice_, CHOICE_PRIVATE_DIRECTORY, iz->T("Skip for now - use App Private Directory")))->OnClick.Handle(this, &MemStickScreen::OnChoiceClick);
|
||||
|
||||
leftColumn->Add(new Spacer(new LinearLayoutParams(FILL_PARENT, 12.0f, 0.0f)));
|
||||
|
||||
const char *confirmButtonText = nullptr;
|
||||
ImageID confirmButtonImage = ImageID::invalid();
|
||||
switch (choice_) {
|
||||
case CHOICE_STORAGE_ROOT:
|
||||
// Old school choice
|
||||
leftColumn->Add(new TextView(iz->T("DataWillStay", "Data will stay even if you uninstall PPSSPP.")))->SetBullet(true);
|
||||
leftColumn->Add(new TextView(iz->T("DataCanBeShared", "Data can be shared between PPSSPP regular/Gold.")))->SetBullet(true);
|
||||
leftColumn->Add(new TextView(iz->T("EasyUSBAccess", "Easy USB access")))->SetBullet(true);
|
||||
|
||||
confirmButtonText = di->T("Confirm");
|
||||
break;
|
||||
case CHOICE_BROWSE_FOLDER:
|
||||
leftColumn->Add(new TextView(iz->T("DataWillStay", "Data will stay even if you uninstall PPSSPP.")))->SetBullet(true);
|
||||
leftColumn->Add(new TextView(iz->T("DataCanBeShared", "Data can be shared between PPSSPP regular/Gold.")))->SetBullet(true);
|
||||
leftColumn->Add(new TextView(iz->T("EasyUSBAccess", "Easy USB access")))->SetBullet(true);
|
||||
|
||||
confirmButtonText = di->T("Browse");
|
||||
confirmButtonImage = ImageID("I_FOLDER_OPEN");
|
||||
break;
|
||||
case CHOICE_PRIVATE_DIRECTORY:
|
||||
// Consider https://www.compart.com/en/unicode/U+26A0 (unicode warning sign?)? or a graphic?
|
||||
leftColumn->Add(new TextView(iz->T("DataWillBeLostOnUninstall", "Warning! Data will be lost when you uninstall PPSSPP!")))->SetBullet(true);
|
||||
leftColumn->Add(new TextView(iz->T("DataCannotBeShared", "Data CANNOT be shared between PPSSPP regular/Gold!")))->SetBullet(true);
|
||||
#if GOLD
|
||||
leftColumn->Add(new TextView(iz->T("USBAccessThroughGold", "USB access through Android/data/org.ppsspp.ppssppgold/files")))->SetBullet(true);
|
||||
#else
|
||||
leftColumn->Add(new TextView(iz->T("USBAccessThrough", "USB access through Android/data/org.ppsspp.ppsspp/files")))->SetBullet(true);
|
||||
#endif
|
||||
confirmButtonText = di->T("Confirm");
|
||||
confirmButtonImage = ImageID("I_WARNING");
|
||||
break;
|
||||
case CHOICE_SET_MANUAL:
|
||||
default:
|
||||
leftColumn->Add(new TextView(iz->T("EasyUSBAccess", "Easy USB access")))->SetBullet(true);
|
||||
// What more?
|
||||
|
||||
// Should we have a special text here? It'll popup a text window for editing.
|
||||
confirmButtonText = di->T("Confirm");
|
||||
break;
|
||||
}
|
||||
|
||||
rightColumnItems->Add(new Button(confirmButtonText, confirmButtonImage))->OnClick.Handle<MemStickScreen>(this, &MemStickScreen::OnConfirmClick);
|
||||
rightColumnItems->Add(new Spacer(new LinearLayoutParams(FILL_PARENT, 12.0f, 0.0f)));
|
||||
|
||||
if (!initialSetup_) {
|
||||
rightColumnItems->Add(new Choice(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
}
|
||||
@@ -189,7 +248,30 @@ UI::EventReturn MemStickScreen::OnHelp(UI::EventParams ¶ms) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn MemStickScreen::OnSetFolderManually(UI::EventParams ¶ms) {
|
||||
UI::EventReturn MemStickScreen::OnChoiceClick(UI::EventParams ¶ms) {
|
||||
// Change the confirm button to match the choice,
|
||||
// and change the text that we show.
|
||||
RecreateViews();
|
||||
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
|
||||
UI::EventReturn MemStickScreen::OnConfirmClick(UI::EventParams ¶ms) {
|
||||
switch (choice_) {
|
||||
case CHOICE_SET_MANUAL:
|
||||
return SetFolderManually(params);
|
||||
case CHOICE_STORAGE_ROOT:
|
||||
return UseStorageRoot(params);
|
||||
case CHOICE_PRIVATE_DIRECTORY:
|
||||
return UseInternalStorage(params);
|
||||
case CHOICE_BROWSE_FOLDER:
|
||||
return Browse(params);
|
||||
}
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn MemStickScreen::SetFolderManually(UI::EventParams ¶ms) {
|
||||
// The old way, from before scoped storage.
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
auto sy = GetI18NCategory("System");
|
||||
@@ -256,7 +338,7 @@ UI::EventReturn MemStickScreen::OnSetFolderManually(UI::EventParams ¶ms) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn MemStickScreen::OnUseInternalStorage(UI::EventParams ¶ms) {
|
||||
UI::EventReturn MemStickScreen::UseInternalStorage(UI::EventParams ¶ms) {
|
||||
Path pendingMemStickFolder = Path(g_extFilesDir);
|
||||
|
||||
if (initialSetup_) {
|
||||
@@ -277,7 +359,7 @@ UI::EventReturn MemStickScreen::OnUseInternalStorage(UI::EventParams ¶ms) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn MemStickScreen::OnUseStorageRoot(UI::EventParams ¶ms) {
|
||||
UI::EventReturn MemStickScreen::UseStorageRoot(UI::EventParams ¶ms) {
|
||||
Path pendingMemStickFolder = Path(g_externalDir);
|
||||
|
||||
if (initialSetup_) {
|
||||
@@ -298,7 +380,7 @@ UI::EventReturn MemStickScreen::OnUseStorageRoot(UI::EventParams ¶ms) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn MemStickScreen::OnBrowse(UI::EventParams ¶ms) {
|
||||
UI::EventReturn MemStickScreen::Browse(UI::EventParams ¶ms) {
|
||||
System_SendMessage("browse_folder", "");
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
@@ -435,7 +517,7 @@ void ConfirmMemstickMoveScreen::CreateViews() {
|
||||
|
||||
if (!oldMemstickFolder.empty()) {
|
||||
std::string oldFreeSpaceText = std::string(iz->T("Free space")) + ": " + FormatSpaceString(freeSpaceOld);
|
||||
rightColumn->Add(new TextView(iz->T("Old PSP Data Folder"), ALIGN_LEFT, false));
|
||||
rightColumn->Add(new TextView(iz->T("Current PSP Data Folder"), ALIGN_LEFT, false));
|
||||
rightColumn->Add(new TextView(oldMemstickFolder.ToVisualString(), ALIGN_LEFT, false));
|
||||
rightColumn->Add(new TextView(oldFreeSpaceText, ALIGN_LEFT, false));
|
||||
}
|
||||
|
||||
+20
-4
@@ -56,16 +56,32 @@ protected:
|
||||
|
||||
private:
|
||||
// Event handlers
|
||||
UI::EventReturn OnBrowse(UI::EventParams &e);
|
||||
UI::EventReturn OnHelp(UI::EventParams &e);
|
||||
UI::EventReturn OnUseInternalStorage(UI::EventParams ¶ms);
|
||||
UI::EventReturn OnUseStorageRoot(UI::EventParams ¶ms);
|
||||
UI::EventReturn OnSetFolderManually(UI::EventParams ¶ms);
|
||||
|
||||
// Confirm button sub handlers
|
||||
UI::EventReturn Browse(UI::EventParams &e);
|
||||
UI::EventReturn UseInternalStorage(UI::EventParams ¶ms);
|
||||
UI::EventReturn UseStorageRoot(UI::EventParams ¶ms);
|
||||
UI::EventReturn SetFolderManually(UI::EventParams ¶ms);
|
||||
|
||||
// Button handlers.
|
||||
UI::EventReturn OnConfirmClick(UI::EventParams ¶ms);
|
||||
UI::EventReturn OnChoiceClick(UI::EventParams ¶ms);
|
||||
|
||||
SettingInfoMessage *settingInfo_ = nullptr;
|
||||
|
||||
enum {
|
||||
CHOICE_BROWSE_FOLDER,
|
||||
CHOICE_PRIVATE_DIRECTORY,
|
||||
CHOICE_STORAGE_ROOT,
|
||||
CHOICE_SET_MANUAL,
|
||||
};
|
||||
|
||||
bool initialSetup_;
|
||||
bool storageBrowserWorking_;
|
||||
bool done_ = false;
|
||||
|
||||
int choice_ = 0;
|
||||
};
|
||||
|
||||
class ProgressReporter {
|
||||
|
||||
Reference in new issue
Block a user