mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add parts of main menu such as version text and info text banner, make connection screen
This commit is contained in:
parent
d6b38c8cd2
commit
5c13983631
@ -4,16 +4,20 @@ use crate::{
|
||||
ui::ice::{
|
||||
component::neat_button,
|
||||
widget::{image, BackgroundContainer, Image},
|
||||
Element,
|
||||
ButtonStyle, Element,
|
||||
},
|
||||
};
|
||||
use iced::{button, Length, Space};
|
||||
use iced::{button, Color, Column, Container, HorizontalAlignment, Length, Row, Space, Text};
|
||||
|
||||
/// Connecting screen for the main menu
|
||||
pub struct Screen {
|
||||
cancel_button: button::State,
|
||||
}
|
||||
|
||||
// TODO: move to super and unify with identical login consts
|
||||
const TEXT_COLOR: iced::Color = iced::Color::from_rgb(1.0, 1.0, 1.0);
|
||||
const DISABLED_TEXT_COLOR: iced::Color = iced::Color::from_rgba(1.0, 1.0, 1.0, 0.2);
|
||||
|
||||
impl Screen {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
@ -26,9 +30,53 @@ impl Screen {
|
||||
imgs: &Imgs,
|
||||
bg_img: image::Handle,
|
||||
start: &std::time::Instant,
|
||||
status_text: &str,
|
||||
version: &str,
|
||||
time: f32,
|
||||
i18n: &Localization,
|
||||
) -> Element<Message> {
|
||||
let content = Space::new(Length::Fill, Length::Fill);
|
||||
let fade_msg = (time * 2.0).sin() * 0.5 + 0.51;
|
||||
let button_style = ButtonStyle::new(imgs.button)
|
||||
.hover_image(imgs.button_hover)
|
||||
.press_image(imgs.button_press)
|
||||
.text_color(TEXT_COLOR)
|
||||
.disabled_text_color(DISABLED_TEXT_COLOR);
|
||||
|
||||
let version = Text::new(version)
|
||||
.size(15) // move version text size to const
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.horizontal_alignment(HorizontalAlignment::Right);
|
||||
|
||||
let status = Text::new(status_text)
|
||||
.size(80)
|
||||
.color(Color::from_rgba(1.0, 1.0, 1.0, fade_msg))
|
||||
.width(Length::Fill);
|
||||
|
||||
let status = Row::with_children(vec![
|
||||
Space::new(Length::Units(80), Length::Shrink).into(),
|
||||
status.into(),
|
||||
]);
|
||||
|
||||
let cancel = neat_button(
|
||||
&mut self.cancel_button,
|
||||
i18n.get("common.cancel"),
|
||||
0.7,
|
||||
button_style,
|
||||
Some(Message::CancelConnect),
|
||||
);
|
||||
|
||||
let cancel = Container::new(cancel)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Units(50))
|
||||
.center_x()
|
||||
.padding(3);
|
||||
|
||||
let content = Column::with_children(vec![version.into(), status.into(), cancel.into()])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.padding(3);
|
||||
|
||||
// Note: could replace this with styling on iced's container since we aren't
|
||||
// using fixed aspect ratio
|
||||
BackgroundContainer::new(Image::new(bg_img), content).into()
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{IcedImgs as Imgs, LoginInfo, Message};
|
||||
use super::{IcedImgs as Imgs, Info, LoginInfo, Message};
|
||||
use crate::{
|
||||
i18n::Localization,
|
||||
ui::ice::{
|
||||
@ -10,7 +10,10 @@ use crate::{
|
||||
ButtonStyle, Element,
|
||||
},
|
||||
};
|
||||
use iced::{button, text_input, Align, Column, Container, Length, Row, Space, TextInput};
|
||||
use iced::{
|
||||
button, text_input, Align, Column, Container, HorizontalAlignment, Length, Row, Space, Text,
|
||||
TextInput,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
const TEXT_COLOR: iced::Color = iced::Color::from_rgb(1.0, 1.0, 1.0);
|
||||
@ -44,6 +47,9 @@ impl Screen {
|
||||
&mut self,
|
||||
imgs: &Imgs,
|
||||
login_info: &LoginInfo,
|
||||
info: &Info,
|
||||
version: &str,
|
||||
show_servers: bool,
|
||||
i18n: &Localization,
|
||||
) -> Element<Message> {
|
||||
let button_style = ButtonStyle::new(imgs.button)
|
||||
@ -77,14 +83,39 @@ impl Screen {
|
||||
])
|
||||
.width(Length::Fill)
|
||||
.max_width(200)
|
||||
.spacing(5)
|
||||
.padding(10);
|
||||
.spacing(5);
|
||||
|
||||
let buttons = Container::new(buttons)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_y(Align::End)
|
||||
.padding(20);
|
||||
.align_y(Align::End);
|
||||
|
||||
let left_column = if matches!(info, Info::Intro) {
|
||||
let intro_text = i18n.get("main.login_process");
|
||||
|
||||
let info_window = BackgroundContainer::new(
|
||||
CompoundGraphic::from_graphics(vec![
|
||||
Graphic::rect(Rgba::new(0, 0, 0, 240), [500, 300], [0, 0]),
|
||||
// Note: a way to tell it to keep the height of this one piece constant and
|
||||
// unstreched would be nice, I suppose we could just break this out into a
|
||||
// column and use Length::Units
|
||||
Graphic::image(imgs.banner_bottom, [500, 30], [0, 300])
|
||||
.color(Rgba::new(255, 255, 255, 240)),
|
||||
])
|
||||
.height(Length::Shrink),
|
||||
Text::new(intro_text).size(21),
|
||||
)
|
||||
.max_width(450)
|
||||
.padding(Padding::new().horizontal(20).top(10).bottom(60));
|
||||
|
||||
Column::with_children(vec![info_window.into(), buttons.into()])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.padding(27)
|
||||
.into()
|
||||
} else {
|
||||
buttons.into()
|
||||
};
|
||||
|
||||
let banner = self.banner.view(imgs, login_info, i18n, button_style);
|
||||
|
||||
@ -94,13 +125,20 @@ impl Screen {
|
||||
.align_x(Align::Center)
|
||||
.align_y(Align::Center);
|
||||
|
||||
let image3 = Image::new(imgs.banner_bottom).fix_aspect_ratio();
|
||||
let right_column = Text::new(version)
|
||||
.size(15)
|
||||
.width(Length::Fill)
|
||||
.horizontal_alignment(HorizontalAlignment::Right);
|
||||
|
||||
let content =
|
||||
Row::with_children(vec![buttons.into(), central_column.into(), image3.into()])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.spacing(10);
|
||||
let content = Row::with_children(vec![
|
||||
left_column,
|
||||
central_column.into(),
|
||||
right_column.into(),
|
||||
])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.spacing(10)
|
||||
.padding(3);
|
||||
|
||||
BackgroundContainer::new(Image::new(imgs.bg), content).into()
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use crate::{
|
||||
GlobalState,
|
||||
};
|
||||
//ImageFrame, Tooltip,
|
||||
use crate::settings::Settings;
|
||||
use common::assets::Asset;
|
||||
use conrod_core::{
|
||||
color,
|
||||
@ -113,6 +114,11 @@ pub struct LoginInfo {
|
||||
pub server: String,
|
||||
}
|
||||
|
||||
enum Info {
|
||||
Disclaimer,
|
||||
Intro,
|
||||
}
|
||||
|
||||
enum Screen {
|
||||
Login {
|
||||
screen: login::Screen,
|
||||
@ -121,6 +127,7 @@ enum Screen {
|
||||
screen: connecting::Screen,
|
||||
// TODO: why instant?
|
||||
start: std::time::Instant,
|
||||
status_text: String,
|
||||
},
|
||||
}
|
||||
|
||||
@ -129,12 +136,16 @@ struct IcedState {
|
||||
imgs: IcedImgs,
|
||||
bg_img: widget::image::Handle,
|
||||
i18n: std::sync::Arc<Localization>,
|
||||
// Voxygen version
|
||||
version: String,
|
||||
|
||||
login_info: LoginInfo,
|
||||
|
||||
// TODO: not sure if this should be used for connecting
|
||||
popup: Option<PopupData>,
|
||||
show_servers: bool,
|
||||
show_disclaimer: bool,
|
||||
login_info: LoginInfo,
|
||||
info: Info,
|
||||
time: f32,
|
||||
|
||||
screen: Screen,
|
||||
}
|
||||
@ -150,6 +161,7 @@ enum Message {
|
||||
Password(String),
|
||||
Server(String),
|
||||
FocusPassword,
|
||||
CancelConnect,
|
||||
}
|
||||
|
||||
impl IcedState {
|
||||
@ -157,32 +169,68 @@ impl IcedState {
|
||||
imgs: IcedImgs,
|
||||
bg_img: widget::image::Handle,
|
||||
i18n: std::sync::Arc<Localization>,
|
||||
settings: &Settings,
|
||||
) -> Self {
|
||||
let version = format!(
|
||||
"{}-{}",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
common::util::GIT_VERSION.to_string()
|
||||
);
|
||||
|
||||
let info = if settings.show_disclaimer {
|
||||
Info::Disclaimer
|
||||
} else {
|
||||
Info::Intro
|
||||
};
|
||||
|
||||
Self {
|
||||
imgs,
|
||||
bg_img,
|
||||
i18n,
|
||||
popup: None,
|
||||
show_servers: false,
|
||||
show_disclaimer: false,
|
||||
version,
|
||||
|
||||
login_info: LoginInfo {
|
||||
username: String::new(),
|
||||
password: String::new(),
|
||||
server: String::new(),
|
||||
},
|
||||
|
||||
popup: None,
|
||||
show_servers: false,
|
||||
info,
|
||||
time: 0.0,
|
||||
|
||||
screen: Screen::Login {
|
||||
screen: login::Screen::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&mut self) -> Element<Message> {
|
||||
fn view(&mut self, dt: f32) -> Element<Message> {
|
||||
self.time = self.time + dt;
|
||||
|
||||
match &mut self.screen {
|
||||
Screen::Login { screen } => screen.view(&self.imgs, &self.login_info, &self.i18n),
|
||||
Screen::Connecting { screen, start } => {
|
||||
screen.view(&self.imgs, self.bg_img, &start, &self.i18n)
|
||||
},
|
||||
Screen::Login { screen } => screen.view(
|
||||
&self.imgs,
|
||||
&self.login_info,
|
||||
&self.info,
|
||||
&self.version,
|
||||
self.show_servers,
|
||||
&self.i18n,
|
||||
),
|
||||
Screen::Connecting {
|
||||
screen,
|
||||
start,
|
||||
status_text,
|
||||
} => screen.view(
|
||||
&self.imgs,
|
||||
self.bg_img,
|
||||
&start,
|
||||
&status_text,
|
||||
&self.version,
|
||||
self.time,
|
||||
&self.i18n,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,16 +239,21 @@ impl IcedState {
|
||||
Message::Quit => events.push(Event::Quit),
|
||||
Message::ShowServers => self.show_servers = true,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
Message::Singleplayer => events.push(Event::StartSingleplayer),
|
||||
Message::Singleplayer => {
|
||||
self.screen = Screen::Connecting {
|
||||
screen: connecting::Screen::new(),
|
||||
start: std::time::Instant::now(),
|
||||
status_text: [self.i18n.get("main.creating_world"), "..."].concat(),
|
||||
};
|
||||
|
||||
events.push(Event::StartSingleplayer);
|
||||
},
|
||||
Message::Multiplayer => {
|
||||
self.screen = Screen::Connecting {
|
||||
screen: connecting::Screen::new(),
|
||||
start: std::time::Instant::now(),
|
||||
status_text: [self.i18n.get("main.connecting"), "..."].concat(),
|
||||
};
|
||||
self.popup = Some(PopupData {
|
||||
msg: [self.i18n.get("main.connecting"), "..."].concat(),
|
||||
popup_type: PopupType::ConnectionInfo,
|
||||
});
|
||||
|
||||
events.push(Event::LoginAttempt {
|
||||
username: self.login_info.username.clone(),
|
||||
@ -212,11 +265,23 @@ impl IcedState {
|
||||
Message::Password(new_value) => self.login_info.password = new_value,
|
||||
Message::Server(new_value) => self.login_info.server = new_value,
|
||||
Message::FocusPassword => {
|
||||
if let Screen::Login { screen } = &mut self.screen {
|
||||
if let Screen::Login { screen, .. } = &mut self.screen {
|
||||
screen.banner.password = text_input::State::focused();
|
||||
screen.banner.username = text_input::State::new();
|
||||
}
|
||||
},
|
||||
Message::CancelConnect => {
|
||||
self.cancel_connection();
|
||||
events.push(Event::CancelLoginAttempt);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn cancel_connection(&mut self) {
|
||||
if matches!(&self.screen, Screen::Connecting {..}) {
|
||||
self.screen = Screen::Login {
|
||||
screen: login::Screen::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -300,23 +365,12 @@ image_ids! {
|
||||
}
|
||||
}
|
||||
|
||||
rotation_image_ids! {
|
||||
pub struct ImgsRot {
|
||||
<VoxelGraphic>
|
||||
|
||||
// Tooltip Test
|
||||
tt_side: "voxygen/element/frames/tt_test_edge",
|
||||
tt_corner: "voxygen/element/frames/tt_test_corner_tr",
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MainMenuUi {
|
||||
ui: Ui,
|
||||
ice_ui: IcedUi,
|
||||
ice_state: IcedState,
|
||||
ids: Ids,
|
||||
imgs: Imgs,
|
||||
rot_imgs: ImgsRot,
|
||||
username: String,
|
||||
password: String,
|
||||
server_address: String,
|
||||
@ -346,7 +400,6 @@ impl<'a> MainMenuUi {
|
||||
let ids = Ids::new(ui.id_generator());
|
||||
// Load images
|
||||
let imgs = Imgs::load(&mut ui).expect("Failed to load images");
|
||||
let rot_imgs = ImgsRot::load(&mut ui).expect("Failed to load images!");
|
||||
let bg_img_spec = BG_IMGS.choose(&mut thread_rng()).unwrap();
|
||||
let bg_img_id = ui.add_graphic(Graphic::Image(DynamicImage::load_expect(bg_img_spec)));
|
||||
// Load language
|
||||
@ -372,8 +425,9 @@ impl<'a> MainMenuUi {
|
||||
let mut ice_ui = IcedUi::new(window, ice_font).unwrap();
|
||||
let ice_state = IcedState::new(
|
||||
IcedImgs::load(&mut ice_ui).expect("Failed to load images"),
|
||||
ice_ui.add_graphic(Graphic::Image(load_expect(bg_img_spec))),
|
||||
ice_ui.add_graphic(Graphic::Image(DynamicImage::load_expect(bg_img_spec))),
|
||||
i18n.clone(),
|
||||
&global_state.settings,
|
||||
);
|
||||
|
||||
Self {
|
||||
@ -382,7 +436,6 @@ impl<'a> MainMenuUi {
|
||||
ice_state,
|
||||
ids,
|
||||
imgs,
|
||||
rot_imgs,
|
||||
username: networking.username.clone(),
|
||||
password: "".to_owned(),
|
||||
server_address: networking
|
||||
@ -429,24 +482,6 @@ impl<'a> MainMenuUi {
|
||||
|
||||
let intro_text = &self.i18n.get("main.login_process");
|
||||
|
||||
// Tooltip
|
||||
/*let _tooltip = Tooltip::new({
|
||||
// Edge images [t, b, r, l]
|
||||
// Corner images [tr, tl, br, bl]
|
||||
let edge = &self.rot_imgs.tt_side;
|
||||
let corner = &self.rot_imgs.tt_corner;
|
||||
ImageFrame::new(
|
||||
[edge.cw180, edge.none, edge.cw270, edge.cw90],
|
||||
[corner.none, corner.cw270, corner.cw90, corner.cw180],
|
||||
Color::Rgba(0.08, 0.07, 0.04, 1.0),
|
||||
5.0,
|
||||
)
|
||||
})
|
||||
.title_font_size(self.fonts.cyri.scale(15))
|
||||
.desc_font_size(self.fonts.cyri.scale(10))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.desc_text_color(TEXT_COLOR_2);*/
|
||||
|
||||
// Background image, Veloren logo, Alpha-Version Label
|
||||
Image::new(if self.connect {
|
||||
self.bg_img_id
|
||||
@ -1047,6 +1082,7 @@ impl<'a> MainMenuUi {
|
||||
self.popup = None;
|
||||
self.connecting = None;
|
||||
self.connect = false;
|
||||
self.ice_state.cancel_connection();
|
||||
}
|
||||
|
||||
pub fn handle_event(&mut self, event: ui::Event) {
|
||||
@ -1055,17 +1091,24 @@ impl<'a> MainMenuUi {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_iced_event(&mut self, event: ui::ice::Event) { self.ice_ui.handle_event(event); }
|
||||
pub fn handle_iced_event(&mut self, event: ui::ice::Event) {
|
||||
if self.show_iced {
|
||||
self.ice_ui.handle_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maintain(&mut self, global_state: &mut GlobalState, dt: Duration) -> Vec<Event> {
|
||||
let mut events = self.update_layout(global_state, dt);
|
||||
self.ui.maintain(global_state.window.renderer_mut(), None);
|
||||
let (messages, _) = self
|
||||
.ice_ui
|
||||
.maintain(self.ice_state.view(), global_state.window.renderer_mut());
|
||||
messages
|
||||
.into_iter()
|
||||
.for_each(|message| self.ice_state.update(message, &mut events));
|
||||
if self.show_iced {
|
||||
let (messages, _) = self.ice_ui.maintain(
|
||||
self.ice_state.view(dt.as_secs_f32()),
|
||||
global_state.window.renderer_mut(),
|
||||
);
|
||||
messages
|
||||
.into_iter()
|
||||
.for_each(|message| self.ice_state.update(message, &mut events));
|
||||
}
|
||||
|
||||
events
|
||||
}
|
||||
|
@ -541,6 +541,7 @@ impl IcedRenderer {
|
||||
// TODO: support nested clips?
|
||||
// TODO: if last command is a clip changing back to the default replace it with
|
||||
// this
|
||||
// TODO: cull primitives outside the current scissor
|
||||
|
||||
// Renderer child
|
||||
self.draw_primitive(*content, renderer);
|
||||
|
@ -1,6 +1,10 @@
|
||||
use iced::{layout, Clipboard, Element, Event, Hasher, Layout, Length, Point, Size, Widget};
|
||||
use std::{hash::Hash, u32};
|
||||
|
||||
// TODO: decouple from image/compound graphic widgets (they could still use
|
||||
// common types, but the info we want here for the background is a subset of
|
||||
// what a fullblown widget might need)
|
||||
|
||||
// Note: it might be more efficient to make this generic over the content type
|
||||
|
||||
// Note: maybe we could just use the container styling for this (not really with
|
||||
|
Loading…
Reference in New Issue
Block a user