mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Basic structure of character selection
This commit is contained in:
parent
bc42f3f229
commit
de770694d8
BIN
assets/voxygen/element/frames/gray/corner.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/frames/gray/corner.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/frames/gray/edge.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/frames/gray/edge.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/frames/server_frame.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/server_frame.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/frames/window_4.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/window_4.vox
(Stored with Git LFS)
Binary file not shown.
@ -470,10 +470,10 @@ magischen Gegenstände ergattern?"#,
|
||||
"char_selection.change_server": "Server wechseln.",
|
||||
"char_selection.enter_world": "Betreten",
|
||||
"char_selection.logout": "Ausloggen",
|
||||
"char_selection.create_charater": "Charakter erstellen",
|
||||
"char_selection.create_character": "Charakter erstellen",
|
||||
"char_selection.create_new_character": "Neuen Charakter erstellen",
|
||||
"char_selection.creating_character": "Erstelle Charakter...",
|
||||
"char_selection.character_creation": "Charaktererstellung",
|
||||
"char_selection.create_new_charater": "Neuen Charakter erstellen",
|
||||
|
||||
"char_selection.human_default": "Human Default",
|
||||
"char_selection.level_fmt": "Level {level_nb}",
|
||||
|
@ -477,7 +477,7 @@ magically infused items?"#,
|
||||
"char_selection.change_server": "Change Server",
|
||||
"char_selection.enter_world": "Enter World",
|
||||
"char_selection.logout": "Logout",
|
||||
"char_selection.create_new_charater": "Create New Character",
|
||||
"char_selection.create_new_character": "Create New Character",
|
||||
"char_selection.creating_character": "Creating Character...",
|
||||
"char_selection.character_creation": "Character Creation",
|
||||
|
||||
|
@ -358,7 +358,7 @@ objetos imbuidos de magia?"#,
|
||||
"char_selection.change_server": "Cambiar de servidor",
|
||||
"char_selection.enter_world": "Entrar al mundo",
|
||||
"char_selection.logout": "Salir",
|
||||
"char_selection.create_new_charater": "Crear nuevo personaje",
|
||||
"char_selection.create_new_character": "Crear nuevo personaje",
|
||||
"char_selection.creating_character": "Creando personaje...",
|
||||
"char_selection.character_creation": "Creación de personaje",
|
||||
|
||||
|
@ -372,7 +372,7 @@ objets magiques ?"#,
|
||||
"char_selection.change_server": "Changer de serveur",
|
||||
"char_selection.enter_world": "Entrer dans le monde",
|
||||
"char_selection.logout": "Se déconnecter",
|
||||
"char_selection.create_new_charater": "Créer un nouveau personnage",
|
||||
"char_selection.create_new_character": "Créer un nouveau personnage",
|
||||
"char_selection.creating_character": "Création du personnage...",
|
||||
"char_selection.character_creation": "Création de personnage",
|
||||
|
||||
|
@ -462,7 +462,7 @@ oggetti infusi di magia?"#,
|
||||
"char_selection.change_server": "Cambia Server",
|
||||
"char_selection.enter_world": "Unisciti al Mondo",
|
||||
"char_selection.logout": "Disconnettiti",
|
||||
"char_selection.create_new_charater": "Crea un nuovo Personaggio",
|
||||
"char_selection.create_new_character": "Crea un nuovo Personaggio",
|
||||
"char_selection.creating_character": "Creazione Personaggio...",
|
||||
"char_selection.character_creation": "Creazione Personaggio",
|
||||
|
||||
|
@ -343,7 +343,7 @@ Comandos de chat:
|
||||
"char_selection.change_server": "Mudar de servidor",
|
||||
"char_selection.enter_world": "Entrar no mundo",
|
||||
"char_selection.logout": "Desconectar",
|
||||
"char_selection.create_new_charater": "Criar nova personagem",
|
||||
"char_selection.create_new_character": "Criar nova personagem",
|
||||
"char_selection.character_creation": "Criação de personagem",
|
||||
|
||||
"char_selection.human_default": "Humano padrão",
|
||||
|
@ -400,7 +400,7 @@ https://veloren.net/account/."#,
|
||||
"char_selection.change_server": "Сменить сервер",
|
||||
"char_selection.enter_world": "Войти в мир",
|
||||
"char_selection.logout": "Выйти в меню",
|
||||
"char_selection.create_new_charater": "Создать нового персонажа",
|
||||
"char_selection.create_new_character": "Создать нового персонажа",
|
||||
"char_selection.creating_character": "Создание персонажа...",
|
||||
"char_selection.character_creation": "Создание персонажа",
|
||||
|
||||
|
@ -37,9 +37,9 @@ impl CharSelectionState {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_humanoid_body(&self) -> Option<comp::humanoid::Body> {
|
||||
fn get_humanoid_body(&self, client: &Client) -> Option<comp::humanoid::Body> {
|
||||
self.char_selection_ui
|
||||
.selected_character()
|
||||
.display_character(&client.character_list.characters)
|
||||
.and_then(|character| match character.body {
|
||||
comp::Body::Humanoid(body) => Some(body),
|
||||
_ => None,
|
||||
@ -92,11 +92,8 @@ impl PlayState for CharSelectionState {
|
||||
ui::Event::DeleteCharacter(character_id) => {
|
||||
self.client.borrow_mut().delete_character(character_id);
|
||||
},
|
||||
ui::Event::Play(character) => {
|
||||
// TODO: eliminate option in character id
|
||||
if let Some(character_id) = character.character.id {
|
||||
self.client.borrow_mut().request_character(character_id);
|
||||
}
|
||||
ui::Event::Play(character_id) => {
|
||||
self.client.borrow_mut().request_character(character_id);
|
||||
|
||||
return PlayStateResult::Switch(Box::new(SessionState::new(
|
||||
global_state,
|
||||
@ -106,12 +103,15 @@ impl PlayState for CharSelectionState {
|
||||
}
|
||||
}
|
||||
|
||||
let humanoid_body = self.get_humanoid_body();
|
||||
let loadout = self.char_selection_ui.get_loadout();
|
||||
|
||||
// Maintain the scene.
|
||||
{
|
||||
let client = self.client.borrow();
|
||||
let humanoid_body = self.get_humanoid_body(&client);
|
||||
let loadout = self.char_selection_ui.get_loadout();
|
||||
|
||||
// Maintain the scene.
|
||||
let scene_data = scene::SceneData {
|
||||
time: client.state().get_time(),
|
||||
delta_time: client.state().ecs().read_resource::<DeltaTime>().0,
|
||||
@ -127,6 +127,7 @@ impl PlayState for CharSelectionState {
|
||||
.figure_lod_render_distance
|
||||
as f32,
|
||||
};
|
||||
|
||||
self.scene.maintain(
|
||||
global_state.window.renderer_mut(),
|
||||
scene_data,
|
||||
@ -185,16 +186,13 @@ impl PlayState for CharSelectionState {
|
||||
fn name(&self) -> &'static str { "Title" }
|
||||
|
||||
fn render(&mut self, renderer: &mut Renderer, _: &Settings) {
|
||||
let humanoid_body = self.get_humanoid_body();
|
||||
let client = self.client.borrow();
|
||||
let humanoid_body = self.get_humanoid_body(&client);
|
||||
let loadout = self.char_selection_ui.get_loadout();
|
||||
|
||||
// Render the scene.
|
||||
self.scene.render(
|
||||
renderer,
|
||||
self.client.borrow().get_tick(),
|
||||
humanoid_body,
|
||||
loadout.as_ref(),
|
||||
);
|
||||
self.scene
|
||||
.render(renderer, client.get_tick(), humanoid_body, loadout.as_ref());
|
||||
|
||||
// Draw the UI to the screen.
|
||||
self.char_selection_ui.render(renderer);
|
||||
|
@ -4,7 +4,12 @@ use crate::{
|
||||
ui::{
|
||||
self,
|
||||
fonts::IcedFonts as Fonts,
|
||||
ice::{component::neat_button, style, widget::Overlay, Element, IcedUi as Ui},
|
||||
ice::{
|
||||
component::neat_button,
|
||||
style,
|
||||
widget::{AspectRatioContainer, Overlay},
|
||||
Element, IcedUi as Ui,
|
||||
},
|
||||
img_ids::{ImageGraphic, VoxelGraphic},
|
||||
},
|
||||
window, GlobalState,
|
||||
@ -13,33 +18,42 @@ use client::Client;
|
||||
use common::{
|
||||
assets::Asset,
|
||||
character::{CharacterId, CharacterItem, MAX_CHARACTERS_PER_PLAYER},
|
||||
comp,
|
||||
comp::humanoid,
|
||||
comp::{self, humanoid},
|
||||
};
|
||||
//ImageFrame, Tooltip,
|
||||
use crate::settings::Settings;
|
||||
//use std::time::Duration;
|
||||
//use ui::ice::widget;
|
||||
use iced::{
|
||||
button, text_input, Align, Button, Column, Container, HorizontalAlignment, Length, Row, Space,
|
||||
Text,
|
||||
button, scrollable, text_input, Align, Button, Column, Container, HorizontalAlignment, Length,
|
||||
Row, Scrollable, Space, Text,
|
||||
};
|
||||
use vek::Rgba;
|
||||
|
||||
pub const TEXT_COLOR: iced::Color = iced::Color::from_rgb(1.0, 1.0, 1.0);
|
||||
pub 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 FILL_FRAC_TWO: f32 = 0.60;
|
||||
|
||||
const STARTER_HAMMER: &str = "common.items.weapons.hammer.starter_hammer";
|
||||
const STARTER_BOW: &str = "common.items.weapons.bow.starter_bow";
|
||||
const STARTER_AXE: &str = "common.items.weapons.axe.starter_axe";
|
||||
const STARTER_STAFF: &str = "common.items.weapons.staff.starter_staff";
|
||||
const STARTER_SWORD: &str = "common.items.weapons.sword.starter_sword";
|
||||
|
||||
// TODO: look into what was using this in old ui
|
||||
const UI_MAIN: iced::Color = iced::Color::from_rgba(0.61, 0.70, 0.70, 1.0); // Greenish Blue
|
||||
|
||||
image_ids_ice! {
|
||||
struct Imgs {
|
||||
<VoxelGraphic>
|
||||
// TODO: convert large frames into borders
|
||||
charlist_frame: "voxygen.element.frames.window_4",
|
||||
server_frame: "voxygen.element.frames.server_frame",
|
||||
slider_range: "voxygen.element.slider.track",
|
||||
slider_indicator: "voxygen.element.slider.indicator",
|
||||
|
||||
<ImageGraphic>
|
||||
gray_corner: "voxygen.element.frames.gray.corner",
|
||||
gray_edge: "voxygen.element.frames.gray.edge",
|
||||
|
||||
selection: "voxygen.element.frames.selection",
|
||||
selection_hover: "voxygen.element.frames.selection_hover",
|
||||
selection_press: "voxygen.element.frames.selection_press",
|
||||
@ -48,7 +62,6 @@ image_ids_ice! {
|
||||
delete_button_hover: "voxygen.element.buttons.x_red_hover",
|
||||
delete_button_press: "voxygen.element.buttons.x_red_press",
|
||||
|
||||
|
||||
name_input: "voxygen.element.misc_bg.textbox",
|
||||
|
||||
// Tool Icons
|
||||
@ -80,7 +93,6 @@ image_ids_ice! {
|
||||
icon_border_press: "voxygen.element.buttons.border_press",
|
||||
icon_border_pressed: "voxygen.element.buttons.border_pressed",
|
||||
|
||||
<ImageGraphic>
|
||||
button: "voxygen.element.buttons.button",
|
||||
button_hover: "voxygen.element.buttons.button_hover",
|
||||
button_press: "voxygen.element.buttons.button_press",
|
||||
@ -100,7 +112,7 @@ image_ids_ice! {
|
||||
|
||||
pub enum Event {
|
||||
Logout,
|
||||
Play(CharacterItem),
|
||||
Play(CharacterId),
|
||||
AddCharacter {
|
||||
alias: String,
|
||||
tool: Option<String>,
|
||||
@ -109,17 +121,14 @@ pub enum Event {
|
||||
DeleteCharacter(CharacterId),
|
||||
}
|
||||
|
||||
struct CharacterList {
|
||||
characters: Vec<CharacterItem>,
|
||||
selected_character: usize,
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
Select {
|
||||
list: Option<CharacterList>,
|
||||
// Index of selected character
|
||||
selected: Option<usize>,
|
||||
|
||||
characters_scroll: scrollable::State,
|
||||
character_buttons: Vec<button::State>,
|
||||
new_character_button: button::State,
|
||||
|
||||
logout_button: button::State,
|
||||
enter_world_button: button::State,
|
||||
change_server_button: button::State,
|
||||
@ -136,6 +145,33 @@ enum Mode {
|
||||
},
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
pub fn select() -> Self {
|
||||
Self::Select {
|
||||
selected: None,
|
||||
characters_scroll: Default::default(),
|
||||
character_buttons: Vec::new(),
|
||||
new_character_button: Default::default(),
|
||||
logout_button: Default::default(),
|
||||
enter_world_button: Default::default(),
|
||||
change_server_button: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(name: String) -> Self {
|
||||
Self::Create {
|
||||
name,
|
||||
body: humanoid::Body::random(),
|
||||
loadout: comp::Loadout::default(),
|
||||
tool: Some(STARTER_SWORD),
|
||||
|
||||
name_input: Default::default(),
|
||||
back_button: Default::default(),
|
||||
create_button: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum InfoContent {
|
||||
Deletion(usize),
|
||||
@ -202,22 +238,16 @@ impl Controls {
|
||||
alpha,
|
||||
|
||||
info_content: None,
|
||||
mode: Mode::Select {
|
||||
list: None,
|
||||
character_buttons: Vec::new(),
|
||||
new_character_button: Default::default(),
|
||||
logout_button: Default::default(),
|
||||
enter_world_button: Default::default(),
|
||||
change_server_button: Default::default(),
|
||||
},
|
||||
mode: Mode::select(),
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&mut self, settings: &Settings) -> Element<Message> {
|
||||
fn view(&mut self, settings: &Settings, client: &Client) -> Element<Message> {
|
||||
// TODO: if enter key pressed and character is selected then enter the world
|
||||
// TODO: tooltip widget
|
||||
|
||||
let imgs = &self.imgs;
|
||||
let fonts = &self.fonts;
|
||||
let i18n = &self.i18n;
|
||||
|
||||
let button_style = style::button::Style::new(imgs.button)
|
||||
@ -232,7 +262,7 @@ impl Controls {
|
||||
.horizontal_alignment(HorizontalAlignment::Right);
|
||||
|
||||
let alpha = iced::Text::new(&self.alpha)
|
||||
.size(self.fonts.cyri.scale(15))
|
||||
.size(self.fonts.cyri.scale(12))
|
||||
.width(Length::Fill)
|
||||
.horizontal_alignment(HorizontalAlignment::Center);
|
||||
|
||||
@ -245,7 +275,8 @@ impl Controls {
|
||||
|
||||
let content = match &mut self.mode {
|
||||
Mode::Select {
|
||||
list,
|
||||
selected,
|
||||
ref mut characters_scroll,
|
||||
ref mut character_buttons,
|
||||
ref mut new_character_button,
|
||||
ref mut logout_button,
|
||||
@ -253,14 +284,41 @@ impl Controls {
|
||||
ref mut change_server_button,
|
||||
} => {
|
||||
// TODO: impl delete prompt as overlay
|
||||
let change_server = Space::new(Length::Units(100), Length::Units(40));
|
||||
let characters = if let Some(list) = list {
|
||||
let num = list.characters.len();
|
||||
let server = Container::new(
|
||||
Column::with_children(vec![
|
||||
Text::new(&client.server_info.name)
|
||||
.size(fonts.cyri.scale(25))
|
||||
//.horizontal_alignment(HorizontalAlignment::Center)
|
||||
.into(),
|
||||
Container::new(neat_button(
|
||||
change_server_button,
|
||||
i18n.get("char_selection.change_server"),
|
||||
FILL_FRAC_TWO,
|
||||
button_style,
|
||||
Some(Message::ChangeServer),
|
||||
))
|
||||
.height(Length::Units(35))
|
||||
.into(),
|
||||
])
|
||||
.spacing(5)
|
||||
.align_items(Align::Center),
|
||||
)
|
||||
.style(style::container::Style::color_with_image_border(
|
||||
Rgba::new(0, 0, 0, 217),
|
||||
imgs.gray_corner,
|
||||
imgs.gray_edge,
|
||||
))
|
||||
.padding(12)
|
||||
.center_x()
|
||||
.width(Length::Fill);
|
||||
|
||||
let characters = {
|
||||
let characters = &client.character_list.characters;
|
||||
let num = characters.len();
|
||||
// Ensure we have enough button states
|
||||
character_buttons.resize_with(num * 2, Default::default);
|
||||
|
||||
let mut characters = list
|
||||
.characters
|
||||
let mut characters = characters
|
||||
.iter()
|
||||
.zip(character_buttons.chunks_exact_mut(2))
|
||||
.map(|(character, buttons)| {
|
||||
@ -273,65 +331,102 @@ impl Controls {
|
||||
.enumerate()
|
||||
.map(|(i, (character, (select_button, delete_button)))| {
|
||||
Overlay::new(
|
||||
Button::new(select_button, Space::new(Length::Fill, Length::Fill))
|
||||
.width(Length::Units(20))
|
||||
.height(Length::Units(20))
|
||||
.style(
|
||||
style::button::Style::new(imgs.delete_button)
|
||||
.hover_image(imgs.delete_button_hover)
|
||||
.press_image(imgs.delete_button_press),
|
||||
),
|
||||
Button::new(
|
||||
delete_button,
|
||||
Column::with_children(vec![
|
||||
Text::new("Hi").into(),
|
||||
Text::new("Hi").into(),
|
||||
Text::new("Hi").into(),
|
||||
]),
|
||||
select_button,
|
||||
Space::new(Length::Units(20), Length::Units(20)),
|
||||
)
|
||||
.style(
|
||||
style::button::Style::new(imgs.selection)
|
||||
.hover_image(imgs.selection_hover)
|
||||
.press_image(imgs.selection_press),
|
||||
style::button::Style::new(imgs.delete_button)
|
||||
.hover_image(imgs.delete_button_hover)
|
||||
.press_image(imgs.delete_button_press),
|
||||
),
|
||||
AspectRatioContainer::new(
|
||||
Button::new(
|
||||
delete_button,
|
||||
Column::with_children(vec![
|
||||
Text::new("Hi").width(Length::Fill).into(),
|
||||
Text::new("Hi").into(),
|
||||
Text::new("Hi").into(),
|
||||
]),
|
||||
)
|
||||
.style(
|
||||
style::button::Style::new(imgs.selection)
|
||||
.hover_image(imgs.selection_hover)
|
||||
.press_image(imgs.selection_press),
|
||||
),
|
||||
)
|
||||
.ratio_of_image(imgs.selection),
|
||||
)
|
||||
.padding(15)
|
||||
.align_x(Align::End)
|
||||
.into()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Add create new character button
|
||||
let color = if num >= MAX_CHARACTERS_PER_PLAYER {
|
||||
iced::Color::from_rgb8(97, 97, 25)
|
||||
(97, 97, 25)
|
||||
} else {
|
||||
iced::Color::from_rgb8(97, 255, 18)
|
||||
(97, 255, 18)
|
||||
};
|
||||
characters.push(
|
||||
Button::new(
|
||||
new_character_button,
|
||||
Text::new(i18n.get("char_selection.create_new_character")),
|
||||
)
|
||||
.style(
|
||||
style::button::Style::new(imgs.selection)
|
||||
.hover_image(imgs.selection_hover)
|
||||
.press_image(imgs.selection_press)
|
||||
.image_color(color)
|
||||
.text_color(color),
|
||||
)
|
||||
AspectRatioContainer::new({
|
||||
let button = Button::new(
|
||||
new_character_button,
|
||||
Container::new(Text::new(
|
||||
i18n.get("char_selection.create_new_character"),
|
||||
))
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.center_x()
|
||||
.center_y(),
|
||||
)
|
||||
.style(
|
||||
style::button::Style::new(imgs.selection)
|
||||
.hover_image(imgs.selection_hover)
|
||||
.press_image(imgs.selection_press)
|
||||
.image_color(Rgba::new(color.0, color.1, color.2, 255))
|
||||
.text_color(iced::Color::from_rgb8(color.0, color.1, color.2))
|
||||
.disabled_text_color(iced::Color::from_rgb8(
|
||||
color.0, color.1, color.2,
|
||||
)),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill);
|
||||
// TODO: try to get better interface for this in iced
|
||||
if num < MAX_CHARACTERS_PER_PLAYER {
|
||||
button.on_press(Message::NewCharacter)
|
||||
} else {
|
||||
button
|
||||
}
|
||||
})
|
||||
.ratio_of_image(imgs.selection)
|
||||
.into(),
|
||||
);
|
||||
characters
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let characters = Column::with_children(characters);
|
||||
// TODO: could replace column with scrollable completely if it had a with
|
||||
// children method
|
||||
let characters = Container::new(
|
||||
Scrollable::new(characters_scroll)
|
||||
.push(Column::with_children(characters).spacing(2)),
|
||||
)
|
||||
.style(style::container::Style::color_with_image_border(
|
||||
Rgba::new(0, 0, 0, 217),
|
||||
imgs.gray_corner,
|
||||
imgs.gray_edge,
|
||||
))
|
||||
.padding(9)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill);
|
||||
|
||||
let right_column =
|
||||
Column::with_children(vec![change_server.into(), characters.into()])
|
||||
.spacing(10)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.max_width(300);
|
||||
let right_column = Column::with_children(vec![server.into(), characters.into()])
|
||||
.padding(15)
|
||||
.spacing(10)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.max_width(360);
|
||||
|
||||
let top = Container::new(right_column)
|
||||
.width(Length::Fill)
|
||||
@ -350,23 +445,22 @@ impl Controls {
|
||||
i18n.get("char_selection.enter_world"),
|
||||
FILL_FRAC_ONE,
|
||||
button_style,
|
||||
Some(Message::EnterWorld),
|
||||
selected.map(|_| Message::EnterWorld),
|
||||
);
|
||||
|
||||
let bottom = Row::with_children(vec![
|
||||
Container::new(logout)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Units(40))
|
||||
.align_y(Align::End)
|
||||
.into(),
|
||||
Container::new(enter_world)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Units(60))
|
||||
.center_x()
|
||||
.align_y(Align::End)
|
||||
.into(),
|
||||
Space::new(Length::Fill, Length::Shrink).into(),
|
||||
]);
|
||||
])
|
||||
.align_items(Align::End);
|
||||
|
||||
Column::with_children(vec![top.into(), bottom.into()])
|
||||
.width(Length::Fill)
|
||||
@ -400,13 +494,72 @@ impl Controls {
|
||||
.into()
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message, events: &mut Vec<Event>, settings: &Settings) {
|
||||
fn update(
|
||||
&mut self,
|
||||
message: Message,
|
||||
events: &mut Vec<Event>,
|
||||
settings: &Settings,
|
||||
characters: &[CharacterItem],
|
||||
) {
|
||||
let servers = &settings.networking.servers;
|
||||
|
||||
//match message { }
|
||||
match message {
|
||||
Message::Back => {
|
||||
if matches!(&self.mode, Mode::Create { .. }) {
|
||||
self.mode = Mode::select();
|
||||
}
|
||||
},
|
||||
Message::Logout => {
|
||||
events.push(Event::Logout);
|
||||
},
|
||||
Message::EnterWorld => {
|
||||
if let Mode::Select {
|
||||
selected: Some(selected),
|
||||
..
|
||||
} = &self.mode
|
||||
{
|
||||
// TODO: eliminate option in character id
|
||||
if let Some(id) = characters.get(*selected).and_then(|i| i.character.id) {
|
||||
events.push(Event::Play(id));
|
||||
}
|
||||
}
|
||||
},
|
||||
Message::Delete(idx) => {
|
||||
if let Some(id) = characters.get(idx).and_then(|i| i.character.id) {
|
||||
events.push(Event::DeleteCharacter(id));
|
||||
}
|
||||
},
|
||||
Message::ChangeServer => {
|
||||
events.push(Event::Logout);
|
||||
},
|
||||
Message::NewCharacter => {
|
||||
if matches!(&self.mode, Mode::Select { .. }) {
|
||||
self.mode = Mode::create(String::new());
|
||||
}
|
||||
},
|
||||
Message::CreateCharacter => {
|
||||
if let Mode::Create {
|
||||
name, body, tool, ..
|
||||
} = &self.mode
|
||||
{
|
||||
events.push(Event::AddCharacter {
|
||||
alias: name.clone(),
|
||||
tool: tool.map(String::from),
|
||||
body: comp::Body::Humanoid(*body),
|
||||
});
|
||||
self.mode = Mode::select();
|
||||
}
|
||||
},
|
||||
Message::Name(value) => {
|
||||
if let Mode::Create { name, .. } = &mut self.mode {
|
||||
*name = value;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn selected_character(&self) -> Option<&CharacterItem> {
|
||||
/// Get the character to display
|
||||
pub fn display_character(&self, characters: &[CharacterItem]) -> Option<&CharacterItem> {
|
||||
match self.mode {
|
||||
// TODO
|
||||
Mode::Select { .. } => None,
|
||||
@ -454,12 +607,13 @@ impl CharSelectionUi {
|
||||
Self { ui, controls }
|
||||
}
|
||||
|
||||
pub fn selected_character(&self) -> Option<&CharacterItem> {
|
||||
self.controls.selected_character()
|
||||
pub fn display_character(&self, characters: &[CharacterItem]) -> Option<&CharacterItem> {
|
||||
self.controls.display_character(characters)
|
||||
}
|
||||
|
||||
// TODO
|
||||
pub fn get_loadout(&mut self) -> Option<comp::Loadout> {
|
||||
// TODO: error gracefully
|
||||
// TODO: don't clone
|
||||
/*match &mut self.mode {
|
||||
Mode::Select(character_list) => {
|
||||
@ -471,20 +625,20 @@ impl CharSelectionUi {
|
||||
},
|
||||
Mode::Create { loadout, tool, .. } => {
|
||||
loadout.active_item = tool.map(|tool| comp::ItemConfig {
|
||||
item: (*load_expect::<comp::Item>(tool)).clone(),
|
||||
item: comp::Item::new_from_asset_expect(tool),
|
||||
ability1: None,
|
||||
ability2: None,
|
||||
ability3: None,
|
||||
block_ability: None,
|
||||
dodge_ability: None,
|
||||
});
|
||||
loadout.chest = Some(assets::load_expect_cloned(
|
||||
loadout.chest = Some(comp::Item::new_from_asset_expect(
|
||||
"common.items.armor.starter.rugged_chest",
|
||||
));
|
||||
loadout.pants = Some(assets::load_expect_cloned(
|
||||
loadout.pants = Some(comp::Item::new_from_asset_expect(
|
||||
"common.items.armor.starter.rugged_pants",
|
||||
));
|
||||
loadout.foot = Some(assets::load_expect_cloned(
|
||||
loadout.foot = Some(comp::Item::new_from_asset_expect(
|
||||
"common.items.armor.starter.sandals_0",
|
||||
));
|
||||
Some(loadout.clone())
|
||||
@ -508,17 +662,22 @@ impl CharSelectionUi {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do we need whole client here or just character list
|
||||
pub fn maintain(&mut self, global_state: &mut GlobalState, client: &mut Client) -> Vec<Event> {
|
||||
let mut events = Vec::new();
|
||||
|
||||
let (messages, _) = self.ui.maintain(
|
||||
self.controls.view(&global_state.settings),
|
||||
self.controls.view(&global_state.settings, &client),
|
||||
global_state.window.renderer_mut(),
|
||||
);
|
||||
|
||||
messages.into_iter().for_each(|message| {
|
||||
self.controls
|
||||
.update(message, &mut events, &global_state.settings)
|
||||
self.controls.update(
|
||||
message,
|
||||
&mut events,
|
||||
&global_state.settings,
|
||||
&client.character_list.characters,
|
||||
)
|
||||
});
|
||||
|
||||
events
|
||||
|
@ -98,11 +98,13 @@ impl Screen {
|
||||
.height(Length::Fill);
|
||||
|
||||
let prompt_window = Container::new(content)
|
||||
.style(style::container::Style::color_double_cornerless_border(
|
||||
(22, 18, 16, 255).into(),
|
||||
(11, 11, 11, 255).into(),
|
||||
(54, 46, 38, 255).into(),
|
||||
))
|
||||
.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)
|
||||
|
@ -64,11 +64,13 @@ impl Screen {
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill),
|
||||
)
|
||||
.style(style::container::Style::color_double_cornerless_border(
|
||||
(22, 19, 17, 255).into(),
|
||||
(11, 11, 11, 255).into(),
|
||||
(54, 46, 38, 255).into(),
|
||||
)),
|
||||
.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()
|
||||
|
@ -95,7 +95,7 @@ impl Screen {
|
||||
// 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::gradient(Rgba::new(0, 0, 0, 240), Rgba::zero(), [500, 30], [0, 300]),
|
||||
Graphic::gradient(Rgba::new(0, 0, 0, 240), Rgba::zero(), [500, 50], [0, 300]),
|
||||
])
|
||||
.height(Length::Shrink),
|
||||
Text::new(intro_text).size(fonts.cyri.scale(21)),
|
||||
@ -128,11 +128,13 @@ impl Screen {
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.style(style::container::Style::color_double_cornerless_border(
|
||||
(22, 18, 16, 255).into(),
|
||||
(11, 11, 11, 255).into(),
|
||||
(54, 46, 38, 255).into(),
|
||||
))
|
||||
.style(
|
||||
style::container::Style::color_with_double_cornerless_border(
|
||||
(22, 18, 16, 255).into(),
|
||||
(11, 11, 11, 255).into(),
|
||||
(54, 46, 38, 255).into(),
|
||||
),
|
||||
)
|
||||
.width(Length::Units(400))
|
||||
.height(Length::Units(180))
|
||||
.padding(20)
|
||||
|
@ -239,7 +239,7 @@ impl Controls {
|
||||
.horizontal_alignment(HorizontalAlignment::Right);
|
||||
|
||||
let alpha = iced::Text::new(&self.alpha)
|
||||
.size(self.fonts.cyri.scale(15))
|
||||
.size(self.fonts.cyri.scale(12))
|
||||
.width(Length::Fill)
|
||||
.horizontal_alignment(HorizontalAlignment::Center);
|
||||
|
||||
|
@ -81,11 +81,13 @@ impl Screen {
|
||||
.spacing(10)
|
||||
.padding(20),
|
||||
)
|
||||
.style(style::container::Style::color_double_cornerless_border(
|
||||
(22, 18, 16, 255).into(),
|
||||
(11, 11, 11, 255).into(),
|
||||
(54, 46, 38, 255).into(),
|
||||
))
|
||||
.style(
|
||||
style::container::Style::color_with_double_cornerless_border(
|
||||
(22, 18, 16, 255).into(),
|
||||
(11, 11, 11, 255).into(),
|
||||
(54, 46, 38, 255).into(),
|
||||
),
|
||||
)
|
||||
.max_width(500),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
|
@ -24,7 +24,7 @@ pub fn neat_button<M: Clone + 'static>(
|
||||
|
||||
let container = AspectRatioContainer::new(button);
|
||||
let container = match button_style.active().0 {
|
||||
Some(img) => container.ratio_of_image(img),
|
||||
Some((img, _)) => container.ratio_of_image(img),
|
||||
None => container,
|
||||
};
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
use super::super::super::widget::image;
|
||||
use iced::Color;
|
||||
use vek::Rgba;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Background {
|
||||
default: image::Handle,
|
||||
hover: image::Handle,
|
||||
press: image::Handle,
|
||||
color: Color,
|
||||
color: Rgba<u8>,
|
||||
}
|
||||
|
||||
impl Background {
|
||||
@ -15,7 +16,7 @@ impl Background {
|
||||
default: image,
|
||||
hover: image,
|
||||
press: image,
|
||||
color: Color::WHITE,
|
||||
color: Rgba::white(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -62,7 +63,7 @@ impl Style {
|
||||
|
||||
// TODO: this needs to be refactored since the color isn't used if there is no
|
||||
// background
|
||||
pub fn image_color(mut self, color: Color) -> Self {
|
||||
pub fn image_color(mut self, color: Rgba<u8>) -> Self {
|
||||
if let Some(background) = &mut self.background {
|
||||
background.color = color;
|
||||
}
|
||||
@ -79,24 +80,30 @@ impl Style {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn disabled(&self) -> (Option<image::Handle>, Color) {
|
||||
pub fn disabled(&self) -> (Option<(image::Handle, Rgba<u8>)>, Color) {
|
||||
(
|
||||
self.background.as_ref().map(|b| b.default),
|
||||
self.background.as_ref().map(|b| (b.default, b.color)),
|
||||
self.disabled_text,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn pressed(&self) -> (Option<image::Handle>, Color) {
|
||||
(self.background.as_ref().map(|b| b.press), self.enabled_text)
|
||||
}
|
||||
|
||||
pub fn hovered(&self) -> (Option<image::Handle>, Color) {
|
||||
(self.background.as_ref().map(|b| b.hover), self.enabled_text)
|
||||
}
|
||||
|
||||
pub fn active(&self) -> (Option<image::Handle>, Color) {
|
||||
pub fn pressed(&self) -> (Option<(image::Handle, Rgba<u8>)>, Color) {
|
||||
(
|
||||
self.background.as_ref().map(|b| b.default),
|
||||
self.background.as_ref().map(|b| (b.press, b.color)),
|
||||
self.enabled_text,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn hovered(&self) -> (Option<(image::Handle, Rgba<u8>)>, Color) {
|
||||
(
|
||||
self.background.as_ref().map(|b| (b.hover, b.color)),
|
||||
self.enabled_text,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn active(&self) -> (Option<(image::Handle, Rgba<u8>)>, Color) {
|
||||
(
|
||||
self.background.as_ref().map(|b| (b.default, b.color)),
|
||||
self.enabled_text,
|
||||
)
|
||||
}
|
||||
|
@ -3,7 +3,14 @@ use vek::Rgba;
|
||||
|
||||
/// Container Border
|
||||
pub enum Border {
|
||||
DoubleCornerless { inner: Rgba<u8>, outer: Rgba<u8> },
|
||||
DoubleCornerless {
|
||||
inner: Rgba<u8>,
|
||||
outer: Rgba<u8>,
|
||||
},
|
||||
Image {
|
||||
corner: image::Handle,
|
||||
edge: image::Handle,
|
||||
},
|
||||
None,
|
||||
}
|
||||
|
||||
@ -22,13 +29,23 @@ impl Style {
|
||||
pub fn color(color: Rgba<u8>) -> Self { Self::Color(color, Border::None) }
|
||||
|
||||
/// Shorthand for a color background with a cornerless border
|
||||
pub fn color_double_cornerless_border(
|
||||
pub fn color_with_double_cornerless_border(
|
||||
color: Rgba<u8>,
|
||||
inner: Rgba<u8>,
|
||||
outer: Rgba<u8>,
|
||||
) -> Self {
|
||||
Self::Color(color, Border::DoubleCornerless { inner, outer })
|
||||
}
|
||||
|
||||
/// Shorthand for a color background with image borders where the corners
|
||||
/// are inset
|
||||
pub fn color_with_image_border(
|
||||
color: Rgba<u8>,
|
||||
corner: image::Handle,
|
||||
edge: image::Handle,
|
||||
) -> Self {
|
||||
Self::Color(color, Border::Image { corner, edge })
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Style {
|
||||
|
@ -1,6 +1,5 @@
|
||||
use super::super::{super::Rotation, style, Defaults, IcedRenderer, Primitive};
|
||||
use iced::{button, mouse, Element, Layout, Point, Rectangle};
|
||||
use vek::Rgba;
|
||||
|
||||
impl button::Renderer for IcedRenderer {
|
||||
// TODO: what if this gets large enough to not be copied around?
|
||||
@ -40,11 +39,11 @@ impl button::Renderer for IcedRenderer {
|
||||
cursor_position,
|
||||
);
|
||||
|
||||
let primitive = if let Some(handle) = maybe_image {
|
||||
let primitive = if let Some((handle, color)) = maybe_image {
|
||||
let background = Primitive::Image {
|
||||
handle: (handle, Rotation::None),
|
||||
bounds,
|
||||
color: Rgba::broadcast(255),
|
||||
color,
|
||||
};
|
||||
|
||||
Primitive::Group {
|
||||
|
@ -2,7 +2,9 @@ use super::super::{super::Rotation, style, IcedRenderer, Primitive};
|
||||
use common::util::srgba_to_linear;
|
||||
use iced::{container, Element, Layout, Point, Rectangle};
|
||||
use style::container::Border;
|
||||
use vek::Rgba;
|
||||
|
||||
// TODO: move to style
|
||||
const BORDER_SIZE: u16 = 8;
|
||||
|
||||
impl container::Renderer for IcedRenderer {
|
||||
@ -148,6 +150,125 @@ impl container::Renderer for IcedRenderer {
|
||||
content,
|
||||
]
|
||||
},
|
||||
Border::Image { corner, edge } => {
|
||||
let border_size = f32::from(BORDER_SIZE)
|
||||
.min(bounds.width / 4.0)
|
||||
.min(bounds.height / 4.0);
|
||||
|
||||
let center = Primitive::Rectangle {
|
||||
bounds: Rectangle {
|
||||
x: bounds.x + border_size,
|
||||
y: bounds.y + border_size,
|
||||
width: bounds.width - border_size * 2.0,
|
||||
height: bounds.height - border_size * 2.0,
|
||||
},
|
||||
linear_color,
|
||||
};
|
||||
|
||||
let color = Rgba::white();
|
||||
|
||||
let tl_corner = Primitive::Image {
|
||||
handle: (*corner, Rotation::None),
|
||||
bounds: Rectangle {
|
||||
x: bounds.x,
|
||||
y: bounds.y,
|
||||
width: border_size,
|
||||
height: border_size,
|
||||
},
|
||||
color,
|
||||
};
|
||||
|
||||
let tr_corner = Primitive::Image {
|
||||
handle: (*corner, Rotation::Cw90),
|
||||
bounds: Rectangle {
|
||||
x: bounds.x + bounds.width - border_size,
|
||||
y: bounds.y,
|
||||
width: border_size,
|
||||
height: border_size,
|
||||
},
|
||||
color,
|
||||
};
|
||||
|
||||
let bl_corner = Primitive::Image {
|
||||
handle: (*corner, Rotation::Cw270),
|
||||
bounds: Rectangle {
|
||||
x: bounds.x,
|
||||
y: bounds.y + bounds.height - border_size,
|
||||
width: border_size,
|
||||
height: border_size,
|
||||
},
|
||||
color,
|
||||
};
|
||||
|
||||
let br_corner = Primitive::Image {
|
||||
handle: (*corner, Rotation::Cw180),
|
||||
bounds: Rectangle {
|
||||
x: bounds.x + bounds.width - border_size,
|
||||
y: bounds.y + bounds.height - border_size,
|
||||
width: border_size,
|
||||
height: border_size,
|
||||
},
|
||||
color,
|
||||
};
|
||||
|
||||
let top_edge = Primitive::Image {
|
||||
handle: (*edge, Rotation::None),
|
||||
bounds: Rectangle {
|
||||
x: bounds.x + border_size,
|
||||
y: bounds.y,
|
||||
width: bounds.width - 2.0 * border_size,
|
||||
height: border_size,
|
||||
},
|
||||
color,
|
||||
};
|
||||
|
||||
let bottom_edge = Primitive::Image {
|
||||
handle: (*edge, Rotation::Cw180),
|
||||
bounds: Rectangle {
|
||||
x: bounds.x + border_size,
|
||||
y: bounds.y + bounds.height - border_size,
|
||||
width: bounds.width - 2.0 * border_size,
|
||||
height: border_size,
|
||||
},
|
||||
color,
|
||||
};
|
||||
|
||||
let left_edge = Primitive::Image {
|
||||
handle: (*edge, Rotation::Cw270),
|
||||
bounds: Rectangle {
|
||||
x: bounds.x,
|
||||
y: bounds.y + border_size,
|
||||
width: border_size,
|
||||
height: bounds.height - 2.0 * border_size,
|
||||
},
|
||||
color,
|
||||
};
|
||||
|
||||
let right_edge = Primitive::Image {
|
||||
handle: (*edge, Rotation::Cw90),
|
||||
bounds: Rectangle {
|
||||
x: bounds.x + bounds.width - border_size,
|
||||
y: bounds.y + border_size,
|
||||
width: border_size,
|
||||
height: bounds.height - 2.0 * border_size,
|
||||
},
|
||||
color,
|
||||
};
|
||||
|
||||
// Is this worth it as opposed to using a giant image? (Probably)
|
||||
vec![
|
||||
center,
|
||||
tl_corner,
|
||||
tr_corner,
|
||||
bl_corner,
|
||||
br_corner,
|
||||
top_edge,
|
||||
bottom_edge,
|
||||
left_edge,
|
||||
right_edge,
|
||||
content,
|
||||
]
|
||||
},
|
||||
};
|
||||
|
||||
Primitive::Group { primitives }
|
||||
|
@ -112,12 +112,12 @@ where
|
||||
let under_size = under.size();
|
||||
|
||||
let limits = limits.pad(padding);
|
||||
let mut over = self.under.layout(renderer, &limits.loose());
|
||||
let mut over = self.over.layout(renderer, &limits.loose());
|
||||
let over_size = over.size();
|
||||
|
||||
let size = limits.resolve(Size {
|
||||
width: under_size.width.max(over_size.width),
|
||||
height: under_size.width.max(over_size.width),
|
||||
height: under_size.height.max(over_size.height),
|
||||
});
|
||||
|
||||
over.move_to(Point::new(padding, padding));
|
||||
|
Loading…
Reference in New Issue
Block a user