diff --git a/src/citron/util/multiplayer_room_overlay.cpp b/src/citron/util/multiplayer_room_overlay.cpp index c7699aaec..8953f078d 100644 --- a/src/citron/util/multiplayer_room_overlay.cpp +++ b/src/citron/util/multiplayer_room_overlay.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include #include #include @@ -23,24 +24,25 @@ MultiplayerRoomOverlay::MultiplayerRoomOverlay(QWidget* parent) main_window = qobject_cast(parent->window()); - // Switched to Qt::Tool to allow keyboard focus for typing in chat setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); setAttribute(Qt::WA_TranslucentBackground); - // Set smaller sizes for Steam Deck - setMinimumSize(240, 180); - resize(260, 220); - main_layout = new QGridLayout(this); - main_layout->setContentsMargins(padding, padding, 0, 0); - main_layout->setSpacing(6); + main_layout->setContentsMargins(padding, padding, padding, padding); + main_layout->setSpacing(8); players_online_label = new QLabel(this); + + QGraphicsDropShadowEffect* shadow = new QGraphicsDropShadowEffect(this); + shadow->setBlurRadius(6); + shadow->setColor(Qt::black); + shadow->setOffset(0, 0); + players_online_label->setGraphicsEffect(shadow); + chat_room_widget = new ChatRoom(this); size_grip = new QSizeGrip(this); - players_online_label->setFont(QFont(QString::fromUtf8("Segoe UI"), 10, QFont::Bold)); - players_online_label->setText(QString::fromUtf8("Players Online: 0")); + players_online_label->setFont(QFont(QString::fromUtf8("Segoe UI"), 12, QFont::Bold)); players_online_label->setAttribute(Qt::WA_TransparentForMouseEvents, true); size_grip->setFixedSize(16, 16); @@ -66,21 +68,19 @@ MultiplayerRoomOverlay::MultiplayerRoomOverlay(QWidget* parent) if (main_window) { connect(main_window, &GMainWindow::themeChanged, this, &MultiplayerRoomOverlay::UpdateTheme); + connect(main_window, &GMainWindow::EmulationStarting, this, &MultiplayerRoomOverlay::OnEmulationStarting); + connect(main_window, &GMainWindow::EmulationStopping, this, &MultiplayerRoomOverlay::OnEmulationStopping); } UpdateTheme(); const bool is_gamescope = UISettings::IsGamescope(); if (is_gamescope) { - setMinimumSize(320, 260); - resize(600, 520); - - players_online_label->setFont(QFont(QString::fromUtf8("Segoe UI"), 11, QFont::Bold)); - - this->padding = 12; - main_layout->setContentsMargins(padding, padding, padding, padding); + setMinimumSize(450, 350); + resize(700, 550); + this->padding = 15; } else { - setMinimumSize(280, 220); - resize(320, 280); + setMinimumSize(360, 260); + resize(420, 300); } UpdatePosition(); @@ -91,17 +91,30 @@ MultiplayerRoomOverlay::~MultiplayerRoomOverlay() { } void MultiplayerRoomOverlay::OnEmulationStarting() { - // The connection is now managed by the overlay's visibility. + // Force a UI refresh immediately when a game starts + UpdateRoomData(); } void MultiplayerRoomOverlay::OnEmulationStopping() { - // The connection should persist even when emulation stops. + update_timer.stop(); + + if (room_member && room_member->IsConnected()) { + // Only send if the state is stable + room_member->SendGameInfo({}); + } + + // Clear the UI text but don't force a full room data poll yet + players_online_label->setText(tr("Emulation Stopped.")); + + // Resume polling after 1 second once the LDN service has safely detached + QTimer::singleShot(1000, this, [this] { + if (is_visible) update_timer.start(500); + }); } void MultiplayerRoomOverlay::SetVisible(bool visible) { if (is_visible == visible) return; is_visible = visible; - if (visible) { show(); ConnectToRoom(); @@ -117,21 +130,36 @@ void MultiplayerRoomOverlay::paintEvent(QPaintEvent* event) { Q_UNUSED(event) QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); + + QRect background_rect = rect(); + + // Move the top of the box down so the text floats above it + int label_area_height = players_online_label->height() + main_layout->spacing() + padding; + background_rect.setTop(label_area_height); + QPainterPath background_path; - background_path.addRoundedRect(rect(), corner_radius, corner_radius); + background_path.addRoundedRect(background_rect, corner_radius, corner_radius); + painter.fillPath(background_path, background_color); painter.setPen(QPen(border_color, border_width)); painter.drawPath(background_path); } -void MultiplayerRoomOverlay::resizeEvent(QResizeEvent* event) { QWidget::resizeEvent(event); if (!has_been_moved) UpdatePosition(); } -bool MultiplayerRoomOverlay::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::MouseButtonPress) { if (chat_room_widget->hasFocus()) { chat_room_widget->clearFocus(); } } return QObject::eventFilter(watched, event); } +void MultiplayerRoomOverlay::resizeEvent(QResizeEvent* event) { + QWidget::resizeEvent(event); + if (!has_been_moved) UpdatePosition(); +} +bool MultiplayerRoomOverlay::eventFilter(QObject* watched, QEvent* event) { + if (event->type() == QEvent::MouseButtonPress) { + if (chat_room_widget->hasFocus()) chat_room_widget->clearFocus(); + } + return QObject::eventFilter(watched, event); +} void MultiplayerRoomOverlay::mousePressEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton && !size_grip->geometry().contains(event->pos())) { - const bool is_gamescope = !qgetenv("GAMESCOPE_WIDTH").isEmpty() || qgetenv("XDG_CURRENT_DESKTOP") == "gamescope"; - if (is_gamescope) { + if (UISettings::IsGamescope()) { is_dragging = true; drag_start_pos = event->globalPosition().toPoint() - this->pos(); setCursor(Qt::ClosedHandCursor); @@ -171,36 +199,27 @@ void MultiplayerRoomOverlay::ConnectToRoom() { if (!main_window) return; multiplayer_state = main_window->GetMultiplayerState(); if (!multiplayer_state) return; - if (multiplayer_state->IsClientRoomVisible()) { chat_room_widget->setEnabled(false); chat_room_widget->Clear(); - chat_room_widget->AppendStatusMessage(tr("In order to use chat functionality in the Overlay, please close the Multiplayer Room Window.")); + chat_room_widget->AppendStatusMessage(tr("Please close the Multiplayer Room Window to use the Overlay.")); return; } - chat_room_widget->setEnabled(true); auto& room_network = multiplayer_state->GetRoomNetwork(); room_member = room_network.GetRoomMember().lock(); - if (room_member) { if (!is_chat_initialized) { chat_room_widget->Initialize(&room_network); is_chat_initialized = true; } } else { - chat_room_widget->Clear(); - chat_room_widget->AppendStatusMessage(tr("Not connected to a room.")); + ClearUI(); } } void MultiplayerRoomOverlay::DisconnectFromRoom() { - // Tell the chat widget to disconnect its signals *before* - // we reset our own state. - if (is_chat_initialized && chat_room_widget) { - chat_room_widget->Shutdown(); - } - + if (is_chat_initialized && chat_room_widget) chat_room_widget->Shutdown(); ClearUI(); room_member.reset(); multiplayer_state = nullptr; @@ -208,70 +227,90 @@ void MultiplayerRoomOverlay::DisconnectFromRoom() { } void MultiplayerRoomOverlay::ClearUI() { - players_online_label->setText(QString::fromUtf8("Players Online: 0")); + players_online_label->setText(tr("Not connected to a room.")); chat_room_widget->Clear(); - chat_room_widget->AppendStatusMessage(tr("Not connected to a room.")); chat_room_widget->SetPlayerList({}); } void MultiplayerRoomOverlay::UpdateRoomData() { - if (!multiplayer_state) { - ConnectToRoom(); - return; - } - - if (multiplayer_state->IsClientRoomVisible()) { - if (chat_room_widget->isEnabled()) { - chat_room_widget->setEnabled(false); - chat_room_widget->Clear(); - chat_room_widget->AppendStatusMessage(tr("In order to use chat functionality in the Overlay, please close the Multiplayer Room Window.")); - } - return; - } - - if (!chat_room_widget->isEnabled()) { - ConnectToRoom(); - } + if (!multiplayer_state) { ConnectToRoom(); return; } + if (multiplayer_state->IsClientRoomVisible()) { chat_room_widget->setEnabled(false); return; } + if (!chat_room_widget->isEnabled()) ConnectToRoom(); if (room_member && room_member->GetState() >= Network::RoomMember::State::Joined) { const auto& members = room_member->GetMemberInformation(); - QString label_text = QString::fromStdString("Players Online: %1").arg(members.size()); - players_online_label->setText(label_text); - if (chat_room_widget->isEnabled()) { - chat_room_widget->SetPlayerList(members); + AnnounceMultiplayerRoom::GameInfo local_game_info; + std::string my_nick = room_member->GetNickname(); + for (const auto& m : members) { + if (m.nickname == my_nick) { + local_game_info = m.game_info; + break; + } } - } else { - ClearUI(); - room_member.reset(); + + // Ensure we don't think we are emulating if the status is "Not playing a game" + bool is_emulating = !local_game_info.name.empty() && + local_game_info.name != tr("Not playing a game").toStdString(); + + int point_size = UISettings::IsGamescope() ? 11 : 10; + if (this->width() < 340) point_size = 10; + + QFont font = players_online_label->font(); + font.setPointSize(point_size); + players_online_label->setFont(font); + + QString label_text; + if (!is_emulating) { + players_online_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + label_text = tr("Players In Room: %1").arg(members.size()); + } else { + players_online_label->setAlignment(Qt::AlignCenter); + int g = 0, d = 0, o = 0; + for (const auto& m : members) { + bool m_playing = !m.game_info.name.empty() && + m.game_info.name != tr("Not playing a game").toStdString(); + + if (m_playing && m.game_info.name == local_game_info.name) { + if (m.game_info.version == local_game_info.version) g++; else d++; + } else { + o++; + } + } + + QStringList parts; + if (g > 0) parts << tr("In-Game: %1").arg(g); + if (d > 0) parts << tr("Different Update: %1").arg(d); + if (o > 0) parts << tr("Other: %1").arg(o); + + QString sep = QStringLiteral("      •      "); + if (this->width() < 400) sep = QStringLiteral("  •  "); + + label_text = parts.join(sep); + } + players_online_label->setText(label_text); + if (chat_room_widget->isEnabled()) chat_room_widget->SetPlayerList(members); } } void MultiplayerRoomOverlay::UpdatePosition() { if (!main_window) return; if (!has_been_moved) { - QPoint main_window_pos = main_window->mapToGlobal(QPoint(0, 0)); - move(main_window_pos.x() + main_window->width() - this->width() - 10, main_window_pos.y() + 10); + QPoint win_pos = main_window->mapToGlobal(QPoint(0, 0)); + move(win_pos.x() + main_window->width() - width() - 15, win_pos.y() + 15); } } void MultiplayerRoomOverlay::UpdateTheme() { if (UISettings::IsDarkTheme()) { - // Dark Theme Colors - background_color = QColor(20, 20, 20, 180); // 180 alpha for transparency - border_color = QColor(60, 60, 60, 120); - players_online_label->setStyleSheet(QStringLiteral("color: #E0E0E0;")); + background_color = QColor(25, 25, 25, 225); + border_color = QColor(255, 255, 255, 40); + players_online_label->setStyleSheet(QStringLiteral("color: #FFFFFF;")); } else { - // Light Theme Colors - background_color = QColor(245, 245, 245, 200); // 200 alpha for transparency - border_color = QColor(200, 200, 200, 120); - players_online_label->setStyleSheet(QStringLiteral("color: #141414;")); + background_color = QColor(245, 245, 245, 235); + border_color = QColor(0, 0, 0, 50); + players_online_label->setStyleSheet(QStringLiteral("color: #111111;")); } - - // The chat widget is a separate custom widget, so we need to tell it to update its theme too. - if (chat_room_widget) { - chat_room_widget->UpdateTheme(); - } - - update(); // Force a repaint of the overlay itself + if (chat_room_widget) chat_room_widget->UpdateTheme(); + update(); }