Embed server browser as main menu modal
Refactors the browser UI into a reusable `CO_Browser.create()` module and adds embedded modal styling so MULTIPLAYER opens inside the main menu instead of swapping to a separate view. Updates main-menu JS/CSS to host, animate, and route input for the browser panel while keeping nav and prompts in sync. On the C++ side, PrismaUI now drives browser show/hide and event dispatch through the main menu view, and `ServerBrowserBridge::SetView()` was added so bridge events target the active host view.
This commit is contained in:
+104
-27
@@ -66,6 +66,8 @@ namespace F4T::PrismaUI
|
||||
void CreateServerBrowserView();
|
||||
void SyncBrowserHover();
|
||||
void WatchMainMenuState();
|
||||
[[nodiscard]] PrismaView GetActiveBrowserView();
|
||||
void ActivateEmbeddedBrowser();
|
||||
void InstallMainMenuCursorReleaseHook();
|
||||
void RegisterMenuAdvanceSink();
|
||||
void ReleaseMenuCursorConstraints();
|
||||
@@ -473,7 +475,8 @@ namespace F4T::PrismaUI
|
||||
|
||||
void SyncBrowserHover()
|
||||
{
|
||||
if (!g_browserVisible || !g_browserDomReady || !g_api || !g_api->IsValid(g_serverBrowserView)) {
|
||||
const auto activeView = GetActiveBrowserView();
|
||||
if (!g_browserVisible || !g_api || activeView == 0 || !g_api->IsValid(activeView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -493,12 +496,48 @@ namespace F4T::PrismaUI
|
||||
|
||||
::ScreenToClient(reinterpret_cast<HWND>(renderWindow->hwnd), &cursor);
|
||||
|
||||
const auto script = std::format(
|
||||
"if(window.CO_Hover&&window.CO_Hover.updateFromPoint){{window.CO_Hover.updateFromPoint({},{});}}",
|
||||
cursor.x,
|
||||
cursor.y);
|
||||
g_api->Invoke(g_serverBrowserView, script.c_str());
|
||||
}
|
||||
const auto script = std::format(
|
||||
"if(window.CO_Hover&&window.CO_Hover.updateFromPoint){{window.CO_Hover.updateFromPoint({},{});}}",
|
||||
cursor.x,
|
||||
cursor.y);
|
||||
g_api->Invoke(activeView, script.c_str());
|
||||
}
|
||||
|
||||
PrismaView GetActiveBrowserView()
|
||||
{
|
||||
if (!g_api) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (g_browserVisible && g_mainMenuVisible && g_mainMenuDomReady && g_api->IsValid(g_mainMenuView)) {
|
||||
return g_mainMenuView;
|
||||
}
|
||||
|
||||
if (g_browserVisible && g_browserDomReady && g_api->IsValid(g_serverBrowserView)) {
|
||||
return g_serverBrowserView;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ActivateEmbeddedBrowser()
|
||||
{
|
||||
if (g_browserVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_browserVisible = true;
|
||||
F4T::MenuInput::SetBrowserActive(true);
|
||||
F4T::MainMenuInject::SetMainMenuInputSuppressed(true);
|
||||
|
||||
if (g_api && g_mainMenuDomReady && g_api->IsValid(g_mainMenuView)) {
|
||||
F4T::ServerBrowser::ServerBrowserBridge::SetView(g_mainMenuView);
|
||||
}
|
||||
|
||||
InitializeBrowserPointerMode();
|
||||
ApplyBrowserPointerMode(!g_menuPreferGamepad);
|
||||
F4T::ServerBrowser::ServerBrowserBridge::OnBrowserShown();
|
||||
}
|
||||
|
||||
void DispatchMainMenuControllerInput(const char* a_button, const char* a_phase)
|
||||
{
|
||||
@@ -518,16 +557,24 @@ namespace F4T::PrismaUI
|
||||
const bool wasVisible = g_browserVisible;
|
||||
g_browserVisible = false;
|
||||
F4T::MenuInput::SetBrowserActive(false);
|
||||
F4T::MainMenuInject::SetMainMenuInputSuppressed(false);
|
||||
|
||||
if (!g_api || !g_api->IsValid(g_serverBrowserView)) {
|
||||
return;
|
||||
}
|
||||
F4T::MainMenuInject::SetMainMenuInputSuppressed(g_mainMenuVisible);
|
||||
|
||||
if (wasVisible) {
|
||||
F4T::ServerBrowser::ServerBrowserBridge::OnBrowserHidden();
|
||||
}
|
||||
|
||||
if (g_api && g_mainMenuVisible && g_mainMenuDomReady && g_api->IsValid(g_mainMenuView)) {
|
||||
g_api->Invoke(
|
||||
g_mainMenuView,
|
||||
"if(window.closeBrowser){window.closeBrowser();}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_api || !g_api->IsValid(g_serverBrowserView)) {
|
||||
RequestNativeCursorRestore();
|
||||
return;
|
||||
}
|
||||
|
||||
g_api->Unfocus(g_serverBrowserView);
|
||||
g_api->Hide(g_serverBrowserView);
|
||||
RequestNativeCursorRestore();
|
||||
@@ -552,6 +599,12 @@ namespace F4T::PrismaUI
|
||||
|
||||
void HideMainMenuInternal()
|
||||
{
|
||||
if (g_browserVisible) {
|
||||
g_browserVisible = false;
|
||||
F4T::MenuInput::SetBrowserActive(false);
|
||||
F4T::ServerBrowser::ServerBrowserBridge::OnBrowserHidden();
|
||||
}
|
||||
|
||||
const bool wasVisible = g_mainMenuVisible;
|
||||
g_mainMenuVisible = false;
|
||||
F4T::MenuInput::SetMainMenuActive(false);
|
||||
@@ -595,6 +648,9 @@ namespace F4T::PrismaUI
|
||||
F4T::MainMenu::MainMenuBridge::Initialize();
|
||||
g_mainMenuBridgeReady = true;
|
||||
|
||||
F4T::ServerBrowser::ServerBrowserBridge::Initialize(g_api, a_view);
|
||||
F4T::ServerBrowser::ServerBrowserBridge::PushUITheme();
|
||||
|
||||
g_api->BindUIEvent(a_view, "coAction", [](const char* a_json) {
|
||||
if (!a_json) {
|
||||
return;
|
||||
@@ -603,14 +659,16 @@ namespace F4T::PrismaUI
|
||||
try {
|
||||
const auto action = nlohmann::json::parse(a_json);
|
||||
const auto actionName = action.value("action", "");
|
||||
|
||||
|
||||
if (actionName == "openView") {
|
||||
const auto viewName = action.value("view", "");
|
||||
if (viewName == "multiplayer") {
|
||||
HideMainMenuInternal();
|
||||
F4T::PrismaUI::ShowServerBrowser();
|
||||
ActivateEmbeddedBrowser();
|
||||
return;
|
||||
}
|
||||
} else if (actionName == "closeBrowser") {
|
||||
HideServerBrowserInternal();
|
||||
return;
|
||||
} else if (actionName == "openGameSettings") {
|
||||
LogInfo("openGameSettings requested from main menu.");
|
||||
F4T::MainMenuVanillaSettings::OpenGameSettings();
|
||||
@@ -619,11 +677,33 @@ namespace F4T::PrismaUI
|
||||
LogInfo("quit requested from main menu (not yet implemented).");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!actionName.empty()) {
|
||||
F4T::ServerBrowser::ServerBrowserBridge::HandleAction(action);
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
REX::WARN("{} [JS] Failed to parse coAction JSON: {}", GetLogPrefix(), ex.what());
|
||||
}
|
||||
});
|
||||
|
||||
g_api->BindUIEvent(a_view, "closeBrowser", [](const char*) {
|
||||
HideServerBrowserInternal();
|
||||
});
|
||||
|
||||
g_api->BindUIEvent(a_view, "connectServer", [](const char*) {
|
||||
if (!F4T::Networking::IsConnectedToServer()) {
|
||||
F4T::Networking::ConnectToLocalServer();
|
||||
}
|
||||
F4T::ServerBrowser::ServerBrowserBridge::PushConnectionStatus();
|
||||
});
|
||||
|
||||
g_api->BindUIEvent(a_view, "disconnectServer", [](const char*) {
|
||||
F4T::Networking::DisconnectFromLocalServer();
|
||||
F4T::ServerBrowser::ServerBrowserBridge::PushConnectionStatus();
|
||||
});
|
||||
|
||||
F4T::ServerBrowser::ServerBrowserBridge::PushConnectionStatus();
|
||||
|
||||
if (g_mainMenuPendingShow) {
|
||||
ShowMainMenuInternal();
|
||||
}
|
||||
@@ -694,27 +774,24 @@ namespace F4T::PrismaUI
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_api->IsValid(g_serverBrowserView)) {
|
||||
if (!g_api->IsValid(g_mainMenuView)) {
|
||||
g_mainMenuPendingShow = true;
|
||||
CreateServerBrowserView();
|
||||
CreateMainMenuView();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_browserDomReady) {
|
||||
if (!g_mainMenuDomReady) {
|
||||
g_mainMenuPendingShow = true;
|
||||
return;
|
||||
}
|
||||
|
||||
g_mainMenuPendingShow = false;
|
||||
g_browserVisible = true;
|
||||
F4T::MenuInput::SetBrowserActive(true);
|
||||
F4T::MainMenuInject::SetMainMenuInputSuppressed(true);
|
||||
InitializeBrowserPointerMode();
|
||||
g_api->Show(g_serverBrowserView);
|
||||
ApplyBrowserPointerMode(!g_menuPreferGamepad);
|
||||
F4T::ServerBrowser::ServerBrowserBridge::OnBrowserShown();
|
||||
if (!g_mainMenuVisible) {
|
||||
ShowMainMenuInternal();
|
||||
}
|
||||
|
||||
ActivateEmbeddedBrowser();
|
||||
g_api->Invoke(
|
||||
g_serverBrowserView,
|
||||
g_mainMenuView,
|
||||
"if(window.onBrowserShown){window.onBrowserShown();}");
|
||||
}
|
||||
|
||||
|
||||
@@ -377,6 +377,11 @@ namespace F4T::ServerBrowser
|
||||
g_data.SetAllServers(ServerBrowserData::CreateMockServers());
|
||||
}
|
||||
|
||||
void ServerBrowserBridge::SetView(PrismaView a_view)
|
||||
{
|
||||
g_view = a_view;
|
||||
}
|
||||
|
||||
void ServerBrowserBridge::OnBrowserShown()
|
||||
{
|
||||
PushUIThemeInternal();
|
||||
|
||||
Reference in New Issue
Block a user