mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
260 lines
9.3 KiB
Rust
260 lines
9.3 KiB
Rust
use std::str::FromStr;
|
|
|
|
use super::{ConnectionState, Imgs, Message};
|
|
|
|
use crate::{
|
|
game_input::GameInput,
|
|
settings::ControlSettings,
|
|
ui::{
|
|
fonts::IcedFonts as Fonts,
|
|
ice::{component::neat_button, style, widget::Image, Element, IcedUi as Ui, Id},
|
|
Graphic,
|
|
},
|
|
};
|
|
use common::assets::{self, AssetExt};
|
|
use i18n::Localization;
|
|
use iced::{button, Align, Column, Container, Length, Row, Space, Text};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
struct LoadingAnimation {
|
|
speed_factor: f32,
|
|
frames: Vec<Id>,
|
|
}
|
|
impl LoadingAnimation {
|
|
fn new(raw: &(f32, Vec<String>), ui: &mut Ui) -> Self {
|
|
let mut frames = vec![];
|
|
for frame_path in raw.1.iter() {
|
|
if let Ok(image) = assets::Image::load(frame_path) {
|
|
frames.push(ui.add_graphic(Graphic::Image(image.read().to_image(), None)));
|
|
} else {
|
|
frames.push(
|
|
ui.add_graphic(Graphic::Image(
|
|
assets::Image::load("voxygen.element.not_found")
|
|
.unwrap_or_else(|_| panic!("Missing asset '{}'", frame_path))
|
|
.read()
|
|
.to_image(),
|
|
None,
|
|
)),
|
|
)
|
|
}
|
|
}
|
|
Self {
|
|
speed_factor: raw.0,
|
|
frames,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
struct LoadingAnimationManifest(Vec<(f32, Vec<String>)>);
|
|
impl assets::Asset for LoadingAnimationManifest {
|
|
type Loader = assets::RonLoader;
|
|
|
|
const EXTENSION: &'static str = "ron";
|
|
}
|
|
|
|
/// Connecting screen for the main menu
|
|
pub struct Screen {
|
|
cancel_button: button::State,
|
|
add_button: button::State,
|
|
tip_number: u16,
|
|
loading_animation: LoadingAnimation,
|
|
}
|
|
|
|
impl Screen {
|
|
pub fn new(ui: &mut Ui) -> Self {
|
|
let animations =
|
|
LoadingAnimationManifest::load("voxygen.element.animation.loaders.manifest")
|
|
.expect(
|
|
"Missing loader manifest file 'voxygen/element/animation/loaders/manifest.ron'",
|
|
)
|
|
.cloned()
|
|
.0;
|
|
Self {
|
|
cancel_button: Default::default(),
|
|
add_button: Default::default(),
|
|
tip_number: rand::random(),
|
|
loading_animation: LoadingAnimation::new(
|
|
&animations[rand::random::<usize>() % animations.len()],
|
|
ui,
|
|
),
|
|
}
|
|
}
|
|
|
|
pub(super) fn view(
|
|
&mut self,
|
|
fonts: &Fonts,
|
|
imgs: &Imgs,
|
|
connection_state: &ConnectionState,
|
|
time: f64,
|
|
i18n: &Localization,
|
|
button_style: style::button::Style,
|
|
show_tip: bool,
|
|
controls: &ControlSettings,
|
|
) -> Element<Message> {
|
|
// TODO: add built in support for animated images
|
|
let frame_index = (time * self.loading_animation.speed_factor as f64)
|
|
% self.loading_animation.frames.len() as f64;
|
|
let frame_id = self.loading_animation.frames[frame_index as usize];
|
|
|
|
let children = match connection_state {
|
|
ConnectionState::InProgress => {
|
|
let tip = if show_tip {
|
|
let tip = &i18n.get_variation("loading.tips", self.tip_number);
|
|
let mut new_tip = String::with_capacity(tip.len());
|
|
let mut last_index = 0;
|
|
|
|
// This could be done with regex instead, but adding new dependencies is
|
|
// scary...
|
|
tip.match_indices("{gameinput.").for_each(|(start, s)| {
|
|
println!("start {}", start);
|
|
if let Some(end) = tip[start + s.len()..].find('}') {
|
|
let end = start + s.len() + end;
|
|
println!("end {}", end);
|
|
if let Ok(game_input) = GameInput::from_str(&tip[start + 1..end]) {
|
|
println!("input {:?}", game_input);
|
|
new_tip.push_str(&tip[last_index..start]);
|
|
new_tip.push_str(
|
|
controls.keybindings[&game_input]
|
|
.display_string(&None)
|
|
.as_str(),
|
|
);
|
|
last_index = end + 1;
|
|
}
|
|
}
|
|
});
|
|
// If there is any text left over append it
|
|
if last_index < tip.len() {
|
|
new_tip.push_str(&tip[last_index..]);
|
|
}
|
|
|
|
let tip = format!("{} {}", i18n.get("main.tip"), new_tip.as_str());
|
|
Container::new(Text::new(tip).size(fonts.cyri.scale(25)))
|
|
.width(Length::Fill)
|
|
.height(Length::Fill)
|
|
.center_x()
|
|
.align_y(Align::End)
|
|
.into()
|
|
} else {
|
|
Space::new(Length::Fill, Length::Fill).into()
|
|
};
|
|
|
|
let cancel = Container::new(neat_button(
|
|
&mut self.cancel_button,
|
|
i18n.get("common.cancel"),
|
|
0.7,
|
|
button_style,
|
|
Some(Message::CancelConnect),
|
|
))
|
|
.width(Length::Fill)
|
|
.height(Length::Units(fonts.cyri.scale(30)))
|
|
.center_x()
|
|
.padding(3);
|
|
|
|
let tip_cancel = Column::with_children(vec![tip, cancel.into()])
|
|
.width(Length::FillPortion(3))
|
|
.align_items(Align::Center)
|
|
.spacing(5)
|
|
.padding(5);
|
|
|
|
let gear = Container::new(
|
|
Image::new(frame_id)
|
|
.width(Length::Units(64))
|
|
.height(Length::Units(64)),
|
|
)
|
|
.width(Length::Fill)
|
|
.padding(10)
|
|
.align_x(Align::End);
|
|
|
|
let bottom_content = Row::with_children(vec![
|
|
Space::new(Length::Fill, Length::Shrink).into(),
|
|
tip_cancel.into(),
|
|
gear.into(),
|
|
])
|
|
.align_items(Align::Center)
|
|
.width(Length::Fill);
|
|
|
|
let left_art = Image::new(imgs.loading_art_l)
|
|
.width(Length::Units(12))
|
|
.height(Length::Units(12));
|
|
let right_art = Image::new(imgs.loading_art_r)
|
|
.width(Length::Units(12))
|
|
.height(Length::Units(12));
|
|
|
|
let bottom_bar = Container::new(Row::with_children(vec![
|
|
left_art.into(),
|
|
bottom_content.into(),
|
|
right_art.into(),
|
|
]))
|
|
.height(Length::Units(85))
|
|
.style(style::container::Style::image(imgs.loading_art));
|
|
|
|
vec![
|
|
Space::new(Length::Fill, Length::Fill).into(),
|
|
bottom_bar.into(),
|
|
]
|
|
},
|
|
ConnectionState::AuthTrustPrompt { msg, .. } => {
|
|
let text = Text::new(msg).size(fonts.cyri.scale(25));
|
|
|
|
let cancel = neat_button(
|
|
&mut self.cancel_button,
|
|
i18n.get("common.cancel"),
|
|
0.7,
|
|
button_style,
|
|
Some(Message::TrustPromptCancel),
|
|
);
|
|
let add = neat_button(
|
|
&mut self.add_button,
|
|
i18n.get("common.add"),
|
|
0.7,
|
|
button_style,
|
|
Some(Message::TrustPromptAdd),
|
|
);
|
|
|
|
let content = Column::with_children(vec![
|
|
text.into(),
|
|
Container::new(
|
|
Row::with_children(vec![cancel, add])
|
|
.spacing(20)
|
|
.height(Length::Units(25)),
|
|
)
|
|
.align_x(Align::End)
|
|
.width(Length::Fill)
|
|
.into(),
|
|
])
|
|
.spacing(4)
|
|
.max_width(520)
|
|
.width(Length::Fill)
|
|
.height(Length::Fill);
|
|
|
|
let prompt_window = Container::new(content)
|
|
.style(
|
|
style::container::Style::color_with_double_cornerless_border(
|
|
(22, 18, 16, 255).into(),
|
|
(11, 11, 11, 255).into(),
|
|
(54, 46, 38, 255).into(),
|
|
),
|
|
)
|
|
.padding(20);
|
|
|
|
let container = Container::new(prompt_window)
|
|
.width(Length::Fill)
|
|
.height(Length::Fill)
|
|
.center_x()
|
|
.center_y();
|
|
|
|
vec![
|
|
container.into(),
|
|
Space::new(Length::Fill, Length::Units(fonts.cyri.scale(15))).into(),
|
|
]
|
|
},
|
|
};
|
|
|
|
Column::with_children(children)
|
|
.width(Length::Fill)
|
|
.height(Length::Fill)
|
|
.into()
|
|
}
|
|
}
|