Slint fixes (#433)

* Slint fixes

* more

* more

* more

* more

* more

* more

* more

* more

* more
This commit is contained in:
Logan McNaughton
2025-06-26 09:00:23 +02:00
committed by GitHub
parent f213b0b9a9
commit 0bb3d2cd5d
9 changed files with 220 additions and 713 deletions
+1
View File
@@ -227,6 +227,7 @@ pub fn init(device: &mut device::Device) {
device.cpu.clock_rate = if !device.cpu.overclock {
93750000
} else {
println!("Overclocking enabled, setting clock rate to 125 MHz");
125000000
};
+46 -14
View File
@@ -108,7 +108,7 @@ fn local_game_window(app: &AppWindow, controller_paths: &[Option<String>]) {
});
}
fn get_input_profiles(config: &ui::config::Config) -> Vec<String> {
fn input_profiles(config: &ui::config::Config) -> Vec<String> {
let mut profiles = vec![];
for key in config.input.input_profiles.keys() {
profiles.push(key.clone())
@@ -122,12 +122,33 @@ fn settings_window(app: &AppWindow, config: &ui::config::Config) {
app.set_widescreen(config.video.widescreen);
app.set_apply_crt_shader(config.video.crt);
app.set_overclock_n64_cpu(config.emulation.overclock);
app.set_resolution(format!("{}x", config.video.upscale).into());
let combobox_value = match config.video.upscale {
1 => 0,
2 => 1,
4 => 2,
_ => 0,
};
app.set_resolution(combobox_value);
}
fn update_input_profiles(weak: &slint::Weak<AppWindow>, config: &ui::config::Config) {
let profiles = get_input_profiles(config);
let profiles = input_profiles(config);
let config_bindings = config.input.input_profile_binding.clone();
let weak2 = weak.clone();
weak.upgrade_in_event_loop(move |handle| {
let profile_bindings = slint::VecModel::default();
for (i, input_profile_binding) in handle.get_selected_profile_binding().iter().enumerate() {
let currently_selected = handle
.get_input_profiles()
.row_data(input_profile_binding as usize)
.unwrap_or(config_bindings[i].clone().into())
.to_string();
let position = profiles
.iter()
.position(|profile| *profile == currently_selected);
profile_bindings.push(position.unwrap() as i32);
}
let input_profiles = slint::VecModel::default();
for profile in profiles {
input_profiles.push(profile.into());
@@ -135,6 +156,20 @@ fn update_input_profiles(weak: &slint::Weak<AppWindow>, config: &ui::config::Con
let input_profiles_model: std::rc::Rc<slint::VecModel<slint::SharedString>> =
std::rc::Rc::new(input_profiles);
handle.set_input_profiles(slint::ModelRc::from(input_profiles_model));
let input_profile_binding_model: std::rc::Rc<slint::VecModel<i32>> =
std::rc::Rc::new(profile_bindings);
handle.set_selected_profile_binding(slint::ModelRc::from(input_profile_binding_model));
// this is a workaround to make the input profile combobox update
handle.set_blank_profiles(true);
slint::Timer::single_shot(std::time::Duration::from_millis(200), move || {
weak2
.upgrade_in_event_loop(move |handle| {
handle.set_blank_profiles(false);
})
.unwrap();
});
})
.unwrap();
}
@@ -156,14 +191,6 @@ fn controller_window(
std::rc::Rc::new(slint::VecModel::from(config.input.transfer_pak.to_vec()));
app.set_transferpak(slint::ModelRc::from(transferpak_enabled_model));
let profile_bindings = slint::VecModel::default();
for binding in config.input.input_profile_binding.iter() {
profile_bindings.push(binding.into());
}
let input_profile_binding_model: std::rc::Rc<slint::VecModel<slint::SharedString>> =
std::rc::Rc::new(profile_bindings);
app.set_input_profile_binding(slint::ModelRc::from(input_profile_binding_model));
update_input_profiles(&app.as_weak(), config);
let controllers = slint::VecModel::default();
@@ -224,7 +251,8 @@ fn save_settings(app: &AppWindow, controller_paths: &[Option<String>]) {
config.video.widescreen = app.get_widescreen();
config.video.crt = app.get_apply_crt_shader();
config.emulation.overclock = app.get_overclock_n64_cpu();
config.video.upscale = app.get_resolution().trim_end_matches('x').parse().unwrap();
let upscale_values = [1, 2, 4];
config.video.upscale = upscale_values[app.get_resolution() as usize];
config.input.emulate_vru = app.get_emulate_vru();
for (i, controller_enabled) in app.get_controller_enabled().iter().enumerate() {
@@ -233,8 +261,12 @@ fn save_settings(app: &AppWindow, controller_paths: &[Option<String>]) {
for (i, transferpak_enabled) in app.get_transferpak().iter().enumerate() {
config.input.transfer_pak[i] = transferpak_enabled;
}
for (i, input_profile_binding) in app.get_input_profile_binding().iter().enumerate() {
config.input.input_profile_binding[i] = input_profile_binding.into();
for (i, input_profile_binding) in app.get_selected_profile_binding().iter().enumerate() {
config.input.input_profile_binding[i] = app
.get_input_profiles()
.row_data(input_profile_binding as usize)
.unwrap()
.to_string();
}
for (i, selected_controller) in app.get_selected_controller().iter().enumerate() {
+3 -2
View File
@@ -1,7 +1,7 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { LocalGame, ControllerConfig,Netplay,Settings,About } from "pages.slint";
import { LocalGame, ControllerConfig, Netplay, Settings, About } from "pages.slint";
import { SideBar } from "side_bar.slint";
import { SettingsData } from "settings_page.slint";
import { AboutData } from "about_page.slint";
@@ -34,11 +34,12 @@ export component AppWindow inherits Window {
in-out property emulate_vru <=> ControllerData.emulate_vru;
in-out property controller_enabled <=> ControllerData.controller_enabled;
in-out property transferpak <=> ControllerData.transferpak;
in-out property input_profile_binding <=> ControllerData.input_profile_binding;
in-out property selected_profile_binding <=> ControllerData.selected_profile_binding;
in-out property input_profiles <=> ControllerData.input_profiles;
in-out property controller_names <=> ControllerData.controller_names;
in-out property selected_controller <=> ControllerData.selected_controller;
in-out property game_running <=> State.game_running;
in-out property blank_profiles <=> ControllerData.blank_profiles;
preferred-width: 700px;
preferred-height: 500px;
title: @tr("Gopher64");
+62 -198
View File
@@ -1,7 +1,7 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { CheckBox, ComboBox, Button, HorizontalBox, VerticalBox, GridBox } from "std-widgets.slint";
import { CheckBox, ComboBox, Button, HorizontalBox, VerticalBox, GroupBox } from "std-widgets.slint";
import { Page } from "page.slint";
import { State } from "localgame_page.slint";
@@ -9,20 +9,14 @@ export global ControllerData {
in-out property <bool> emulate_vru;
in-out property <[bool]> controller_enabled;
in-out property <[bool]> transferpak;
in-out property <[string]> input_profile_binding;
in-out property <[int]> selected_profile_binding: [-1, -1, -1, -1];
in-out property <[string]> input_profiles;
in-out property <[string]> controller_names;
in-out property <[int]> selected_controller;
in-out property <bool> blank_profiles;
}
export component ControllerConfig inherits Page {
property <[{name: string, vru-enabled: bool}]> rows: [
{ name: "1", vru-enabled: false },
{ name: "2", vru-enabled: false },
{ name: "3", vru-enabled: false },
{ name: "4", vru-enabled: true }
];
callback input_profile_button_clicked;
title: @tr("Controller Configuration");
@@ -41,213 +35,83 @@ export component ControllerConfig inherits Page {
Rectangle { }
Text {
text: @tr("Controller Settings:");
font-weight: 600;
}
GridBox {
Row {
Text {
text: @tr("Port");
}
Text {
text: @tr("Enabled");
}
Text {
text: @tr("Emulate VRU");
}
Text {
text: @tr("Transfer Pak");
}
Text {
text: @tr("Profile");
}
Text {
text: @tr("Controller");
}
}
Row { // 0
property <int> number: 0;
Text { // Port
text: rows[number].name;
vertical-alignment: center;
}
CheckBox { // Enabled
checked: ControllerData.controller_enabled[number];
toggled => {
ControllerData.controller_enabled[number] = self.checked;
}
}
CheckBox { // Emulate VRU
enabled: rows[number].vru-enabled;
checked: false;
}
CheckBox { // Transfer Pak
checked: ControllerData.transferpak[number];
toggled => {
ControllerData.transferpak[number] = self.checked;
}
}
ComboBox { // Profile
model: ControllerData.input_profiles;
current-value: ControllerData.input_profile_binding[number];
selected => {
ControllerData.input_profile_binding[number] = self.current-value;
}
}
ComboBox { // Controller
model: ControllerData.controller_names;
width: self.preferred-width;
current-value: ControllerData.controller_names[ControllerData.selected_controller[number]];
selected => {
ControllerData.selected_controller[number] = self.current-index;
HorizontalBox {
GroupBox {
title: @tr("Port");
VerticalLayout {
alignment: space-between;
for player in [0, 1, 2, 3]: Text {
text: player + 1;
vertical-alignment: center;
}
}
}
Row { // 1
property <int> number: 1;
Text { // Port
text: rows[number].name;
vertical-alignment: center;
}
CheckBox { // Enabled
checked: ControllerData.controller_enabled[number];
toggled => {
ControllerData.controller_enabled[number] = self.checked;
}
}
CheckBox { // Emulate VRU
enabled: rows[number].vru-enabled;
checked: false;
}
CheckBox { // Transfer Pak
checked: ControllerData.transferpak[number];
toggled => {
ControllerData.transferpak[number] = self.checked;
}
}
ComboBox { // Profile
model: ControllerData.input_profiles;
current-value: ControllerData.input_profile_binding[number];
selected => {
ControllerData.input_profile_binding[number] = self.current-value;
}
}
ComboBox { // Controller
model: ControllerData.controller_names;
width: self.preferred-width;
current-value: ControllerData.controller_names[ControllerData.selected_controller[number]];
selected => {
ControllerData.selected_controller[number] = self.current-index;
GroupBox {
title: @tr("Enabled");
VerticalLayout {
alignment: space-between;
for player in [0, 1, 2, 3]: CheckBox {
checked: ControllerData.controller_enabled[player];
toggled => {
ControllerData.controller_enabled[player] = self.checked;
}
}
}
}
Row { // 2
property <int> number: 2;
Text { // Port
text: rows[number].name;
vertical-alignment: center;
}
CheckBox { // Enabled
checked: ControllerData.controller_enabled[number];
toggled => {
ControllerData.controller_enabled[number] = self.checked;
}
}
CheckBox { // Emulate VRU
enabled: rows[number].vru-enabled;
checked: false;
}
CheckBox { // Transfer Pak
checked: ControllerData.transferpak[number];
toggled => {
ControllerData.transferpak[number] = self.checked;
}
}
ComboBox { // Profile
model: ControllerData.input_profiles;
current-value: ControllerData.input_profile_binding[number];
selected => {
ControllerData.input_profile_binding[number] = self.current-value;
}
}
ComboBox { // Controller
model: ControllerData.controller_names;
width: self.preferred-width;
current-value: ControllerData.controller_names[ControllerData.selected_controller[number]];
selected => {
ControllerData.selected_controller[number] = self.current-index;
GroupBox {
title: @tr("Emulate VRU");
VerticalLayout {
alignment: space-between;
for valid in [false, false, false, true]: CheckBox {
enabled: valid;
checked: valid && ControllerData.emulate_vru;
toggled => {
ControllerData.emulate_vru = self.checked;
}
}
}
}
Row { // 3
property <int> number: 3;
Text { // Port
text: rows[number].name;
vertical-alignment: center;
}
CheckBox { // Enabled
checked: ControllerData.controller_enabled[number];
toggled => {
ControllerData.controller_enabled[number] = self.checked;
GroupBox {
title: @tr("Transfer Pak");
VerticalLayout {
alignment: space-between;
for player in [0, 1, 2, 3]: CheckBox {
checked: ControllerData.transferpak[player];
toggled => {
ControllerData.transferpak[player] = self.checked;
}
}
}
}
CheckBox { // Emulate VRU
enabled: rows[number].vru-enabled;
checked: ControllerData.emulate_vru;
toggled => {
ControllerData.emulate_vru = self.checked;
if !ControllerData.blank_profiles: GroupBox {
title: @tr("Profile");
VerticalLayout {
alignment: space-between;
for player in [0, 1, 2, 3]: ComboBox {
model: ControllerData.input_profiles;
current-index: ControllerData.selected_profile_binding[player];
selected => {
ControllerData.selected_profile_binding[player] = self.current-index;
}
}
}
}
CheckBox { // Transfer Pak
checked: ControllerData.transferpak[number];
toggled => {
ControllerData.transferpak[number] = self.checked;
}
}
ComboBox { // Profile
model: ControllerData.input_profiles;
current-value: ControllerData.input_profile_binding[number];
selected => {
ControllerData.input_profile_binding[number] = self.current-value;
}
}
ComboBox { // Controller
model: ControllerData.controller_names;
width: self.preferred-width;
current-value: ControllerData.controller_names[ControllerData.selected_controller[number]];
selected => {
ControllerData.selected_controller[number] = self.current-index;
GroupBox {
title: @tr("Controller");
VerticalLayout {
alignment: space-between;
for player in [0, 1, 2, 3]: ComboBox {
model: ControllerData.controller_names;
width: self.preferred-width;
current-index: ControllerData.selected_controller[player];
selected => {
ControllerData.selected_controller[player] = self.current-index;
}
}
}
}
+1 -1
View File
@@ -65,7 +65,7 @@ export component NetplayCreate inherits Window {
HorizontalBox {
server := ComboBox {
model: NetplayData.server_names;
selected(current-value) => {
selected => {
if (self.current-index >= 0) {
get_ping(NetplayData.server_urls[self.current-index]);
}
+1 -1
View File
@@ -42,7 +42,7 @@ export component NetplayJoin inherits Window {
HorizontalBox {
server := ComboBox {
model: NetplayData.server_names;
selected(current-value) => {
selected => {
if (self.current-index >= 0) {
get_ping(NetplayData.server_urls[self.current-index]);
}
+3 -3
View File
@@ -10,7 +10,7 @@ export global SettingsData {
in-out property <bool> widescreen;
in-out property <bool> apply_crt_shader;
in-out property <bool> overclock_n64_cpu;
in-out property <string> resolution;
in-out property <int> resolution;
}
export component Settings inherits Page {
@@ -27,9 +27,9 @@ export component Settings inherits Page {
ComboBox {
model: ["1x", "2x", "4x"];
current-value: SettingsData.resolution;
current-index: SettingsData.resolution;
selected => {
SettingsData.resolution = self.current-value;
SettingsData.resolution = self.current-index;
}
}
}
+1 -1
View File
@@ -112,7 +112,7 @@ impl NetplayPages for NetplayJoin {
}
fn populate_server_names<T: ComponentHandle + NetplayPages + 'static>(weak: slint::Weak<T>) {
let task = reqwest::get("https://m64p.s3.amazonaws.com/servers.json");
let task = reqwest::get("https://m64p.s3.amazonaws.com/serverstest.json");
tokio::spawn(async move {
let mut local_servers: Vec<(String, String)> = vec![];