diff --git a/CMakeLists.txt b/CMakeLists.txt index a9b8b7f232..32149723a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1569,6 +1569,8 @@ list(APPEND NativeAppSource UI/ImDebugger/ImJitViewer.h UI/DiscordIntegration.cpp UI/NativeApp.cpp + UI/AdhocServerScreen.h + UI/AdhocServerScreen.cpp UI/BackgroundAudio.h UI/BackgroundAudio.cpp UI/Background.h diff --git a/UI/AdhocServerScreen.cpp b/UI/AdhocServerScreen.cpp new file mode 100644 index 0000000000..03cfd6ecba --- /dev/null +++ b/UI/AdhocServerScreen.cpp @@ -0,0 +1,215 @@ +#include "AdhocServerScreen.h" + +#include "Common/Net/Resolve.h" +#include "Common/UI/Root.h" +#include "Common/StringUtils.h" + +AdhocServerScreen::AdhocServerScreen(std::string *value, std::vector &listItems, std::string_view title) + : UI::PopupScreen(title, T(I18NCat::DIALOG, "OK"), T(I18NCat::DIALOG, "Cancel")), listItems_(listItems), value_(value) { + resolver_ = std::thread([](AdhocServerScreen *thiz) { + thiz->ResolverThread(); + }, this); +} +AdhocServerScreen::~AdhocServerScreen() { + { + std::unique_lock guard(resolverLock_); + resolverState_ = ResolverState::QUIT; + resolverCond_.notify_one(); + } + resolver_.join(); +} + +void AdhocServerScreen::CreatePopupContents(UI::ViewGroup *parent) { + using namespace UI; + auto sy = GetI18NCategory(I18NCat::SYSTEM); + auto di = GetI18NCategory(I18NCat::DIALOG); + auto n = GetI18NCategory(I18NCat::NETWORKING); + + LinearLayout *valueRow = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, Margins(0, 0, 0, 10))); + + addrView_ = new TextEdit(*value_, n->T("Hostname"), ""); + addrView_->SetTextAlign(FLAG_DYNAMIC_ASCII); + valueRow->Add(addrView_); + parent->Add(valueRow); + + LinearLayout *buttonsRow1 = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); + LinearLayout *buttonsRow2 = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); + parent->Add(buttonsRow1); + parent->Add(buttonsRow2); + + buttonsRow1->Add(new Spacer(new LinearLayoutParams(1.0, Gravity::G_LEFT))); + for (char c = '0'; c <= '9'; ++c) { + char label[] = {c, '\0'}; + auto button = buttonsRow1->Add(new Button(label)); + button->OnClick.Handle(this, &AdhocServerScreen::OnNumberClick); + button->SetTag(label); + } + buttonsRow1->Add(new Button("."))->OnClick.Handle(this, &AdhocServerScreen::OnPointClick); + buttonsRow1->Add(new Spacer(new LinearLayoutParams(1.0, Gravity::G_RIGHT))); + + buttonsRow2->Add(new Spacer(new LinearLayoutParams(1.0, Gravity::G_LEFT))); + if (System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) { + buttonsRow2->Add(new Button(di->T("Edit")))->OnClick.Handle(this, &AdhocServerScreen::OnEditClick); + } + buttonsRow2->Add(new Button(di->T("Delete")))->OnClick.Handle(this, &AdhocServerScreen::OnDeleteClick); + buttonsRow2->Add(new Button(di->T("Delete all")))->OnClick.Handle(this, &AdhocServerScreen::OnDeleteAllClick); + buttonsRow2->Add(new Spacer(new LinearLayoutParams(1.0, Gravity::G_RIGHT))); + + std::vector listIP; + for (const auto &item : listItems_) { + listIP.push_back(item.hostname); + } + + // Add non-editable items + listIP.push_back("localhost"); + net::GetLocalIP4List(listIP); + + LinearLayout *ipRows_ = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0)); + ScrollView *scrollView = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); + LinearLayout* innerView = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); + if (listIP.size() > 0) { + for (const auto& label : listIP) { + // Filter out IP prefixed with "127." and "169.254." also "0." since they can be rendundant or unusable + if (label.find("127.") != 0 && label.find("169.254.") != 0 && label.find("0.") != 0) { + auto button = innerView->Add(new Button(label, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + button->OnClick.Handle(this, &AdhocServerScreen::OnIPClick); + button->SetTag(label); + } + } + } + + scrollView->Add(innerView); + ipRows_->Add(scrollView); + parent->Add(ipRows_); + listIP.clear(); listIP.shrink_to_fit(); + + progressView_ = parent->Add(new TextView(n->T("Validating address..."), ALIGN_HCENTER, false, new LinearLayoutParams(Margins(0, 5, 0, 0)))); + progressView_->SetVisibility(UI::V_GONE); +} + +void AdhocServerScreen::SendEditKey(InputKeyCode keyCode, KeyInputFlags flags) { + auto oldView = UI::GetFocusedView(); + UI::SetFocusedView(addrView_); + KeyInput fakeKey{DEVICE_ID_KEYBOARD, keyCode, KeyInputFlags::DOWN | flags}; + addrView_->Key(fakeKey); + UI::SetFocusedView(oldView); +} + +void AdhocServerScreen::OnNumberClick(UI::EventParams &e) { + std::string text = e.v ? e.v->Tag() : ""; + if (text.length() == 1 && text[0] >= '0' && text[0] <= '9') { + SendEditKey((InputKeyCode)text[0], KeyInputFlags::CHAR); // ASCII for digits match keycodes. + } +} + +void AdhocServerScreen::OnPointClick(UI::EventParams &e) { + SendEditKey((InputKeyCode)'.', KeyInputFlags::CHAR); +} + +void AdhocServerScreen::OnDeleteClick(UI::EventParams &e) { + SendEditKey(NKCODE_DEL); +} + +void AdhocServerScreen::OnDeleteAllClick(UI::EventParams &e) { + addrView_->SetText(""); +} + +void AdhocServerScreen::OnEditClick(UI::EventParams& e) { + auto n = GetI18NCategory(I18NCat::NETWORKING); + System_InputBoxGetString(GetRequesterToken(), n->T("proAdhocServer Address:"), addrView_->GetText(), false, [this](const std::string& value, int) { + addrView_->SetText(value); + }); +} + +void AdhocServerScreen::OnIPClick(UI::EventParams& e) { + std::string text = e.v ? e.v->Tag() : ""; + if (text.length() > 0) { + addrView_->SetText(text); + // Copy the IP to clipboard for the host to easily share their IP through chatting apps. + System_CopyStringToClipboard(text); + } +} + +void AdhocServerScreen::ResolverThread() { + std::unique_lock guard(resolverLock_); + + while (resolverState_ != ResolverState::QUIT) { + resolverCond_.wait(guard); + + if (resolverState_ == ResolverState::QUEUED) { + resolverState_ = ResolverState::PROGRESS; + + addrinfo *resolved = nullptr; + std::string err; + toResolveResult_ = net::DNSResolve(toResolve_, "80", &resolved, err); + if (resolved) + net::DNSResolveFree(resolved); + + resolverState_ = ResolverState::READY; + } + } +} + +bool AdhocServerScreen::CanComplete(DialogResult result) { + auto n = GetI18NCategory(I18NCat::NETWORKING); + + if (result != DR_OK) + return true; + + std::string value = addrView_->GetText(); + if (lastResolved_ == value) { + return true; + } + + // Currently running. + if (resolverState_ == ResolverState::PROGRESS) + return false; + + std::lock_guard guard(resolverLock_); + switch (resolverState_) { + case ResolverState::PROGRESS: + case ResolverState::QUIT: + return false; + + case ResolverState::QUEUED: + case ResolverState::WAITING: + break; + + case ResolverState::READY: + if (toResolve_ == value) { + // Reset the state, nothing there now. + resolverState_ = ResolverState::WAITING; + toResolve_.clear(); + lastResolved_ = value; + lastResolvedResult_ = toResolveResult_; + + if (lastResolvedResult_) { + progressView_->SetVisibility(UI::V_GONE); + } else { + progressView_->SetText(n->T("Invalid IP or hostname")); + progressView_->SetTextColor(0xFF3030FF); + progressView_->SetVisibility(UI::V_VISIBLE); + } + return true; + } + + // Throw away that last result, it was for a different value. + break; + } + + resolverState_ = ResolverState::QUEUED; + toResolve_ = value; + resolverCond_.notify_one(); + + progressView_->SetText(n->T("Validating address...")); + progressView_->SetTextColor(0xFFFFFFFF); + progressView_->SetVisibility(UI::V_VISIBLE); + + return false; +} + +void AdhocServerScreen::OnCompleted(DialogResult result) { + if (result == DR_OK) { + *value_ = StripSpaces(addrView_->GetText()); + } +} diff --git a/UI/AdhocServerScreen.h b/UI/AdhocServerScreen.h new file mode 100644 index 0000000000..497e8c9826 --- /dev/null +++ b/UI/AdhocServerScreen.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include "Common/UI/View.h" +#include "Common/UI/PopupScreens.h" +#include "Core/Config.h" // for AdhocServerListEntry! + +class AdhocServerScreen : public UI::PopupScreen { +public: + AdhocServerScreen(std::string *value, std::vector &listItems, std::string_view title); + ~AdhocServerScreen(); + + void CreatePopupContents(UI::ViewGroup *parent) override; + + const char *tag() const override { return "AdhocServer"; } + +protected: + void OnCompleted(DialogResult result) override; + bool CanComplete(DialogResult result) override; + +private: + void ResolverThread(); + void SendEditKey(InputKeyCode keyCode, KeyInputFlags flags = (KeyInputFlags)0); + + void OnNumberClick(UI::EventParams &e); + void OnPointClick(UI::EventParams &e); + void OnDeleteClick(UI::EventParams &e); + void OnDeleteAllClick(UI::EventParams &e); + void OnEditClick(UI::EventParams& e); + void OnIPClick(UI::EventParams& e); + + enum class ResolverState { + WAITING, + QUEUED, + PROGRESS, + READY, + QUIT, + }; + + std::string *value_; + std::vector listItems_; + UI::TextEdit *addrView_ = nullptr; + UI::TextView *progressView_ = nullptr; + + std::thread resolver_; + ResolverState resolverState_ = ResolverState::WAITING; + std::mutex resolverLock_; + std::condition_variable resolverCond_; + std::string toResolve_ = ""; + bool toResolveResult_ = false; + std::string lastResolved_ = ""; + bool lastResolvedResult_ = false; +}; + diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 7748b63167..e33028321c 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -63,6 +63,7 @@ #include "UI/Background.h" #include "UI/BackgroundAudio.h" #include "UI/MiscViews.h" +#include "UI/AdhocServerScreen.h" #include "Common/File/FileUtil.h" #include "Common/File/AndroidContentURI.h" @@ -1053,7 +1054,7 @@ void GameSettingsScreen::CreateNetworkingSettings(UI::ViewGroup *networkingSetti list_to_use = downloadedProAdhocServerList; } downloadedProAdhocServerListMutex.unlock(); - screenManager()->push(new HostnameSelectScreen(&g_Config.sProAdhocServer, list_to_use, n->T("proAdhocServer Address:"))); + screenManager()->push(new AdhocServerScreen(&g_Config.sProAdhocServer, list_to_use, n->T("proAdhocServer Address:"))); }); networkingSettings->Add(new SettingHint(n->T("Change proAdhocServer address hint"))); @@ -1871,210 +1872,6 @@ void GameSettingsScreen::OnRestoreDefaultSettings(UI::EventParams &e) { } } -void HostnameSelectScreen::CreatePopupContents(UI::ViewGroup *parent) { - using namespace UI; - auto sy = GetI18NCategory(I18NCat::SYSTEM); - auto di = GetI18NCategory(I18NCat::DIALOG); - auto n = GetI18NCategory(I18NCat::NETWORKING); - - LinearLayout *valueRow = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, Margins(0, 0, 0, 10))); - - addrView_ = new TextEdit(*value_, n->T("Hostname"), ""); - addrView_->SetTextAlign(FLAG_DYNAMIC_ASCII); - valueRow->Add(addrView_); - parent->Add(valueRow); - - LinearLayout *buttonsRow1 = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); - LinearLayout *buttonsRow2 = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); - parent->Add(buttonsRow1); - parent->Add(buttonsRow2); - - buttonsRow1->Add(new Spacer(new LinearLayoutParams(1.0, Gravity::G_LEFT))); - for (char c = '0'; c <= '9'; ++c) { - char label[] = { c, '\0' }; - auto button = buttonsRow1->Add(new Button(label)); - button->OnClick.Handle(this, &HostnameSelectScreen::OnNumberClick); - button->SetTag(label); - } - buttonsRow1->Add(new Button("."))->OnClick.Handle(this, &HostnameSelectScreen::OnPointClick); - buttonsRow1->Add(new Spacer(new LinearLayoutParams(1.0, Gravity::G_RIGHT))); - - buttonsRow2->Add(new Spacer(new LinearLayoutParams(1.0, Gravity::G_LEFT))); - if (System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) { - buttonsRow2->Add(new Button(di->T("Edit")))->OnClick.Handle(this, &HostnameSelectScreen::OnEditClick); - } - buttonsRow2->Add(new Button(di->T("Delete")))->OnClick.Handle(this, &HostnameSelectScreen::OnDeleteClick); - buttonsRow2->Add(new Button(di->T("Delete all")))->OnClick.Handle(this, &HostnameSelectScreen::OnDeleteAllClick); - buttonsRow2->Add(new Button(di->T("Toggle List")))->OnClick.Handle(this, &HostnameSelectScreen::OnShowIPListClick); - buttonsRow2->Add(new Spacer(new LinearLayoutParams(1.0, Gravity::G_RIGHT))); - - std::vector listIP; - for (const auto &item : listItems_) { - listIP.push_back(item.hostname); - } - - // Add non-editable items - listIP.push_back("localhost"); - net::GetLocalIP4List(listIP); - - ipRows_ = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0)); - ScrollView* scrollView = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); - LinearLayout* innerView = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); - if (listIP.size() > 0) { - for (const auto& label : listIP) { - // Filter out IP prefixed with "127." and "169.254." also "0." since they can be rendundant or unusable - if (label.find("127.") != 0 && label.find("169.254.") != 0 && label.find("0.") != 0) { - auto button = innerView->Add(new Button(label, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); - button->OnClick.Handle(this, &HostnameSelectScreen::OnIPClick); - button->SetTag(label); - } - } - } - scrollView->Add(innerView); - ipRows_->Add(scrollView); - ipRows_->SetVisibility(V_GONE); - parent->Add(ipRows_); - listIP.clear(); listIP.shrink_to_fit(); - - progressView_ = parent->Add(new TextView(n->T("Validating address..."), ALIGN_HCENTER, false, new LinearLayoutParams(Margins(0, 5, 0, 0)))); - progressView_->SetVisibility(UI::V_GONE); -} - -void HostnameSelectScreen::SendEditKey(InputKeyCode keyCode, KeyInputFlags flags) { - auto oldView = UI::GetFocusedView(); - UI::SetFocusedView(addrView_); - KeyInput fakeKey{ DEVICE_ID_KEYBOARD, keyCode, KeyInputFlags::DOWN | flags }; - addrView_->Key(fakeKey); - UI::SetFocusedView(oldView); -} - -void HostnameSelectScreen::OnNumberClick(UI::EventParams &e) { - std::string text = e.v ? e.v->Tag() : ""; - if (text.length() == 1 && text[0] >= '0' && text[0] <= '9') { - SendEditKey((InputKeyCode)text[0], KeyInputFlags::CHAR); // ASCII for digits match keycodes. - } -} - -void HostnameSelectScreen::OnPointClick(UI::EventParams &e) { - SendEditKey((InputKeyCode)'.', KeyInputFlags::CHAR); -} - -void HostnameSelectScreen::OnDeleteClick(UI::EventParams &e) { - SendEditKey(NKCODE_DEL); -} - -void HostnameSelectScreen::OnDeleteAllClick(UI::EventParams &e) { - addrView_->SetText(""); -} - -void HostnameSelectScreen::OnEditClick(UI::EventParams& e) { - auto n = GetI18NCategory(I18NCat::NETWORKING); - System_InputBoxGetString(GetRequesterToken(), n->T("proAdhocServer Address:"), addrView_->GetText(), false, [this](const std::string& value, int) { - addrView_->SetText(value); - }); -} - -void HostnameSelectScreen::OnShowIPListClick(UI::EventParams& e) { - if (ipRows_->GetVisibility() == UI::V_GONE) { - ipRows_->SetVisibility(UI::V_VISIBLE); - } - else { - ipRows_->SetVisibility(UI::V_GONE); - } -} - -void HostnameSelectScreen::OnIPClick(UI::EventParams& e) { - std::string text = e.v ? e.v->Tag() : ""; - if (text.length() > 0) { - addrView_->SetText(text); - // Copy the IP to clipboard for the host to easily share their IP through chatting apps. - System_CopyStringToClipboard(text); - } -} - -void HostnameSelectScreen::ResolverThread() { - std::unique_lock guard(resolverLock_); - - while (resolverState_ != ResolverState::QUIT) { - resolverCond_.wait(guard); - - if (resolverState_ == ResolverState::QUEUED) { - resolverState_ = ResolverState::PROGRESS; - - addrinfo *resolved = nullptr; - std::string err; - toResolveResult_ = net::DNSResolve(toResolve_, "80", &resolved, err); - if (resolved) - net::DNSResolveFree(resolved); - - resolverState_ = ResolverState::READY; - } - } -} - -bool HostnameSelectScreen::CanComplete(DialogResult result) { - auto n = GetI18NCategory(I18NCat::NETWORKING); - - if (result != DR_OK) - return true; - - std::string value = addrView_->GetText(); - if (lastResolved_ == value) { - return true; - } - - // Currently running. - if (resolverState_ == ResolverState::PROGRESS) - return false; - - std::lock_guard guard(resolverLock_); - switch (resolverState_) { - case ResolverState::PROGRESS: - case ResolverState::QUIT: - return false; - - case ResolverState::QUEUED: - case ResolverState::WAITING: - break; - - case ResolverState::READY: - if (toResolve_ == value) { - // Reset the state, nothing there now. - resolverState_ = ResolverState::WAITING; - toResolve_.clear(); - lastResolved_ = value; - lastResolvedResult_ = toResolveResult_; - - if (lastResolvedResult_) { - progressView_->SetVisibility(UI::V_GONE); - } else { - progressView_->SetText(n->T("Invalid IP or hostname")); - progressView_->SetTextColor(0xFF3030FF); - progressView_->SetVisibility(UI::V_VISIBLE); - } - return true; - } - - // Throw away that last result, it was for a different value. - break; - } - - resolverState_ = ResolverState::QUEUED; - toResolve_ = value; - resolverCond_.notify_one(); - - progressView_->SetText(n->T("Validating address...")); - progressView_->SetTextColor(0xFFFFFFFF); - progressView_->SetVisibility(UI::V_VISIBLE); - - return false; -} - -void HostnameSelectScreen::OnCompleted(DialogResult result) { - if (result == DR_OK) - *value_ = StripSpaces(addrView_->GetText()); -} - void GestureMappingScreen::CreateTabs() { auto di = GetI18NCategory(I18NCat::DIALOG); AddTab("Gesture", di->T("Left side"), [this](UI::LinearLayout *parent) { CreateGestureTab(parent, 0, GetDeviceOrientation() == DeviceOrientation::Portrait); }); diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 67d36c1a5b..001949107e 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -113,67 +113,6 @@ private: std::string pendingMemstickFolder_; }; -class HostnameSelectScreen : public UI::PopupScreen { -public: - HostnameSelectScreen(std::string *value, std::vector &listItems, std::string_view title) - : UI::PopupScreen(title, T(I18NCat::DIALOG, "OK"), T(I18NCat::DIALOG, "Cancel")), listItems_(listItems), value_(value) { - resolver_ = std::thread([](HostnameSelectScreen *thiz) { - thiz->ResolverThread(); - }, this); - } - ~HostnameSelectScreen() { - { - std::unique_lock guard(resolverLock_); - resolverState_ = ResolverState::QUIT; - resolverCond_.notify_one(); - } - resolver_.join(); - } - - void CreatePopupContents(UI::ViewGroup *parent) override; - - const char *tag() const override { return "HostnameSelect"; } - -protected: - void OnCompleted(DialogResult result) override; - bool CanComplete(DialogResult result) override; - -private: - void ResolverThread(); - void SendEditKey(InputKeyCode keyCode, KeyInputFlags flags = (KeyInputFlags)0); - - void OnNumberClick(UI::EventParams &e); - void OnPointClick(UI::EventParams &e); - void OnDeleteClick(UI::EventParams &e); - void OnDeleteAllClick(UI::EventParams &e); - void OnEditClick(UI::EventParams& e); - void OnShowIPListClick(UI::EventParams& e); - void OnIPClick(UI::EventParams& e); - - enum class ResolverState { - WAITING, - QUEUED, - PROGRESS, - READY, - QUIT, - }; - - std::string *value_; - std::vector listItems_; - UI::TextEdit *addrView_ = nullptr; - UI::TextView *progressView_ = nullptr; - UI::LinearLayout *ipRows_ = nullptr; - - std::thread resolver_; - ResolverState resolverState_ = ResolverState::WAITING; - std::mutex resolverLock_; - std::condition_variable resolverCond_; - std::string toResolve_ = ""; - bool toResolveResult_ = false; - std::string lastResolved_ = ""; - bool lastResolvedResult_ = false; -}; - class GestureMappingScreen : public UITabbedBaseDialogScreen { public: GestureMappingScreen(const Path &gamePath) : UITabbedBaseDialogScreen(gamePath) {} diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index e199b21376..c80c1c5eb5 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -27,6 +27,7 @@ + @@ -82,6 +83,7 @@ + diff --git a/UI/UI.vcxproj.filters b/UI/UI.vcxproj.filters index fc871858a6..272a1fbab5 100644 --- a/UI/UI.vcxproj.filters +++ b/UI/UI.vcxproj.filters @@ -144,6 +144,9 @@ Screens + + Screens + @@ -285,6 +288,9 @@ Screens + + Screens + diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index dacc3e0a04..aff7d22ab8 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -85,6 +85,7 @@ + @@ -140,6 +141,7 @@ + @@ -211,4 +213,4 @@ - + \ No newline at end of file diff --git a/UWP/UI_UWP/UI_UWP.vcxproj.filters b/UWP/UI_UWP/UI_UWP.vcxproj.filters index bc90bc3a1c..d217ef4ef9 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj.filters +++ b/UWP/UI_UWP/UI_UWP.vcxproj.filters @@ -135,6 +135,9 @@ + + Screens + @@ -268,6 +271,9 @@ + + Screens + diff --git a/android/jni/Android.mk b/android/jni/Android.mk index eb3326d33b..9ec54ad1f8 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -915,6 +915,7 @@ LOCAL_SRC_FILES := \ $(SRC)/UI/EmuScreen.cpp \ $(SRC)/UI/MainScreen.cpp \ $(SRC)/UI/TabbedDialogScreen.cpp \ + $(SRC)/UI/AdhocServerScreen.cpp \ $(SRC)/UI/SimpleDialogScreen.cpp \ $(SRC)/UI/MemStickScreen.cpp \ $(SRC)/UI/IAPScreen.cpp \ diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index ecb08f0470..04e0f0b921 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -497,8 +497,8 @@ Supported = Stöds There is no data = Det finns ingen data. This change will not take effect until PPSSPP is restarted. = Denna ändring träder inte i kraft förrän PPSSPP har startats om. This will overwrite the existing configuration = Detta kommer att skriva över den befintliga konfigurationen # AI translated -Toggle All = Vänd alla -Toggle List = Vänd lista +Toggle All = Toggla alla +Toggle List = Toggla lista Top Center = Överkant centrerad Top Left = Överkant vänster Top Right = Överkant höger