mirror of
https://github.com/gopher64/gopher64.git
synced 2026-07-11 01:25:20 +02:00
Track recent roms (#786)
* track recent roms * more * more * more * more * more * more * more * more * more * more * more * more * more * more
This commit is contained in:
+12
-3
@@ -140,7 +140,11 @@ fn swap_rom(contents: Vec<u8>) -> Option<Vec<u8>> {
|
||||
|
||||
pub fn get_rom_contents(file_path: &std::path::Path) -> Option<Vec<u8>> {
|
||||
let mut contents = vec![];
|
||||
if file_path.extension().unwrap().eq_ignore_ascii_case("zip") {
|
||||
if file_path
|
||||
.extension()
|
||||
.unwrap_or_default()
|
||||
.eq_ignore_ascii_case("zip")
|
||||
{
|
||||
let zip_file = fs::File::open(file_path).unwrap();
|
||||
let mut archive = zip::ZipArchive::new(zip_file).unwrap();
|
||||
for i in 0..archive.len() {
|
||||
@@ -157,7 +161,11 @@ pub fn get_rom_contents(file_path: &std::path::Path) -> Option<Vec<u8>> {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if file_path.extension().unwrap().eq_ignore_ascii_case("7z") {
|
||||
} else if file_path
|
||||
.extension()
|
||||
.unwrap_or_default()
|
||||
.eq_ignore_ascii_case("7z")
|
||||
{
|
||||
let mut archive =
|
||||
sevenz_rust2::ArchiveReader::open(file_path, sevenz_rust2::Password::empty()).unwrap();
|
||||
|
||||
@@ -182,7 +190,8 @@ pub fn get_rom_contents(file_path: &std::path::Path) -> Option<Vec<u8>> {
|
||||
)
|
||||
.expect("ok");
|
||||
} else {
|
||||
contents = fs::read(file_path).expect("Should have been able to read the file");
|
||||
contents = fs::read(file_path)
|
||||
.unwrap_or_else(|_| panic!("Could not read ROM file: {}", file_path.display()));
|
||||
}
|
||||
|
||||
if contents.is_empty() {
|
||||
|
||||
@@ -138,6 +138,11 @@ async fn main() -> std::io::Result<()> {
|
||||
}
|
||||
|
||||
let mut device = device::Device::new();
|
||||
|
||||
device.ui.config.recent_roms.retain(|x| *x != game);
|
||||
device.ui.config.recent_roms.insert(0, game);
|
||||
device.ui.config.recent_roms.truncate(5);
|
||||
|
||||
if args.fullscreen {
|
||||
device.ui.video.fullscreen = true;
|
||||
} else {
|
||||
|
||||
@@ -73,6 +73,7 @@ pub struct Config {
|
||||
pub video: Video,
|
||||
pub emulation: Emulation,
|
||||
pub rom_dir: std::path::PathBuf,
|
||||
pub recent_roms: Vec<String>,
|
||||
}
|
||||
|
||||
impl Drop for Cheats {
|
||||
@@ -161,6 +162,7 @@ impl Config {
|
||||
usb: false,
|
||||
},
|
||||
rom_dir: std::path::PathBuf::new(),
|
||||
recent_roms: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+145
-55
@@ -54,47 +54,88 @@ fn check_latest_version(weak: slint::Weak<AppWindow>) {
|
||||
});
|
||||
}
|
||||
|
||||
fn run_with_path(
|
||||
weak: slint::Weak<AppWindow>,
|
||||
path: std::path::PathBuf,
|
||||
controller_paths: &[Option<String>],
|
||||
) {
|
||||
let controller_paths = controller_paths.to_owned();
|
||||
let weak2 = weak.clone();
|
||||
weak.upgrade_in_event_loop(move |handle| {
|
||||
if handle.get_game_running() {
|
||||
return;
|
||||
}
|
||||
save_settings(&handle, &controller_paths);
|
||||
|
||||
run_rom(
|
||||
path,
|
||||
ui::GameSettings {
|
||||
overclock: handle.get_overclock_n64_cpu(),
|
||||
disable_expansion_pak: handle.get_disable_expansion_pak(),
|
||||
cheats: std::collections::HashMap::new(), // will be filled in later
|
||||
load_savestate_slot: None,
|
||||
},
|
||||
None,
|
||||
RASettings {
|
||||
enabled: handle.get_ra_enabled(),
|
||||
hardcore: handle.get_ra_hardcore(),
|
||||
challenge: handle.get_ra_challenge(),
|
||||
leaderboard: handle.get_ra_leaderboard(),
|
||||
},
|
||||
weak2,
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn file_dropped(app: &AppWindow, controller_paths: &[Option<String>]) {
|
||||
let weak = app.as_weak();
|
||||
let owned_controller_paths = controller_paths.to_owned();
|
||||
let controller_paths = controller_paths.to_owned();
|
||||
app.window()
|
||||
.on_winit_window_event(move |_winit_window, event| {
|
||||
if let slint::winit_030::winit::event::WindowEvent::DroppedFile(path) = event {
|
||||
let controller_paths = owned_controller_paths.clone();
|
||||
let path = path.clone();
|
||||
let weak2 = weak.clone();
|
||||
weak.upgrade_in_event_loop(move |handle| {
|
||||
if handle.get_game_running() {
|
||||
return;
|
||||
}
|
||||
save_settings(&handle, &controller_paths);
|
||||
|
||||
run_rom(
|
||||
path,
|
||||
ui::GameSettings {
|
||||
overclock: handle.get_overclock_n64_cpu(),
|
||||
disable_expansion_pak: handle.get_disable_expansion_pak(),
|
||||
cheats: std::collections::HashMap::new(), // will be filled in later
|
||||
load_savestate_slot: None,
|
||||
},
|
||||
None,
|
||||
RASettings {
|
||||
enabled: handle.get_ra_enabled(),
|
||||
hardcore: handle.get_ra_hardcore(),
|
||||
challenge: handle.get_ra_challenge(),
|
||||
leaderboard: handle.get_ra_leaderboard(),
|
||||
},
|
||||
weak2,
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
run_with_path(weak.clone(), path.to_path_buf(), &controller_paths);
|
||||
}
|
||||
slint::winit_030::EventResult::Propagate
|
||||
});
|
||||
}
|
||||
|
||||
fn local_game_window(app: &AppWindow, controller_paths: &[Option<String>]) {
|
||||
fn local_game_window(
|
||||
app: &AppWindow,
|
||||
config: &ui::config::Config,
|
||||
controller_paths: &[Option<String>],
|
||||
) {
|
||||
let dirs = ui::get_dirs();
|
||||
|
||||
app.set_recent_roms(slint::ModelRc::from(std::rc::Rc::new(
|
||||
slint::VecModel::from(
|
||||
config
|
||||
.recent_roms
|
||||
.iter()
|
||||
.filter(|x| {
|
||||
if let Ok(exists) = std::fs::exists(x)
|
||||
&& exists
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|x| {
|
||||
(
|
||||
x.into(),
|
||||
std::path::Path::new(x)
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.into(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<(slint::SharedString, slint::SharedString)>>(),
|
||||
),
|
||||
)));
|
||||
|
||||
let weak = app.as_weak();
|
||||
let owned_controller_paths = controller_paths.to_owned();
|
||||
app.on_open_rom_button_clicked(move || {
|
||||
@@ -106,6 +147,20 @@ fn local_game_window(app: &AppWindow, controller_paths: &[Option<String>]) {
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
let weak = app.as_weak();
|
||||
let owned_controller_paths = controller_paths.to_owned();
|
||||
app.on_recent_rom_button_clicked(move |rom| {
|
||||
let controller_paths = owned_controller_paths.clone();
|
||||
weak.upgrade_in_event_loop(move |handle| {
|
||||
run_with_path(
|
||||
handle.as_weak(),
|
||||
std::path::PathBuf::from(rom.to_string()),
|
||||
&controller_paths,
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
let saves_path = dirs.data_dir.join("saves");
|
||||
app.on_saves_folder_button_clicked(move || {
|
||||
open::that_detached(saves_path.clone()).unwrap();
|
||||
@@ -162,11 +217,14 @@ fn update_input_profiles(weak: &slint::Weak<AppWindow>, config: &ui::config::Con
|
||||
profile_bindings.push(position.unwrap() as i32);
|
||||
}
|
||||
|
||||
let input_profiles = slint::VecModel::default();
|
||||
for profile in profiles {
|
||||
input_profiles.push(profile.into());
|
||||
}
|
||||
handle.set_input_profiles(slint::ModelRc::from(std::rc::Rc::new(input_profiles)));
|
||||
handle.set_input_profiles(slint::ModelRc::from(std::rc::Rc::new(
|
||||
slint::VecModel::from(
|
||||
profiles
|
||||
.iter()
|
||||
.map(|x| x.into())
|
||||
.collect::<Vec<slint::SharedString>>(),
|
||||
),
|
||||
)));
|
||||
|
||||
handle
|
||||
.set_selected_profile_binding(slint::ModelRc::from(std::rc::Rc::new(profile_bindings)));
|
||||
@@ -187,7 +245,7 @@ fn update_input_profiles(weak: &slint::Weak<AppWindow>, config: &ui::config::Con
|
||||
fn controller_window(
|
||||
app: &AppWindow,
|
||||
config: &ui::config::Config,
|
||||
controller_names: &Vec<String>,
|
||||
controller_names: &[String],
|
||||
controller_paths: &[Option<String>],
|
||||
) {
|
||||
app.set_emulate_vru(config.input.emulate_vru);
|
||||
@@ -200,25 +258,38 @@ fn controller_window(
|
||||
slint::VecModel::from(config.input.transfer_pak.to_vec()),
|
||||
)));
|
||||
|
||||
let gb_rom_paths = slint::VecModel::default();
|
||||
for gb_rom_path in config.input.gb_rom_path.iter() {
|
||||
gb_rom_paths.push(gb_rom_path.into());
|
||||
}
|
||||
app.set_gb_rom_paths(slint::ModelRc::from(std::rc::Rc::new(gb_rom_paths)));
|
||||
app.set_gb_rom_paths(slint::ModelRc::from(std::rc::Rc::new(
|
||||
slint::VecModel::from(
|
||||
config
|
||||
.input
|
||||
.gb_rom_path
|
||||
.iter()
|
||||
.map(|x| x.into())
|
||||
.collect::<Vec<slint::SharedString>>(),
|
||||
),
|
||||
)));
|
||||
|
||||
let gb_ram_paths = slint::VecModel::default();
|
||||
for gb_ram_path in config.input.gb_ram_path.iter() {
|
||||
gb_ram_paths.push(gb_ram_path.into());
|
||||
}
|
||||
app.set_gb_ram_paths(slint::ModelRc::from(std::rc::Rc::new(gb_ram_paths)));
|
||||
app.set_gb_ram_paths(slint::ModelRc::from(std::rc::Rc::new(
|
||||
slint::VecModel::from(
|
||||
config
|
||||
.input
|
||||
.gb_ram_path
|
||||
.iter()
|
||||
.map(|x| x.into())
|
||||
.collect::<Vec<slint::SharedString>>(),
|
||||
),
|
||||
)));
|
||||
|
||||
update_input_profiles(&app.as_weak(), config);
|
||||
|
||||
let controllers = slint::VecModel::default();
|
||||
for controller in controller_names {
|
||||
controllers.push(controller.into());
|
||||
}
|
||||
app.set_controller_names(slint::ModelRc::from(std::rc::Rc::new(controllers)));
|
||||
app.set_controller_names(slint::ModelRc::from(std::rc::Rc::new(
|
||||
slint::VecModel::from(
|
||||
controller_names
|
||||
.iter()
|
||||
.map(|x| x.into())
|
||||
.collect::<Vec<slint::SharedString>>(),
|
||||
),
|
||||
)));
|
||||
|
||||
let controller_changed = slint::VecModel::default();
|
||||
let selected_controllers = slint::VecModel::default();
|
||||
@@ -395,8 +466,8 @@ pub fn app_window() {
|
||||
controller_paths.insert(0, None);
|
||||
settings_window(&app, &game_ui.config);
|
||||
controller_window(&app, &game_ui.config, &controller_names, &controller_paths);
|
||||
local_game_window(&app, &game_ui.config, &controller_paths);
|
||||
}
|
||||
local_game_window(&app, &controller_paths);
|
||||
ui::netplay::netplay_window(&app, &controller_paths);
|
||||
ui::cheats::cheats_window(&app);
|
||||
app.run().unwrap();
|
||||
@@ -453,13 +524,14 @@ pub fn run_rom(
|
||||
}
|
||||
}
|
||||
|
||||
if !command
|
||||
let success = command
|
||||
.arg(file_path.to_str().unwrap())
|
||||
.status()
|
||||
.await
|
||||
.unwrap()
|
||||
.success()
|
||||
{
|
||||
.success();
|
||||
|
||||
if !success {
|
||||
eprintln!("Failed to run game");
|
||||
}
|
||||
|
||||
@@ -469,6 +541,24 @@ pub fn run_rom(
|
||||
if let Some(rom_dir) = file_path.parent().unwrap().to_str() {
|
||||
handle.set_rom_dir(rom_dir.into());
|
||||
}
|
||||
if success {
|
||||
let recent_roms = slint::VecModel::default();
|
||||
recent_roms.push((
|
||||
file_path.to_str().unwrap().into(),
|
||||
file_path.file_name().unwrap().to_str().unwrap().into(),
|
||||
));
|
||||
|
||||
for rom in handle.get_recent_roms().iter() {
|
||||
if rom.0 != file_path.to_str().unwrap()
|
||||
&& recent_roms.row_count() < 5
|
||||
&& let Ok(exists) = std::fs::exists(&rom.0)
|
||||
&& exists
|
||||
{
|
||||
recent_roms.push(rom);
|
||||
}
|
||||
}
|
||||
handle.set_recent_roms(slint::ModelRc::from(std::rc::Rc::new(recent_roms)));
|
||||
}
|
||||
handle.set_game_running(false);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -22,6 +22,7 @@ export component AppWindow inherits Window {
|
||||
callback wiki_button_clicked;
|
||||
callback discord_button_clicked;
|
||||
callback newversion_button_clicked;
|
||||
callback recent_rom_button_clicked(string);
|
||||
callback patreon_button_clicked;
|
||||
callback github_sponsors_button_clicked;
|
||||
callback source_code_button_clicked;
|
||||
@@ -72,6 +73,7 @@ export component AppWindow inherits Window {
|
||||
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 recent_roms <=> State.recent_roms;
|
||||
in-out property blank_profiles <=> ControllerData.blank_profiles;
|
||||
in-out property cheat_game_name <=> CheatsData.cheat_game_name;
|
||||
in-out property cheat_game_crc <=> CheatsData.cheat_game_crc;
|
||||
@@ -105,6 +107,9 @@ export component AppWindow inherits Window {
|
||||
newversion_button_clicked => {
|
||||
newversion_button_clicked();
|
||||
}
|
||||
recent_rom_button_clicked(rom) => {
|
||||
recent_rom_button_clicked(rom);
|
||||
}
|
||||
}
|
||||
if(side-bar.current-item == 1): ControllerConfig {
|
||||
input_profile_button_clicked => {
|
||||
|
||||
@@ -69,7 +69,7 @@ export component Cheats inherits Page {
|
||||
cheat_toggled(CheatsData.cheat_game_crc,data.cheat_name,"",self.checked);
|
||||
}
|
||||
}
|
||||
for item[index] in data.options: CheckBox {
|
||||
for item in data.options: CheckBox {
|
||||
text: item.option;
|
||||
enabled: !data.enabled || (data.enabled && item.enabled);
|
||||
checked: item.enabled;
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { Button, HorizontalBox, VerticalBox } from "std-widgets.slint";
|
||||
import { Button, HorizontalBox, VerticalBox, GroupBox } from "std-widgets.slint";
|
||||
import { Page } from "page.slint";
|
||||
import { AboutData, NewVersionButton } from "about_page.slint";
|
||||
|
||||
export global State {
|
||||
in-out property <bool> game_running;
|
||||
in-out property <[{a:string, b:string}]> recent_roms;
|
||||
}
|
||||
|
||||
export component LocalGame inherits Page {
|
||||
callback open_rom_button_clicked;
|
||||
callback saves_folder_button_clicked;
|
||||
callback newversion_button_clicked;
|
||||
callback recent_rom_button_clicked(string);
|
||||
title: @tr("Local Game");
|
||||
|
||||
VerticalBox {
|
||||
@@ -44,5 +46,22 @@ export component LocalGame inherits Page {
|
||||
}
|
||||
}
|
||||
Rectangle { }
|
||||
|
||||
if State.recent_roms.length>0:HorizontalBox {
|
||||
alignment: center;
|
||||
GroupBox {
|
||||
title: @tr("Recent ROMs");
|
||||
VerticalLayout {
|
||||
alignment: space-between;
|
||||
for rom in State.recent_roms: Button {
|
||||
text: rom.b;
|
||||
enabled: !State.game_running;
|
||||
clicked => {
|
||||
recent_rom_button_clicked(rom.a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -1051,13 +1051,13 @@ fn setup_wait_window(
|
||||
handle.set_can_start(false);
|
||||
}
|
||||
|
||||
let players_vec: slint::VecModel<slint::SharedString> =
|
||||
slint::VecModel::default();
|
||||
for player in player_names {
|
||||
players_vec.push(player.into());
|
||||
}
|
||||
handle.set_players(slint::ModelRc::from(std::rc::Rc::new(
|
||||
players_vec,
|
||||
slint::VecModel::from(
|
||||
player_names
|
||||
.iter()
|
||||
.map(|x| x.into())
|
||||
.collect::<Vec<slint::SharedString>>(),
|
||||
),
|
||||
)));
|
||||
}
|
||||
})
|
||||
|
||||
+8
-5
@@ -17,11 +17,14 @@ pub fn prompt_for_match(words: &[String], frame_time: f64) -> u16 {
|
||||
vru_dialog_weak.unwrap().window().hide().unwrap();
|
||||
});
|
||||
|
||||
let words_vec = slint::VecModel::default();
|
||||
for word in dedup_words {
|
||||
words_vec.push(word.into());
|
||||
}
|
||||
vru_dialog.set_words(slint::ModelRc::from(std::rc::Rc::new(words_vec)));
|
||||
vru_dialog.set_words(slint::ModelRc::from(std::rc::Rc::new(
|
||||
slint::VecModel::from(
|
||||
dedup_words
|
||||
.iter()
|
||||
.map(|x| x.into())
|
||||
.collect::<Vec<slint::SharedString>>(),
|
||||
),
|
||||
)));
|
||||
|
||||
let timer = slint::Timer::default();
|
||||
timer.start(
|
||||
|
||||
Reference in New Issue
Block a user