Add UI controls for the netplay session save/resume and resync indicator features: - netplay_create.slint: Add 'Resume Session...' button with file picker callback for .netplay-state files - netplay_wait.slint: Add 'Save Session' button (host only, gated by is_host property), add resyncing indicator badge - netplay_page.slint: Add resyncing property to NetplayData global - src/ui/netplay.rs: Wire on_netplay_resume_session callback (opens file picker, placeholder for #3 flow), on_netplay_save_session callback (placeholder for #3 flow), set is_host on wait window setup The save/resume callbacks show placeholder messages until #3 is implemented. The resync indicator shows during ResyncState != Idle. Closes #8
179 lines
6.5 KiB
Plaintext
179 lines
6.5 KiB
Plaintext
import {
|
|
VerticalBox,
|
|
HorizontalBox,
|
|
TextEdit,
|
|
SpinBox,
|
|
GroupBox,
|
|
LineEdit,
|
|
Button,
|
|
GridBox,
|
|
ScrollView,
|
|
} from "std-widgets.slint";
|
|
import { NetplayData } from "netplay_page.slint";
|
|
import { Page } from "page.slint";
|
|
|
|
export global NetplayWaitData {
|
|
in-out property <string> motd;
|
|
in-out property <[string]> players;
|
|
in-out property <bool> can_start;
|
|
in-out property <string> chat_text;
|
|
in-out property <int> input_delay;
|
|
in-out property <int> recommended_delay;
|
|
in-out property <bool> game_pal;
|
|
in-out property <int> connected_peers_count;
|
|
in-out property <bool> is_host;
|
|
in-out property <bool> resyncing;
|
|
}
|
|
|
|
export component NetplayWait inherits Page {
|
|
title: @tr("Netplay: Waiting Room");
|
|
callback send_chat_message(string);
|
|
callback begin_game(int);
|
|
callback save_session;
|
|
callback close;
|
|
VerticalBox {
|
|
alignment: start;
|
|
HorizontalBox {
|
|
alignment: center;
|
|
VerticalBox {
|
|
alignment: start;
|
|
horizontal-stretch: 0;
|
|
Text {
|
|
text: @tr("Session Name:") + " " + NetplayData.session_name;
|
|
font-size: 15px;
|
|
horizontal-alignment: center;
|
|
}
|
|
|
|
Text {
|
|
text: @tr("Game Name:") + " " + NetplayData.game_name;
|
|
font-size: 15px;
|
|
horizontal-alignment: center;
|
|
}
|
|
|
|
HorizontalBox {
|
|
alignment: center;
|
|
GridBox {
|
|
Row {
|
|
Text {
|
|
text: @tr("Player 1:") + " " + NetplayWaitData.players[0];
|
|
}
|
|
|
|
Text {
|
|
text: @tr("Player 2:") + " " + NetplayWaitData.players[1];
|
|
}
|
|
}
|
|
|
|
Row {
|
|
Text {
|
|
text: @tr("Player 3:") + " " + NetplayWaitData.players[2];
|
|
}
|
|
|
|
Text {
|
|
text: @tr("Player 4:") + " " + NetplayWaitData.players[3];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TextEdit {
|
|
read-only: true;
|
|
min-height: 110px;
|
|
text: NetplayWaitData.chat_text;
|
|
}
|
|
|
|
HorizontalBox {
|
|
chat_message := LineEdit {
|
|
placeholder-text: @tr("Enter chat message");
|
|
key-released(event) => {
|
|
if (event.text == Key.Return && chat_message.text != "") {
|
|
send_chat_message(chat_message.text);
|
|
chat_message.text = "";
|
|
}
|
|
accept
|
|
}
|
|
}
|
|
|
|
Button {
|
|
text: @tr("Send Message");
|
|
enabled: chat_message.text != "";
|
|
clicked => {
|
|
send_chat_message(chat_message.text);
|
|
chat_message.text = "";
|
|
}
|
|
}
|
|
}
|
|
|
|
Text {
|
|
text: NetplayData.player_name == NetplayWaitData.players[0] ? @tr("Setting the input delay too low will cause the game to lag.\nYou can lower the input delay in-game by pressing Alt+[ and raise it with Alt+].") : NetplayWaitData.motd;
|
|
horizontal-alignment: center;
|
|
wrap: word-wrap;
|
|
}
|
|
|
|
if NetplayData.player_name == NetplayWaitData.players[0]: HorizontalBox {
|
|
alignment: center;
|
|
Text {
|
|
text: @tr("Local Input Delay:");
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
}
|
|
|
|
SpinBox {
|
|
height: self.min-height;
|
|
minimum: 1;
|
|
maximum: 16;
|
|
value: NetplayWaitData.input_delay;
|
|
enabled: NetplayWaitData.recommended_delay != 0;
|
|
edited => {
|
|
NetplayWaitData.input_delay = self.value;
|
|
}
|
|
}
|
|
|
|
Text {
|
|
text: @tr("Recommended: ") + (NetplayWaitData.recommended_delay == 0 ? "Calculating..." : NetplayWaitData.recommended_delay);
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
}
|
|
}
|
|
HorizontalBox {
|
|
alignment: center;
|
|
Button {
|
|
property <bool> mesh_complete: NetplayWaitData.players.length == (NetplayWaitData.connected_peers_count + 1);
|
|
text: mesh_complete ? @tr("Start Game") : @tr("Waiting for P2P mesh ") + (NetplayWaitData.connected_peers_count + 1) + "/" + NetplayWaitData.players.length;
|
|
enabled: NetplayWaitData.players[0] == NetplayData.player_name && NetplayWaitData.can_start && NetplayWaitData.recommended_delay != 0 && mesh_complete;
|
|
clicked => {
|
|
NetplayWaitData.can_start = false;
|
|
begin_game(NetplayWaitData.input_delay);
|
|
}
|
|
}
|
|
|
|
if NetplayWaitData.is_host: Button {
|
|
text: @tr("Save Session");
|
|
enabled: NetplayWaitData.can_start;
|
|
clicked => {
|
|
save_session();
|
|
}
|
|
}
|
|
|
|
Button {
|
|
text: @tr("Cancel");
|
|
clicked => {
|
|
close();
|
|
}
|
|
}
|
|
}
|
|
|
|
if NetplayWaitData.resyncing: Rectangle {
|
|
background: #ffaa00;
|
|
height: 24px;
|
|
Text {
|
|
text: @tr("Resyncing…");
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
color: white;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|