mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-16 07:50:28 +02:00
Merge pull request #20913 from hrydgard/ui-refactor
UI refactoring, better back button on tabbed dialog like SettingsScreen
This commit is contained in:
37 files changed
+1592
-2440
No files matched your search
@@ -884,6 +884,8 @@ add_library(Common STATIC
|
||||
Common/UI/ViewGroup.h
|
||||
Common/UI/ScrollView.cpp
|
||||
Common/UI/ScrollView.h
|
||||
Common/UI/TabHolder.cpp
|
||||
Common/UI/TabHolder.h
|
||||
Common/UI/PopupScreens.cpp
|
||||
Common/UI/PopupScreens.h
|
||||
Common/BitScan.h
|
||||
|
||||
@@ -538,6 +538,7 @@
|
||||
<ClInclude Include="UI\Root.h" />
|
||||
<ClInclude Include="UI\Screen.h" />
|
||||
<ClInclude Include="UI\ScrollView.h" />
|
||||
<ClInclude Include="UI\TabHolder.h" />
|
||||
<ClInclude Include="UI\Tween.h" />
|
||||
<ClInclude Include="UI\UI.h" />
|
||||
<ClInclude Include="UI\UIScreen.h" />
|
||||
@@ -983,6 +984,7 @@
|
||||
<ClCompile Include="UI\Root.cpp" />
|
||||
<ClCompile Include="UI\Screen.cpp" />
|
||||
<ClCompile Include="UI\ScrollView.cpp" />
|
||||
<ClCompile Include="UI\TabHolder.cpp" />
|
||||
<ClCompile Include="UI\Tween.cpp" />
|
||||
<ClCompile Include="UI\UI.cpp" />
|
||||
<ClCompile Include="UI\UIScreen.cpp" />
|
||||
|
||||
@@ -698,6 +698,9 @@
|
||||
<ClInclude Include="..\ext\nanosvg\src\nanosvgrast.h">
|
||||
<Filter>ext\nanosvg</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UI\TabHolder.h">
|
||||
<Filter>UI</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ABI.cpp" />
|
||||
@@ -1302,6 +1305,9 @@
|
||||
<ClCompile Include="Render\AtlasGen.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="UI\TabHolder.cpp">
|
||||
<Filter>UI</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Crypto">
|
||||
|
||||
+9
-4
@@ -31,7 +31,8 @@ void EventTriggered(Event *e, EventParams params) {
|
||||
g_dispatchQueue.push_front(item);
|
||||
}
|
||||
|
||||
void DispatchEvents() {
|
||||
DialogResult DispatchEvents() {
|
||||
DialogResult result = DR_NONE;
|
||||
while (!g_dispatchQueue.empty()) {
|
||||
DispatchQueueItem item;
|
||||
if (g_dispatchQueue.empty())
|
||||
@@ -40,8 +41,12 @@ void DispatchEvents() {
|
||||
g_dispatchQueue.pop_back();
|
||||
if (item.e) {
|
||||
item.e->Dispatch(item.params);
|
||||
if (item.params.bubbleResult != DR_NONE) {
|
||||
result = item.params.bubbleResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void RemoveQueuedEventsByView(View *view) {
|
||||
@@ -363,13 +368,13 @@ restart:
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateViewHierarchy(ViewGroup *root) {
|
||||
DialogResult UpdateViewHierarchy(ViewGroup *root) {
|
||||
ProcessHeldKeys(root);
|
||||
frameCount++;
|
||||
|
||||
if (!root) {
|
||||
ERROR_LOG(Log::UI, "Tried to update a view hierarchy from a zero pointer root");
|
||||
return;
|
||||
return DR_NONE;
|
||||
}
|
||||
|
||||
if (focusMoves.size()) {
|
||||
@@ -402,7 +407,7 @@ void UpdateViewHierarchy(ViewGroup *root) {
|
||||
}
|
||||
|
||||
root->Update();
|
||||
DispatchEvents();
|
||||
return DispatchEvents();
|
||||
}
|
||||
|
||||
} // namespace UI
|
||||
+3
-2
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "Common/UI/Context.h"
|
||||
#include "Common/Input/InputState.h"
|
||||
#include "Common/UI/Screen.h"
|
||||
|
||||
namespace UI {
|
||||
|
||||
@@ -17,12 +18,12 @@ void RemoveQueuedEventsByEvent(Event *e);
|
||||
void RemoveQueuedEventsByView(View * v);
|
||||
|
||||
void EventTriggered(Event *e, EventParams params);
|
||||
void DispatchEvents();
|
||||
DialogResult DispatchEvents();
|
||||
|
||||
class ViewGroup;
|
||||
|
||||
void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root, bool ignoreInsets);
|
||||
void UpdateViewHierarchy(ViewGroup *root);
|
||||
DialogResult UpdateViewHierarchy(ViewGroup *root);
|
||||
|
||||
enum class KeyEventResult {
|
||||
IGNORE_KEY, // Don't let it be processed.
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace UI {
|
||||
}
|
||||
|
||||
enum DialogResult {
|
||||
DR_NONE,
|
||||
DR_OK,
|
||||
DR_CANCEL,
|
||||
DR_YES,
|
||||
|
||||
@@ -0,0 +1,320 @@
|
||||
#include "Common/Math/curves.h"
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/UI/TabHolder.h"
|
||||
#include "Common/UI/Root.h"
|
||||
#include "Common/UI/ScrollView.h"
|
||||
#include "Common/UI/ViewGroup.h"
|
||||
#include "Common/UI/UIScreen.h"
|
||||
|
||||
namespace UI {
|
||||
|
||||
TabHolder::TabHolder(Orientation orientation, float stripSize, TabHolderFlags flags, View *bannerView, LayoutParams *layoutParams)
|
||||
: LinearLayout(Opposite(orientation), layoutParams) {
|
||||
SetSpacing(0.0f);
|
||||
if (orientation == ORIENT_HORIZONTAL) {
|
||||
// This orientation supports adding a back button.
|
||||
tabStrip_ = new ChoiceStrip(orientation, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||
tabStrip_->SetTopTabs(true);
|
||||
if (flags & TabHolderFlags::BackButton) {
|
||||
tabStrip_->AddBackButton();
|
||||
}
|
||||
tabScroll_ = new ScrollView(orientation, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
tabScroll_->Add(tabStrip_);
|
||||
Add(tabScroll_);
|
||||
} else {
|
||||
tabContainer_ = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(stripSize, FILL_PARENT));
|
||||
tabStrip_ = new ChoiceStrip(orientation, new LayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
tabStrip_->SetTopTabs(true);
|
||||
tabScroll_ = new ScrollView(orientation, new LinearLayoutParams(1.0f));
|
||||
tabScroll_->Add(tabStrip_);
|
||||
tabContainer_->Add(tabScroll_);
|
||||
Add(tabContainer_);
|
||||
}
|
||||
tabStrip_->OnChoice.Handle(this, &TabHolder::OnTabClick);
|
||||
|
||||
Add(new Spacer(4.0f))->SetSeparator();
|
||||
|
||||
ViewGroup *contentHolder_ = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f));
|
||||
if (bannerView) {
|
||||
contentHolder_->Add(bannerView);
|
||||
bannerView_ = bannerView;
|
||||
}
|
||||
contents_ = contentHolder_->Add(new AnchorLayout(new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f)));
|
||||
contents_->SetClip(true);
|
||||
Add(contentHolder_);
|
||||
}
|
||||
|
||||
void TabHolder::AddBack(UIScreen *parent) {
|
||||
if (tabContainer_) {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
tabContainer_->Add(new Choice(di->T("Back"), "", false, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 0.0f, Margins(0, 0, 10, 10))))->OnClick.Handle<UIScreen>(parent, &UIScreen::OnBack);
|
||||
}
|
||||
}
|
||||
|
||||
void TabHolder::AddTabContents(std::string_view title, ViewGroup *tabContents) {
|
||||
tabs_.push_back(tabContents);
|
||||
tabStrip_->AddChoice(title);
|
||||
contents_->Add(tabContents);
|
||||
if (tabs_.size() > 1)
|
||||
tabContents->SetVisibility(V_GONE);
|
||||
tabContents->ReplaceLayoutParams(new AnchorLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
|
||||
// Will be filled in later.
|
||||
tabTweens_.push_back(nullptr);
|
||||
// This entry doesn't need one.
|
||||
createFuncs_.push_back(nullptr);
|
||||
}
|
||||
|
||||
void TabHolder::AddTabDeferred(std::string_view title, std::function<ViewGroup *()> createCb) {
|
||||
tabs_.push_back(nullptr); // marker
|
||||
tabStrip_->AddChoice(title);
|
||||
tabTweens_.push_back(nullptr);
|
||||
createFuncs_.push_back(createCb);
|
||||
|
||||
if (tabs_.size() == 1) {
|
||||
EnsureTab(0);
|
||||
}
|
||||
}
|
||||
|
||||
void TabHolder::EnsureAllCreated() {
|
||||
for (int i = 0; i < createFuncs_.size(); i++) {
|
||||
if (createFuncs_[i]) {
|
||||
EnsureTab(i);
|
||||
tabs_[i]->SetVisibility(i == currentTab_ ? V_VISIBLE : V_GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TabHolder::EnsureTab(int index) {
|
||||
_dbg_assert_(index >= 0 && index < createFuncs_.size());
|
||||
|
||||
if (!tabs_[index]) {
|
||||
_dbg_assert_(index < createFuncs_.size());
|
||||
_dbg_assert_(createFuncs_[index]);
|
||||
std::function<UI::ViewGroup * ()> func;
|
||||
createFuncs_[index].swap(func);
|
||||
|
||||
ViewGroup *tabContents = func();
|
||||
tabs_[index] = tabContents;
|
||||
contents_->Add(tabContents);
|
||||
|
||||
tabContents->ReplaceLayoutParams(new AnchorLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TabHolder::SetCurrentTab(int tab, bool skipTween) {
|
||||
if (tab >= (int)tabs_.size()) {
|
||||
// Ignore
|
||||
return false;
|
||||
}
|
||||
|
||||
bool created = false;
|
||||
|
||||
if (tab != currentTab_) {
|
||||
_dbg_assert_(tabs_[currentTab_]); // we should always have a tab to switch *from*.
|
||||
created = EnsureTab(tab);
|
||||
}
|
||||
|
||||
auto setupTween = [&](View *view, AnchorTranslateTween *&tween) {
|
||||
_dbg_assert_(view != nullptr);
|
||||
if (tween)
|
||||
return;
|
||||
|
||||
tween = new AnchorTranslateTween(0.15f, bezierEaseInOut);
|
||||
tween->Finish.Add([&](EventParams &e) {
|
||||
e.v->SetVisibility(tabs_[currentTab_] == e.v ? V_VISIBLE : V_GONE);
|
||||
});
|
||||
view->AddTween(tween)->Persist();
|
||||
};
|
||||
|
||||
if (tab != currentTab_) {
|
||||
Orientation orient = Opposite(orientation_);
|
||||
// Direction from which the new tab will come.
|
||||
float dir = tab < currentTab_ ? -1.0f : 1.0f;
|
||||
|
||||
// First, setup any missing tweens.
|
||||
setupTween(tabs_[currentTab_], tabTweens_[currentTab_]);
|
||||
setupTween(tabs_[tab], tabTweens_[tab]);
|
||||
|
||||
// Currently displayed, so let's reset it.
|
||||
if (skipTween) {
|
||||
tabs_[currentTab_]->SetVisibility(V_GONE);
|
||||
tabTweens_[tab]->Reset(Point2D(0.0f, 0.0f));
|
||||
tabTweens_[tab]->Apply(tabs_[tab]);
|
||||
} else {
|
||||
tabTweens_[currentTab_]->Reset(Point2D(0.0f, 0.0f));
|
||||
|
||||
if (orient == ORIENT_HORIZONTAL) {
|
||||
tabTweens_[tab]->Reset(Point2D(bounds_.w * dir, 0.0f));
|
||||
tabTweens_[currentTab_]->Divert(Point2D(bounds_.w * -dir, 0.0f));
|
||||
} else {
|
||||
tabTweens_[tab]->Reset(Point2D(0.0f, bounds_.h * dir));
|
||||
tabTweens_[currentTab_]->Divert(Point2D(0.0f, bounds_.h * -dir));
|
||||
}
|
||||
// Actually move it to the initial position now, just to avoid any flicker.
|
||||
tabTweens_[tab]->Apply(tabs_[tab]);
|
||||
tabTweens_[tab]->Divert(Point2D(0.0f, 0.0f));
|
||||
}
|
||||
tabs_[tab]->SetVisibility(V_VISIBLE);
|
||||
|
||||
currentTab_ = tab;
|
||||
}
|
||||
tabStrip_->SetSelection(tab, false);
|
||||
|
||||
return created;
|
||||
}
|
||||
|
||||
void TabHolder::OnTabClick(EventParams &e) {
|
||||
// We have e.b set when it was an explicit click action.
|
||||
// In that case, we make the view gone and then visible - this scrolls scrollviews to the top.
|
||||
if (e.b != 0) {
|
||||
EnsureTab(e.a);
|
||||
SetCurrentTab((int)e.a);
|
||||
}
|
||||
}
|
||||
|
||||
void TabHolder::PersistData(PersistStatus status, std::string anonId, PersistMap &storage) {
|
||||
ViewGroup::PersistData(status, anonId, storage);
|
||||
|
||||
std::string tag = Tag();
|
||||
if (tag.empty()) {
|
||||
tag = anonId;
|
||||
}
|
||||
|
||||
PersistBuffer &buffer = storage["TabHolder::" + tag];
|
||||
switch (status) {
|
||||
case PERSIST_SAVE:
|
||||
buffer.resize(1);
|
||||
buffer[0] = currentTab_;
|
||||
break;
|
||||
|
||||
case PERSIST_RESTORE:
|
||||
if (buffer.size() == 1) {
|
||||
if (SetCurrentTab(buffer[0], true)) {
|
||||
// Re-run PersistData. TODO: Only need to do it for the new tab.
|
||||
ViewGroup::PersistData(status, anonId, storage);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TabHolder::EnableTab(int tab, bool enabled) {
|
||||
tabStrip_->EnableChoice(tab, enabled);
|
||||
}
|
||||
|
||||
|
||||
ChoiceStrip::ChoiceStrip(Orientation orientation, LayoutParams *layoutParams)
|
||||
: LinearLayout(orientation, layoutParams) {
|
||||
SetSpacing(0.0f);
|
||||
}
|
||||
|
||||
void ChoiceStrip::AddChoice(std::string_view title) {
|
||||
StickyChoice *c = new StickyChoice(title, "",
|
||||
orientation_ == ORIENT_HORIZONTAL ?
|
||||
nullptr :
|
||||
new LinearLayoutParams(FILL_PARENT, ITEM_HEIGHT));
|
||||
c->OnClick.Handle(this, &ChoiceStrip::OnChoiceClick);
|
||||
Add(c);
|
||||
choices_.push_back(c);
|
||||
if (selected_ == (int)choices_.size() - 1)
|
||||
c->Press();
|
||||
}
|
||||
|
||||
void ChoiceStrip::AddChoice(ImageID buttonImage) {
|
||||
StickyChoice *c = new StickyChoice(buttonImage,
|
||||
orientation_ == ORIENT_HORIZONTAL ?
|
||||
nullptr :
|
||||
new LinearLayoutParams(FILL_PARENT, ITEM_HEIGHT));
|
||||
c->OnClick.Handle(this, &ChoiceStrip::OnChoiceClick);
|
||||
Add(c);
|
||||
choices_.push_back(c);
|
||||
if (selected_ == (int)choices_.size() - 1)
|
||||
c->Press();
|
||||
}
|
||||
|
||||
void ChoiceStrip::AddBackButton() {
|
||||
Choice *c = new Choice(ImageID("I_NAVIGATE_BACK"));
|
||||
c->OnClick.Add([](EventParams &e) {
|
||||
e.bubbleResult = DR_BACK;
|
||||
});
|
||||
// c->OnClick.Handle(this, &UIScreen::OnBack);
|
||||
Add(c);
|
||||
Add(new Spacer(5.0f));
|
||||
}
|
||||
|
||||
void ChoiceStrip::OnChoiceClick(EventParams &e) {
|
||||
// Unstick the other choices that weren't clicked.
|
||||
for (int i = 0; i < (int)choices_.size(); i++) {
|
||||
if (choices_[i] != e.v) {
|
||||
choices_[i]->Release();
|
||||
} else {
|
||||
selected_ = i;
|
||||
}
|
||||
}
|
||||
|
||||
EventParams e2{};
|
||||
e2.v = selected_ < choices_.size() ? choices_[selected_] : nullptr;
|
||||
e2.a = selected_;
|
||||
// Set to 1 to indicate an explicit click.
|
||||
e2.b = 1;
|
||||
// Dispatch immediately (we're already on the UI thread as we're in an event handler).
|
||||
OnChoice.Dispatch(e2);
|
||||
}
|
||||
|
||||
void ChoiceStrip::SetSelection(int sel, bool triggerClick) {
|
||||
int prevSelected = selected_;
|
||||
if (selected_ < choices_.size()) {
|
||||
StickyChoice *prevChoice = choices_[selected_];
|
||||
prevChoice->Release();
|
||||
}
|
||||
selected_ = sel;
|
||||
if (selected_ < choices_.size()) {
|
||||
StickyChoice *newChoice = choices_[selected_];
|
||||
newChoice->Press();
|
||||
if (topTabs_ && prevSelected != selected_) {
|
||||
EventParams e{};
|
||||
e.v = choices_[selected_];
|
||||
e.a = selected_;
|
||||
// Set to 0 to indicate a selection change (not a click.)
|
||||
e.b = triggerClick ? 1 : 0;
|
||||
OnChoice.Trigger(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChoiceStrip::EnableChoice(int choice, bool enabled) {
|
||||
if (choice < (int)choices_.size()) {
|
||||
choices_[choice]->SetEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChoiceStrip::Key(const KeyInput &input) {
|
||||
bool ret = false;
|
||||
if (topTabs_ && (input.flags & KEY_DOWN)) {
|
||||
if (IsTabLeftKey(input)) {
|
||||
if (selected_ > 0) {
|
||||
SetSelection(selected_ - 1, true);
|
||||
UI::PlayUISound(UI::UISound::TOGGLE_OFF); // Maybe make specific sounds for this at some point?
|
||||
}
|
||||
ret = true;
|
||||
} else if (IsTabRightKey(input)) {
|
||||
if (selected_ < (int)choices_.size() - 1) {
|
||||
SetSelection(selected_ + 1, true);
|
||||
UI::PlayUISound(UI::UISound::TOGGLE_ON);
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
return ret || ViewGroup::Key(input);
|
||||
}
|
||||
|
||||
std::string ChoiceStrip::DescribeText() const {
|
||||
auto u = GetI18NCategory(I18NCat::UI_ELEMENTS);
|
||||
return DescribeListUnordered(u->T("Choices:"));
|
||||
}
|
||||
|
||||
} // namespace UI
|
||||
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "Common/UI/View.h"
|
||||
#include "Common/UI/ViewGroup.h"
|
||||
#include "Common/UI/Tween.h"
|
||||
|
||||
namespace UI {
|
||||
|
||||
class ChoiceStrip;
|
||||
class ScrollView;
|
||||
|
||||
enum class TabHolderFlags {
|
||||
Default = 0,
|
||||
BackButton = 1,
|
||||
};
|
||||
ENUM_CLASS_BITOPS(TabHolderFlags);
|
||||
|
||||
class TabHolder : public LinearLayout {
|
||||
public:
|
||||
TabHolder(Orientation orientation, float stripSize, TabHolderFlags flags, View *bannerView, LayoutParams *layoutParams);
|
||||
|
||||
template <class T>
|
||||
T *AddTab(std::string_view title, T *tabContents) {
|
||||
AddTabContents(title, tabContents);
|
||||
return tabContents;
|
||||
}
|
||||
void AddTabDeferred(std::string_view title, std::function<ViewGroup *()> createCb);
|
||||
void EnableTab(int tab, bool enabled);
|
||||
|
||||
void AddBack(UIScreen *parent);
|
||||
|
||||
// Returns true if the tab wasn't created before (but is now).
|
||||
bool SetCurrentTab(int tab, bool skipTween = false);
|
||||
|
||||
int GetCurrentTab() const { return currentTab_; }
|
||||
std::string DescribeLog() const override { return "TabHolder: " + View::DescribeLog(); }
|
||||
|
||||
void PersistData(PersistStatus status, std::string anonId, PersistMap &storage) override;
|
||||
|
||||
void EnsureAllCreated();
|
||||
|
||||
LinearLayout *Container() { return tabContainer_; }
|
||||
|
||||
const std::vector<ViewGroup *> &GetTabContentViews() const {
|
||||
return tabs_;
|
||||
}
|
||||
|
||||
private:
|
||||
void AddTabContents(std::string_view title, ViewGroup *tabContents);
|
||||
void OnTabClick(EventParams &e);
|
||||
bool EnsureTab(int index); // return true if it actually created a tab.
|
||||
|
||||
View *bannerView_ = nullptr;
|
||||
LinearLayout *tabContainer_ = nullptr;
|
||||
ChoiceStrip *tabStrip_ = nullptr;
|
||||
ScrollView *tabScroll_ = nullptr;
|
||||
ViewGroup *contents_ = nullptr;
|
||||
|
||||
int currentTab_ = 0;
|
||||
std::vector<ViewGroup *> tabs_;
|
||||
std::vector<AnchorTranslateTween *> tabTweens_;
|
||||
std::vector<std::function<ViewGroup *()>> createFuncs_;
|
||||
};
|
||||
|
||||
class ChoiceStrip : public LinearLayout {
|
||||
public:
|
||||
ChoiceStrip(Orientation orientation, LayoutParams *layoutParams = 0);
|
||||
|
||||
void AddChoice(std::string_view title);
|
||||
void AddChoice(ImageID buttonImage);
|
||||
void AddBackButton();
|
||||
|
||||
int GetSelection() const { return selected_; }
|
||||
void SetSelection(int sel, bool triggerClick);
|
||||
|
||||
void EnableChoice(int choice, bool enabled);
|
||||
|
||||
bool Key(const KeyInput &input) override;
|
||||
|
||||
void SetTopTabs(bool tabs) { topTabs_ = tabs; }
|
||||
|
||||
std::string DescribeLog() const override { return "ChoiceStrip: " + View::DescribeLog(); }
|
||||
std::string DescribeText() const override;
|
||||
|
||||
Event OnChoice;
|
||||
|
||||
private:
|
||||
void OnChoiceClick(EventParams &e);
|
||||
|
||||
std::vector<UI::StickyChoice *> choices_;
|
||||
int selected_ = 0; // Can be controlled with L/R.
|
||||
bool topTabs_ = false;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -149,7 +149,10 @@ void UIScreen::update() {
|
||||
DoRecreateViews();
|
||||
|
||||
if (root_) {
|
||||
UpdateViewHierarchy(root_);
|
||||
DialogResult result = UpdateViewHierarchy(root_);
|
||||
if (result != DR_NONE) {
|
||||
TriggerFinish(result);
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
namespace UI {
|
||||
|
||||
static constexpr Size ITEM_HEIGHT = 64.f;
|
||||
static constexpr float MIN_TEXT_SCALE = 0.8f;
|
||||
static constexpr float MAX_ITEM_SIZE = 65535.0f;
|
||||
|
||||
|
||||
+8
-3
@@ -22,6 +22,7 @@
|
||||
#include "Common/Input/KeyCodes.h"
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/UI/Screen.h" // for DialogResult
|
||||
|
||||
#undef small
|
||||
|
||||
@@ -139,6 +140,9 @@ typedef float Size; // can also be WRAP_CONTENT or FILL_PARENT.
|
||||
static constexpr Size WRAP_CONTENT = -1.0f;
|
||||
static constexpr Size FILL_PARENT = -2.0f;
|
||||
|
||||
// TODO: This needs to move to the theme.
|
||||
static constexpr Size ITEM_HEIGHT = 64.f;
|
||||
|
||||
// Gravity
|
||||
enum Gravity {
|
||||
G_LEFT = 0,
|
||||
@@ -240,10 +244,11 @@ struct MeasureSpec {
|
||||
|
||||
// Should cover all bases.
|
||||
struct EventParams {
|
||||
View *v;
|
||||
uint32_t a, b, x, y;
|
||||
float f;
|
||||
View *v = nullptr;
|
||||
uint32_t a = 0, b = 0, x = 0, y = 0;
|
||||
float f = 0.0f;
|
||||
std::string s;
|
||||
DialogResult bubbleResult = DialogResult::DR_NONE;
|
||||
};
|
||||
|
||||
typedef std::function<void(EventParams &)> EventCallback;
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
namespace UI {
|
||||
|
||||
static constexpr Size ITEM_HEIGHT = 64.f;
|
||||
|
||||
void ApplyGravity(const Bounds &outer, const Margins &margins, float w, float h, int gravity, Bounds &inner) {
|
||||
inner.w = w;
|
||||
inner.h = h;
|
||||
@@ -957,300 +955,6 @@ std::string GridLayoutList::DescribeText() const {
|
||||
return DescribeListOrdered(u->T("List:"));
|
||||
}
|
||||
|
||||
TabHolder::TabHolder(Orientation orientation, float stripSize, View *bannerView, LayoutParams *layoutParams)
|
||||
: LinearLayout(Opposite(orientation), layoutParams) {
|
||||
SetSpacing(0.0f);
|
||||
if (orientation == ORIENT_HORIZONTAL) {
|
||||
tabStrip_ = new ChoiceStrip(orientation, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||
tabStrip_->SetTopTabs(true);
|
||||
tabScroll_ = new ScrollView(orientation, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
tabScroll_->Add(tabStrip_);
|
||||
Add(tabScroll_);
|
||||
} else {
|
||||
tabContainer_ = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(stripSize, FILL_PARENT));
|
||||
tabStrip_ = new ChoiceStrip(orientation, new LayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
tabStrip_->SetTopTabs(true);
|
||||
tabScroll_ = new ScrollView(orientation, new LinearLayoutParams(1.0f));
|
||||
tabScroll_->Add(tabStrip_);
|
||||
tabContainer_->Add(tabScroll_);
|
||||
Add(tabContainer_);
|
||||
}
|
||||
tabStrip_->OnChoice.Handle(this, &TabHolder::OnTabClick);
|
||||
|
||||
Add(new Spacer(4.0f))->SetSeparator();
|
||||
|
||||
ViewGroup *contentHolder_ = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f));
|
||||
if (bannerView) {
|
||||
contentHolder_->Add(bannerView);
|
||||
bannerView_ = bannerView;
|
||||
}
|
||||
contents_ = contentHolder_->Add(new AnchorLayout(new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f)));
|
||||
contents_->SetClip(true);
|
||||
Add(contentHolder_);
|
||||
}
|
||||
|
||||
void TabHolder::AddBack(UIScreen *parent) {
|
||||
if (tabContainer_) {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
tabContainer_->Add(new Choice(di->T("Back"), "", false, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 0.0f, Margins(0, 0, 10, 10))))->OnClick.Handle<UIScreen>(parent, &UIScreen::OnBack);
|
||||
}
|
||||
}
|
||||
|
||||
void TabHolder::AddTabContents(std::string_view title, ViewGroup *tabContents) {
|
||||
tabs_.push_back(tabContents);
|
||||
tabStrip_->AddChoice(title);
|
||||
contents_->Add(tabContents);
|
||||
if (tabs_.size() > 1)
|
||||
tabContents->SetVisibility(V_GONE);
|
||||
tabContents->ReplaceLayoutParams(new AnchorLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
|
||||
// Will be filled in later.
|
||||
tabTweens_.push_back(nullptr);
|
||||
// This entry doesn't need one.
|
||||
createFuncs_.push_back(nullptr);
|
||||
}
|
||||
|
||||
void TabHolder::AddTabDeferred(std::string_view title, std::function<ViewGroup *()> createCb) {
|
||||
tabs_.push_back(nullptr); // marker
|
||||
tabStrip_->AddChoice(title);
|
||||
tabTweens_.push_back(nullptr);
|
||||
createFuncs_.push_back(createCb);
|
||||
|
||||
if (tabs_.size() == 1) {
|
||||
EnsureTab(0);
|
||||
}
|
||||
}
|
||||
|
||||
void TabHolder::EnsureAllCreated() {
|
||||
for (int i = 0; i < createFuncs_.size(); i++) {
|
||||
if (createFuncs_[i]) {
|
||||
EnsureTab(i);
|
||||
tabs_[i]->SetVisibility(i == currentTab_ ? V_VISIBLE : V_GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TabHolder::EnsureTab(int index) {
|
||||
_dbg_assert_(index >= 0 && index < createFuncs_.size());
|
||||
|
||||
if (!tabs_[index]) {
|
||||
_dbg_assert_(index < createFuncs_.size());
|
||||
_dbg_assert_(createFuncs_[index]);
|
||||
std::function<UI::ViewGroup * ()> func;
|
||||
createFuncs_[index].swap(func);
|
||||
|
||||
ViewGroup *tabContents = func();
|
||||
tabs_[index] = tabContents;
|
||||
contents_->Add(tabContents);
|
||||
|
||||
tabContents->ReplaceLayoutParams(new AnchorLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TabHolder::SetCurrentTab(int tab, bool skipTween) {
|
||||
if (tab >= (int)tabs_.size()) {
|
||||
// Ignore
|
||||
return false;
|
||||
}
|
||||
|
||||
bool created = false;
|
||||
|
||||
if (tab != currentTab_) {
|
||||
_dbg_assert_(tabs_[currentTab_]); // we should always have a tab to switch *from*.
|
||||
created = EnsureTab(tab);
|
||||
}
|
||||
|
||||
auto setupTween = [&](View *view, AnchorTranslateTween *&tween) {
|
||||
_dbg_assert_(view != nullptr);
|
||||
if (tween)
|
||||
return;
|
||||
|
||||
tween = new AnchorTranslateTween(0.15f, bezierEaseInOut);
|
||||
tween->Finish.Add([&](EventParams &e) {
|
||||
e.v->SetVisibility(tabs_[currentTab_] == e.v ? V_VISIBLE : V_GONE);
|
||||
});
|
||||
view->AddTween(tween)->Persist();
|
||||
};
|
||||
|
||||
if (tab != currentTab_) {
|
||||
Orientation orient = Opposite(orientation_);
|
||||
// Direction from which the new tab will come.
|
||||
float dir = tab < currentTab_ ? -1.0f : 1.0f;
|
||||
|
||||
// First, setup any missing tweens.
|
||||
setupTween(tabs_[currentTab_], tabTweens_[currentTab_]);
|
||||
setupTween(tabs_[tab], tabTweens_[tab]);
|
||||
|
||||
// Currently displayed, so let's reset it.
|
||||
if (skipTween) {
|
||||
tabs_[currentTab_]->SetVisibility(V_GONE);
|
||||
tabTweens_[tab]->Reset(Point2D(0.0f, 0.0f));
|
||||
tabTweens_[tab]->Apply(tabs_[tab]);
|
||||
} else {
|
||||
tabTweens_[currentTab_]->Reset(Point2D(0.0f, 0.0f));
|
||||
|
||||
if (orient == ORIENT_HORIZONTAL) {
|
||||
tabTweens_[tab]->Reset(Point2D(bounds_.w * dir, 0.0f));
|
||||
tabTweens_[currentTab_]->Divert(Point2D(bounds_.w * -dir, 0.0f));
|
||||
} else {
|
||||
tabTweens_[tab]->Reset(Point2D(0.0f, bounds_.h * dir));
|
||||
tabTweens_[currentTab_]->Divert(Point2D(0.0f, bounds_.h * -dir));
|
||||
}
|
||||
// Actually move it to the initial position now, just to avoid any flicker.
|
||||
tabTweens_[tab]->Apply(tabs_[tab]);
|
||||
tabTweens_[tab]->Divert(Point2D(0.0f, 0.0f));
|
||||
}
|
||||
tabs_[tab]->SetVisibility(V_VISIBLE);
|
||||
|
||||
currentTab_ = tab;
|
||||
}
|
||||
tabStrip_->SetSelection(tab, false);
|
||||
|
||||
return created;
|
||||
}
|
||||
|
||||
void TabHolder::OnTabClick(EventParams &e) {
|
||||
// We have e.b set when it was an explicit click action.
|
||||
// In that case, we make the view gone and then visible - this scrolls scrollviews to the top.
|
||||
if (e.b != 0) {
|
||||
EnsureTab(e.a);
|
||||
SetCurrentTab((int)e.a);
|
||||
}
|
||||
}
|
||||
|
||||
void TabHolder::PersistData(PersistStatus status, std::string anonId, PersistMap &storage) {
|
||||
ViewGroup::PersistData(status, anonId, storage);
|
||||
|
||||
std::string tag = Tag();
|
||||
if (tag.empty()) {
|
||||
tag = anonId;
|
||||
}
|
||||
|
||||
PersistBuffer &buffer = storage["TabHolder::" + tag];
|
||||
switch (status) {
|
||||
case PERSIST_SAVE:
|
||||
buffer.resize(1);
|
||||
buffer[0] = currentTab_;
|
||||
break;
|
||||
|
||||
case PERSIST_RESTORE:
|
||||
if (buffer.size() == 1) {
|
||||
if (SetCurrentTab(buffer[0], true)) {
|
||||
// Re-run PersistData. TODO: Only need to do it for the new tab.
|
||||
ViewGroup::PersistData(status, anonId, storage);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ChoiceStrip::ChoiceStrip(Orientation orientation, LayoutParams *layoutParams)
|
||||
: LinearLayout(orientation, layoutParams) {
|
||||
SetSpacing(0.0f);
|
||||
}
|
||||
|
||||
void ChoiceStrip::AddChoice(std::string_view title) {
|
||||
StickyChoice *c = new StickyChoice(title, "",
|
||||
orientation_ == ORIENT_HORIZONTAL ?
|
||||
nullptr :
|
||||
new LinearLayoutParams(FILL_PARENT, ITEM_HEIGHT));
|
||||
c->OnClick.Handle(this, &ChoiceStrip::OnChoiceClick);
|
||||
Add(c);
|
||||
if (selected_ == (int)views_.size() - 1)
|
||||
c->Press();
|
||||
}
|
||||
|
||||
void ChoiceStrip::AddChoice(ImageID buttonImage) {
|
||||
StickyChoice *c = new StickyChoice(buttonImage,
|
||||
orientation_ == ORIENT_HORIZONTAL ?
|
||||
nullptr :
|
||||
new LinearLayoutParams(FILL_PARENT, ITEM_HEIGHT));
|
||||
c->OnClick.Handle(this, &ChoiceStrip::OnChoiceClick);
|
||||
Add(c);
|
||||
if (selected_ == (int)views_.size() - 1)
|
||||
c->Press();
|
||||
}
|
||||
|
||||
void ChoiceStrip::OnChoiceClick(EventParams &e) {
|
||||
// Unstick the other choices that weren't clicked.
|
||||
for (int i = 0; i < (int)views_.size(); i++) {
|
||||
if (views_[i] != e.v) {
|
||||
Choice(i)->Release();
|
||||
} else {
|
||||
selected_ = i;
|
||||
}
|
||||
}
|
||||
|
||||
EventParams e2{};
|
||||
e2.v = views_[selected_];
|
||||
e2.a = selected_;
|
||||
// Set to 1 to indicate an explicit click.
|
||||
e2.b = 1;
|
||||
// Dispatch immediately (we're already on the UI thread as we're in an event handler).
|
||||
OnChoice.Dispatch(e2);
|
||||
}
|
||||
|
||||
void ChoiceStrip::SetSelection(int sel, bool triggerClick) {
|
||||
int prevSelected = selected_;
|
||||
StickyChoice *prevChoice = Choice(selected_);
|
||||
if (prevChoice)
|
||||
prevChoice->Release();
|
||||
selected_ = sel;
|
||||
StickyChoice *newChoice = Choice(selected_);
|
||||
if (newChoice) {
|
||||
newChoice->Press();
|
||||
|
||||
if (topTabs_ && prevSelected != selected_) {
|
||||
EventParams e{};
|
||||
e.v = views_[selected_];
|
||||
e.a = selected_;
|
||||
// Set to 0 to indicate a selection change (not a click.)
|
||||
e.b = triggerClick ? 1 : 0;
|
||||
OnChoice.Trigger(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChoiceStrip::EnableChoice(int choice, bool enabled) {
|
||||
if (choice < (int)views_.size()) {
|
||||
Choice(choice)->SetEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChoiceStrip::Key(const KeyInput &input) {
|
||||
bool ret = false;
|
||||
if (topTabs_ && (input.flags & KEY_DOWN)) {
|
||||
if (IsTabLeftKey(input)) {
|
||||
if (selected_ > 0) {
|
||||
SetSelection(selected_ - 1, true);
|
||||
UI::PlayUISound(UI::UISound::TOGGLE_OFF); // Maybe make specific sounds for this at some point?
|
||||
}
|
||||
ret = true;
|
||||
} else if (IsTabRightKey(input)) {
|
||||
if (selected_ < (int)views_.size() - 1) {
|
||||
SetSelection(selected_ + 1, true);
|
||||
UI::PlayUISound(UI::UISound::TOGGLE_ON);
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
return ret || ViewGroup::Key(input);
|
||||
}
|
||||
|
||||
std::string ChoiceStrip::DescribeText() const {
|
||||
auto u = GetI18NCategory(I18NCat::UI_ELEMENTS);
|
||||
return DescribeListUnordered(u->T("Choices:"));
|
||||
}
|
||||
|
||||
StickyChoice *ChoiceStrip::Choice(int index) {
|
||||
if ((size_t)index < views_.size())
|
||||
return static_cast<StickyChoice *>(views_[index]);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CollapsibleSection::CollapsibleSection(std::string_view title, LayoutParams *layoutParams) : LinearLayout(ORIENT_VERTICAL, layoutParams) {
|
||||
open_ = &localOpen_;
|
||||
SetSpacing(0.0f);
|
||||
|
||||
@@ -260,84 +260,6 @@ public:
|
||||
std::string DescribeText() const override;
|
||||
};
|
||||
|
||||
class ChoiceStrip : public LinearLayout {
|
||||
public:
|
||||
ChoiceStrip(Orientation orientation, LayoutParams *layoutParams = 0);
|
||||
|
||||
void AddChoice(std::string_view title);
|
||||
void AddChoice(ImageID buttonImage);
|
||||
|
||||
int GetSelection() const { return selected_; }
|
||||
void SetSelection(int sel, bool triggerClick);
|
||||
|
||||
void EnableChoice(int choice, bool enabled);
|
||||
|
||||
bool Key(const KeyInput &input) override;
|
||||
|
||||
void SetTopTabs(bool tabs) { topTabs_ = tabs; }
|
||||
|
||||
std::string DescribeLog() const override { return "ChoiceStrip: " + View::DescribeLog(); }
|
||||
std::string DescribeText() const override;
|
||||
|
||||
Event OnChoice;
|
||||
|
||||
private:
|
||||
StickyChoice *Choice(int index);
|
||||
void OnChoiceClick(EventParams &e);
|
||||
|
||||
int selected_ = 0; // Can be controlled with L/R.
|
||||
bool topTabs_ = false;
|
||||
};
|
||||
|
||||
class TabHolder : public LinearLayout {
|
||||
public:
|
||||
TabHolder(Orientation orientation, float stripSize, View *bannerView, LayoutParams *layoutParams = 0);
|
||||
|
||||
template <class T>
|
||||
T *AddTab(std::string_view title, T *tabContents) {
|
||||
AddTabContents(title, tabContents);
|
||||
return tabContents;
|
||||
}
|
||||
void AddTabDeferred(std::string_view title, std::function<ViewGroup *()> createCb);
|
||||
void EnableTab(int tab, bool enabled) {
|
||||
tabStrip_->EnableChoice(tab, enabled);
|
||||
}
|
||||
|
||||
void AddBack(UIScreen *parent);
|
||||
|
||||
// Returns true if the tab wasn't created before (but is now).
|
||||
bool SetCurrentTab(int tab, bool skipTween = false);
|
||||
|
||||
int GetCurrentTab() const { return currentTab_; }
|
||||
std::string DescribeLog() const override { return "TabHolder: " + View::DescribeLog(); }
|
||||
|
||||
void PersistData(PersistStatus status, std::string anonId, PersistMap &storage) override;
|
||||
|
||||
void EnsureAllCreated();
|
||||
|
||||
LinearLayout *Container() { return tabContainer_; }
|
||||
|
||||
const std::vector<ViewGroup *> &GetTabContentViews() const {
|
||||
return tabs_;
|
||||
}
|
||||
|
||||
private:
|
||||
void AddTabContents(std::string_view title, ViewGroup *tabContents);
|
||||
void OnTabClick(EventParams &e);
|
||||
bool EnsureTab(int index); // return true if it actually created a tab.
|
||||
|
||||
View *bannerView_ = nullptr;
|
||||
LinearLayout *tabContainer_ = nullptr;
|
||||
ChoiceStrip *tabStrip_ = nullptr;
|
||||
ScrollView *tabScroll_ = nullptr;
|
||||
ViewGroup *contents_ = nullptr;
|
||||
|
||||
int currentTab_ = 0;
|
||||
std::vector<ViewGroup *> tabs_;
|
||||
std::vector<AnchorTranslateTween *> tabTweens_;
|
||||
std::vector<std::function<ViewGroup *()>> createFuncs_;
|
||||
};
|
||||
|
||||
class CollapsibleHeader;
|
||||
|
||||
class CollapsibleSection : public LinearLayout {
|
||||
|
||||
@@ -245,6 +245,8 @@ static const ConfigSetting generalSettings[] = {
|
||||
ConfigSetting("CwCheatRefreshRate", &g_Config.iCwCheatRefreshIntervalMs, 77, CfgFlag::PER_GAME),
|
||||
ConfigSetting("CwCheatScrollPosition", &g_Config.fCwCheatScrollPosition, 0.0f, CfgFlag::PER_GAME),
|
||||
ConfigSetting("GameListScrollPosition", &g_Config.fGameListScrollPosition, 0.0f, CfgFlag::DEFAULT),
|
||||
ConfigSetting("HomebrewScrollPosition", &g_Config.fHomebrewScrollPosition, 0.0f, CfgFlag::DEFAULT),
|
||||
ConfigSetting("RemoteScrollPosition", &g_Config.fRemoteScrollPosition, 0.0f, CfgFlag::DEFAULT),
|
||||
ConfigSetting("DebugOverlay", &g_Config.iDebugOverlay, 0, CfgFlag::DONT_SAVE),
|
||||
ConfigSetting("DefaultTab", &g_Config.iDefaultTab, 0, CfgFlag::DEFAULT),
|
||||
ConfigSetting("DisableHLEFlags", &g_Config.iDisableHLE, 0, CfgFlag::PER_GAME),
|
||||
@@ -270,6 +272,7 @@ static const ConfigSetting generalSettings[] = {
|
||||
ConfigSetting("GridView1", &g_Config.bGridView1, true, CfgFlag::DEFAULT),
|
||||
ConfigSetting("GridView2", &g_Config.bGridView2, true, CfgFlag::DEFAULT),
|
||||
ConfigSetting("GridView3", &g_Config.bGridView3, false, CfgFlag::DEFAULT),
|
||||
ConfigSetting("GridView4", &g_Config.bGridView4, false, CfgFlag::DEFAULT),
|
||||
ConfigSetting("RightAnalogUp", &g_Config.iRightAnalogUp, 0, CfgFlag::PER_GAME),
|
||||
ConfigSetting("RightAnalogDown", &g_Config.iRightAnalogDown, 0, CfgFlag::PER_GAME),
|
||||
ConfigSetting("RightAnalogLeft", &g_Config.iRightAnalogLeft, 0, CfgFlag::PER_GAME),
|
||||
|
||||
+4
-1
@@ -260,6 +260,8 @@ public:
|
||||
int iCwCheatRefreshIntervalMs;
|
||||
float fCwCheatScrollPosition;
|
||||
float fGameListScrollPosition;
|
||||
float fHomebrewScrollPosition;
|
||||
float fRemoteScrollPosition;
|
||||
int iBloomHack; //0 = off, 1 = safe, 2 = balanced, 3 = aggressive
|
||||
int iSkipGPUReadbackMode; // 0 = off, 1 = skip, 2 = to texture
|
||||
int iSplineBezierQuality; // 0 = low , 1 = Intermediate , 2 = High
|
||||
@@ -350,10 +352,11 @@ public:
|
||||
// 0 - no tilt, 1 - analog stick, 2 - D-Pad, 3 - Action Buttons (Tri, Cross, Square, Circle)
|
||||
int iTiltInputType;
|
||||
|
||||
// The three tabs.
|
||||
// The four tabs (including Remote last)
|
||||
bool bGridView1;
|
||||
bool bGridView2;
|
||||
bool bGridView3;
|
||||
bool bGridView4;
|
||||
|
||||
// Right analog binding
|
||||
int iRightAnalogUp;
|
||||
|
||||
+2
-2
@@ -474,7 +474,7 @@ void ShaderListScreen::CreateViews() {
|
||||
LinearLayout *layout = new LinearLayout(ORIENT_VERTICAL);
|
||||
root_ = layout;
|
||||
|
||||
tabs_ = new TabHolder(ORIENT_HORIZONTAL, 40, nullptr, new LinearLayoutParams(1.0));
|
||||
tabs_ = new TabHolder(ORIENT_HORIZONTAL, 40, TabHolderFlags::Default, nullptr, new LinearLayoutParams(1.0));
|
||||
tabs_->SetTag("DevShaderList");
|
||||
layout->Add(tabs_);
|
||||
layout->Add(new Button(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
@@ -549,7 +549,7 @@ void FrameDumpTestScreen::CreateViews() {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
|
||||
TabHolder *tabHolder;
|
||||
tabHolder = new TabHolder(ORIENT_VERTICAL, 200, nullptr, new AnchorLayoutParams(10, 0, 10, 0, false));
|
||||
tabHolder = new TabHolder(ORIENT_VERTICAL, 200, TabHolderFlags::Default, nullptr, new AnchorLayoutParams(10, 0, 10, 0, false));
|
||||
root_->Add(tabHolder);
|
||||
tabHolder->AddBack(this);
|
||||
tabHolder->SetTag("DumpTypes");
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
#include "Common/UI/Context.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "Common/UI/UIScreen.h"
|
||||
#include "Common/UI/TabHolder.h"
|
||||
#include "Common/Math/math_util.h"
|
||||
#include "Common/System/Display.h"
|
||||
#include "Common/System/NativeApp.h"
|
||||
#include "Common/VR/PPSSPPVR.h"
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
|
||||
#include "MiscScreens.h"
|
||||
|
||||
namespace UI {
|
||||
class ChoiceStrip;
|
||||
}
|
||||
|
||||
class DisplayLayoutScreen : public UIDialogScreenWithGameBackground {
|
||||
public:
|
||||
DisplayLayoutScreen(const Path &filename);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "Core/Config.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "UI/View.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "UI/DriverManagerScreen.h"
|
||||
#include "UI/GameSettingsScreen.h" // for triggerrestart
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
@@ -79,8 +79,6 @@ public:
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
static constexpr UI::Size ITEM_HEIGHT = 64.f;
|
||||
|
||||
DriverChoice::DriverChoice(const std::string &driverName, bool current, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_VERTICAL, layoutParams), name_(driverName) {
|
||||
using namespace UI;
|
||||
SetSpacing(2.0f);
|
||||
|
||||
@@ -301,7 +301,7 @@ void GPUDriverTestScreen::CreateViews() {
|
||||
AnchorLayout *anchor = new AnchorLayout();
|
||||
root_ = anchor;
|
||||
|
||||
tabHolder_ = new TabHolder(ORIENT_HORIZONTAL, 30.0f, nullptr, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, false));
|
||||
tabHolder_ = new TabHolder(ORIENT_HORIZONTAL, 30.0f, TabHolderFlags::Default, nullptr, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, false));
|
||||
anchor->Add(tabHolder_);
|
||||
tabHolder_->AddTab("Discard", new LinearLayout(ORIENT_VERTICAL));
|
||||
tabHolder_->AddTab("Shader", new LinearLayout(ORIENT_VERTICAL));
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Common/UI/Context.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "Common/UI/ViewGroup.h"
|
||||
#include "Common/UI/TabHolder.h"
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
|
||||
+20
-32
@@ -299,7 +299,13 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings)
|
||||
|
||||
static const char *internalResolutions[] = { "Auto (1:1)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP", "6x PSP", "7x PSP", "8x PSP", "9x PSP", "10x PSP" };
|
||||
resolutionChoice_ = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iInternalResolution, gr->T("Rendering Resolution"), internalResolutions, 0, ARRAY_SIZE(internalResolutions), I18NCat::GRAPHICS, screenManager()));
|
||||
resolutionChoice_->OnChoice.Handle(this, &GameSettingsScreen::OnResolutionChange);
|
||||
resolutionChoice_->OnChoice.Add([](UI::EventParams &e) {
|
||||
if (g_Config.iAndroidHwScale == 1) {
|
||||
System_RecreateActivity();
|
||||
}
|
||||
Reporting::UpdateConfig();
|
||||
System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED);
|
||||
});
|
||||
resolutionChoice_->SetEnabledFunc([] {
|
||||
return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects;
|
||||
});
|
||||
@@ -784,8 +790,12 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings)
|
||||
int deviceType = System_GetPropertyInt(SYSPROP_DEVICE_TYPE);
|
||||
|
||||
controlsSettings->Add(new ItemHeader(ms->T("Controls")));
|
||||
controlsSettings->Add(new Choice(co->T("Control Mapping")))->OnClick.Handle(this, &GameSettingsScreen::OnControlMapping);
|
||||
controlsSettings->Add(new Choice(co->T("Calibrate Analog Stick")))->OnClick.Handle(this, &GameSettingsScreen::OnCalibrateAnalogs);
|
||||
controlsSettings->Add(new Choice(co->T("Control Mapping")))->OnClick.Add([this](UI::EventParams &e) {
|
||||
screenManager()->push(new ControlMappingScreen(gamePath_));
|
||||
});
|
||||
controlsSettings->Add(new Choice(co->T("Calibrate Analog Stick")))->OnClick.Add([this](UI::EventParams &e) {
|
||||
screenManager()->push(new AnalogSetupScreen(gamePath_));
|
||||
});
|
||||
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogTriggerThreshold, 0.02f, 0.98f, 0.75f, co->T("Analog trigger threshold"), screenManager()));
|
||||
|
||||
#if defined(USING_WIN_UI) || (PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID))
|
||||
@@ -804,7 +814,9 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings)
|
||||
}
|
||||
return "";
|
||||
}));
|
||||
customizeTilt->OnClick.Handle(this, &GameSettingsScreen::OnTiltCustomize);
|
||||
customizeTilt->OnClick.Add([this](UI::EventParams &e) {
|
||||
screenManager()->push(new TouchControlLayoutScreen(gamePath_));
|
||||
});
|
||||
} else if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_VR) { // TODO: This seems like a regression
|
||||
controlsSettings->Add(new CheckBox(&g_Config.bHapticFeedback, co->T("HapticFeedback", "Haptic Feedback (vibration)")));
|
||||
}
|
||||
@@ -814,7 +826,9 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings)
|
||||
controlsSettings->Add(new ItemHeader(co->T("OnScreen", "On-Screen Touch Controls")));
|
||||
controlsSettings->Add(new CheckBox(&g_Config.bShowTouchControls, co->T("OnScreen", "On-Screen Touch Controls")));
|
||||
layoutEditorChoice_ = controlsSettings->Add(new Choice(co->T("Customize Touch Controls")));
|
||||
layoutEditorChoice_->OnClick.Handle(this, &GameSettingsScreen::OnTouchControlLayout);
|
||||
layoutEditorChoice_->OnClick.Add([this](UI::EventParams &e) {
|
||||
screenManager()->push(new TouchControlLayoutScreen(gamePath_));
|
||||
});
|
||||
layoutEditorChoice_->SetEnabledPtr(&g_Config.bShowTouchControls);
|
||||
|
||||
Choice *gesture = controlsSettings->Add(new Choice(co->T("Gesture mapping")));
|
||||
@@ -922,8 +936,6 @@ public:
|
||||
MacAddressChooser(RequesterToken token, Path gamePath, std::string *value, std::string_view title, ScreenManager *screenManager, UI::LayoutParams *layoutParams = nullptr);
|
||||
};
|
||||
|
||||
static constexpr UI::Size ITEM_HEIGHT = 64.f;
|
||||
|
||||
MacAddressChooser::MacAddressChooser(RequesterToken token, Path gamePath_, std::string *value, std::string_view title, ScreenManager *screenManager, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_HORIZONTAL, layoutParams) {
|
||||
using namespace UI;
|
||||
SetSpacing(5.0f);
|
||||
@@ -1601,14 +1613,6 @@ void GameSettingsScreen::OnFullscreenMultiChange(UI::EventParams &e) {
|
||||
System_ToggleFullscreenState(g_Config.UseFullScreen() ? "1" : "0");
|
||||
}
|
||||
|
||||
void GameSettingsScreen::OnResolutionChange(UI::EventParams &e) {
|
||||
if (g_Config.iAndroidHwScale == 1) {
|
||||
System_RecreateActivity();
|
||||
}
|
||||
Reporting::UpdateConfig();
|
||||
System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED);
|
||||
}
|
||||
|
||||
void GameSettingsScreen::onFinish(DialogResult result) {
|
||||
Reporting::Enable(enableReports_, "report.ppsspp.org");
|
||||
Reporting::UpdateConfig();
|
||||
@@ -1806,22 +1810,6 @@ void GameSettingsScreen::OnTextureShaderChange(UI::EventParams &e) {
|
||||
g_Config.bTexHardwareScaling = g_Config.sTextureShaderName != "Off";
|
||||
}
|
||||
|
||||
void GameSettingsScreen::OnControlMapping(UI::EventParams &e) {
|
||||
screenManager()->push(new ControlMappingScreen(gamePath_));
|
||||
}
|
||||
|
||||
void GameSettingsScreen::OnCalibrateAnalogs(UI::EventParams &e) {
|
||||
screenManager()->push(new AnalogSetupScreen(gamePath_));
|
||||
}
|
||||
|
||||
void GameSettingsScreen::OnTouchControlLayout(UI::EventParams &e) {
|
||||
screenManager()->push(new TouchControlLayoutScreen(gamePath_));
|
||||
}
|
||||
|
||||
void GameSettingsScreen::OnTiltCustomize(UI::EventParams &e) {
|
||||
screenManager()->push(new TiltAnalogSettingsScreen(gamePath_));
|
||||
};
|
||||
|
||||
void GameSettingsScreen::CallbackRestoreDefaults(bool yes) {
|
||||
if (yes) {
|
||||
g_Config.RestoreDefaults(RestoreSettingsBits::SETTINGS);
|
||||
@@ -2055,7 +2043,7 @@ void GestureMappingScreen::CreateViews() {
|
||||
|
||||
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
AddStandardBack(root_);
|
||||
TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, 200, nullptr, new AnchorLayoutParams(10, 0, 10, 0, false));
|
||||
TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, 200, TabHolderFlags::Default, nullptr, new AnchorLayoutParams(10, 0, 10, 0, false));
|
||||
root_->Add(tabHolder);
|
||||
ScrollView *rightPanel = new ScrollView(ORIENT_VERTICAL);
|
||||
tabHolder->AddTab(co->T("Gesture"), rightPanel);
|
||||
|
||||
@@ -74,12 +74,6 @@ private:
|
||||
|
||||
std::string memstickDisplay_;
|
||||
|
||||
// Event handlers
|
||||
void OnControlMapping(UI::EventParams &e);
|
||||
void OnCalibrateAnalogs(UI::EventParams &e);
|
||||
void OnTouchControlLayout(UI::EventParams &e);
|
||||
void OnTiltCustomize(UI::EventParams &e);
|
||||
|
||||
// Global settings handlers
|
||||
void OnAutoFrameskip(UI::EventParams &e);
|
||||
void OnTextureShader(UI::EventParams &e);
|
||||
@@ -92,7 +86,6 @@ private:
|
||||
void OnChangeBackground(UI::EventParams &e);
|
||||
void OnFullscreenChange(UI::EventParams &e);
|
||||
void OnFullscreenMultiChange(UI::EventParams &e);
|
||||
void OnResolutionChange(UI::EventParams &e);
|
||||
void OnRestoreDefaultSettings(UI::EventParams &e);
|
||||
void OnRenderingBackend(UI::EventParams &e);
|
||||
void OnRenderingDevice(UI::EventParams &e);
|
||||
|
||||
+61
-72
@@ -1068,6 +1068,59 @@ MainScreen::~MainScreen() {
|
||||
g_BackgroundAudio.SetGame(Path());
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(IOS)
|
||||
constexpr std::string_view getGamesUri = "https://www.ppsspp.org/getgames_ios";
|
||||
constexpr std::string_view getHomebrewUri = "https://www.ppsspp.org/gethomebrew_ios";
|
||||
#else
|
||||
constexpr std::string_view getGamesUri = "https://www.ppsspp.org/getgames";
|
||||
constexpr std::string_view getHomebrewUri = "https://www.ppsspp.org/gethomebrew";
|
||||
#endif
|
||||
constexpr std::string_view remoteGamesUri = "https://www.ppsspp.org/docs/reference/disc-streaming";
|
||||
|
||||
void MainScreen::CreateRecentTab() {
|
||||
using namespace UI;
|
||||
auto mm = GetI18NCategory(I18NCat::MAINMENU);
|
||||
|
||||
ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
scrollRecentGames->SetTag("MainScreenRecentGames");
|
||||
GameBrowser *tabRecentGames = new GameBrowser(GetRequesterToken(),
|
||||
Path("!RECENT"), BrowseFlags::NONE, &g_Config.bGridView1, screenManager(), "", "",
|
||||
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
scrollRecentGames->Add(tabRecentGames);
|
||||
gameBrowsers_.push_back(tabRecentGames);
|
||||
|
||||
tabHolder_->AddTab(mm->T("Recent"), scrollRecentGames);
|
||||
tabRecentGames->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant);
|
||||
tabRecentGames->OnHoldChoice.Handle(this, &MainScreen::OnGameSelected);
|
||||
tabRecentGames->OnHighlight.Handle(this, &MainScreen::OnGameHighlight);
|
||||
}
|
||||
|
||||
GameBrowser *MainScreen::CreateBrowserTab(const Path &path, std::string_view title, std::string_view howToTitle, std::string_view howToUri, BrowseFlags browseFlags, bool *bGridView, float *scrollPos) {
|
||||
using namespace UI;
|
||||
auto mm = GetI18NCategory(I18NCat::MAINMENU);
|
||||
|
||||
ScrollView *scrollView = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
scrollView->SetTag(title); // Re-use title as tag, should be fine.
|
||||
|
||||
GameBrowser *gameBrowser = new GameBrowser(GetRequesterToken(), path, browseFlags, bGridView, screenManager(),
|
||||
mm->T(howToTitle), howToUri,
|
||||
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
|
||||
scrollView->Add(gameBrowser);
|
||||
gameBrowsers_.push_back(gameBrowser);
|
||||
|
||||
tabHolder_->AddTab(mm->T(title), scrollView);
|
||||
if (scrollPos) {
|
||||
scrollView->RememberPosition(scrollPos);
|
||||
}
|
||||
|
||||
gameBrowser->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant);
|
||||
gameBrowser->OnHoldChoice.Handle(this, &MainScreen::OnGameSelected);
|
||||
gameBrowser->OnHighlight.Handle(this, &MainScreen::OnGameHighlight);
|
||||
|
||||
return gameBrowser;
|
||||
}
|
||||
|
||||
void MainScreen::CreateViews() {
|
||||
// Information in the top left.
|
||||
// Back button to the bottom left.
|
||||
@@ -1078,7 +1131,7 @@ void MainScreen::CreateViews() {
|
||||
|
||||
auto mm = GetI18NCategory(I18NCat::MAINMENU);
|
||||
|
||||
tabHolder_ = new TabHolder(ORIENT_HORIZONTAL, 64, nullptr, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f));
|
||||
tabHolder_ = new TabHolder(ORIENT_HORIZONTAL, 64, TabHolderFlags::Default, nullptr, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f));
|
||||
ViewGroup *leftColumn = tabHolder_;
|
||||
tabHolder_->SetTag("MainScreenGames");
|
||||
gameBrowsers_.clear();
|
||||
@@ -1094,81 +1147,18 @@ void MainScreen::CreateViews() {
|
||||
}
|
||||
|
||||
if (showRecent) {
|
||||
ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
scrollRecentGames->SetTag("MainScreenRecentGames");
|
||||
GameBrowser *tabRecentGames = new GameBrowser(GetRequesterToken(),
|
||||
Path("!RECENT"), BrowseFlags::NONE, &g_Config.bGridView1, screenManager(), "", "",
|
||||
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
scrollRecentGames->Add(tabRecentGames);
|
||||
gameBrowsers_.push_back(tabRecentGames);
|
||||
|
||||
tabHolder_->AddTab(mm->T("Recent"), scrollRecentGames);
|
||||
tabRecentGames->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant);
|
||||
tabRecentGames->OnHoldChoice.Handle(this, &MainScreen::OnGameSelected);
|
||||
tabRecentGames->OnHighlight.Handle(this, &MainScreen::OnGameHighlight);
|
||||
CreateRecentTab();
|
||||
}
|
||||
|
||||
Button *focusButton = nullptr;
|
||||
if (hasStorageAccess) {
|
||||
scrollAllGames_ = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
scrollAllGames_->SetTag("MainScreenAllGames");
|
||||
ScrollView *scrollHomebrew = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
scrollHomebrew->SetTag("MainScreenHomebrew");
|
||||
|
||||
#if PPSSPP_PLATFORM(IOS)
|
||||
std::string_view getGamesUri = "https://www.ppsspp.org/getgames_ios";
|
||||
std::string_view getHomebrewUri = "https://www.ppsspp.org/gethomebrew_ios";
|
||||
#else
|
||||
std::string_view getGamesUri = "https://www.ppsspp.org/getgames";
|
||||
std::string_view getHomebrewUri = "https://www.ppsspp.org/gethomebrew";
|
||||
#endif
|
||||
|
||||
GameBrowser *tabAllGames = new GameBrowser(GetRequesterToken(), Path(g_Config.currentDirectory), BrowseFlags::STANDARD, &g_Config.bGridView2, screenManager(),
|
||||
mm->T("How to get games"), getGamesUri,
|
||||
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
GameBrowser *tabHomebrew = new GameBrowser(GetRequesterToken(), GetSysDirectory(DIRECTORY_GAME), BrowseFlags::HOMEBREW_STORE, &g_Config.bGridView3, screenManager(),
|
||||
mm->T("How to get homebrew & demos", "How to get homebrew && demos"), getHomebrewUri,
|
||||
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
|
||||
scrollAllGames_->Add(tabAllGames);
|
||||
gameBrowsers_.push_back(tabAllGames);
|
||||
scrollHomebrew->Add(tabHomebrew);
|
||||
gameBrowsers_.push_back(tabHomebrew);
|
||||
|
||||
tabHolder_->AddTab(mm->T("Games"), scrollAllGames_);
|
||||
tabHolder_->AddTab(mm->T("Homebrew & Demos"), scrollHomebrew);
|
||||
scrollAllGames_->RememberPosition(&g_Config.fGameListScrollPosition);
|
||||
|
||||
tabAllGames->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant);
|
||||
tabHomebrew->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant);
|
||||
|
||||
tabAllGames->OnHoldChoice.Handle(this, &MainScreen::OnGameSelected);
|
||||
tabHomebrew->OnHoldChoice.Handle(this, &MainScreen::OnGameSelected);
|
||||
|
||||
tabAllGames->OnHighlight.Handle(this, &MainScreen::OnGameHighlight);
|
||||
tabHomebrew->OnHighlight.Handle(this, &MainScreen::OnGameHighlight);
|
||||
CreateBrowserTab(Path(g_Config.currentDirectory), "Games", "How to get games", getGamesUri, BrowseFlags::STANDARD, &g_Config.bGridView2, &g_Config.fGameListScrollPosition);
|
||||
CreateBrowserTab(GetSysDirectory(DIRECTORY_GAME), "Homebrew & Demos", "How to get homebrew & demos", getHomebrewUri, BrowseFlags::HOMEBREW_STORE, &g_Config.bGridView3, &g_Config.fHomebrewScrollPosition);
|
||||
|
||||
if (g_Config.bRemoteTab && !g_Config.sLastRemoteISOServer.empty()) {
|
||||
auto ri = GetI18NCategory(I18NCat::REMOTEISO);
|
||||
|
||||
ScrollView *scrollRemote = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
scrollRemote->SetTag("MainScreenRemote");
|
||||
|
||||
Path remotePath(FormatRemoteISOUrl(g_Config.sLastRemoteISOServer.c_str(), g_Config.iLastRemoteISOPort, RemoteSubdir().c_str()));
|
||||
|
||||
GameBrowser *tabRemote = new GameBrowser(GetRequesterToken(), remotePath, BrowseFlags::NAVIGATE, &g_Config.bGridView3, screenManager(),
|
||||
ri->T("Remote disc streaming"), "https://www.ppsspp.org/docs/reference/disc-streaming",
|
||||
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
tabRemote->SetHomePath(remotePath);
|
||||
|
||||
scrollRemote->Add(tabRemote);
|
||||
gameBrowsers_.push_back(tabRemote);
|
||||
|
||||
tabHolder_->AddTab(ri->T("Remote disc streaming"), scrollRemote);
|
||||
|
||||
tabRemote->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant);
|
||||
tabRemote->OnHoldChoice.Handle(this, &MainScreen::OnGameSelected);
|
||||
tabRemote->OnHighlight.Handle(this, &MainScreen::OnGameHighlight);
|
||||
GameBrowser *remoteBrowser = CreateBrowserTab(remotePath, "Remote disc streaming", "Remote disc streaming", remoteGamesUri, BrowseFlags::NAVIGATE, &g_Config.bGridView4, &g_Config.fRemoteScrollPosition);
|
||||
remoteBrowser->SetHomePath(remotePath);
|
||||
}
|
||||
|
||||
if (g_recentFiles.HasAny()) {
|
||||
@@ -1202,7 +1192,6 @@ void MainScreen::CreateViews() {
|
||||
leftColumn->Add(new Spacer(new LinearLayoutParams(0.1f)));
|
||||
}
|
||||
} else {
|
||||
scrollAllGames_ = nullptr;
|
||||
if (!showRecent) {
|
||||
leftColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f));
|
||||
// Just so it's destroyed on recreate.
|
||||
@@ -1227,7 +1216,6 @@ void MainScreen::CreateViews() {
|
||||
ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL);
|
||||
LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
rightColumnItems->SetSpacing(0.0f);
|
||||
rightColumn->Add(rightColumnItems);
|
||||
|
||||
std::string versionString = PPSSPP_GIT_VERSION;
|
||||
// Strip the 'v' from the displayed version, and shorten the commit hash.
|
||||
@@ -1308,6 +1296,7 @@ void MainScreen::CreateViews() {
|
||||
// Officially, iOS apps should not have exit buttons. Remove it to maximize app store review chances.
|
||||
rightColumnChoices->Add(new Choice(mm->T("Exit")))->OnClick.Handle(this, &MainScreen::OnExit);
|
||||
#endif
|
||||
rightColumn->Add(rightColumnItems);
|
||||
|
||||
if (vertical) {
|
||||
root_ = new LinearLayout(ORIENT_VERTICAL);
|
||||
@@ -1579,7 +1568,7 @@ void UmdReplaceScreen::CreateViews() {
|
||||
auto mm = GetI18NCategory(I18NCat::MAINMENU);
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
|
||||
TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64, nullptr, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0));
|
||||
TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64, TabHolderFlags::Default, nullptr, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0));
|
||||
leftColumn->SetTag("UmdReplace");
|
||||
leftColumn->SetClip(true);
|
||||
|
||||
|
||||
+6
-1
@@ -18,10 +18,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
|
||||
#include "Common/File/Path.h"
|
||||
#include "Common/UI/UIScreen.h"
|
||||
#include "Common/UI/ViewGroup.h"
|
||||
#include "Common/UI/TabHolder.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
#include "Common/File/PathBrowser.h"
|
||||
|
||||
@@ -131,6 +133,10 @@ public:
|
||||
|
||||
protected:
|
||||
void CreateViews() override;
|
||||
void CreateRecentTab();
|
||||
GameBrowser *CreateBrowserTab(const Path &path, std::string_view title, std::string_view howToTitle, std::string_view howToUri, BrowseFlags browseFlags, bool *bGridView, float *scrollPos);
|
||||
UI::ViewGroup *CreateButtons(bool vertical);
|
||||
|
||||
void DrawBackground(UIContext &dc) override;
|
||||
void update() override;
|
||||
void sendMessage(UIMessage message, const char *value) override;
|
||||
@@ -165,7 +171,6 @@ protected:
|
||||
bool lockBackgroundAudio_ = false;
|
||||
bool lastVertical_ = false;
|
||||
bool confirmedTemporary_ = false;
|
||||
UI::ScrollView *scrollAllGames_ = nullptr;
|
||||
bool searchKeyModifier_ = false;
|
||||
bool searchChanged_ = false;
|
||||
std::string searchFilter_;
|
||||
|
||||
@@ -595,7 +595,7 @@ void RemoteISOBrowseScreen::CreateViews() {
|
||||
|
||||
using namespace UI;
|
||||
|
||||
TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64, nullptr, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64, TabHolderFlags::Default, nullptr, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
tabHolder_ = leftColumn;
|
||||
tabHolder_->SetTag("RemoteGames");
|
||||
gameBrowsers_.clear();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Common/System/Request.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "Common/UI/ViewGroup.h"
|
||||
#include "Common/UI/TabHolder.h"
|
||||
#include "Common/UI/Context.h"
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/UI/IconCache.h"
|
||||
@@ -26,8 +27,6 @@ public:
|
||||
UI::UISound sound_;
|
||||
};
|
||||
|
||||
static constexpr UI::Size ITEM_HEIGHT = 64.f;
|
||||
|
||||
AudioFileChooser::AudioFileChooser(RequesterToken token, std::string *value, std::string_view title, UI::UISound sound, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_HORIZONTAL, layoutParams), sound_(sound) {
|
||||
using namespace UI;
|
||||
SetSpacing(2.0f);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Common/System/NativeApp.h"
|
||||
#include "Common/System/Request.h"
|
||||
#include "Common/System/Display.h"
|
||||
#include "Common/UI/TabHolder.h"
|
||||
#include "UI/TabbedDialogScreen.h"
|
||||
|
||||
void TabbedUIDialogScreenWithGameBackground::AddTab(const char *tag, std::string_view title, std::function<void(UI::LinearLayout *)> createCallback, bool isSearch) {
|
||||
@@ -39,13 +40,12 @@ void TabbedUIDialogScreenWithGameBackground::CreateViews() {
|
||||
if (vertical) {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
LinearLayout *verticalLayout = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
tabHolder_ = new TabHolder(ORIENT_HORIZONTAL, 200, filterNotice_, new LinearLayoutParams(1.0f));
|
||||
tabHolder_ = new TabHolder(ORIENT_HORIZONTAL, 200, TabHolderFlags::BackButton, filterNotice_, new LinearLayoutParams(1.0f));
|
||||
verticalLayout->Add(tabHolder_);
|
||||
CreateExtraButtons(verticalLayout, 0);
|
||||
verticalLayout->Add(new Choice(di->T("Back"), "", false, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 0.0f, Margins(10, 0))))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
root_->Add(verticalLayout);
|
||||
} else {
|
||||
tabHolder_ = new TabHolder(ORIENT_VERTICAL, 200, filterNotice_, new AnchorLayoutParams(10, 0, 10, 0, false));
|
||||
tabHolder_ = new TabHolder(ORIENT_VERTICAL, 200, TabHolderFlags::Default, filterNotice_, new AnchorLayoutParams(10, 0, 10, 0, false));
|
||||
CreateExtraButtons(tabHolder_->Container(), 10);
|
||||
tabHolder_->AddBack(this);
|
||||
root_->Add(tabHolder_);
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#include "Core/ConfigValues.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
|
||||
namespace UI {
|
||||
class TabHolder;
|
||||
}
|
||||
|
||||
class TabbedUIDialogScreenWithGameBackground : public UIDialogScreenWithGameBackground {
|
||||
public:
|
||||
TabbedUIDialogScreenWithGameBackground(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) {}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "Common/UI/View.h"
|
||||
#include "Common/UI/ViewGroup.h"
|
||||
#include "Common/UI/TabHolder.h"
|
||||
#include "MiscScreens.h"
|
||||
|
||||
class ControlLayoutView;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "Common/UI/TabHolder.h"
|
||||
#include "Common/Render/TextureAtlas.h"
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/StringUtils.h"
|
||||
@@ -57,7 +58,7 @@ void TouchControlVisibilityScreen::CreateViews() {
|
||||
Choice *toggleAll = new Choice(di->T("Toggle All"), "", false, new AnchorLayoutParams(leftColumnWidth - 10, WRAP_CONTENT, 10, NONE, NONE, 84));
|
||||
root_->Add(toggleAll)->OnClick.Handle(this, &TouchControlVisibilityScreen::OnToggleAll);
|
||||
|
||||
TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, leftColumnWidth, nullptr, new AnchorLayoutParams(10, 0, 10, 0, false));
|
||||
TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, leftColumnWidth, TabHolderFlags::Default, nullptr, new AnchorLayoutParams(10, 0, 10, 0, false));
|
||||
tabHolder->SetTag("TouchControlVisibility");
|
||||
root_->Add(tabHolder);
|
||||
ScrollView *rightPanel = new ScrollView(ORIENT_VERTICAL);
|
||||
@@ -142,7 +143,7 @@ void RightAnalogMappingScreen::CreateViews() {
|
||||
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(leftColumnWidth - 10, WRAP_CONTENT, 10, NONE, NONE, 10));
|
||||
root_->Add(back)->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, leftColumnWidth, nullptr, new AnchorLayoutParams(10, 0, 10, 0, false));
|
||||
TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, leftColumnWidth, TabHolderFlags::Default, nullptr, new AnchorLayoutParams(10, 0, 10, 0, false));
|
||||
root_->Add(tabHolder);
|
||||
ScrollView *rightPanel = new ScrollView(ORIENT_VERTICAL);
|
||||
tabHolder->AddTab(co->T("Binds"), rightPanel);
|
||||
|
||||
@@ -129,6 +129,14 @@ static const ImageMeta imageIDs[] = {
|
||||
{"I_PIN", false},
|
||||
{"I_UNPIN", false},
|
||||
{"I_FOLDER_PINNED", false},
|
||||
{"I_FILLED_CIRCLE_1", false},
|
||||
{"I_FILLED_CIRCLE_2", false},
|
||||
{"I_FILLED_CIRCLE_3", false},
|
||||
{"I_FILLED_CIRCLE_4", false},
|
||||
{"I_FILLED_CIRCLE_5", false},
|
||||
{"I_SETTINGS_DISPLAY", false},
|
||||
{"I_NAVIGATE_BACK", false},
|
||||
{"I_NAVIGATE_FORWARD", false},
|
||||
};
|
||||
|
||||
static std::string PNGNameFromID(std::string_view id) {
|
||||
|
||||
@@ -221,6 +221,7 @@
|
||||
<ClInclude Include="..\..\Common\UI\Root.h" />
|
||||
<ClInclude Include="..\..\Common\UI\Screen.h" />
|
||||
<ClInclude Include="..\..\Common\UI\ScrollView.h" />
|
||||
<ClInclude Include="..\..\Common\UI\TabHolder.h" />
|
||||
<ClInclude Include="..\..\Common\UI\Tween.h" />
|
||||
<ClInclude Include="..\..\Common\UI\UI.h" />
|
||||
<ClInclude Include="..\..\Common\UI\UIScreen.h" />
|
||||
@@ -384,6 +385,7 @@
|
||||
<ClCompile Include="..\..\Common\UI\Root.cpp" />
|
||||
<ClCompile Include="..\..\Common\UI\Screen.cpp" />
|
||||
<ClCompile Include="..\..\Common\UI\ScrollView.cpp" />
|
||||
<ClCompile Include="..\..\Common\UI\TabHolder.cpp" />
|
||||
<ClCompile Include="..\..\Common\UI\Tween.cpp" />
|
||||
<ClCompile Include="..\..\Common\UI\UI.cpp" />
|
||||
<ClCompile Include="..\..\Common\UI\UIScreen.cpp" />
|
||||
|
||||
@@ -523,6 +523,9 @@
|
||||
<ClCompile Include="..\..\Common\Render\AtlasGen.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Common\UI\TabHolder.cpp">
|
||||
<Filter>UI</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="targetver.h" />
|
||||
@@ -1005,6 +1008,9 @@
|
||||
<ClInclude Include="..\..\Common\Render\AtlasGen.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Common\UI\TabHolder.h">
|
||||
<Filter>UI</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\Common\Math\fast\fast_matrix_neon.S">
|
||||
|
||||
@@ -365,6 +365,7 @@ EXEC_AND_LIB_FILES := \
|
||||
$(SRC)/Common/UI/View.cpp \
|
||||
$(SRC)/Common/UI/ViewGroup.cpp \
|
||||
$(SRC)/Common/UI/ScrollView.cpp \
|
||||
$(SRC)/Common/UI/TabHolder.cpp \
|
||||
$(SRC)/Common/UI/PopupScreens.cpp \
|
||||
$(SRC)/Common/Serialize/Serializer.cpp \
|
||||
$(SRC)/Common/ArmCPUDetect.cpp \
|
||||
|
||||
+1001
-1927
File diff suppressed because it is too large.
Load diff
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 203 KiB |
@@ -0,0 +1,5 @@
|
||||
Most of the vectors in images.svg are custom drawn by hrydgard and NABN00B.
|
||||
|
||||
Some are derived from public domain SVGs from the following sites:
|
||||
|
||||
www.svgrepo.com
|
||||
Reference in new issue
Block a user