mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-11-15 18:32:48 +00:00
add portable user directory setting
This commit is contained in:
parent
b22ca8b35e
commit
890c0596ed
|
@ -133,7 +133,14 @@
|
||||||
"advanced": "Advanced...",
|
"advanced": "Advanced...",
|
||||||
"advanced_menu": {
|
"advanced_menu": {
|
||||||
"open_user_data": "Open user data directory",
|
"open_user_data": "Open user data directory",
|
||||||
"open_game_data": "Open game data directory"
|
"open_game_data": "Open game data directory",
|
||||||
|
"make_portable": "Make portable user directory"
|
||||||
|
},
|
||||||
|
"portable_menu": {
|
||||||
|
"explanation": "This will create a local user data directory and copy your settings and save files.",
|
||||||
|
"restart_question": "Reload the game to use the new location?",
|
||||||
|
"restart": "Save and return to title",
|
||||||
|
"cancel": "Cancel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"controls_menu": {
|
"controls_menu": {
|
||||||
|
|
|
@ -133,7 +133,14 @@
|
||||||
"advanced": "詳細設定",
|
"advanced": "詳細設定",
|
||||||
"advanced_menu": {
|
"advanced_menu": {
|
||||||
"open_user_data": "ユーザープロファイルを開く",
|
"open_user_data": "ユーザープロファイルを開く",
|
||||||
"open_game_data": "ゲームファイルを開く"
|
"open_game_data": "ゲームファイルを開く",
|
||||||
|
"make_portable": "ポータブルユーザーディレクトリを作成する"
|
||||||
|
},
|
||||||
|
"portable_menu": {
|
||||||
|
"explanation": "ローカルのユーザーデータディレクトリが作成され、設定とセーブファイルがそこにコピーされます。",
|
||||||
|
"restart_question": "新しい場所を使うには、ゲームを再起動しますか?",
|
||||||
|
"restart": "保存してタイトルに戻る",
|
||||||
|
"cancel": "キャンセル"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"controls_menu": {
|
"controls_menu": {
|
||||||
|
|
|
@ -160,7 +160,7 @@ impl Filesystem {
|
||||||
pub(crate) fn user_read_dir<P: AsRef<path::Path>>(
|
pub(crate) fn user_read_dir<P: AsRef<path::Path>>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
) -> GameResult<Box<dyn Iterator<Item=path::PathBuf>>> {
|
) -> GameResult<Box<dyn Iterator<Item = path::PathBuf>>> {
|
||||||
let itr = self
|
let itr = self
|
||||||
.user_vfs
|
.user_vfs
|
||||||
.read_dir(path.as_ref())?
|
.read_dir(path.as_ref())?
|
||||||
|
@ -175,7 +175,7 @@ impl Filesystem {
|
||||||
pub(crate) fn read_dir<P: AsRef<path::Path>>(
|
pub(crate) fn read_dir<P: AsRef<path::Path>>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
) -> GameResult<Box<dyn Iterator<Item=path::PathBuf>>> {
|
) -> GameResult<Box<dyn Iterator<Item = path::PathBuf>>> {
|
||||||
let itr = self
|
let itr = self
|
||||||
.vfs
|
.vfs
|
||||||
.read_dir(path.as_ref())?
|
.read_dir(path.as_ref())?
|
||||||
|
@ -221,6 +221,14 @@ impl Filesystem {
|
||||||
pub fn mount_user_vfs(&mut self, vfs: Box<dyn vfs::VFS>) {
|
pub fn mount_user_vfs(&mut self, vfs: Box<dyn vfs::VFS>) {
|
||||||
self.user_vfs.push_back(vfs);
|
self.user_vfs.push_back(vfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unmount_vfs(&mut self, root: &PathBuf) {
|
||||||
|
self.vfs.remove(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unmount_user_vfs(&mut self, root: &PathBuf) {
|
||||||
|
self.user_vfs.remove(root);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opens the given path and returns the resulting `File`
|
/// Opens the given path and returns the resulting `File`
|
||||||
|
@ -303,7 +311,7 @@ pub fn user_is_dir<P: AsRef<path::Path>>(ctx: &Context, path: P) -> bool {
|
||||||
pub fn user_read_dir<P: AsRef<path::Path>>(
|
pub fn user_read_dir<P: AsRef<path::Path>>(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
path: P,
|
path: P,
|
||||||
) -> GameResult<Box<dyn Iterator<Item=path::PathBuf>>> {
|
) -> GameResult<Box<dyn Iterator<Item = path::PathBuf>>> {
|
||||||
ctx.filesystem.user_read_dir(path)
|
ctx.filesystem.user_read_dir(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +347,7 @@ pub fn is_dir<P: AsRef<path::Path>>(ctx: &Context, path: P) -> bool {
|
||||||
/// in no particular order.
|
/// in no particular order.
|
||||||
///
|
///
|
||||||
/// Lists the base directory if an empty path is given.
|
/// Lists the base directory if an empty path is given.
|
||||||
pub fn read_dir<P: AsRef<path::Path>>(ctx: &Context, path: P) -> GameResult<Box<dyn Iterator<Item=path::PathBuf>>> {
|
pub fn read_dir<P: AsRef<path::Path>>(ctx: &Context, path: P) -> GameResult<Box<dyn Iterator<Item = path::PathBuf>>> {
|
||||||
ctx.filesystem.read_dir(path)
|
ctx.filesystem.read_dir(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +355,7 @@ pub fn read_dir_find<P: AsRef<path::Path>>(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
roots: &Vec<String>,
|
roots: &Vec<String>,
|
||||||
path: P,
|
path: P,
|
||||||
) -> GameResult<Box<dyn Iterator<Item=path::PathBuf>>> {
|
) -> GameResult<Box<dyn Iterator<Item = path::PathBuf>>> {
|
||||||
let mut files = Vec::new();
|
let mut files = Vec::new();
|
||||||
|
|
||||||
for root in roots {
|
for root in roots {
|
||||||
|
@ -383,3 +391,13 @@ pub fn mount_vfs(ctx: &mut Context, vfs: Box<dyn vfs::VFS>) {
|
||||||
pub fn mount_user_vfs(ctx: &mut Context, vfs: Box<dyn vfs::VFS>) {
|
pub fn mount_user_vfs(ctx: &mut Context, vfs: Box<dyn vfs::VFS>) {
|
||||||
ctx.filesystem.mount_user_vfs(vfs)
|
ctx.filesystem.mount_user_vfs(vfs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unmounts a VFS with a provided root path.
|
||||||
|
pub fn unmount_vfs(ctx: &mut Context, root: &PathBuf) {
|
||||||
|
ctx.filesystem.unmount_vfs(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmounts a user VFS with a provided root path.
|
||||||
|
pub fn unmount_user_vfs(ctx: &mut Context, root: &PathBuf) {
|
||||||
|
ctx.filesystem.unmount_user_vfs(root)
|
||||||
|
}
|
||||||
|
|
|
@ -441,6 +441,11 @@ impl OverlayFS {
|
||||||
pub fn roots(&self) -> &VecDeque<Box<dyn VFS>> {
|
pub fn roots(&self) -> &VecDeque<Box<dyn VFS>> {
|
||||||
&self.roots
|
&self.roots
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes a VFS with a provided root.
|
||||||
|
pub fn remove(&mut self, root: &PathBuf) {
|
||||||
|
self.roots.iter().position(|fs| fs.to_path_buf() == Some(root.clone())).map(|i| self.roots.remove(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VFS for OverlayFS {
|
impl VFS for OverlayFS {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
framework::{
|
framework::{
|
||||||
context::Context,
|
context::Context,
|
||||||
error::GameResult,
|
error::GameResult,
|
||||||
filesystem::{mount_user_vfs, mount_vfs},
|
filesystem::{mount_user_vfs, mount_vfs, unmount_user_vfs},
|
||||||
vfs::PhysicalFS,
|
vfs::PhysicalFS,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -13,11 +13,13 @@ use crate::{
|
||||||
pub struct FilesystemContainer {
|
pub struct FilesystemContainer {
|
||||||
pub user_path: PathBuf,
|
pub user_path: PathBuf,
|
||||||
pub game_path: PathBuf,
|
pub game_path: PathBuf,
|
||||||
|
|
||||||
|
pub is_portable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilesystemContainer {
|
impl FilesystemContainer {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { user_path: PathBuf::new(), game_path: PathBuf::new() }
|
Self { user_path: PathBuf::new(), game_path: PathBuf::new(), is_portable: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mount_fs(&mut self, context: &mut Context) -> GameResult {
|
pub fn mount_fs(&mut self, context: &mut Context) -> GameResult {
|
||||||
|
@ -125,14 +127,15 @@ impl FilesystemContainer {
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "horizon")))]
|
#[cfg(not(any(target_os = "android", target_os = "horizon")))]
|
||||||
{
|
{
|
||||||
if crate::framework::filesystem::open(&context, "/.drs_localstorage").is_ok() {
|
|
||||||
let mut user_dir = resource_dir.clone();
|
let mut user_dir = resource_dir.clone();
|
||||||
user_dir.push("_drs_profile");
|
user_dir.pop();
|
||||||
|
user_dir.push("user");
|
||||||
|
|
||||||
let _ = std::fs::create_dir_all(&user_dir);
|
if user_dir.is_dir() {
|
||||||
|
// portable mode
|
||||||
mount_user_vfs(context, Box::new(PhysicalFS::new(&user_dir, false)));
|
mount_user_vfs(context, Box::new(PhysicalFS::new(&user_dir, false)));
|
||||||
|
|
||||||
self.user_path = user_dir.clone();
|
self.user_path = user_dir.clone();
|
||||||
|
self.is_portable = true;
|
||||||
} else {
|
} else {
|
||||||
let user_dir = project_dirs.data_local_dir();
|
let user_dir = project_dirs.data_local_dir();
|
||||||
mount_user_vfs(context, Box::new(PhysicalFS::new(user_dir, false)));
|
mount_user_vfs(context, Box::new(PhysicalFS::new(user_dir, false)));
|
||||||
|
@ -155,6 +158,39 @@ impl FilesystemContainer {
|
||||||
self.open_directory(self.game_path.clone())
|
self.open_directory(self.game_path.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn make_portable_user_directory(&mut self, ctx: &mut Context) -> GameResult {
|
||||||
|
let mut user_dir = self.game_path.clone();
|
||||||
|
user_dir.pop();
|
||||||
|
user_dir.push("user");
|
||||||
|
|
||||||
|
if user_dir.is_dir() {
|
||||||
|
return Ok(()); // portable directory already exists
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = std::fs::create_dir_all(user_dir.clone());
|
||||||
|
|
||||||
|
// copy user data from current user dir
|
||||||
|
for entry in std::fs::read_dir(&self.user_path)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = entry.path();
|
||||||
|
let file_name = path.file_name().unwrap().to_str().unwrap();
|
||||||
|
let mut new_path = user_dir.clone();
|
||||||
|
new_path.push(file_name);
|
||||||
|
std::fs::copy(path, new_path)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmount old user dir
|
||||||
|
unmount_user_vfs(ctx, &self.user_path);
|
||||||
|
|
||||||
|
// mount new user dir
|
||||||
|
mount_user_vfs(ctx, Box::new(PhysicalFS::new(&user_dir, false)));
|
||||||
|
|
||||||
|
self.user_path = user_dir.clone();
|
||||||
|
self.is_portable = true;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn open_directory(&self, path: PathBuf) -> GameResult {
|
fn open_directory(&self, path: PathBuf) -> GameResult {
|
||||||
#[cfg(target_os = "horizon")]
|
#[cfg(target_os = "horizon")]
|
||||||
return Ok(()); // can't open directories on switch
|
return Ok(()); // can't open directories on switch
|
||||||
|
|
|
@ -211,10 +211,8 @@ impl ControlsMenu {
|
||||||
MainMenuEntry::Controller,
|
MainMenuEntry::Controller,
|
||||||
MenuEntry::Active(state.loc.t("menus.controls_menu.controller.entry").to_owned()),
|
MenuEntry::Active(state.loc.t("menus.controls_menu.controller.entry").to_owned()),
|
||||||
);
|
);
|
||||||
self.main.push_entry(
|
self.main
|
||||||
MainMenuEntry::Rebind,
|
.push_entry(MainMenuEntry::Rebind, MenuEntry::Active(state.loc.t("menus.controls_menu.rebind").to_owned()));
|
||||||
MenuEntry::Active(state.loc.t("menus.controls_menu.rebind").to_owned()),
|
|
||||||
);
|
|
||||||
self.main.push_entry(MainMenuEntry::Rumble, MenuEntry::Hidden);
|
self.main.push_entry(MainMenuEntry::Rumble, MenuEntry::Hidden);
|
||||||
self.main.push_entry(MainMenuEntry::Back, MenuEntry::Active(state.loc.t("common.back").to_owned()));
|
self.main.push_entry(MainMenuEntry::Back, MenuEntry::Active(state.loc.t("common.back").to_owned()));
|
||||||
|
|
||||||
|
@ -246,28 +244,28 @@ impl ControlsMenu {
|
||||||
|
|
||||||
fn update_sizes(&mut self, state: &SharedGameState) {
|
fn update_sizes(&mut self, state: &SharedGameState) {
|
||||||
self.main.update_width(state);
|
self.main.update_width(state);
|
||||||
self.main.update_height();
|
self.main.update_height(state);
|
||||||
self.main.x = ((state.canvas_size.0 - self.main.width as f32) / 2.0).floor() as isize;
|
self.main.x = ((state.canvas_size.0 - self.main.width as f32) / 2.0).floor() as isize;
|
||||||
self.main.y = ((state.canvas_size.1 - self.main.height as f32) / 2.0).floor() as isize;
|
self.main.y = ((state.canvas_size.1 - self.main.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.select_controller.update_width(state);
|
self.select_controller.update_width(state);
|
||||||
self.select_controller.update_height();
|
self.select_controller.update_height(state);
|
||||||
self.select_controller.x = ((state.canvas_size.0 - self.select_controller.width as f32) / 2.0).floor() as isize;
|
self.select_controller.x = ((state.canvas_size.0 - self.select_controller.width as f32) / 2.0).floor() as isize;
|
||||||
self.select_controller.y =
|
self.select_controller.y =
|
||||||
((state.canvas_size.1 - self.select_controller.height as f32) / 2.0).floor() as isize;
|
((state.canvas_size.1 - self.select_controller.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.rebind.update_width(state);
|
self.rebind.update_width(state);
|
||||||
self.rebind.update_height();
|
self.rebind.update_height(state);
|
||||||
self.rebind.x = ((state.canvas_size.0 - self.rebind.width as f32) / 2.0).floor() as isize;
|
self.rebind.x = ((state.canvas_size.0 - self.rebind.width as f32) / 2.0).floor() as isize;
|
||||||
self.rebind.y = ((state.canvas_size.1 - self.rebind.height as f32) / 2.0).floor() as isize;
|
self.rebind.y = ((state.canvas_size.1 - self.rebind.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.confirm_rebind.update_width(state);
|
self.confirm_rebind.update_width(state);
|
||||||
self.confirm_rebind.update_height();
|
self.confirm_rebind.update_height(state);
|
||||||
self.confirm_rebind.x = ((state.canvas_size.0 - self.confirm_rebind.width as f32) / 2.0).floor() as isize;
|
self.confirm_rebind.x = ((state.canvas_size.0 - self.confirm_rebind.width as f32) / 2.0).floor() as isize;
|
||||||
self.confirm_rebind.y = ((state.canvas_size.1 - self.confirm_rebind.height as f32) / 2.0).floor() as isize;
|
self.confirm_rebind.y = ((state.canvas_size.1 - self.confirm_rebind.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.confirm_reset.update_width(state);
|
self.confirm_reset.update_width(state);
|
||||||
self.confirm_reset.update_height();
|
self.confirm_reset.update_height(state);
|
||||||
self.confirm_reset.x = ((state.canvas_size.0 - self.confirm_reset.width as f32) / 2.0).floor() as isize;
|
self.confirm_reset.x = ((state.canvas_size.0 - self.confirm_reset.width as f32) / 2.0).floor() as isize;
|
||||||
self.confirm_reset.y = ((state.canvas_size.1 - self.confirm_reset.height as f32) / 2.0).floor() as isize;
|
self.confirm_reset.y = ((state.canvas_size.1 - self.confirm_reset.height as f32) / 2.0).floor() as isize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,12 +96,12 @@ impl PlayerCountMenu {
|
||||||
|
|
||||||
fn update_sizes(&mut self, state: &SharedGameState) {
|
fn update_sizes(&mut self, state: &SharedGameState) {
|
||||||
self.coop_menu.update_width(state);
|
self.coop_menu.update_width(state);
|
||||||
self.coop_menu.update_height();
|
self.coop_menu.update_height(state);
|
||||||
self.coop_menu.x = ((state.canvas_size.0 - self.coop_menu.width as f32) / 2.0).floor() as isize;
|
self.coop_menu.x = ((state.canvas_size.0 - self.coop_menu.width as f32) / 2.0).floor() as isize;
|
||||||
self.coop_menu.y = 30 + ((state.canvas_size.1 - self.coop_menu.height as f32) / 2.0).floor() as isize;
|
self.coop_menu.y = 30 + ((state.canvas_size.1 - self.coop_menu.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.skin_menu.update_width(state);
|
self.skin_menu.update_width(state);
|
||||||
self.skin_menu.update_height();
|
self.skin_menu.update_height(state);
|
||||||
self.skin_menu.x = ((state.canvas_size.0 - self.coop_menu.width as f32) / 2.0).floor() as isize;
|
self.skin_menu.x = ((state.canvas_size.0 - self.coop_menu.width as f32) / 2.0).floor() as isize;
|
||||||
self.skin_menu.y = 30 + ((state.canvas_size.1 - self.coop_menu.height as f32) / 2.0).floor() as isize;
|
self.skin_menu.y = 30 + ((state.canvas_size.1 - self.coop_menu.height as f32) / 2.0).floor() as isize;
|
||||||
}
|
}
|
||||||
|
|
122
src/menu/mod.rs
122
src/menu/mod.rs
|
@ -28,6 +28,8 @@ pub enum ControlMenuData {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum MenuEntry {
|
pub enum MenuEntry {
|
||||||
Hidden,
|
Hidden,
|
||||||
|
Title(String, bool, bool), // text, centered, white
|
||||||
|
LongText(String, bool, bool), // text, centered, white
|
||||||
Active(String),
|
Active(String),
|
||||||
DisabledWhite(String),
|
DisabledWhite(String),
|
||||||
Disabled(String),
|
Disabled(String),
|
||||||
|
@ -40,12 +42,15 @@ pub enum MenuEntry {
|
||||||
NewSave,
|
NewSave,
|
||||||
PlayerSkin,
|
PlayerSkin,
|
||||||
Control(String, ControlMenuData),
|
Control(String, ControlMenuData),
|
||||||
|
Spacer(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MenuEntry {
|
impl MenuEntry {
|
||||||
pub fn height(&self) -> f64 {
|
pub fn height(&self) -> f64 {
|
||||||
match self {
|
match self {
|
||||||
MenuEntry::Hidden => 0.0,
|
MenuEntry::Hidden => 0.0,
|
||||||
|
MenuEntry::Title(_, _, _) => 16.0, // individual line
|
||||||
|
MenuEntry::LongText(_, _, _) => 16.0, // individual line
|
||||||
MenuEntry::Active(_) => 16.0,
|
MenuEntry::Active(_) => 16.0,
|
||||||
MenuEntry::DisabledWhite(_) => 16.0,
|
MenuEntry::DisabledWhite(_) => 16.0,
|
||||||
MenuEntry::Disabled(_) => 16.0,
|
MenuEntry::Disabled(_) => 16.0,
|
||||||
|
@ -58,12 +63,15 @@ impl MenuEntry {
|
||||||
MenuEntry::NewSave => 32.0,
|
MenuEntry::NewSave => 32.0,
|
||||||
MenuEntry::PlayerSkin => 24.0,
|
MenuEntry::PlayerSkin => 24.0,
|
||||||
MenuEntry::Control(_, _) => 16.0,
|
MenuEntry::Control(_, _) => 16.0,
|
||||||
|
MenuEntry::Spacer(height) => *height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn selectable(&self) -> bool {
|
pub fn selectable(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
MenuEntry::Hidden => false,
|
MenuEntry::Hidden => false,
|
||||||
|
MenuEntry::Title(_, _, _) => false,
|
||||||
|
MenuEntry::LongText(_, _, _) => false,
|
||||||
MenuEntry::Active(_) => true,
|
MenuEntry::Active(_) => true,
|
||||||
MenuEntry::DisabledWhite(_) => false,
|
MenuEntry::DisabledWhite(_) => false,
|
||||||
MenuEntry::Disabled(_) => false,
|
MenuEntry::Disabled(_) => false,
|
||||||
|
@ -76,6 +84,7 @@ impl MenuEntry {
|
||||||
MenuEntry::NewSave => true,
|
MenuEntry::NewSave => true,
|
||||||
MenuEntry::PlayerSkin => true,
|
MenuEntry::PlayerSkin => true,
|
||||||
MenuEntry::Control(_, _) => true,
|
MenuEntry::Control(_, _) => true,
|
||||||
|
MenuEntry::Spacer(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,11 +104,13 @@ pub struct Menu<T: std::cmp::PartialEq> {
|
||||||
pub height: u16,
|
pub height: u16,
|
||||||
pub selected: T,
|
pub selected: T,
|
||||||
pub entries: Vec<(T, MenuEntry)>,
|
pub entries: Vec<(T, MenuEntry)>,
|
||||||
|
pub height_overrides: Vec<(T, f64)>,
|
||||||
anim_num: u16,
|
anim_num: u16,
|
||||||
anim_wait: u16,
|
anim_wait: u16,
|
||||||
custom_cursor: Cell<bool>,
|
custom_cursor: Cell<bool>,
|
||||||
pub draw_cursor: bool,
|
pub draw_cursor: bool,
|
||||||
pub non_interactive: bool,
|
pub non_interactive: bool,
|
||||||
|
pub center_options: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: std::cmp::PartialEq + std::default::Default + Clone> Menu<T> {
|
impl<T: std::cmp::PartialEq + std::default::Default + Clone> Menu<T> {
|
||||||
|
@ -113,9 +124,11 @@ impl<T: std::cmp::PartialEq + std::default::Default + Clone> Menu<T> {
|
||||||
anim_num: 0,
|
anim_num: 0,
|
||||||
anim_wait: 0,
|
anim_wait: 0,
|
||||||
entries: Vec::new(),
|
entries: Vec::new(),
|
||||||
|
height_overrides: Vec::new(),
|
||||||
custom_cursor: Cell::new(true),
|
custom_cursor: Cell::new(true),
|
||||||
draw_cursor: true,
|
draw_cursor: true,
|
||||||
non_interactive: false,
|
non_interactive: false,
|
||||||
|
center_options: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,6 +164,10 @@ impl<T: std::cmp::PartialEq + std::default::Default + Clone> Menu<T> {
|
||||||
let entry_width = state.font.builder().compute_width(&entry) + 32.0;
|
let entry_width = state.font.builder().compute_width(&entry) + 32.0;
|
||||||
width = width.max(entry_width);
|
width = width.max(entry_width);
|
||||||
}
|
}
|
||||||
|
MenuEntry::Title(entry, _, _) | MenuEntry::LongText(entry, _, _) => {
|
||||||
|
let entry_width = state.font.builder().compute_width(&entry).min(state.canvas_size.0) + 32.0;
|
||||||
|
width = width.max(entry_width);
|
||||||
|
}
|
||||||
MenuEntry::Toggle(entry, _) => {
|
MenuEntry::Toggle(entry, _) => {
|
||||||
let mut entry_with_option = entry.clone();
|
let mut entry_with_option = entry.clone();
|
||||||
entry_with_option.push_str(" ");
|
entry_with_option.push_str(" ");
|
||||||
|
@ -199,19 +216,34 @@ impl<T: std::cmp::PartialEq + std::default::Default + Clone> Menu<T> {
|
||||||
MenuEntry::NewSave => {}
|
MenuEntry::NewSave => {}
|
||||||
MenuEntry::PlayerSkin => {}
|
MenuEntry::PlayerSkin => {}
|
||||||
MenuEntry::Control(_, _) => {}
|
MenuEntry::Control(_, _) => {}
|
||||||
|
MenuEntry::Spacer(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
width = width.max(16.0);
|
width = width.max(16.0).min(state.canvas_size.0 - MENU_MIN_PADDING);
|
||||||
self.width = if (width + 4.0) % 8.0 != 0.0 { (width + 4.0 - width % 8.0) as u16 } else { width as u16 };
|
self.width = if (width + 4.0) % 8.0 != 0.0 { (width + 4.0 - width % 8.0) as u16 } else { width as u16 };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_height(&mut self) {
|
pub fn update_height(&mut self, state: &SharedGameState) {
|
||||||
let mut height = 8.0;
|
let mut height = 8.0;
|
||||||
|
|
||||||
for (_, entry) in &self.entries {
|
for (id, entry) in &self.entries {
|
||||||
|
match entry {
|
||||||
|
MenuEntry::Title(text, _, _) | MenuEntry::LongText(text, _, _) => {
|
||||||
|
let text_width = state.font.builder().compute_width(text) + 32.0;
|
||||||
|
let lines = (text_width / state.canvas_size.0).ceil();
|
||||||
|
|
||||||
|
let actual_entry_height = lines as f64 * entry.height();
|
||||||
|
|
||||||
|
self.height_overrides.push((id.clone(), actual_entry_height));
|
||||||
|
|
||||||
|
height += actual_entry_height;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
height += entry.height();
|
height += entry.height();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.height = height.max(16.0) as u16;
|
self.height = height.max(16.0) as u16;
|
||||||
}
|
}
|
||||||
|
@ -320,6 +352,26 @@ impl<T: std::cmp::PartialEq + std::default::Default + Clone> Menu<T> {
|
||||||
|
|
||||||
batch.draw(ctx)?;
|
batch.draw(ctx)?;
|
||||||
|
|
||||||
|
let options_x = if self.center_options {
|
||||||
|
let mut longest_option_width = 20.0;
|
||||||
|
|
||||||
|
for (_, entry) in &self.entries {
|
||||||
|
match entry {
|
||||||
|
MenuEntry::Options(text, _, _) | MenuEntry::Active(text) => {
|
||||||
|
let text_width = state.font.builder().compute_width(text) + 32.0;
|
||||||
|
if text_width > longest_option_width {
|
||||||
|
longest_option_width = text_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(state.canvas_size.0 / 2.0) - (longest_option_width / 2.0)
|
||||||
|
} else {
|
||||||
|
self.x as f32
|
||||||
|
};
|
||||||
|
|
||||||
if self.draw_cursor {
|
if self.draw_cursor {
|
||||||
if self.custom_cursor.get() {
|
if self.custom_cursor.get() {
|
||||||
if let Ok(batch) = state.texture_set.get_or_load_batch(ctx, &state.constants, "MenuCursor") {
|
if let Ok(batch) = state.texture_set.get_or_load_batch(ctx, &state.constants, "MenuCursor") {
|
||||||
|
@ -328,7 +380,7 @@ impl<T: std::cmp::PartialEq + std::default::Default + Clone> Menu<T> {
|
||||||
rect.right = rect.left + 16;
|
rect.right = rect.left + 16;
|
||||||
rect.bottom = rect.top + 16;
|
rect.bottom = rect.top + 16;
|
||||||
|
|
||||||
batch.add_rect(self.x as f32, computed_y + 3.0 + selected_y, &rect);
|
batch.add_rect(options_x, computed_y + 3.0 + selected_y, &rect);
|
||||||
|
|
||||||
batch.draw(ctx)?;
|
batch.draw(ctx)?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -365,7 +417,7 @@ impl<T: std::cmp::PartialEq + std::default::Default + Clone> Menu<T> {
|
||||||
|
|
||||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, menu_texture)?;
|
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, menu_texture)?;
|
||||||
|
|
||||||
batch.add_rect(self.x as f32, computed_y + 4.0 + selected_y, &character_rect[self.anim_num as usize]);
|
batch.add_rect(options_x, computed_y + 4.0 + selected_y, &character_rect[self.anim_num as usize]);
|
||||||
|
|
||||||
batch.draw(ctx)?;
|
batch.draw(ctx)?;
|
||||||
}
|
}
|
||||||
|
@ -375,13 +427,60 @@ impl<T: std::cmp::PartialEq + std::default::Default + Clone> Menu<T> {
|
||||||
for (_, entry) in &self.entries {
|
for (_, entry) in &self.entries {
|
||||||
match entry {
|
match entry {
|
||||||
MenuEntry::Active(name) | MenuEntry::DisabledWhite(name) => {
|
MenuEntry::Active(name) | MenuEntry::DisabledWhite(name) => {
|
||||||
state.font.builder().position(self.x as f32 + 20.0, y).draw(
|
state.font.builder().position(options_x + 20.0, y).draw(
|
||||||
name,
|
name,
|
||||||
ctx,
|
ctx,
|
||||||
&state.constants,
|
&state.constants,
|
||||||
&mut state.texture_set,
|
&mut state.texture_set,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
MenuEntry::Title(text, is_centered, is_white) | MenuEntry::LongText(text, is_centered, is_white) => {
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
let mut line = String::new();
|
||||||
|
|
||||||
|
// we should probably abstract this away in some capacity
|
||||||
|
let separator = match state.loc.code.as_str() {
|
||||||
|
"jp" => "",
|
||||||
|
_ => " ",
|
||||||
|
};
|
||||||
|
|
||||||
|
for word in text.split(separator) {
|
||||||
|
let combined_word = line.clone() + separator + word;
|
||||||
|
let line_length = state.font.builder().compute_width(&combined_word) + 32.0;
|
||||||
|
|
||||||
|
if line_length > state.canvas_size.0 as f32 {
|
||||||
|
lines.push(line);
|
||||||
|
line = String::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
line.push_str(word);
|
||||||
|
line.push_str(separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push(line);
|
||||||
|
|
||||||
|
let mut local_y = y;
|
||||||
|
|
||||||
|
for line in lines.iter() {
|
||||||
|
let x = if *is_centered {
|
||||||
|
(state.canvas_size.0 as f32 - state.font.builder().compute_width(&line)) / 2.0
|
||||||
|
} else {
|
||||||
|
self.x as f32 + 20.0
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut builder = state.font.builder().position(x, local_y);
|
||||||
|
|
||||||
|
if !*is_white {
|
||||||
|
builder = builder.color((0xa0, 0xa0, 0xff, 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.draw(&line, ctx, &state.constants, &mut state.texture_set)?;
|
||||||
|
|
||||||
|
local_y += entry.height() as f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
y += entry.height() as f32 * (lines.len() - 1) as f32;
|
||||||
|
}
|
||||||
MenuEntry::Disabled(name) => {
|
MenuEntry::Disabled(name) => {
|
||||||
state.font.builder().position(self.x as f32 + 20.0, y).color((0xa0, 0xa0, 0xff, 0xff)).draw(
|
state.font.builder().position(self.x as f32 + 20.0, y).color((0xa0, 0xa0, 0xff, 0xff)).draw(
|
||||||
name,
|
name,
|
||||||
|
@ -412,14 +511,14 @@ impl<T: std::cmp::PartialEq + std::default::Default + Clone> Menu<T> {
|
||||||
let value_text = if let Some(text) = value.get(*index) { text } else { "???" };
|
let value_text = if let Some(text) = value.get(*index) { text } else { "???" };
|
||||||
let name_text_len = state.font.builder().compute_width(name);
|
let name_text_len = state.font.builder().compute_width(name);
|
||||||
|
|
||||||
state.font.builder().position(self.x as f32 + 20.0, y).draw(
|
state.font.builder().position(options_x + 20.0, y).draw(
|
||||||
name,
|
name,
|
||||||
ctx,
|
ctx,
|
||||||
&state.constants,
|
&state.constants,
|
||||||
&mut state.texture_set,
|
&mut state.texture_set,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
state.font.builder().position(self.x as f32 + 25.0 + name_text_len, y).draw(
|
state.font.builder().position(options_x + 25.0 + name_text_len, y).draw(
|
||||||
value_text,
|
value_text,
|
||||||
ctx,
|
ctx,
|
||||||
&state.constants,
|
&state.constants,
|
||||||
|
@ -780,7 +879,12 @@ impl<T: std::cmp::PartialEq + std::default::Default + Clone> Menu<T> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sum += entry.height();
|
let entry_height = match self.height_overrides.iter().find(|(entry_id, _)| *entry_id == *id) {
|
||||||
|
Some((_, height)) => *height,
|
||||||
|
None => entry.height(),
|
||||||
|
};
|
||||||
|
|
||||||
|
sum += entry_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry_y = sum as u16;
|
entry_y = sum as u16;
|
||||||
|
|
|
@ -122,12 +122,12 @@ impl PauseMenu {
|
||||||
|
|
||||||
fn update_sizes(&mut self, state: &SharedGameState) {
|
fn update_sizes(&mut self, state: &SharedGameState) {
|
||||||
self.pause_menu.update_width(state);
|
self.pause_menu.update_width(state);
|
||||||
self.pause_menu.update_height();
|
self.pause_menu.update_height(state);
|
||||||
self.pause_menu.x = ((state.canvas_size.0 - self.pause_menu.width as f32) / 2.0).floor() as isize;
|
self.pause_menu.x = ((state.canvas_size.0 - self.pause_menu.width as f32) / 2.0).floor() as isize;
|
||||||
self.pause_menu.y = ((state.canvas_size.1 - self.pause_menu.height as f32) / 2.0).floor() as isize;
|
self.pause_menu.y = ((state.canvas_size.1 - self.pause_menu.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.confirm_menu.update_width(state);
|
self.confirm_menu.update_width(state);
|
||||||
self.confirm_menu.update_height();
|
self.confirm_menu.update_height(state);
|
||||||
self.confirm_menu.x = ((state.canvas_size.0 - self.confirm_menu.width as f32) / 2.0).floor() as isize;
|
self.confirm_menu.x = ((state.canvas_size.0 - self.confirm_menu.width as f32) / 2.0).floor() as isize;
|
||||||
self.confirm_menu.y = ((state.canvas_size.1 - self.confirm_menu.height as f32) / 2.0).floor() as isize;
|
self.confirm_menu.y = ((state.canvas_size.1 - self.confirm_menu.height as f32) / 2.0).floor() as isize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,28 +217,28 @@ impl SaveSelectMenu {
|
||||||
|
|
||||||
fn update_sizes(&mut self, state: &SharedGameState) {
|
fn update_sizes(&mut self, state: &SharedGameState) {
|
||||||
self.save_menu.update_width(state);
|
self.save_menu.update_width(state);
|
||||||
self.save_menu.update_height();
|
self.save_menu.update_height(state);
|
||||||
self.save_menu.x = ((state.canvas_size.0 - self.save_menu.width as f32) / 2.0).floor() as isize;
|
self.save_menu.x = ((state.canvas_size.0 - self.save_menu.width as f32) / 2.0).floor() as isize;
|
||||||
self.save_menu.y = ((state.canvas_size.1 - self.save_menu.height as f32) / 2.0).floor() as isize;
|
self.save_menu.y = ((state.canvas_size.1 - self.save_menu.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.difficulty_menu.update_width(state);
|
self.difficulty_menu.update_width(state);
|
||||||
self.difficulty_menu.update_height();
|
self.difficulty_menu.update_height(state);
|
||||||
self.difficulty_menu.x = ((state.canvas_size.0 - self.difficulty_menu.width as f32) / 2.0).floor() as isize;
|
self.difficulty_menu.x = ((state.canvas_size.0 - self.difficulty_menu.width as f32) / 2.0).floor() as isize;
|
||||||
self.difficulty_menu.y =
|
self.difficulty_menu.y =
|
||||||
30 + ((state.canvas_size.1 - self.difficulty_menu.height as f32) / 2.0).floor() as isize;
|
30 + ((state.canvas_size.1 - self.difficulty_menu.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.delete_confirm.update_width(state);
|
self.delete_confirm.update_width(state);
|
||||||
self.delete_confirm.update_height();
|
self.delete_confirm.update_height(state);
|
||||||
self.delete_confirm.x = ((state.canvas_size.0 - self.delete_confirm.width as f32) / 2.0).floor() as isize;
|
self.delete_confirm.x = ((state.canvas_size.0 - self.delete_confirm.width as f32) / 2.0).floor() as isize;
|
||||||
self.delete_confirm.y = 30 + ((state.canvas_size.1 - self.delete_confirm.height as f32) / 2.0).floor() as isize;
|
self.delete_confirm.y = 30 + ((state.canvas_size.1 - self.delete_confirm.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.load_confirm.update_width(state);
|
self.load_confirm.update_width(state);
|
||||||
self.load_confirm.update_height();
|
self.load_confirm.update_height(state);
|
||||||
self.load_confirm.x = ((state.canvas_size.0 - self.load_confirm.width as f32) / 2.0).floor() as isize;
|
self.load_confirm.x = ((state.canvas_size.0 - self.load_confirm.width as f32) / 2.0).floor() as isize;
|
||||||
self.load_confirm.y = 30 + ((state.canvas_size.1 - self.load_confirm.height as f32) / 2.0).floor() as isize;
|
self.load_confirm.y = 30 + ((state.canvas_size.1 - self.load_confirm.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.save_detailed.update_width(state);
|
self.save_detailed.update_width(state);
|
||||||
self.save_detailed.update_height();
|
self.save_detailed.update_height(state);
|
||||||
self.save_detailed.x = ((state.canvas_size.0 - self.save_detailed.width as f32) / 2.0).floor() as isize;
|
self.save_detailed.x = ((state.canvas_size.0 - self.save_detailed.width as f32) / 2.0).floor() as isize;
|
||||||
self.save_detailed.y = -40 + ((state.canvas_size.1 - self.save_detailed.height as f32) / 2.0).floor() as isize;
|
self.save_detailed.y = -40 + ((state.canvas_size.1 - self.save_detailed.height as f32) / 2.0).floor() as isize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ enum CurrentMenu {
|
||||||
BehaviorMenu,
|
BehaviorMenu,
|
||||||
LinksMenu,
|
LinksMenu,
|
||||||
AdvancedMenu,
|
AdvancedMenu,
|
||||||
|
PortableMenu,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
|
@ -143,6 +144,8 @@ enum AdvancedMenuEntry {
|
||||||
Title,
|
Title,
|
||||||
OpenUserData,
|
OpenUserData,
|
||||||
OpenGameData,
|
OpenGameData,
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "horizon")))]
|
||||||
|
MakePortable,
|
||||||
Back,
|
Back,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +155,22 @@ impl Default for AdvancedMenuEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
|
enum PortableMenuEntry {
|
||||||
|
Title,
|
||||||
|
Explanation,
|
||||||
|
RestartQuestion,
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
Spacer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PortableMenuEntry {
|
||||||
|
fn default() -> Self {
|
||||||
|
PortableMenuEntry::No
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SettingsMenu {
|
pub struct SettingsMenu {
|
||||||
current: CurrentMenu,
|
current: CurrentMenu,
|
||||||
main: Menu<MainMenuEntry>,
|
main: Menu<MainMenuEntry>,
|
||||||
|
@ -162,6 +181,7 @@ pub struct SettingsMenu {
|
||||||
behavior: Menu<BehaviorMenuEntry>,
|
behavior: Menu<BehaviorMenuEntry>,
|
||||||
links: Menu<LinksMenuEntry>,
|
links: Menu<LinksMenuEntry>,
|
||||||
advanced: Menu<AdvancedMenuEntry>,
|
advanced: Menu<AdvancedMenuEntry>,
|
||||||
|
portable: Menu<PortableMenuEntry>,
|
||||||
controls_menu: ControlsMenu,
|
controls_menu: ControlsMenu,
|
||||||
pub on_title: bool,
|
pub on_title: bool,
|
||||||
}
|
}
|
||||||
|
@ -184,6 +204,7 @@ impl SettingsMenu {
|
||||||
let behavior = Menu::new(0, 0, 220, 0);
|
let behavior = Menu::new(0, 0, 220, 0);
|
||||||
let links = Menu::new(0, 0, 220, 0);
|
let links = Menu::new(0, 0, 220, 0);
|
||||||
let advanced = Menu::new(0, 0, 220, 0);
|
let advanced = Menu::new(0, 0, 220, 0);
|
||||||
|
let portable = Menu::new(0, 0, 220, 0);
|
||||||
|
|
||||||
let controls_menu = ControlsMenu::new();
|
let controls_menu = ControlsMenu::new();
|
||||||
|
|
||||||
|
@ -198,6 +219,7 @@ impl SettingsMenu {
|
||||||
links,
|
links,
|
||||||
advanced,
|
advanced,
|
||||||
controls_menu,
|
controls_menu,
|
||||||
|
portable,
|
||||||
on_title: false,
|
on_title: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,8 +410,56 @@ impl SettingsMenu {
|
||||||
AdvancedMenuEntry::OpenGameData,
|
AdvancedMenuEntry::OpenGameData,
|
||||||
MenuEntry::Active(state.loc.t("menus.options_menu.advanced_menu.open_game_data").to_owned()),
|
MenuEntry::Active(state.loc.t("menus.options_menu.advanced_menu.open_game_data").to_owned()),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "horizon")))]
|
||||||
|
if let Some(fs_container) = &state.fs_container {
|
||||||
|
if !fs_container.is_portable && self.on_title {
|
||||||
|
self.advanced.push_entry(
|
||||||
|
AdvancedMenuEntry::MakePortable,
|
||||||
|
MenuEntry::Active(state.loc.t("menus.options_menu.advanced_menu.make_portable").to_owned()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.advanced.push_entry(AdvancedMenuEntry::Back, MenuEntry::Active(state.loc.t("common.back").to_owned()));
|
self.advanced.push_entry(AdvancedMenuEntry::Back, MenuEntry::Active(state.loc.t("common.back").to_owned()));
|
||||||
|
|
||||||
|
self.portable.center_options = true;
|
||||||
|
|
||||||
|
self.portable.push_entry(
|
||||||
|
PortableMenuEntry::Title,
|
||||||
|
MenuEntry::Title(state.loc.t("menus.options_menu.advanced_menu.make_portable").to_owned(), true, false),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.portable.push_entry(PortableMenuEntry::Spacer, MenuEntry::Spacer(8.0));
|
||||||
|
|
||||||
|
self.portable.push_entry(
|
||||||
|
PortableMenuEntry::Explanation,
|
||||||
|
MenuEntry::LongText(state.loc.t("menus.options_menu.portable_menu.explanation").to_owned(), true, true),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.portable.push_entry(PortableMenuEntry::Spacer, MenuEntry::Spacer(8.0));
|
||||||
|
|
||||||
|
self.portable.push_entry(
|
||||||
|
PortableMenuEntry::RestartQuestion,
|
||||||
|
MenuEntry::LongText(
|
||||||
|
state.loc.t("menus.options_menu.portable_menu.restart_question").to_owned(),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.portable.push_entry(PortableMenuEntry::Spacer, MenuEntry::Spacer(8.0));
|
||||||
|
|
||||||
|
self.portable.push_entry(
|
||||||
|
PortableMenuEntry::Yes,
|
||||||
|
MenuEntry::Active(state.loc.t("menus.options_menu.portable_menu.restart").to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.portable.push_entry(
|
||||||
|
PortableMenuEntry::No,
|
||||||
|
MenuEntry::Active(state.loc.t("menus.options_menu.portable_menu.cancel").to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
self.main.push_entry(MainMenuEntry::Back, MenuEntry::Active(state.loc.t("common.back").to_owned()));
|
self.main.push_entry(MainMenuEntry::Back, MenuEntry::Active(state.loc.t("common.back").to_owned()));
|
||||||
|
|
||||||
self.sound.push_entry(
|
self.sound.push_entry(
|
||||||
|
@ -524,44 +594,49 @@ impl SettingsMenu {
|
||||||
|
|
||||||
fn update_sizes(&mut self, state: &SharedGameState) {
|
fn update_sizes(&mut self, state: &SharedGameState) {
|
||||||
self.main.update_width(state);
|
self.main.update_width(state);
|
||||||
self.main.update_height();
|
self.main.update_height(state);
|
||||||
self.main.x = ((state.canvas_size.0 - self.main.width as f32) / 2.0).floor() as isize;
|
self.main.x = ((state.canvas_size.0 - self.main.width as f32) / 2.0).floor() as isize;
|
||||||
self.main.y = 30 + ((state.canvas_size.1 - self.main.height as f32) / 2.0).floor() as isize;
|
self.main.y = 30 + ((state.canvas_size.1 - self.main.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.graphics.update_width(state);
|
self.graphics.update_width(state);
|
||||||
self.graphics.update_height();
|
self.graphics.update_height(state);
|
||||||
self.graphics.x = ((state.canvas_size.0 - self.graphics.width as f32) / 2.0).floor() as isize;
|
self.graphics.x = ((state.canvas_size.0 - self.graphics.width as f32) / 2.0).floor() as isize;
|
||||||
self.graphics.y = 20 + ((state.canvas_size.1 - self.graphics.height as f32) / 2.0).floor() as isize;
|
self.graphics.y = 20 + ((state.canvas_size.1 - self.graphics.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.sound.update_width(state);
|
self.sound.update_width(state);
|
||||||
self.sound.update_height();
|
self.sound.update_height(state);
|
||||||
self.sound.x = ((state.canvas_size.0 - self.sound.width as f32) / 2.0).floor() as isize;
|
self.sound.x = ((state.canvas_size.0 - self.sound.width as f32) / 2.0).floor() as isize;
|
||||||
self.sound.y = 30 + ((state.canvas_size.1 - self.sound.height as f32) / 2.0).floor() as isize;
|
self.sound.y = 30 + ((state.canvas_size.1 - self.sound.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.soundtrack.update_width(state);
|
self.soundtrack.update_width(state);
|
||||||
self.soundtrack.update_height();
|
self.soundtrack.update_height(state);
|
||||||
self.soundtrack.x = ((state.canvas_size.0 - self.soundtrack.width as f32) / 2.0).floor() as isize;
|
self.soundtrack.x = ((state.canvas_size.0 - self.soundtrack.width as f32) / 2.0).floor() as isize;
|
||||||
self.soundtrack.y = ((state.canvas_size.1 - self.soundtrack.height as f32) / 2.0).floor() as isize;
|
self.soundtrack.y = ((state.canvas_size.1 - self.soundtrack.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.language.update_width(state);
|
self.language.update_width(state);
|
||||||
self.language.update_height();
|
self.language.update_height(state);
|
||||||
self.language.x = ((state.canvas_size.0 - self.language.width as f32) / 2.0).floor() as isize;
|
self.language.x = ((state.canvas_size.0 - self.language.width as f32) / 2.0).floor() as isize;
|
||||||
self.language.y = ((state.canvas_size.1 - self.language.height as f32) / 2.0).floor() as isize;
|
self.language.y = ((state.canvas_size.1 - self.language.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.behavior.update_width(state);
|
self.behavior.update_width(state);
|
||||||
self.behavior.update_height();
|
self.behavior.update_height(state);
|
||||||
self.behavior.x = ((state.canvas_size.0 - self.behavior.width as f32) / 2.0).floor() as isize;
|
self.behavior.x = ((state.canvas_size.0 - self.behavior.width as f32) / 2.0).floor() as isize;
|
||||||
self.behavior.y = 30 + ((state.canvas_size.1 - self.behavior.height as f32) / 2.0).floor() as isize;
|
self.behavior.y = 30 + ((state.canvas_size.1 - self.behavior.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.links.update_width(state);
|
self.links.update_width(state);
|
||||||
self.links.update_height();
|
self.links.update_height(state);
|
||||||
self.links.x = ((state.canvas_size.0 - self.links.width as f32) / 2.0).floor() as isize;
|
self.links.x = ((state.canvas_size.0 - self.links.width as f32) / 2.0).floor() as isize;
|
||||||
self.links.y = 30 + ((state.canvas_size.1 - self.links.height as f32) / 2.0).floor() as isize;
|
self.links.y = 30 + ((state.canvas_size.1 - self.links.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.advanced.update_width(state);
|
self.advanced.update_width(state);
|
||||||
self.advanced.update_height();
|
self.advanced.update_height(state);
|
||||||
self.advanced.x = ((state.canvas_size.0 - self.advanced.width as f32) / 2.0).floor() as isize;
|
self.advanced.x = ((state.canvas_size.0 - self.advanced.width as f32) / 2.0).floor() as isize;
|
||||||
self.advanced.y = 30 + ((state.canvas_size.1 - self.advanced.height as f32) / 2.0).floor() as isize;
|
self.advanced.y = 30 + ((state.canvas_size.1 - self.advanced.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
|
self.portable.update_width(state);
|
||||||
|
self.portable.update_height(state);
|
||||||
|
self.portable.x = ((state.canvas_size.0 - self.portable.width as f32) / 2.0).floor() as isize;
|
||||||
|
self.portable.y = 30 + ((state.canvas_size.1 - self.portable.height as f32) / 2.0).floor() as isize;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(
|
pub fn tick(
|
||||||
|
@ -957,11 +1032,26 @@ impl SettingsMenu {
|
||||||
fs_container.open_game_directory()?;
|
fs_container.open_game_directory()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
MenuSelectionResult::Selected(AdvancedMenuEntry::MakePortable, _) => {
|
||||||
|
self.current = CurrentMenu::PortableMenu;
|
||||||
|
}
|
||||||
MenuSelectionResult::Selected(AdvancedMenuEntry::Back, _) | MenuSelectionResult::Canceled => {
|
MenuSelectionResult::Selected(AdvancedMenuEntry::Back, _) | MenuSelectionResult::Canceled => {
|
||||||
self.current = CurrentMenu::MainMenu;
|
self.current = CurrentMenu::MainMenu;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
|
CurrentMenu::PortableMenu => match self.portable.tick(controller, state) {
|
||||||
|
MenuSelectionResult::Selected(PortableMenuEntry::Yes, _) => {
|
||||||
|
if let Some(fs_container) = &mut state.fs_container {
|
||||||
|
fs_container.make_portable_user_directory(ctx)?;
|
||||||
|
state.next_scene = Some(Box::new(TitleScene::new()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MenuSelectionResult::Selected(PortableMenuEntry::No, _) | MenuSelectionResult::Canceled => {
|
||||||
|
self.current = CurrentMenu::AdvancedMenu;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -977,6 +1067,7 @@ impl SettingsMenu {
|
||||||
CurrentMenu::BehaviorMenu => self.behavior.draw(state, ctx)?,
|
CurrentMenu::BehaviorMenu => self.behavior.draw(state, ctx)?,
|
||||||
CurrentMenu::LinksMenu => self.links.draw(state, ctx)?,
|
CurrentMenu::LinksMenu => self.links.draw(state, ctx)?,
|
||||||
CurrentMenu::AdvancedMenu => self.advanced.draw(state, ctx)?,
|
CurrentMenu::AdvancedMenu => self.advanced.draw(state, ctx)?,
|
||||||
|
CurrentMenu::PortableMenu => self.portable.draw(state, ctx)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -290,12 +290,12 @@ impl Scene for TitleScene {
|
||||||
self.controller.update_trigger();
|
self.controller.update_trigger();
|
||||||
|
|
||||||
self.main_menu.update_width(state);
|
self.main_menu.update_width(state);
|
||||||
self.main_menu.update_height();
|
self.main_menu.update_height(state);
|
||||||
self.main_menu.x = ((state.canvas_size.0 - self.main_menu.width as f32) / 2.0).floor() as isize;
|
self.main_menu.x = ((state.canvas_size.0 - self.main_menu.width as f32) / 2.0).floor() as isize;
|
||||||
self.main_menu.y = ((state.canvas_size.1 + 70.0 - self.main_menu.height as f32) / 2.0).floor() as isize;
|
self.main_menu.y = ((state.canvas_size.1 + 70.0 - self.main_menu.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
self.challenges_menu.update_width(state);
|
self.challenges_menu.update_width(state);
|
||||||
self.challenges_menu.update_height();
|
self.challenges_menu.update_height(state);
|
||||||
self.challenges_menu.x = ((state.canvas_size.0 - self.challenges_menu.width as f32) / 2.0).floor() as isize;
|
self.challenges_menu.x = ((state.canvas_size.0 - self.challenges_menu.width as f32) / 2.0).floor() as isize;
|
||||||
self.challenges_menu.y =
|
self.challenges_menu.y =
|
||||||
((state.canvas_size.1 + 30.0 - self.challenges_menu.height as f32) / 2.0).floor() as isize;
|
((state.canvas_size.1 + 30.0 - self.challenges_menu.height as f32) / 2.0).floor() as isize;
|
||||||
|
@ -446,7 +446,7 @@ impl Scene for TitleScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.confirm_menu.update_width(state);
|
self.confirm_menu.update_width(state);
|
||||||
self.confirm_menu.update_height();
|
self.confirm_menu.update_height(state);
|
||||||
self.confirm_menu.x = ((state.canvas_size.0 - self.confirm_menu.width as f32) / 2.0).floor() as isize;
|
self.confirm_menu.x = ((state.canvas_size.0 - self.confirm_menu.width as f32) / 2.0).floor() as isize;
|
||||||
self.confirm_menu.y = ((state.canvas_size.1 + 30.0 - self.confirm_menu.height as f32) / 2.0).floor() as isize;
|
self.confirm_menu.y = ((state.canvas_size.1 + 30.0 - self.confirm_menu.height as f32) / 2.0).floor() as isize;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue