mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
More main menu work, split main menu ui into multiple modules, misc fixes in the renderer
This commit is contained in:
parent
d2f5a44d02
commit
d6b38c8cd2
36
voxygen/src/menu/main/ui/connecting.rs
Normal file
36
voxygen/src/menu/main/ui/connecting.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use super::{IcedImgs as Imgs, Message};
|
||||
use crate::{
|
||||
i18n::Localization,
|
||||
ui::ice::{
|
||||
component::neat_button,
|
||||
widget::{image, BackgroundContainer, Image},
|
||||
Element,
|
||||
},
|
||||
};
|
||||
use iced::{button, Length, Space};
|
||||
|
||||
/// Connecting screen for the main menu
|
||||
pub struct Screen {
|
||||
cancel_button: button::State,
|
||||
}
|
||||
|
||||
impl Screen {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
cancel_button: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn view(
|
||||
&mut self,
|
||||
imgs: &Imgs,
|
||||
bg_img: image::Handle,
|
||||
start: &std::time::Instant,
|
||||
i18n: &Localization,
|
||||
) -> Element<Message> {
|
||||
let content = Space::new(Length::Fill, Length::Fill);
|
||||
// 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()
|
||||
}
|
||||
}
|
237
voxygen/src/menu/main/ui/login.rs
Normal file
237
voxygen/src/menu/main/ui/login.rs
Normal file
@ -0,0 +1,237 @@
|
||||
use super::{IcedImgs as Imgs, LoginInfo, Message};
|
||||
use crate::{
|
||||
i18n::Localization,
|
||||
ui::ice::{
|
||||
component::neat_button,
|
||||
widget::{
|
||||
compound_graphic::{CompoundGraphic, Graphic},
|
||||
BackgroundContainer, Image, Padding,
|
||||
},
|
||||
ButtonStyle, Element,
|
||||
},
|
||||
};
|
||||
use iced::{button, text_input, Align, Column, Container, Length, Row, Space, TextInput};
|
||||
use vek::*;
|
||||
|
||||
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);
|
||||
const FILL_FRAC_ONE: f32 = 0.77;
|
||||
const FILL_FRAC_TWO: f32 = 0.53;
|
||||
const INPUT_WIDTH: u16 = 250;
|
||||
const INPUT_TEXT_SIZE: u16 = 24;
|
||||
|
||||
/// Login screen for the main menu
|
||||
pub struct Screen {
|
||||
quit_button: button::State,
|
||||
settings_button: button::State,
|
||||
servers_button: button::State,
|
||||
|
||||
pub banner: Banner,
|
||||
}
|
||||
|
||||
impl Screen {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
servers_button: Default::default(),
|
||||
settings_button: Default::default(),
|
||||
quit_button: Default::default(),
|
||||
|
||||
banner: Banner::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn view(
|
||||
&mut self,
|
||||
imgs: &Imgs,
|
||||
login_info: &LoginInfo,
|
||||
i18n: &Localization,
|
||||
) -> Element<Message> {
|
||||
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 buttons = Column::with_children(vec![
|
||||
neat_button(
|
||||
&mut self.servers_button,
|
||||
i18n.get("common.servers"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
Some(Message::ShowServers),
|
||||
),
|
||||
neat_button(
|
||||
&mut self.settings_button,
|
||||
i18n.get("common.settings"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
None,
|
||||
),
|
||||
neat_button(
|
||||
&mut self.quit_button,
|
||||
i18n.get("common.quit"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
Some(Message::Quit),
|
||||
),
|
||||
])
|
||||
.width(Length::Fill)
|
||||
.max_width(200)
|
||||
.spacing(5)
|
||||
.padding(10);
|
||||
|
||||
let buttons = Container::new(buttons)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_y(Align::End)
|
||||
.padding(20);
|
||||
|
||||
let banner = self.banner.view(imgs, login_info, i18n, button_style);
|
||||
|
||||
let central_column = Container::new(banner)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_x(Align::Center)
|
||||
.align_y(Align::Center);
|
||||
|
||||
let image3 = Image::new(imgs.banner_bottom).fix_aspect_ratio();
|
||||
|
||||
let content =
|
||||
Row::with_children(vec![buttons.into(), central_column.into(), image3.into()])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.spacing(10);
|
||||
|
||||
BackgroundContainer::new(Image::new(imgs.bg), content).into()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Banner {
|
||||
pub username: text_input::State,
|
||||
pub password: text_input::State,
|
||||
pub server: text_input::State,
|
||||
|
||||
multiplayer_button: button::State,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
singleplayer_button: button::State,
|
||||
}
|
||||
|
||||
impl Banner {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
username: Default::default(),
|
||||
password: Default::default(),
|
||||
server: Default::default(),
|
||||
|
||||
multiplayer_button: Default::default(),
|
||||
#[cfg(feature = "singleplayer")]
|
||||
singleplayer_button: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn view(
|
||||
&mut self,
|
||||
imgs: &Imgs,
|
||||
login_info: &LoginInfo,
|
||||
i18n: &Localization,
|
||||
button_style: ButtonStyle,
|
||||
) -> Element<Message> {
|
||||
let banner_content = Column::with_children(vec![
|
||||
Image::new(imgs.v_logo)
|
||||
.fix_aspect_ratio()
|
||||
.height(Length::FillPortion(20))
|
||||
.into(),
|
||||
Space::new(Length::Fill, Length::FillPortion(5)).into(),
|
||||
Column::with_children(vec![
|
||||
BackgroundContainer::new(
|
||||
Image::new(imgs.input_bg)
|
||||
.width(Length::Units(INPUT_WIDTH))
|
||||
.fix_aspect_ratio(),
|
||||
TextInput::new(
|
||||
&mut self.username,
|
||||
"Username",
|
||||
&login_info.username,
|
||||
Message::Username,
|
||||
)
|
||||
.size(INPUT_TEXT_SIZE)
|
||||
.on_submit(Message::FocusPassword),
|
||||
)
|
||||
.padding(Padding::new().horizontal(10).top(10))
|
||||
.into(),
|
||||
BackgroundContainer::new(
|
||||
Image::new(imgs.input_bg)
|
||||
.width(Length::Units(INPUT_WIDTH))
|
||||
.fix_aspect_ratio(),
|
||||
TextInput::new(
|
||||
&mut self.password,
|
||||
"Password",
|
||||
&login_info.password,
|
||||
Message::Password,
|
||||
)
|
||||
.size(INPUT_TEXT_SIZE)
|
||||
.password()
|
||||
.on_submit(Message::Multiplayer),
|
||||
)
|
||||
.padding(Padding::new().horizontal(10).top(8))
|
||||
.into(),
|
||||
BackgroundContainer::new(
|
||||
Image::new(imgs.input_bg)
|
||||
.width(Length::Units(INPUT_WIDTH))
|
||||
.fix_aspect_ratio(),
|
||||
TextInput::new(
|
||||
&mut self.server,
|
||||
"Server",
|
||||
&login_info.server,
|
||||
Message::Server,
|
||||
)
|
||||
.size(INPUT_TEXT_SIZE)
|
||||
.on_submit(Message::Multiplayer),
|
||||
)
|
||||
.padding(Padding::new().horizontal(10).top(8))
|
||||
.into(),
|
||||
])
|
||||
.spacing(2)
|
||||
.height(Length::FillPortion(50))
|
||||
.into(),
|
||||
Column::with_children(vec![
|
||||
neat_button(
|
||||
&mut self.multiplayer_button,
|
||||
i18n.get("common.multiplayer"),
|
||||
FILL_FRAC_TWO,
|
||||
button_style,
|
||||
Some(Message::Multiplayer),
|
||||
),
|
||||
#[cfg(feature = "singleplayer")]
|
||||
neat_button(
|
||||
&mut self.singleplayer_button,
|
||||
i18n.get("common.singleplayer"),
|
||||
FILL_FRAC_TWO,
|
||||
button_style,
|
||||
Some(Message::Singleplayer),
|
||||
),
|
||||
])
|
||||
.max_width(240)
|
||||
.spacing(8)
|
||||
.into(),
|
||||
])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_items(Align::Center);
|
||||
|
||||
let banner = BackgroundContainer::new(
|
||||
CompoundGraphic::from_graphics(vec![
|
||||
Graphic::image(imgs.banner_top, [138, 17], [0, 0]),
|
||||
Graphic::rect(Rgba::new(0, 0, 0, 230), [130, 195], [4, 17]),
|
||||
Graphic::image(imgs.banner, [130, 15], [4, 212])
|
||||
.color(Rgba::new(255, 255, 255, 230)),
|
||||
])
|
||||
.fix_aspect_ratio()
|
||||
.height(Length::Fill),
|
||||
banner_content,
|
||||
)
|
||||
.padding(Padding::new().horizontal(16).vertical(20))
|
||||
.max_width(330);
|
||||
|
||||
banner.into()
|
||||
}
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
mod connecting;
|
||||
mod login;
|
||||
|
||||
use crate::{
|
||||
i18n::{i18n_asset_key, Localization},
|
||||
render::Renderer,
|
||||
@ -22,6 +25,7 @@ use conrod_core::{
|
||||
use image::DynamicImage;
|
||||
use rand::{seq::SliceRandom, thread_rng, Rng};
|
||||
use std::time::Duration;
|
||||
use ui::ice::widget;
|
||||
|
||||
const COL1: Color = Color::Rgba(0.07, 0.1, 0.1, 0.9);
|
||||
|
||||
@ -29,6 +33,194 @@ const COL1: Color = Color::Rgba(0.07, 0.1, 0.1, 0.9);
|
||||
/*const UI_MAIN: Color = Color::Rgba(0.61, 0.70, 0.70, 1.0); // Greenish Blue
|
||||
const UI_HIGHLIGHT_0: Color = Color::Rgba(0.79, 1.09, 1.09, 1.0);*/
|
||||
|
||||
use iced::text_input;
|
||||
image_ids_ice! {
|
||||
struct IcedImgs {
|
||||
<VoxelGraphic>
|
||||
v_logo: "voxygen.element.v_logo",
|
||||
|
||||
info_frame: "voxygen.element.frames.info_frame_2",
|
||||
|
||||
//banner: "voxygen.element.frames.banner",
|
||||
<ImageGraphic>
|
||||
bg: "voxygen.background.bg_main",
|
||||
banner: "voxygen.element.frames.banner_png",
|
||||
banner_bottom: "voxygen.element.frames.banner_bottom_png",
|
||||
banner_top: "voxygen.element.frames.banner_top",
|
||||
button: "voxygen.element.buttons.button",
|
||||
button_hover: "voxygen.element.buttons.button_hover",
|
||||
button_press: "voxygen.element.buttons.button_press",
|
||||
input_bg: "voxygen.element.misc_bg.textbox",
|
||||
disclaimer: "voxygen.element.frames.disclaimer",
|
||||
loading_art: "voxygen.element.frames.loading_screen.loading_bg",
|
||||
loading_art_l: "voxygen.element.frames.loading_screen.loading_bg_l",
|
||||
loading_art_r: "voxygen.element.frames.loading_screen.loading_bg_r",
|
||||
|
||||
<BlankGraphic>
|
||||
nothing: (),
|
||||
}
|
||||
}
|
||||
|
||||
// Randomly loaded background images
|
||||
const BG_IMGS: [&str; 16] = [
|
||||
"voxygen.background.bg_1",
|
||||
"voxygen.background.bg_2",
|
||||
"voxygen.background.bg_3",
|
||||
"voxygen.background.bg_4",
|
||||
"voxygen.background.bg_5",
|
||||
"voxygen.background.bg_6",
|
||||
"voxygen.background.bg_7",
|
||||
"voxygen.background.bg_8",
|
||||
"voxygen.background.bg_9",
|
||||
//"voxygen.background.bg_10",
|
||||
"voxygen.background.bg_11",
|
||||
//"voxygen.background.bg_12",
|
||||
"voxygen.background.bg_13",
|
||||
//"voxygen.background.bg_14",
|
||||
"voxygen.background.bg_15",
|
||||
"voxygen.background.bg_16",
|
||||
];
|
||||
|
||||
pub enum Event {
|
||||
LoginAttempt {
|
||||
username: String,
|
||||
password: String,
|
||||
server_address: String,
|
||||
},
|
||||
CancelLoginAttempt,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
StartSingleplayer,
|
||||
Quit,
|
||||
Settings,
|
||||
//DisclaimerClosed,
|
||||
AuthServerTrust(String, bool),
|
||||
}
|
||||
|
||||
pub enum PopupType {
|
||||
Error,
|
||||
ConnectionInfo,
|
||||
AuthTrustPrompt(String),
|
||||
}
|
||||
|
||||
pub struct PopupData {
|
||||
msg: String,
|
||||
popup_type: PopupType,
|
||||
}
|
||||
|
||||
pub struct LoginInfo {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub server: String,
|
||||
}
|
||||
|
||||
enum Screen {
|
||||
Login {
|
||||
screen: login::Screen,
|
||||
},
|
||||
Connecting {
|
||||
screen: connecting::Screen,
|
||||
// TODO: why instant?
|
||||
start: std::time::Instant,
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: use i18n font scale thing
|
||||
struct IcedState {
|
||||
imgs: IcedImgs,
|
||||
bg_img: widget::image::Handle,
|
||||
i18n: std::sync::Arc<Localization>,
|
||||
|
||||
// TODO: not sure if this should be used for connecting
|
||||
popup: Option<PopupData>,
|
||||
show_servers: bool,
|
||||
show_disclaimer: bool,
|
||||
login_info: LoginInfo,
|
||||
|
||||
screen: Screen,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Message {
|
||||
Quit,
|
||||
ShowServers,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
Singleplayer,
|
||||
Multiplayer,
|
||||
Username(String),
|
||||
Password(String),
|
||||
Server(String),
|
||||
FocusPassword,
|
||||
}
|
||||
|
||||
impl IcedState {
|
||||
fn new(
|
||||
imgs: IcedImgs,
|
||||
bg_img: widget::image::Handle,
|
||||
i18n: std::sync::Arc<Localization>,
|
||||
) -> Self {
|
||||
Self {
|
||||
imgs,
|
||||
bg_img,
|
||||
i18n,
|
||||
popup: None,
|
||||
show_servers: false,
|
||||
show_disclaimer: false,
|
||||
login_info: LoginInfo {
|
||||
username: String::new(),
|
||||
password: String::new(),
|
||||
server: String::new(),
|
||||
},
|
||||
|
||||
screen: Screen::Login {
|
||||
screen: login::Screen::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&mut self) -> Element<Message> {
|
||||
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)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message, events: &mut Vec<Event>) {
|
||||
match message {
|
||||
Message::Quit => events.push(Event::Quit),
|
||||
Message::ShowServers => self.show_servers = true,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
Message::Singleplayer => events.push(Event::StartSingleplayer),
|
||||
Message::Multiplayer => {
|
||||
self.screen = Screen::Connecting {
|
||||
screen: connecting::Screen::new(),
|
||||
start: std::time::Instant::now(),
|
||||
};
|
||||
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(),
|
||||
password: self.login_info.password.clone(),
|
||||
server_address: self.login_info.server.clone(),
|
||||
});
|
||||
},
|
||||
Message::Username(new_value) => self.login_info.username = new_value,
|
||||
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 {
|
||||
screen.banner.password = text_input::State::focused();
|
||||
screen.banner.username = text_input::State::new();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
widget_ids! {
|
||||
struct Ids {
|
||||
// Background and logo
|
||||
@ -38,7 +230,6 @@ widget_ids! {
|
||||
alpha_text,
|
||||
banner,
|
||||
banner_top,
|
||||
gears,
|
||||
// Disclaimer
|
||||
//disc_window,
|
||||
//disc_text_1,
|
||||
@ -82,13 +273,6 @@ widget_ids! {
|
||||
info_bottom,
|
||||
// Auth Trust Prompt
|
||||
button_add_auth_trust,
|
||||
// Loading Screen Tips
|
||||
tip_txt_bg,
|
||||
tip_txt,
|
||||
// Loading Screen Artwork
|
||||
mid,
|
||||
left,
|
||||
right,
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,39 +293,7 @@ image_ids! {
|
||||
button_press: "voxygen.element.buttons.button_press",
|
||||
input_bg: "voxygen.element.misc_bg.textbox",
|
||||
//disclaimer: "voxygen.element.frames.disclaimer",
|
||||
loading_art: "voxygen.element.frames.loading_screen.loading_bg",
|
||||
loading_art_l: "voxygen.element.frames.loading_screen.loading_bg_l",
|
||||
loading_art_r: "voxygen.element.frames.loading_screen.loading_bg_r",
|
||||
// Animation
|
||||
f1: "voxygen.element.animation.gears.1",
|
||||
f2: "voxygen.element.animation.gears.2",
|
||||
f3: "voxygen.element.animation.gears.3",
|
||||
f4: "voxygen.element.animation.gears.4",
|
||||
f5: "voxygen.element.animation.gears.5",
|
||||
|
||||
<BlankGraphic>
|
||||
nothing: (),
|
||||
}
|
||||
}
|
||||
|
||||
image_ids_ice! {
|
||||
struct IcedImgs {
|
||||
<VoxelGraphic>
|
||||
v_logo: "voxygen.element.v_logo",
|
||||
|
||||
info_frame: "voxygen.element.frames.info_frame_2",
|
||||
|
||||
//banner: "voxygen.element.frames.banner",
|
||||
<ImageGraphic>
|
||||
bg: "voxygen.background.bg_main",
|
||||
banner: "voxygen.element.frames.banner_png",
|
||||
banner_bottom: "voxygen.element.frames.banner_bottom_png",
|
||||
banner_top: "voxygen.element.frames.banner_top",
|
||||
button: "voxygen.element.buttons.button",
|
||||
button_hover: "voxygen.element.buttons.button_hover",
|
||||
button_press: "voxygen.element.buttons.button_press",
|
||||
input_bg: "voxygen.element.misc_bg.textbox",
|
||||
disclaimer: "voxygen.element.frames.disclaimer",
|
||||
|
||||
<BlankGraphic>
|
||||
nothing: (),
|
||||
@ -150,7 +302,7 @@ image_ids_ice! {
|
||||
|
||||
rotation_image_ids! {
|
||||
pub struct ImgsRot {
|
||||
<ImageGraphic>
|
||||
<VoxelGraphic>
|
||||
|
||||
// Tooltip Test
|
||||
tt_side: "voxygen/element/frames/tt_test_edge",
|
||||
@ -158,267 +310,6 @@ rotation_image_ids! {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
LoginAttempt {
|
||||
username: String,
|
||||
password: String,
|
||||
server_address: String,
|
||||
},
|
||||
CancelLoginAttempt,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
StartSingleplayer,
|
||||
Quit,
|
||||
Settings,
|
||||
//DisclaimerClosed,
|
||||
AuthServerTrust(String, bool),
|
||||
}
|
||||
|
||||
pub enum PopupType {
|
||||
Error,
|
||||
ConnectionInfo,
|
||||
AuthTrustPrompt(String),
|
||||
}
|
||||
|
||||
pub struct PopupData {
|
||||
msg: String,
|
||||
popup_type: PopupType,
|
||||
}
|
||||
|
||||
use ui::ice::component::neat_button;
|
||||
struct IcedState {
|
||||
imgs: IcedImgs,
|
||||
quit_button: neat_button::State,
|
||||
settings_button: neat_button::State,
|
||||
servers_button: neat_button::State,
|
||||
multiplayer_button: neat_button::State,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
singleplayer_button: neat_button::State,
|
||||
username_input: iced::text_input::State,
|
||||
password_input: iced::text_input::State,
|
||||
server_input: iced::text_input::State,
|
||||
username_value: String,
|
||||
password_value: String,
|
||||
server_value: String,
|
||||
show_servers: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)] // TODO: why does iced require Clone?
|
||||
enum Message {
|
||||
Quit,
|
||||
ShowServers,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
Singleplayer,
|
||||
Multiplayer,
|
||||
Username(String),
|
||||
Password(String),
|
||||
Server(String),
|
||||
FocusPassword,
|
||||
}
|
||||
|
||||
impl IcedState {
|
||||
pub fn new(imgs: IcedImgs) -> Self {
|
||||
Self {
|
||||
imgs,
|
||||
servers_button: Default::default(),
|
||||
settings_button: Default::default(),
|
||||
quit_button: Default::default(),
|
||||
multiplayer_button: Default::default(),
|
||||
#[cfg(feature = "singleplayer")]
|
||||
singleplayer_button: Default::default(),
|
||||
username_input: Default::default(),
|
||||
password_input: Default::default(),
|
||||
server_input: Default::default(),
|
||||
username_value: String::new(),
|
||||
password_value: String::new(),
|
||||
server_value: String::new(),
|
||||
show_servers: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view(&mut self, i18n: &Localization) -> Element<Message> {
|
||||
//let button_font_size = 30;
|
||||
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);
|
||||
const FILL_FRAC_ONE: f32 = 0.77;
|
||||
const FILL_FRAC_TWO: f32 = 0.53;
|
||||
|
||||
use iced::{Align, Column, Container, Length, Row, Space, TextInput};
|
||||
use ui::ice::{
|
||||
widget::{
|
||||
compound_graphic::{CompoundGraphic, Graphic},
|
||||
BackgroundContainer, Image, Padding,
|
||||
},
|
||||
ButtonStyle,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
let button_style = ButtonStyle::new(self.imgs.button)
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.text_color(TEXT_COLOR)
|
||||
.disabled_text_color(DISABLED_TEXT_COLOR);
|
||||
|
||||
let buttons = Column::with_children(vec![
|
||||
self.servers_button.view(
|
||||
i18n.get("common.servers"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
Some(Message::ShowServers),
|
||||
),
|
||||
self.settings_button.view(
|
||||
i18n.get("common.settings"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
None,
|
||||
),
|
||||
self.quit_button.view(
|
||||
i18n.get("common.quit"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
Some(Message::Quit),
|
||||
),
|
||||
])
|
||||
.width(Length::Fill)
|
||||
.max_width(200)
|
||||
.spacing(5)
|
||||
.padding(10);
|
||||
|
||||
let buttons = Container::new(buttons)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_y(Align::End)
|
||||
.padding(20);
|
||||
const INPUT_WIDTH: u16 = 250;
|
||||
const INPUT_TEXT_SIZE: u16 = 24;
|
||||
let banner_content = Column::with_children(vec![
|
||||
Image::new(self.imgs.v_logo)
|
||||
.fix_aspect_ratio()
|
||||
.height(Length::FillPortion(20))
|
||||
.into(),
|
||||
Space::new(Length::Fill, Length::FillPortion(5)).into(),
|
||||
Column::with_children(vec![
|
||||
BackgroundContainer::new(
|
||||
Image::new(self.imgs.input_bg)
|
||||
.width(Length::Units(INPUT_WIDTH))
|
||||
.fix_aspect_ratio(),
|
||||
TextInput::new(
|
||||
&mut self.username_input,
|
||||
"Username",
|
||||
&self.username_value,
|
||||
Message::Username,
|
||||
)
|
||||
.size(INPUT_TEXT_SIZE)
|
||||
.on_submit(Message::FocusPassword),
|
||||
)
|
||||
.padding(Padding::new().horizontal(10).top(10))
|
||||
.into(),
|
||||
BackgroundContainer::new(
|
||||
Image::new(self.imgs.input_bg)
|
||||
.width(Length::Units(INPUT_WIDTH))
|
||||
.fix_aspect_ratio(),
|
||||
TextInput::new(
|
||||
&mut self.password_input,
|
||||
"Password",
|
||||
&self.password_value,
|
||||
Message::Password,
|
||||
)
|
||||
.size(INPUT_TEXT_SIZE)
|
||||
.password()
|
||||
.on_submit(Message::Multiplayer),
|
||||
)
|
||||
.padding(Padding::new().horizontal(10).top(8))
|
||||
.into(),
|
||||
BackgroundContainer::new(
|
||||
Image::new(self.imgs.input_bg)
|
||||
.width(Length::Units(INPUT_WIDTH))
|
||||
.fix_aspect_ratio(),
|
||||
TextInput::new(
|
||||
&mut self.server_input,
|
||||
"Server",
|
||||
&self.server_value,
|
||||
Message::Server,
|
||||
)
|
||||
.size(INPUT_TEXT_SIZE)
|
||||
.on_submit(Message::Multiplayer),
|
||||
)
|
||||
.padding(Padding::new().horizontal(10).top(8))
|
||||
.into(),
|
||||
])
|
||||
.spacing(2)
|
||||
.height(Length::FillPortion(50))
|
||||
.into(),
|
||||
Column::with_children(vec![
|
||||
self.multiplayer_button.view(
|
||||
i18n.get("common.multiplayer"),
|
||||
FILL_FRAC_TWO,
|
||||
button_style,
|
||||
Some(Message::Multiplayer),
|
||||
),
|
||||
#[cfg(feature = "singleplayer")]
|
||||
self.singleplayer_button.view(
|
||||
i18n.get("common.singleplayer"),
|
||||
FILL_FRAC_TWO,
|
||||
button_style,
|
||||
Some(Message::Singleplayer),
|
||||
),
|
||||
])
|
||||
.max_width(240)
|
||||
.spacing(8) // TODO scale with available window size, awkward because both width and height can become limiting factors, might need custom column, could also just use fill portion
|
||||
.into(),
|
||||
])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_items(Align::Center);
|
||||
|
||||
let banner = BackgroundContainer::new(
|
||||
CompoundGraphic::from_graphics(vec![
|
||||
Graphic::image(self.imgs.banner_top, [138, 17], [0, 0]),
|
||||
Graphic::rect(Rgba::new(0, 0, 0, 230), [130, 195], [4, 17]),
|
||||
Graphic::image(self.imgs.banner, [130, 15], [4, 212])
|
||||
.color(Rgba::new(255, 255, 255, 230)),
|
||||
])
|
||||
.fix_aspect_ratio()
|
||||
.height(Length::Fill),
|
||||
banner_content,
|
||||
)
|
||||
.padding(Padding::new().horizontal(16).vertical(20))
|
||||
.max_width(330);
|
||||
|
||||
let central_column = Container::new(banner)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_x(Align::Center)
|
||||
.align_y(Align::Center);
|
||||
|
||||
let image3 = Image::new(self.imgs.banner_bottom).fix_aspect_ratio();
|
||||
|
||||
let content =
|
||||
Row::with_children(vec![buttons.into(), central_column.into(), image3.into()])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.spacing(10);
|
||||
|
||||
BackgroundContainer::new(Image::new(self.imgs.bg), content).into()
|
||||
}
|
||||
|
||||
pub fn update(&mut self, message: Message, events: &mut Vec<Event>) {
|
||||
match message {
|
||||
Message::Quit => events.push(Event::Quit),
|
||||
Message::ShowServers => self.show_servers = true,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
Message::Singleplayer => events.push(Event::StartSingleplayer),
|
||||
Message::Multiplayer => (), //TODO
|
||||
Message::Username(new_value) => self.username_value = new_value,
|
||||
Message::Password(new_value) => self.password_value = new_value,
|
||||
Message::Server(new_value) => self.server_value = new_value,
|
||||
Message::FocusPassword => {
|
||||
self.password_input = iced::text_input::State::focused();
|
||||
self.username_input = iced::text_input::State::new();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MainMenuUi {
|
||||
ui: Ui,
|
||||
ice_ui: IcedUi,
|
||||
@ -448,26 +339,6 @@ impl<'a> MainMenuUi {
|
||||
let window = &mut global_state.window;
|
||||
let networking = &global_state.settings.networking;
|
||||
let gameplay = &global_state.settings.gameplay;
|
||||
// Randomly loaded background images
|
||||
let bg_imgs = [
|
||||
"voxygen.background.bg_1",
|
||||
"voxygen.background.bg_2",
|
||||
"voxygen.background.bg_3",
|
||||
"voxygen.background.bg_4",
|
||||
"voxygen.background.bg_5",
|
||||
"voxygen.background.bg_6",
|
||||
"voxygen.background.bg_7",
|
||||
"voxygen.background.bg_8",
|
||||
"voxygen.background.bg_9",
|
||||
//"voxygen.background.bg_10",
|
||||
"voxygen.background.bg_11",
|
||||
//"voxygen.background.bg_12",
|
||||
"voxygen.background.bg_13",
|
||||
//"voxygen.background.bg_14",
|
||||
"voxygen.background.bg_15",
|
||||
"voxygen.background.bg_16",
|
||||
];
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let mut ui = Ui::new(window).unwrap();
|
||||
ui.set_scaling_mode(gameplay.ui_scale);
|
||||
@ -476,11 +347,8 @@ impl<'a> MainMenuUi {
|
||||
// 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_id = ui.add_graphic(Graphic::Image(
|
||||
DynamicImage::load_expect(bg_imgs.choose(&mut rng).unwrap()),
|
||||
None,
|
||||
));
|
||||
//let chosen_tip = *tips.choose(&mut rng).unwrap();
|
||||
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
|
||||
let i18n = Localization::load_expect(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
@ -502,7 +370,11 @@ 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"));
|
||||
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))),
|
||||
i18n.clone(),
|
||||
);
|
||||
|
||||
Self {
|
||||
ui,
|
||||
@ -1188,10 +1060,9 @@ impl<'a> MainMenuUi {
|
||||
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(&self.i18n),
|
||||
global_state.window.renderer_mut(),
|
||||
);
|
||||
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));
|
@ -1 +1,2 @@
|
||||
pub mod neat_button;
|
||||
pub use neat_button::neat_button;
|
||||
|
@ -1,29 +1,18 @@
|
||||
use crate::ui::ice as ui;
|
||||
use iced::{Button, Element, Length};
|
||||
use iced::{button::State, Button, Element, Length};
|
||||
use ui::{
|
||||
widget::{AspectRatioContainer, FillText},
|
||||
ButtonStyle,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct State {
|
||||
state: iced::button::State,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn new() -> Self { Self::default() }
|
||||
|
||||
pub fn view<M: Clone + 'static>(
|
||||
&mut self,
|
||||
pub fn neat_button<M: Clone + 'static>(
|
||||
state: &mut State,
|
||||
label: impl Into<String>,
|
||||
fill_fraction: f32,
|
||||
button_style: ButtonStyle,
|
||||
message: Option<M>,
|
||||
) -> Element<M, ui::IcedRenderer> {
|
||||
let button = Button::new(
|
||||
&mut self.state,
|
||||
FillText::new(label).fill_fraction(fill_fraction),
|
||||
)
|
||||
) -> Element<M, ui::IcedRenderer> {
|
||||
let button = Button::new(state, FillText::new(label).fill_fraction(fill_fraction))
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fill)
|
||||
.style(button_style);
|
||||
@ -40,5 +29,4 @@ impl State {
|
||||
};
|
||||
|
||||
container.into()
|
||||
}
|
||||
}
|
||||
|
@ -446,7 +446,7 @@ impl IcedRenderer {
|
||||
},
|
||||
Primitive::Text {
|
||||
glyphs,
|
||||
bounds, // iced::Rectangle
|
||||
bounds: _bounds, // iced::Rectangle
|
||||
linear_color,
|
||||
/*font,
|
||||
*horizontal_alignment,
|
||||
@ -505,8 +505,6 @@ impl IcedRenderer {
|
||||
},
|
||||
Primitive::Clip { bounds, content } => {
|
||||
let new_scissor = {
|
||||
let min_x = bounds.x;
|
||||
let min_y = bounds.y;
|
||||
let intersection = Aabr {
|
||||
min: Vec2 {
|
||||
x: (bounds.x * self.p_scale) as u16,
|
||||
|
@ -80,6 +80,13 @@ impl text::Renderer for IcedRenderer {
|
||||
.cache
|
||||
.glyph_cache_mut()
|
||||
.glyphs(section)
|
||||
.filter(|g| {
|
||||
!content[g.byte_index..]
|
||||
.chars()
|
||||
.next()
|
||||
.unwrap()
|
||||
.is_whitespace()
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
@ -37,7 +37,7 @@ impl text_input::Renderer for IcedRenderer {
|
||||
};
|
||||
|
||||
let mut glyph_calculator = self.cache.glyph_calculator();
|
||||
let mut width = glyph_calculator
|
||||
let width = glyph_calculator
|
||||
.glyph_bounds(section)
|
||||
.map_or(0.0, |rect| rect.width() / p_scale);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user