mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add basic credits screen to the main menu with some example data loaded from a ron file
This commit is contained in:
parent
5da9f93ff7
commit
40240a4005
23
assets/common/credits.ron
Normal file
23
assets/common/credits.ron
Normal file
@ -0,0 +1,23 @@
|
||||
(
|
||||
music: [(
|
||||
name: "Desert jams",
|
||||
authors: ["AuthorOne", "author two"],
|
||||
)],
|
||||
fonts: [(
|
||||
name: "Wizard",
|
||||
license: "cc-by-sa 3",
|
||||
)],
|
||||
other_art: [(
|
||||
name: "Voxel shrooms",
|
||||
authors: ["AuthorOne", "author two"],
|
||||
)],
|
||||
contributors: [
|
||||
(
|
||||
name: "Example",
|
||||
contributions: "An example note",
|
||||
),
|
||||
(
|
||||
name: "Example Two",
|
||||
),
|
||||
],
|
||||
)
|
@ -61,6 +61,14 @@ https://veloren.net/account/."#,
|
||||
"main.login.client_version": "Client Version",
|
||||
"main.login.server_version": "Server Version",
|
||||
"main.servers.select_server": "Select a server",
|
||||
|
||||
// Credits screen
|
||||
"main.credits": "Credits",
|
||||
"main.credits.music": "Music",
|
||||
"main.credits.fonts": "Fonts",
|
||||
"main.credits.other_art": "Other Art",
|
||||
"main.credits.contributors": "Contributors",
|
||||
|
||||
/// End Main screen section
|
||||
},
|
||||
|
||||
|
43
voxygen/src/credits.rs
Normal file
43
voxygen/src/credits.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use common::assets;
|
||||
use serde::Deserialize;
|
||||
|
||||
// NOTE: we are free to split the manifest asset format and the format processed
|
||||
// for display into separate structs but they happen to be identical for now
|
||||
|
||||
// TODO: add serde attribs to certain fields
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub struct Art {
|
||||
pub name: String,
|
||||
// Include asset path as a field?
|
||||
#[serde(default)]
|
||||
pub authors: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub license: String,
|
||||
// Include optional license file path and/or web link?
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub struct Contributor {
|
||||
pub name: String,
|
||||
/// Short note or description of the contributions
|
||||
/// Optional, can be left empty/ommitted
|
||||
#[serde(default)]
|
||||
pub contributions: String,
|
||||
}
|
||||
|
||||
/// Credits manifest processed into format for display in the UI
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub struct Credits {
|
||||
pub music: Vec<Art>,
|
||||
pub fonts: Vec<Art>,
|
||||
pub other_art: Vec<Art>,
|
||||
pub contributors: Vec<Contributor>,
|
||||
// TODO: include credits for dependencies where the license requires attribution?
|
||||
}
|
||||
|
||||
impl assets::Asset for Credits {
|
||||
type Loader = assets::RonLoader;
|
||||
|
||||
const EXTENSION: &'static str = "ron";
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
pub mod ui;
|
||||
pub mod audio;
|
||||
pub mod controller;
|
||||
mod credits;
|
||||
mod ecs;
|
||||
pub mod error;
|
||||
pub mod game_input;
|
||||
|
195
voxygen/src/menu/main/ui/credits.rs
Normal file
195
voxygen/src/menu/main/ui/credits.rs
Normal file
@ -0,0 +1,195 @@
|
||||
use super::Message;
|
||||
use crate::{
|
||||
credits::Credits,
|
||||
ui::{
|
||||
fonts::IcedFonts as Fonts,
|
||||
ice::{component::neat_button, style, Element},
|
||||
},
|
||||
};
|
||||
use i18n::Localization;
|
||||
use iced::{button, scrollable, Column, Container, Length, Scrollable, Space};
|
||||
|
||||
/// Connecting screen for the main menu
|
||||
pub struct Screen {
|
||||
back_button: button::State,
|
||||
scroll: scrollable::State,
|
||||
}
|
||||
|
||||
impl Screen {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
back_button: Default::default(),
|
||||
scroll: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn view(
|
||||
&mut self,
|
||||
fonts: &Fonts,
|
||||
i18n: &Localization,
|
||||
credits: &Credits,
|
||||
button_style: style::button::Style,
|
||||
) -> Element<Message> {
|
||||
use core::fmt::Write;
|
||||
// TODO: i18n and better formating
|
||||
let format_art_credit = |credit: &crate::credits::Art| -> Result<String, core::fmt::Error> {
|
||||
let mut text = String::new();
|
||||
text.push_str(&credit.name);
|
||||
|
||||
let mut authors = credit.authors.iter();
|
||||
if let Some(author) = authors.next() {
|
||||
write!(&mut text, " created by {}", author)?;
|
||||
}
|
||||
authors.try_for_each(|author| write!(&mut text, ", {}", author))?;
|
||||
|
||||
if !credit.license.is_empty() {
|
||||
write!(&mut text, " ({})", &credit.license)?;
|
||||
}
|
||||
|
||||
Ok::<_, core::fmt::Error>(text)
|
||||
};
|
||||
let format_contributor_credit =
|
||||
|credit: &crate::credits::Contributor| -> Result<String, core::fmt::Error> {
|
||||
let mut text = String::new();
|
||||
text.push_str(&credit.name);
|
||||
|
||||
if !credit.contributions.is_empty() {
|
||||
write!(&mut text, ": {}", &credit.contributions)?;
|
||||
}
|
||||
|
||||
Ok(text)
|
||||
};
|
||||
|
||||
let music_header_color = iced::Color::from_rgb8(0xfc, 0x71, 0x76);
|
||||
let fonts_header_color = iced::Color::from_rgb8(0xf7, 0xd1, 0x81);
|
||||
let other_art_header_color = iced::Color::from_rgb8(0xc5, 0xe9, 0x80);
|
||||
let contributors_header_color = iced::Color::from_rgb8(0x4a, 0xa6, 0x7b);
|
||||
|
||||
Container::new(
|
||||
Container::new(
|
||||
Column::with_children(vec![
|
||||
iced::Text::new(i18n.get("main.credits"))
|
||||
.font(fonts.alkhemi.id)
|
||||
.size(fonts.alkhemi.scale(35))
|
||||
.into(),
|
||||
Space::new(Length::Fill, Length::Units(25)).into(),
|
||||
Scrollable::new(&mut self.scroll)
|
||||
.push(Column::with_children(
|
||||
core::iter::once(
|
||||
iced::Text::new(i18n.get("main.credits.music"))
|
||||
.font(fonts.cyri.id)
|
||||
.size(fonts.cyri.scale(30))
|
||||
.color(music_header_color)
|
||||
.into(),
|
||||
)
|
||||
.chain(credits.music.iter().map(|credit| {
|
||||
let text = format_art_credit(credit).expect("Formatting failed!!!");
|
||||
iced::Text::new(text)
|
||||
.font(fonts.cyri.id)
|
||||
.size(fonts.cyri.scale(23))
|
||||
.into()
|
||||
}))
|
||||
.chain(core::iter::once(
|
||||
Space::new(Length::Fill, Length::Units(15)).into(),
|
||||
))
|
||||
.collect(),
|
||||
))
|
||||
.push(Column::with_children(
|
||||
core::iter::once(
|
||||
iced::Text::new(i18n.get("main.credits.fonts"))
|
||||
.font(fonts.cyri.id)
|
||||
.size(fonts.cyri.scale(30))
|
||||
.color(fonts_header_color)
|
||||
.into(),
|
||||
)
|
||||
.chain(credits.fonts.iter().map(|credit| {
|
||||
let text = format_art_credit(credit).expect("Formatting failed!!!");
|
||||
iced::Text::new(text)
|
||||
.font(fonts.cyri.id)
|
||||
.size(fonts.cyri.scale(23))
|
||||
.into()
|
||||
}))
|
||||
.chain(core::iter::once(
|
||||
Space::new(Length::Fill, Length::Units(15)).into(),
|
||||
))
|
||||
.collect(),
|
||||
))
|
||||
.push(Column::with_children(
|
||||
core::iter::once(
|
||||
iced::Text::new(i18n.get("main.credits.other_art"))
|
||||
.font(fonts.cyri.id)
|
||||
.size(fonts.cyri.scale(30))
|
||||
.color(other_art_header_color)
|
||||
.into(),
|
||||
)
|
||||
.chain(credits.other_art.iter().map(|credit| {
|
||||
let text = format_art_credit(credit).expect("Formatting failed!!!");
|
||||
iced::Text::new(text)
|
||||
.font(fonts.cyri.id)
|
||||
.size(fonts.cyri.scale(23))
|
||||
.into()
|
||||
}))
|
||||
.chain(core::iter::once(
|
||||
Space::new(Length::Fill, Length::Units(15)).into(),
|
||||
))
|
||||
.collect(),
|
||||
))
|
||||
.push(Column::with_children(
|
||||
core::iter::once(
|
||||
iced::Text::new(i18n.get("main.credits.contributors"))
|
||||
.font(fonts.cyri.id)
|
||||
.size(fonts.cyri.scale(30))
|
||||
.color(contributors_header_color)
|
||||
.into(),
|
||||
)
|
||||
.chain(credits.contributors.iter().map(|credit| {
|
||||
let text = format_contributor_credit(credit)
|
||||
.expect("Formatting failed!!!");
|
||||
iced::Text::new(text)
|
||||
.font(fonts.cyri.id)
|
||||
.size(fonts.cyri.scale(23))
|
||||
.into()
|
||||
}))
|
||||
.chain(core::iter::once(
|
||||
Space::new(Length::Fill, Length::Units(15)).into(),
|
||||
))
|
||||
.collect(),
|
||||
))
|
||||
.height(Length::FillPortion(1))
|
||||
.into(),
|
||||
Container::new(
|
||||
Container::new(neat_button(
|
||||
&mut self.back_button,
|
||||
i18n.get("common.back"),
|
||||
0.7,
|
||||
button_style,
|
||||
Some(Message::Back),
|
||||
))
|
||||
.height(Length::Units(fonts.cyri.scale(50))),
|
||||
)
|
||||
.center_x()
|
||||
.height(Length::Shrink)
|
||||
.width(Length::Fill)
|
||||
.into(),
|
||||
])
|
||||
.spacing(5)
|
||||
.padding(20)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill),
|
||||
)
|
||||
.style(
|
||||
style::container::Style::color_with_double_cornerless_border(
|
||||
(22, 19, 17, 255).into(),
|
||||
(11, 11, 11, 255).into(),
|
||||
(54, 46, 38, 255).into(),
|
||||
),
|
||||
),
|
||||
)
|
||||
.center_x()
|
||||
.center_y()
|
||||
.padding(70)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ pub struct Screen {
|
||||
quit_button: button::State,
|
||||
settings_button: button::State,
|
||||
servers_button: button::State,
|
||||
credits_button: button::State,
|
||||
language_select_button: button::State,
|
||||
|
||||
error_okay_button: button::State,
|
||||
@ -38,6 +39,7 @@ impl Screen {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
servers_button: Default::default(),
|
||||
credits_button: Default::default(),
|
||||
settings_button: Default::default(),
|
||||
quit_button: Default::default(),
|
||||
language_select_button: Default::default(),
|
||||
@ -85,6 +87,13 @@ impl Screen {
|
||||
button_style,
|
||||
Some(Message::OpenLanguageMenu),
|
||||
),
|
||||
neat_button(
|
||||
&mut self.credits_button,
|
||||
i18n.get("main.credits"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
Some(Message::ShowCredits),
|
||||
),
|
||||
neat_button(
|
||||
&mut self.quit_button,
|
||||
i18n.get("common.quit"),
|
||||
|
@ -1,10 +1,12 @@
|
||||
mod connecting;
|
||||
// Note: Keeping in case we re-add the disclaimer
|
||||
//mod disclaimer;
|
||||
mod credits;
|
||||
mod login;
|
||||
mod servers;
|
||||
|
||||
use crate::{
|
||||
credits::Credits,
|
||||
render::UiDrawer,
|
||||
ui::{
|
||||
self,
|
||||
@ -101,6 +103,9 @@ enum Screen {
|
||||
/*Disclaimer {
|
||||
screen: disclaimer::Screen,
|
||||
},*/
|
||||
Credits {
|
||||
screen: credits::Screen,
|
||||
},
|
||||
Login {
|
||||
screen: login::Screen,
|
||||
// Error to display in a box
|
||||
@ -124,6 +129,7 @@ struct Controls {
|
||||
version: String,
|
||||
// Alpha disclaimer
|
||||
alpha: String,
|
||||
credits: Credits,
|
||||
|
||||
selected_server_index: Option<usize>,
|
||||
login_info: LoginInfo,
|
||||
@ -141,6 +147,7 @@ enum Message {
|
||||
Quit,
|
||||
Back,
|
||||
ShowServers,
|
||||
ShowCredits,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
Singleplayer,
|
||||
Multiplayer,
|
||||
@ -170,6 +177,8 @@ impl Controls {
|
||||
let version = common::util::DISPLAY_VERSION_LONG.clone();
|
||||
let alpha = format!("Veloren {}", common::util::DISPLAY_VERSION.as_str());
|
||||
|
||||
let credits = Credits::load_expect_cloned("common.credits");
|
||||
|
||||
// Note: Keeping in case we re-add the disclaimer
|
||||
let screen = /* if settings.show_disclaimer {
|
||||
Screen::Disclaimer {
|
||||
@ -205,6 +214,7 @@ impl Controls {
|
||||
i18n,
|
||||
version,
|
||||
alpha,
|
||||
credits,
|
||||
|
||||
selected_server_index,
|
||||
login_info,
|
||||
@ -263,6 +273,9 @@ impl Controls {
|
||||
let content = match &mut self.screen {
|
||||
// Note: Keeping in case we re-add the disclaimer
|
||||
//Screen::Disclaimer { screen } => screen.view(&self.fonts, &self.i18n, button_style),
|
||||
Screen::Credits { screen } => {
|
||||
screen.view(&self.fonts, &self.i18n.read(), &self.credits, button_style)
|
||||
},
|
||||
Screen::Login { screen, error } => screen.view(
|
||||
&self.fonts,
|
||||
&self.imgs,
|
||||
@ -334,6 +347,11 @@ impl Controls {
|
||||
};
|
||||
}
|
||||
},
|
||||
Message::ShowCredits => {
|
||||
self.screen = Screen::Credits {
|
||||
screen: credits::Screen::new(),
|
||||
};
|
||||
},
|
||||
#[cfg(feature = "singleplayer")]
|
||||
Message::Singleplayer => {
|
||||
self.screen = Screen::Connecting {
|
||||
|
Loading…
Reference in New Issue
Block a user