Rewrite the UI system (Closes #12)

This commit is contained in:
Thinkofname 2016-04-24 12:22:04 +01:00
parent b0c54a3561
commit a7caa50b6f
18 changed files with 2016 additions and 2371 deletions

View File

@ -181,18 +181,25 @@ impl Vars {
pub struct Console { pub struct Console {
history: Vec<Component>, history: Vec<Component>,
dirty: bool,
collection: ui::Collection, elements: Option<ConsoleElements>,
active: bool, active: bool,
position: f64, position: f64,
} }
struct ConsoleElements {
background: ui::ImageRef,
lines: Vec<ui::FormattedRef>,
}
impl Console { impl Console {
pub fn new() -> Console { pub fn new() -> Console {
Console { Console {
history: vec![Component::Text(TextComponent::new("")); 200], history: vec![Component::Text(TextComponent::new("")); 200],
dirty: false,
collection: ui::Collection::new(), elements: None,
active: false, active: false,
position: -220.0, position: -220.0,
} }
@ -208,14 +215,11 @@ impl Console {
pub fn tick(&mut self, pub fn tick(&mut self,
ui_container: &mut ui::Container, ui_container: &mut ui::Container,
renderer: &mut render::Renderer, renderer: &render::Renderer,
delta: f64, delta: f64,
width: f64) { width: f64) {
// To make sure the console is always on top it constant removes and readds itself.
// Its hacky but the console should never appear for normal users so its not really
// a major issue.
self.collection.remove_all(ui_container);
if !self.active && self.position <= -220.0 { if !self.active && self.position <= -220.0 {
self.elements = None;
return; return;
} }
if self.active { if self.active {
@ -229,39 +233,48 @@ impl Console {
} else { } else {
self.position = -220.0; self.position = -220.0;
} }
let w = match ui_container.mode { let w = match ui_container.mode {
ui::Mode::Scaled => width, ui::Mode::Scaled => width,
ui::Mode::Unscaled(scale) => 854.0 / scale, ui::Mode::Unscaled(scale) => 854.0 / scale,
}; };
if self.elements.is_none() {
let mut background = ui::Image::new( let background = ui::ImageBuilder::new()
render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"), .texture("steven:solid")
0.0, self.position, w, 220.0, .position(0.0, self.position)
0.0, 0.0, 1.0, 1.0, .size(w, 220.0)
0, 0, 0 .colour((0, 0, 0, 180))
); .draw_index(500)
background.set_a(180); .create(ui_container);
let background = self.collection.add(ui_container.add(background)); self.elements = Some(ConsoleElements {
background: background,
let mut lines = Vec::new(); lines: vec![],
let mut offset = 0.0; });
for line in self.history.iter().rev() { self.dirty = true;
if offset >= 210.0 {
break;
}
let mut fmt = ui::Formatted::with_width_limit(
renderer,
line.clone(),
5.0, 5.0 + offset,
w - 1.0
);
fmt.set_parent(&background);
fmt.set_v_attach(ui::VAttach::Bottom);
offset += fmt.get_height();
lines.push(ui_container.add(fmt));
} }
for fmt in lines { let elements = self.elements.as_mut().unwrap();
self.collection.add(fmt); let mut background = elements.background.borrow_mut();
background.y = self.position;
background.width = w;
if self.dirty {
self.dirty = false;
elements.lines.clear();
let mut offset = 0.0;
for line in self.history.iter().rev() {
if offset >= 210.0 {
break;
}
let (_, height) = ui::Formatted::compute_size(renderer, line, w - 10.0);
elements.lines.push(ui::FormattedBuilder::new()
.text(line.clone())
.position(5.0, 5.0 + offset)
.max_width(w - 10.0)
.alignment(ui::VAttach::Bottom, ui::HAttach::Left)
.create(&mut *background));
offset += height;
}
} }
} }
@ -314,6 +327,7 @@ impl Console {
Component::Text(TextComponent::new(&format!("{}", record.args()))) Component::Text(TextComponent::new(&format!("{}", record.args())))
]); ]);
self.history.push(Component::Text(msg)); self.history.push(Component::Text(msg));
self.dirty = true;
} }
} }

View File

@ -494,7 +494,6 @@ struct MovementHandler {
gamemode: ecs::Key<Gamemode>, gamemode: ecs::Key<Gamemode>,
position: ecs::Key<TargetPosition>, position: ecs::Key<TargetPosition>,
velocity: ecs::Key<Velocity>, velocity: ecs::Key<Velocity>,
game_info: ecs::Key<GameInfo>,
bounds: ecs::Key<Bounds>, bounds: ecs::Key<Bounds>,
rotation: ecs::Key<Rotation>, rotation: ecs::Key<Rotation>,
} }
@ -518,7 +517,6 @@ impl MovementHandler {
gamemode: m.get_key(), gamemode: m.get_key(),
position: position, position: position,
velocity: velocity, velocity: velocity,
game_info: m.get_key(),
bounds: bounds, bounds: bounds,
rotation: rotation, rotation: rotation,
} }

View File

@ -14,6 +14,7 @@
#![recursion_limit="300"] #![recursion_limit="300"]
#![feature(const_fn)] #![feature(const_fn)]
#![feature(rc_would_unwrap)]
extern crate sdl2; extern crate sdl2;
extern crate image; extern crate image;
@ -243,7 +244,6 @@ fn main() {
let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time; let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
let (width, height) = window.drawable_size(); let (width, height) = window.drawable_size();
let vsync_changed = *game.vars.get(settings::R_VSYNC); let vsync_changed = *game.vars.get(settings::R_VSYNC);
if vsync != vsync_changed { if vsync != vsync_changed {
vsync = vsync_changed; vsync = vsync_changed;
@ -262,7 +262,7 @@ fn main() {
game.console game.console
.lock() .lock()
.unwrap() .unwrap()
.tick(&mut ui_container, &mut game.renderer, delta, width as f64); .tick(&mut ui_container, &game.renderer, delta, width as f64);
ui_container.tick(&mut game.renderer, delta, width as f64, height as f64); ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
game.renderer.tick(&mut game.server.world, delta, width, height); game.renderer.tick(&mut game.server.world, delta, width, height);

View File

@ -1200,13 +1200,14 @@ impl TextureManager {
height: height, height: height,
}; };
self.pending_uploads.push((tex.atlas, rect, data)); self.pending_uploads.push((tex.atlas, rect, data));
let t = tex.relative(0.0, 0.0, (width as f32) / (tex.width as f32), (height as f32) / (tex.height as f32)); let mut t = tex.relative(0.0, 0.0, (width as f32) / (tex.width as f32), (height as f32) / (tex.height as f32));
let old_name = mem::replace(&mut tex.name, format!("steven-dynamic:{}", name)); let old_name = mem::replace(&mut tex.name, format!("steven-dynamic:{}", name));
self.dynamic_textures.insert(name.to_owned(), (tex.clone(), img)); self.dynamic_textures.insert(name.to_owned(), (tex.clone(), img));
// We need to rename the texture itself so that get_texture calls // We need to rename the texture itself so that get_texture calls
// work with the new name // work with the new name
let mut old = self.textures.remove(&old_name).unwrap(); let mut old = self.textures.remove(&old_name).unwrap();
old.name = format!("steven-dynamic:{}", name); old.name = format!("steven-dynamic:{}", name);
t.name = old.name.clone();
self.textures.insert(format!("steven-dynamic:{}", name), old); self.textures.insert(format!("steven-dynamic:{}", name), old);
t t
} else { } else {
@ -1239,7 +1240,7 @@ struct AnimationFrame {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Texture { pub struct Texture {
name: String, pub name: String,
version: usize, version: usize,
pub atlas: i32, pub atlas: i32,
x: usize, x: usize,

View File

@ -14,7 +14,6 @@
use ui; use ui;
use render; use render;
use format::{self, Component, TextComponent};
pub struct Connecting { pub struct Connecting {
elements: Option<UIElements>, elements: Option<UIElements>,
@ -23,7 +22,9 @@ pub struct Connecting {
struct UIElements { struct UIElements {
logo: ui::logo::Logo, logo: ui::logo::Logo,
elements: ui::Collection, _connect_msg: ui::TextRef,
_msg: ui::TextRef,
_disclaimer: ui::TextRef,
} }
@ -38,63 +39,48 @@ impl Connecting {
impl super::Screen for Connecting { impl super::Screen for Connecting {
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container); let logo = ui::logo::Logo::new(renderer.resources.clone(), ui_container);
let mut elements = ui::Collection::new();
let mut connect_msg = ui::Formatted::new( let connect_msg = ui::TextBuilder::new()
renderer, .text("Connecting to")
Component::Text(TextComponent::new("Connecting to")), .position(0.0, -16.0)
0.0, -16.0 .alignment(ui::VAttach::Middle, ui::HAttach::Center)
); .create(ui_container);
connect_msg.set_v_attach(ui::VAttach::Middle);
connect_msg.set_h_attach(ui::HAttach::Center);
elements.add(ui_container.add(connect_msg));
let mut msg = TextComponent::new(&self.target); let msg = ui::TextBuilder::new()
msg.modifier.color = Some(format::Color::Yellow); .text(self.target.clone())
let mut server_msg = ui::Formatted::new( .position(0.0, 16.0)
renderer, .colour((255, 255, 85, 255))
Component::Text(msg), .alignment(ui::VAttach::Middle, ui::HAttach::Center)
0.0, 16.0 .create(ui_container);
);
server_msg.set_v_attach(ui::VAttach::Middle);
server_msg.set_h_attach(ui::HAttach::Center);
elements.add(ui_container.add(server_msg));
// Disclaimer // Disclaimer
let mut warn = ui::Text::new(renderer, let disclaimer = ui::TextBuilder::new()
"Not affiliated with Mojang/Minecraft", .text("Not affiliated with Mojang/Minecraft")
5.0, .position(5.0, 5.0)
5.0, .colour((255, 200, 200, 255))
255, .alignment(ui::VAttach::Bottom, ui::HAttach::Right)
200, .create(ui_container);
200);
warn.set_v_attach(ui::VAttach::Bottom);
warn.set_h_attach(ui::HAttach::Right);
elements.add(ui_container.add(warn));
self.elements = Some(UIElements { self.elements = Some(UIElements {
logo: logo, logo: logo,
elements: elements, _disclaimer: disclaimer,
_msg: msg,
_connect_msg: connect_msg,
}); });
} }
fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
// Clean up // Clean up
{
let elements = self.elements.as_mut().unwrap();
elements.logo.remove(ui_container);
elements.elements.remove_all(ui_container);
}
self.elements = None self.elements = None
} }
fn tick(&mut self, fn tick(&mut self,
_delta: f64, _delta: f64,
renderer: &mut render::Renderer, renderer: &mut render::Renderer,
ui_container: &mut ui::Container) -> Option<Box<super::Screen>>{ _ui_container: &mut ui::Container) -> Option<Box<super::Screen>>{
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
elements.logo.tick(renderer, ui_container); elements.logo.tick(renderer);
None None
} }
} }

View File

@ -27,7 +27,11 @@ pub struct EditServerEntry {
struct UIElements { struct UIElements {
logo: ui::logo::Logo, logo: ui::logo::Logo,
elements: ui::Collection,
_name: ui::TextBoxRef,
_address: ui::TextBoxRef,
_done: ui::ButtonRef,
_cancel: ui::ButtonRef,
} }
impl EditServerEntry { impl EditServerEntry {
@ -77,104 +81,99 @@ impl EditServerEntry {
impl super::Screen for EditServerEntry { impl super::Screen for EditServerEntry {
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container); let logo = ui::logo::Logo::new(renderer.resources.clone(), ui_container);
let mut elements = ui::Collection::new();
// Name // Name
let mut server_name = ui::TextBox::new( let server_name = ui::TextBoxBuilder::new()
renderer, self.entry_info.as_ref().map_or("", |v| &v.1), .input(self.entry_info.as_ref().map_or("", |v| &v.1))
0.0, -20.0, 400.0, 40.0 .position(0.0, -20.0)
); .size(400.0, 40.0)
server_name.set_v_attach(ui::VAttach::Middle); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
server_name.set_h_attach(ui::HAttach::Center); .create(ui_container);
server_name.add_submit_func(|_, ui| { ui::TextBuilder::new()
ui.cycle_focus(); .text("Name:")
}); .position(0.0, -18.0)
let ure = ui_container.add(server_name); .attach(&mut *server_name.borrow_mut());
let mut server_name_label = ui::Text::new(renderer, "Name:", 0.0, -18.0, 255, 255, 255);
server_name_label.set_parent(&ure);
let server_name_txt = elements.add(ure);
elements.add(ui_container.add(server_name_label));
// Name // Address
let mut server_address = ui::TextBox::new( let server_address = ui::TextBoxBuilder::new()
renderer, self.entry_info.as_ref().map_or("", |v| &v.2), .input(self.entry_info.as_ref().map_or("", |v| &v.2))
0.0, 40.0, 400.0, 40.0 .position(0.0, 40.0)
); .size(400.0, 40.0)
server_address.set_v_attach(ui::VAttach::Middle); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
server_address.set_h_attach(ui::HAttach::Center); .create(ui_container);
server_address.add_submit_func(|_, ui| { ui::TextBuilder::new()
ui.cycle_focus(); .text("Address")
}); .position(0.0, -18.0)
let ure = ui_container.add(server_address); .attach(&mut *server_address.borrow_mut());
let mut server_address_label = ui::Text::new(renderer, "Address:", 0.0, -18.0, 255, 255, 255);
server_address_label.set_parent(&ure);
let server_address_txt = elements.add(ure);
elements.add(ui_container.add(server_address_label));
// Done // Done
let (mut done, mut txt) = super::new_button_text( let done = ui::ButtonBuilder::new()
renderer, "Done", .position(110.0, 100.0)
110.0, 100.0, 200.0, 40.0 .size(200.0, 40.0)
); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
done.set_v_attach(ui::VAttach::Middle); .create(ui_container);
done.set_h_attach(ui::HAttach::Center); {
let re = ui_container.add(done); let mut done = done.borrow_mut();
txt.set_parent(&re); let txt = ui::TextBuilder::new()
let tre = ui_container.add(txt); .text("Done")
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
let index = self.entry_info.as_ref().map(|v| v.0); .attach(&mut *done);
super::button_action(ui_container, re.clone(), Some(tre.clone()), move |game, uic| { done.add_text(txt);
Self::save_servers( let index = self.entry_info.as_ref().map(|v| v.0);
index, let server_name = server_name.clone();
&uic.get(&server_name_txt).get_input(), let server_address = server_address.clone();
&uic.get(&server_address_txt).get_input() done.add_click_func(move |_, game| {
); Self::save_servers(
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None))); index,
}); &server_name.borrow().input,
elements.add(re); &server_address.borrow().input,
elements.add(tre); );
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None)));
true
});
}
// Cancel // Cancel
let (mut cancel, mut txt) = super::new_button_text( let cancel = ui::ButtonBuilder::new()
renderer, "Cancel", .position(-110.0, 100.0)
-110.0, 100.0, 200.0, 40.0 .size(200.0, 40.0)
); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
cancel.set_v_attach(ui::VAttach::Middle); .create(ui_container);
cancel.set_h_attach(ui::HAttach::Center); {
let re = ui_container.add(cancel); let mut cancel = cancel.borrow_mut();
txt.set_parent(&re); let txt = ui::TextBuilder::new()
let tre = ui_container.add(txt); .text("Cancel")
super::button_action(ui_container, re.clone(), Some(tre.clone()), |game, _| { .alignment(ui::VAttach::Middle, ui::HAttach::Center)
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None))); .attach(&mut *cancel);
}); cancel.add_text(txt);
elements.add(re); cancel.add_click_func(|_, game| {
elements.add(tre); game.screen_sys.replace_screen(Box::new(super::ServerList::new(None)));
true
});
}
self.elements = Some(UIElements { self.elements = Some(UIElements {
logo: logo, logo: logo,
elements: elements, _name: server_name,
_address: server_address,
_done: done,
_cancel: cancel,
}); });
} }
fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
// Clean up // Clean up
{
let elements = self.elements.as_mut().unwrap();
elements.logo.remove(ui_container);
elements.elements.remove_all(ui_container);
}
self.elements = None self.elements = None
} }
fn tick(&mut self, fn tick(&mut self,
_delta: f64, _delta: f64,
renderer: &mut render::Renderer, renderer: &mut render::Renderer,
ui_container: &mut ui::Container) -> Option<Box<super::Screen>> { _ui_container: &mut ui::Container) -> Option<Box<super::Screen>> {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
elements.logo.tick(renderer, ui_container); elements.logo.tick(renderer);
None None
} }

View File

@ -33,13 +33,13 @@ pub struct Login {
struct UIElements { struct UIElements {
logo: ui::logo::Logo, logo: ui::logo::Logo,
elements: ui::Collection,
login_btn: ui::ElementRef<ui::Button>, login_btn: ui::ButtonRef,
login_btn_text: ui::ElementRef<ui::Text>, login_btn_text: ui::TextRef,
login_error: ui::ElementRef<ui::Text>, login_error: ui::TextRef,
username_txt: ui::ElementRef<ui::TextBox>, username_txt: ui::TextBoxRef,
password_txt: ui::ElementRef<ui::TextBox>, password_txt: ui::TextBoxRef,
_disclaimer: ui::TextRef,
try_login: Rc<Cell<bool>>, try_login: Rc<Cell<bool>>,
refresh: bool, refresh: bool,
login_res: Option<mpsc::Receiver<Result<mojang::Profile, protocol::Error>>>, login_res: Option<mpsc::Receiver<Result<mojang::Profile, protocol::Error>>>,
@ -56,73 +56,76 @@ impl Login {
impl super::Screen for Login { impl super::Screen for Login {
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container); let logo = ui::logo::Logo::new(renderer.resources.clone(), ui_container);
let mut elements = ui::Collection::new();
let try_login = Rc::new(Cell::new(false)); let try_login = Rc::new(Cell::new(false));
// Login // Login
let (mut login, mut txt) = super::new_button_text(renderer, "Login", 0.0, 100.0, 400.0, 40.0); let login_btn = ui::ButtonBuilder::new()
login.set_v_attach(ui::VAttach::Middle); .position(0.0, 100.0)
login.set_h_attach(ui::HAttach::Center); .size(400.0, 40.0)
let re = ui_container.add(login); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
txt.set_parent(&re); .create(ui_container);
let tre = ui_container.add(txt); let login_btn_text = ui::TextBuilder::new()
let tl = try_login.clone(); .text("Login")
super::button_action(ui_container, .position(0.0, 0.0)
re.clone(), .alignment(ui::VAttach::Middle, ui::HAttach::Center)
Some(tre.clone()), .attach(&mut *login_btn.borrow_mut());
move |_, _| { {
tl.set(true); let mut btn = login_btn.borrow_mut();
}); btn.add_text(login_btn_text.clone());
let login_btn = elements.add(re); let tl = try_login.clone();
let login_btn_text = elements.add(tre); btn.add_click_func(move |_, _| {
tl.set(true);
true
});
}
// Login Error // Login Error
let mut login_error = ui::Text::new(renderer, "", 0.0, 150.0, 255, 50, 50); let login_error = ui::TextBuilder::new()
login_error.set_v_attach(ui::VAttach::Middle); .text("")
login_error.set_h_attach(ui::HAttach::Center); .position(0.0, 150.0)
let login_error = elements.add(ui_container.add(login_error)); .colour((255, 50, 50, 255))
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.create(ui_container);
// Username // Username
let mut username = ui::TextBox::new(renderer, "", 0.0, -20.0, 400.0, 40.0); let username_txt = ui::TextBoxBuilder::new()
username.set_v_attach(ui::VAttach::Middle); .position(0.0, -20.0)
username.set_h_attach(ui::HAttach::Center); .size(400.0, 40.0)
username.add_submit_func(|_, ui| { .alignment(ui::VAttach::Middle, ui::HAttach::Center)
ui.cycle_focus(); .create(ui_container);
}); ui::TextBox::make_focusable(&username_txt, ui_container);
let ure = ui_container.add(username); ui::TextBuilder::new()
let mut username_label = ui::Text::new(renderer, "Username/Email:", 0.0, -18.0, 255, 255, 255); .text("Username/Email:")
username_label.set_parent(&ure); .position(0.0, -18.0)
let username_txt = elements.add(ure); .attach(&mut *username_txt.borrow_mut());
elements.add(ui_container.add(username_label));
// Password // Password
let mut password = ui::TextBox::new(renderer, "", 0.0, 40.0, 400.0, 40.0); let password_txt = ui::TextBoxBuilder::new()
password.set_v_attach(ui::VAttach::Middle); .position(0.0, 40.0)
password.set_h_attach(ui::HAttach::Center); .size(400.0, 40.0)
password.set_password(true); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
.password(true)
.create(ui_container);
ui::TextBox::make_focusable(&password_txt, ui_container);
ui::TextBuilder::new()
.text("Password:")
.position(0.0, -18.0)
.attach(&mut *password_txt.borrow_mut());
let tl = try_login.clone(); let tl = try_login.clone();
password.add_submit_func(move |_, _| { password_txt.borrow_mut().add_submit_func(move |_, _| {
tl.set(true); tl.set(true);
}); });
let pre = ui_container.add(password);
let mut password_label = ui::Text::new(renderer, "Password:", 0.0, -18.0, 255, 255, 255);
password_label.set_parent(&pre);
let password_txt = elements.add(pre);
elements.add(ui_container.add(password_label));
// Disclaimer // Disclaimer
let mut warn = ui::Text::new(renderer, let disclaimer = ui::TextBuilder::new()
"Not affiliated with Mojang/Minecraft", .text("Not affiliated with Mojang/Minecraft")
5.0, .position(5.0, 5.0)
5.0, .colour((255, 200, 200, 255))
255, .alignment(ui::VAttach::Bottom, ui::HAttach::Right)
200, .create(ui_container);
200);
warn.set_v_attach(ui::VAttach::Bottom);
warn.set_h_attach(ui::HAttach::Right);
elements.add(ui_container.add(warn));
let profile = mojang::Profile { let profile = mojang::Profile {
username: self.vars.get(auth::CL_USERNAME).clone(), username: self.vars.get(auth::CL_USERNAME).clone(),
@ -134,7 +137,6 @@ impl super::Screen for Login {
self.elements = Some(UIElements { self.elements = Some(UIElements {
logo: logo, logo: logo,
elements: elements,
profile: profile, profile: profile,
login_btn: login_btn, login_btn: login_btn,
login_btn_text: login_btn_text, login_btn_text: login_btn_text,
@ -143,52 +145,37 @@ impl super::Screen for Login {
refresh: refresh, refresh: refresh,
login_res: None, login_res: None,
_disclaimer: disclaimer,
username_txt: username_txt, username_txt: username_txt,
password_txt: password_txt, password_txt: password_txt,
}); });
} }
fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
// Clean up // Clean up
{
let elements = self.elements.as_mut().unwrap();
elements.logo.remove(ui_container);
elements.elements.remove_all(ui_container);
}
self.elements = None self.elements = None
} }
fn tick(&mut self, fn tick(&mut self,
_delta: f64, _delta: f64,
renderer: &mut render::Renderer, renderer: &mut render::Renderer,
ui_container: &mut ui::Container) -> Option<Box<super::Screen>> { _ui_container: &mut ui::Container) -> Option<Box<super::Screen>> {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
if elements.try_login.get() && elements.login_res.is_none() { if elements.try_login.get() && elements.login_res.is_none() {
elements.try_login.set(false); elements.try_login.set(false);
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
elements.login_res = Some(rx); elements.login_res = Some(rx);
{ elements.login_btn.borrow_mut().disabled = true;
let btn = ui_container.get_mut(&elements.login_btn); elements.login_btn_text.borrow_mut().text = "Logging in...".into();
btn.set_disabled(true);
}
{
let txt = ui_container.get_mut(&elements.login_btn_text);
txt.set_text(renderer, "Logging in...");
}
let mut client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone(); let mut client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone();
if client_token.is_empty() { if client_token.is_empty() {
client_token = rand::thread_rng().gen_ascii_chars().take(20).collect::<String>(); client_token = rand::thread_rng().gen_ascii_chars().take(20).collect::<String>();
self.vars.set(auth::AUTH_CLIENT_TOKEN, client_token); self.vars.set(auth::AUTH_CLIENT_TOKEN, client_token);
} }
let client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone(); let client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone();
let username = { let username = elements.username_txt.borrow().input.clone();
let txt = ui_container.get(&elements.username_txt); let password = elements.password_txt.borrow().input.clone();
txt.get_input()
};
let password = {
let txt = ui_container.get(&elements.password_txt);
txt.get_input()
};
let refresh = elements.refresh; let refresh = elements.refresh;
let profile = elements.profile.clone(); let profile = elements.profile.clone();
thread::spawn(move || { thread::spawn(move || {
@ -203,14 +190,8 @@ impl super::Screen for Login {
if let Some(rx) = elements.login_res.as_ref() { if let Some(rx) = elements.login_res.as_ref() {
if let Ok(res) = rx.try_recv() { if let Ok(res) = rx.try_recv() {
done = true; done = true;
{ elements.login_btn.borrow_mut().disabled = false;
let btn = ui_container.get_mut(&elements.login_btn); elements.login_btn_text.borrow_mut().text = "Login".into();
btn.set_disabled(false);
}
{
let txt = ui_container.get_mut(&elements.login_btn_text);
txt.set_text(renderer, "Login");
}
match res { match res {
Ok(val) => { Ok(val) => {
self.vars.set(auth::CL_USERNAME, val.username.clone()); self.vars.set(auth::CL_USERNAME, val.username.clone());
@ -220,8 +201,7 @@ impl super::Screen for Login {
return Some(Box::new(super::ServerList::new(None))); return Some(Box::new(super::ServerList::new(None)));
}, },
Err(err) => { Err(err) => {
let login_error = ui_container.get_mut(&elements.login_error); elements.login_error.borrow_mut().text = format!("{}", err);
login_error.set_text(renderer, &format!("{}", err));
}, },
} }
} }
@ -230,7 +210,7 @@ impl super::Screen for Login {
elements.login_res = None; elements.login_res = None;
} }
elements.logo.tick(renderer, ui_container); elements.logo.tick(renderer);
None None
} }
} }

View File

@ -15,11 +15,12 @@
mod server_list; mod server_list;
pub use self::server_list::*; pub use self::server_list::*;
mod login; mod login;
pub mod settings_menu;
pub use self::login::*; pub use self::login::*;
pub mod connecting; pub mod connecting;
pub mod edit_server; pub mod edit_server;
pub mod settings_menu;
pub use self::settings_menu::{SettingsMenu, VideoSettingsMenu, AudioSettingsMenu}; pub use self::settings_menu::{SettingsMenu, VideoSettingsMenu, AudioSettingsMenu};
use render; use render;
@ -148,40 +149,3 @@ impl ScreenSystem {
current.screen.on_scroll(x, y); current.screen.on_scroll(x, y);
} }
} }
pub fn new_button_text(renderer: &mut render::Renderer,
val: &str,
x: f64,
y: f64,
w: f64,
h: f64)
-> (ui::Button, ui::Text) {
let btn = ui::Button::new(x, y, w, h);
let mut text = ui::Text::new(renderer, val, 0.0, 0.0, 255, 255, 255);
text.set_v_attach(ui::VAttach::Middle);
text.set_h_attach(ui::HAttach::Center);
(btn, text)
}
pub fn button_action<F: Fn(&mut ::Game, &mut ui::Container) + 'static>(ui_container: &mut ui::Container,
btn: ui::ElementRef<ui::Button>,
txt: Option<ui::ElementRef<ui::Text>>,
click: F) {
let button = ui_container.get_mut(&btn);
button.add_hover_func(move |over, _, ui_container| {
let disabled = {
let button = ui_container.get_mut(&btn);
button.is_disabled()
};
let txt = txt.clone();
if let Some(txt) = txt {
let text = ui_container.get_mut(&txt);
text.set_b(if over && !disabled {
160
} else {
255
});
}
});
button.add_click_func(click);
}

View File

@ -40,22 +40,27 @@ pub struct ServerList {
struct UIElements { struct UIElements {
logo: ui::logo::Logo, logo: ui::logo::Logo,
elements: ui::Collection,
servers: Vec<Server>, servers: Vec<Server>,
_add_btn: ui::ButtonRef,
_refresh_btn: ui::ButtonRef,
_options_btn: ui::ButtonRef,
_disclaimer: ui::TextRef,
_disconnected: Option<ui::ImageRef>,
} }
struct Server { struct Server {
collection: ui::Collection, back: ui::ImageRef,
back: ui::ElementRef<ui::Image>,
offset: f64, offset: f64,
y: f64, y: f64,
motd: ui::ElementRef<ui::Formatted>, motd: ui::FormattedRef,
ping: ui::ElementRef<ui::Image>, ping: ui::ImageRef,
players: ui::ElementRef<ui::Text>, players: ui::TextRef,
version: ui::ElementRef<ui::Formatted>, version: ui::FormattedRef,
icon: ui::ElementRef<ui::Image>, icon: ui::ImageRef,
icon_texture: Option<String>, icon_texture: Option<String>,
done_ping: bool, done_ping: bool,
@ -98,10 +103,9 @@ impl ServerList {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
*self.needs_reload.borrow_mut() = false; *self.needs_reload.borrow_mut() = false;
{ {
// Clean up previous list entries and icons. // Clean up previous list icons.
let mut tex = renderer.get_textures_ref().write().unwrap(); let mut tex = renderer.get_textures_ref().write().unwrap();
for server in &mut elements.servers { for server in &mut elements.servers {
server.collection.remove_all(ui_container);
if let Some(ref icon) = server.icon_texture { if let Some(ref icon) = server.icon_texture {
tex.remove_dynamic(&icon); tex.remove_dynamic(&icon);
} }
@ -117,161 +121,139 @@ impl ServerList {
let servers = servers_info.find("servers").unwrap().as_array().unwrap(); let servers = servers_info.find("servers").unwrap().as_array().unwrap();
let mut offset = 0.0; let mut offset = 0.0;
// Default icon whilst we ping the servers or if the server doesn't provide one
let default_icon = render::Renderer::get_texture(renderer.get_textures_ref(),
"misc/unknown_server");
// General gui icons
let icons = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/icons");
for (index, svr) in servers.iter().enumerate() { for (index, svr) in servers.iter().enumerate() {
let name = svr.find("name").unwrap().as_string().unwrap().to_owned(); let name = svr.find("name").unwrap().as_string().unwrap().to_owned();
let address = svr.find("address").unwrap().as_string().unwrap().to_owned(); let address = svr.find("address").unwrap().as_string().unwrap().to_owned();
let solid = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid");
// Everything is attached to this // Everything is attached to this
let mut back = ui::Image::new(solid, let back = ui::ImageBuilder::new()
0.0, .texture("steven:solid")
offset * 100.0, .position(0.0, offset * 100.0)
700.0, .size(700.0, 100.0)
100.0, .colour((0, 0, 0, 100))
0.0, .alignment(ui::VAttach::Middle, ui::HAttach::Center)
0.0, .create(ui_container);
1.0,
1.0,
0,
0,
0);
back.set_a(100);
back.set_v_attach(ui::VAttach::Middle);
back.set_h_attach(ui::HAttach::Center);
let (send, recv) = mpsc::channel::<PingInfo>(); let (send, recv) = mpsc::channel::<PingInfo>();
// Make whole entry interactable
{
let mut backr = back.borrow_mut();
let address = address.clone();
backr.add_hover_func(move |this, over, _| {
this.colour.3 = if over {
200
} else {
100
};
false
});
backr.add_click_func(move |_, game| {
game.screen_sys.replace_screen(Box::new(super::connecting::Connecting::new(&address)));
game.connect_to(&address);
true
});
}
// Server name
ui::TextBuilder::new()
.text(name.clone())
.position(100.0, 5.0)
.attach(&mut *back.borrow_mut());
// Server icon
let icon = ui::ImageBuilder::new()
.texture("misc/unknown_server")
.position(5.0, 5.0)
.size(90.0, 90.0)
.attach(&mut *back.borrow_mut());
// Ping indicator
let ping = ui::ImageBuilder::new()
.texture("gui/icons")
.position(5.0, 5.0)
.size(20.0, 16.0)
.texture_coords((0.0, 56.0 / 256.0, 10.0 / 256.0, 8.0 / 256.0))
.alignment(ui::VAttach::Top, ui::HAttach::Right)
.attach(&mut *back.borrow_mut());
// Player count
let players = ui::TextBuilder::new()
.text("???")
.position(30.0, 5.0)
.alignment(ui::VAttach::Top, ui::HAttach::Right)
.attach(&mut *back.borrow_mut());
// Server's message of the day
let motd = ui::FormattedBuilder::new()
.text(Component::Text(TextComponent::new("Connecting...")))
.position(100.0, 23.0)
.max_width(700.0 - (90.0 + 10.0 + 5.0))
.attach(&mut *back.borrow_mut());
// Version information
let version = ui::FormattedBuilder::new()
.text(Component::Text(TextComponent::new("")))
.position(100.0, 5.0)
.max_width(700.0 - (90.0 + 10.0 + 5.0))
.alignment(ui::VAttach::Bottom, ui::HAttach::Left)
.attach(&mut *back.borrow_mut());
// Delete entry button
let delete_entry = ui::ButtonBuilder::new()
.position(0.0, 0.0)
.size(25.0, 25.0)
.alignment(ui::VAttach::Bottom, ui::HAttach::Right)
.attach(&mut *back.borrow_mut());
{
let mut btn = delete_entry.borrow_mut();
let txt = ui::TextBuilder::new()
.text("X")
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *btn);
btn.add_text(txt);
}
// Edit entry button
let edit_entry = ui::ButtonBuilder::new()
.position(25.0, 0.0)
.size(25.0, 25.0)
.alignment(ui::VAttach::Bottom, ui::HAttach::Right)
.attach(&mut *back.borrow_mut());
{
let mut btn = edit_entry.borrow_mut();
let txt = ui::TextBuilder::new()
.text("E")
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *btn);
btn.add_text(txt);
let index = index;
let sname = name.clone();
let saddr = address.clone();
btn.add_click_func(move |_, game| {
game.screen_sys.replace_screen(Box::new(super::edit_server::EditServerEntry::new(
Some((index, sname.clone(), saddr.clone()))
)));
true
})
}
let mut server = Server { let mut server = Server {
collection: ui::Collection::new(), back: back,
back: ui_container.add(back),
offset: offset, offset: offset,
y: 0.0, y: 0.0,
done_ping: false, done_ping: false,
recv: recv, recv: recv,
motd: Default::default(), motd: motd,
ping: Default::default(), ping: ping,
players: Default::default(), players: players,
version: Default::default(), version: version,
icon: Default::default(), icon: icon,
icon_texture: None, icon_texture: None,
}; };
server.collection.add(server.back.clone());
server.update_position(); server.update_position();
// Make whole entry interactable
{
let back = ui_container.get_mut(&server.back);
let back_ref = server.back.clone();
let address = address.clone();
back.add_hover_func(move |over, _, ui_container| {
let back = ui_container.get_mut(&back_ref);
back.set_a(if over {
200
} else {
100
});
});
back.add_click_func(move |game, _| {
game.screen_sys.replace_screen(Box::new(super::connecting::Connecting::new(&address)));
game.connect_to(&address);
});
}
// Server name
let mut text = ui::Text::new(renderer, &name, 100.0, 5.0, 255, 255, 255);
text.set_parent(&server.back);
server.collection.add(ui_container.add(text));
// Server icon
let mut icon = ui::Image::new(
default_icon.clone(),
5.0, 5.0, 90.0, 90.0,
0.0, 0.0, 1.0, 1.0,
255, 255, 255
);
icon.set_parent(&server.back);
server.icon = server.collection.add(ui_container.add(icon));
// Ping indicator
let mut ping = ui::Image::new(
icons.clone(),
5.0, 5.0, 20.0, 16.0,
0.0, 56.0 / 256.0, 10.0 / 256.0, 8.0 / 256.0,
255, 255, 255
);
ping.set_h_attach(ui::HAttach::Right);
ping.set_parent(&server.back);
server.ping = server.collection.add(ui_container.add(ping));
// Player count
let mut players = ui::Text::new(renderer, "???", 30.0, 5.0, 255, 255, 255);
players.set_h_attach(ui::HAttach::Right);
players.set_parent(&server.back);
server.players = server.collection.add(ui_container.add(players));
// Server's message of the day
let mut motd =
ui::Formatted::with_width_limit(renderer,
Component::Text(TextComponent::new("Connecting.\
..")),
100.0,
23.0,
700.0 - (90.0 + 10.0 + 5.0));
motd.set_parent(&server.back);
server.motd = server.collection.add(ui_container.add(motd));
// Version information
let mut version =
ui::Formatted::with_width_limit(renderer,
Component::Text(TextComponent::new("")),
100.0,
5.0,
700.0 - (90.0 + 10.0 + 5.0));
version.set_v_attach(ui::VAttach::Bottom);
version.set_parent(&server.back);
server.version = server.collection.add(ui_container.add(version));
// Delete entry button
let (mut del, mut txt) = super::new_button_text(renderer, "X", 0.0, 0.0, 25.0, 25.0);
del.set_v_attach(ui::VAttach::Bottom);
del.set_h_attach(ui::HAttach::Right);
del.set_parent(&server.back);
let re = ui_container.add(del);
txt.set_parent(&re);
let tre = ui_container.add(txt);
super::button_action(ui_container, re.clone(), Some(tre.clone()), |_,_| {}); // TOOO: delete entry
server.collection.add(re);
server.collection.add(tre);
// Edit entry button
let (mut edit, mut txt) = super::new_button_text(renderer, "E", 25.0, 0.0, 25.0, 25.0);
edit.set_v_attach(ui::VAttach::Bottom);
edit.set_h_attach(ui::HAttach::Right);
edit.set_parent(&server.back);
let re = ui_container.add(edit);
txt.set_parent(&re);
let tre = ui_container.add(txt);
let index = index;
let sname = name.clone();
let saddr = address.clone();
super::button_action(ui_container, re.clone(), Some(tre.clone()), move |game,_|{
let sname = sname.clone();
let saddr = saddr.clone();
game.screen_sys.replace_screen(Box::new(super::edit_server::EditServerEntry::new(
Some((index, sname, saddr))
)));
});
server.collection.add(re);
server.collection.add(tre);
elements.servers.push(server); elements.servers.push(server);
offset += 1.0; offset += 1.0;
@ -304,7 +286,7 @@ impl ServerList {
let e = format!("{}", err); let e = format!("{}", err);
let mut msg = TextComponent::new(&e); let mut msg = TextComponent::new(&e);
msg.modifier.color = Some(format::Color::Red); msg.modifier.color = Some(format::Color::Red);
drop(send.send(PingInfo { let _ = send.send(PingInfo {
motd: Component::Text(msg), motd: Component::Text(msg),
ping: time::Duration::seconds(99999), ping: time::Duration::seconds(99999),
exists: false, exists: false,
@ -313,7 +295,7 @@ impl ServerList {
protocol_version: 0, protocol_version: 0,
protocol_name: "".to_owned(), protocol_name: "".to_owned(),
favicon: None, favicon: None,
})); });
} }
} }
}); });
@ -323,140 +305,129 @@ impl ServerList {
impl super::Screen for ServerList { impl super::Screen for ServerList {
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container); let logo = ui::logo::Logo::new(renderer.resources.clone(), ui_container);
let mut elements = ui::Collection::new();
// Refresh the server list // Refresh the server list
let (mut refresh, mut txt) = super::new_button_text(renderer, let refresh = ui::ButtonBuilder::new()
"Refresh", .position(300.0, -50.0 - 15.0)
300.0, .size(100.0, 30.0)
-50.0 - 15.0, .alignment(ui::VAttach::Middle, ui::HAttach::Center)
100.0, .draw_index(2)
30.0); .create(ui_container);
refresh.set_v_attach(ui::VAttach::Middle); {
refresh.set_h_attach(ui::HAttach::Center); let mut refresh = refresh.borrow_mut();
let re = ui_container.add(refresh); let txt = ui::TextBuilder::new()
txt.set_parent(&re); .text("Refresh")
let tre = ui_container.add(txt); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
let nr = self.needs_reload.clone(); .attach(&mut *refresh);
super::button_action(ui_container, refresh.add_text(txt);
re.clone(), let nr = self.needs_reload.clone();
Some(tre.clone()), refresh.add_click_func(move |_, _| {
move |_, _| { *nr.borrow_mut() = true;
*nr.borrow_mut() = true; true
}); })
elements.add(re); }
elements.add(tre);
// Add a new server to the list // Add a new server to the list
let (mut add, mut txt) = super::new_button_text( let add = ui::ButtonBuilder::new()
renderer, "Add", .position(200.0, -50.0 - 15.0)
200.0, -50.0 - 15.0, 100.0, 30.0 .size(100.0, 30.0)
); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
add.set_v_attach(ui::VAttach::Middle); .draw_index(2)
add.set_h_attach(ui::HAttach::Center); .create(ui_container);
let re = ui_container.add(add); {
txt.set_parent(&re); let mut add = add.borrow_mut();
let tre = ui_container.add(txt); let txt = ui::TextBuilder::new()
super::button_action(ui_container, re.clone(), Some(tre.clone()), |game, _|{ .text("Add")
game.screen_sys.replace_screen(Box::new(super::edit_server::EditServerEntry::new( .alignment(ui::VAttach::Middle, ui::HAttach::Center)
None .attach(&mut *add);
))); add.add_text(txt);
}); add.add_click_func(move |_, game| {
elements.add(re); game.screen_sys.replace_screen(Box::new(super::edit_server::EditServerEntry::new(
elements.add(tre); None
)));
true
})
}
// Options menu // Options menu
let mut options = ui::Button::new(5.0, 25.0, 40.0, 40.0); let options = ui::ButtonBuilder::new()
options.set_v_attach(ui::VAttach::Bottom); .position(5.0, 25.0)
options.set_h_attach(ui::HAttach::Right); .size(40.0, 40.0)
let re = ui_container.add(options); .alignment(ui::VAttach::Bottom, ui::HAttach::Right)
let mut cog = ui::Image::new(render::Renderer::get_texture(renderer.get_textures_ref(), .create(ui_container);
"steven:gui/cog"), {
0.0, let mut options = options.borrow_mut();
0.0, ui::ImageBuilder::new()
40.0, .texture("steven:gui/cog")
40.0, .position(0.0, 0.0)
0.0, .size(40.0, 40.0)
0.0, .alignment(ui::VAttach::Middle, ui::HAttach::Center)
1.0, .attach(&mut *options);
1.0, options.add_click_func(|_, game| {
255, game.screen_sys.add_screen(Box::new(super::SettingsMenu::new(game.vars.clone(), false)));
255, true
255); });
cog.set_parent(&re); }
cog.set_v_attach(ui::VAttach::Middle);
cog.set_h_attach(ui::HAttach::Center);
super::button_action(ui_container, re.clone(), None, | game, _ | {
game.screen_sys.add_screen(Box::new(super::SettingsMenu::new(game.vars.clone(), false)));
});
elements.add(re);
elements.add(ui_container.add(cog));
// Disclaimer // Disclaimer
let mut warn = ui::Text::new(renderer, let disclaimer = ui::TextBuilder::new()
"Not affiliated with Mojang/Minecraft", .text("Not affiliated with Mojang/Minecraft")
5.0, .position(5.0, 5.0)
5.0, .colour((255, 200, 200, 255))
255, .alignment(ui::VAttach::Bottom, ui::HAttach::Right)
200, .create(ui_container);
200);
warn.set_v_attach(ui::VAttach::Bottom);
warn.set_h_attach(ui::HAttach::Right);
elements.add(ui_container.add(warn));
// If we are kicked from a server display the reason // If we are kicked from a server display the reason
if let Some(ref disconnect_reason) = self.disconnect_reason { let disconnected = if let Some(ref disconnect_reason) = self.disconnect_reason {
let mut dis_msg = ui::Text::new(renderer, "Disconnected", 0.0, 32.0, 255, 0, 0); let (width, height) = ui::Formatted::compute_size(renderer, disconnect_reason, 600.0);
dis_msg.set_h_attach(ui::HAttach::Center); let background = ui::ImageBuilder::new()
let mut dis = ui::Formatted::with_width_limit(renderer, .texture("steven:solid")
disconnect_reason.clone(), .position(0.0, 3.0)
0.0, .size(width.max(renderer.ui.size_of_string("Disconnected")) + 4.0, height + 4.0 + 16.0)
48.0, .colour((0, 0, 0, 100))
600.0); .alignment(ui::VAttach::Top, ui::HAttach::Center)
dis.set_h_attach(ui::HAttach::Center); .create(ui_container);
let mut back = ui::TextBuilder::new()
ui::Image::new(render::Renderer::get_texture(renderer.get_textures_ref(), .text("Disconnected")
"steven:solid"), .position(0.0, 2.0)
0.0, .colour((255, 0, 0, 255))
30.0, .alignment(ui::VAttach::Top, ui::HAttach::Center)
dis.get_width().max(dis_msg.get_width()) + 4.0, .attach(&mut *background.borrow_mut());
dis.get_height() + 4.0 + 16.0, ui::FormattedBuilder::new()
0.0, .text(disconnect_reason.clone())
0.0, .position(0.0, 18.0)
1.0, .max_width(600.0)
1.0, .alignment(ui::VAttach::Top, ui::HAttach::Center)
0, .attach(&mut *background.borrow_mut());
0, Some(background)
0); } else {
back.set_a(100); None
back.set_h_attach(ui::HAttach::Center); };
elements.add(ui_container.add(back));
elements.add(ui_container.add(dis));
elements.add(ui_container.add(dis_msg));
}
self.elements = Some(UIElements { self.elements = Some(UIElements {
logo: logo, logo: logo,
elements: elements,
servers: Vec::new(), servers: Vec::new(),
_add_btn: add,
_refresh_btn: refresh,
_options_btn: options,
_disclaimer: disclaimer,
_disconnected: disconnected,
}); });
self.reload_server_list(renderer, ui_container); self.reload_server_list(renderer, ui_container);
} }
fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_deactive(&mut self, renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
// Clean up // Clean up
{ {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
elements.logo.remove(ui_container);
elements.elements.remove_all(ui_container);
let mut tex = renderer.get_textures_ref().write().unwrap(); let mut tex = renderer.get_textures_ref().write().unwrap();
for server in &mut elements.servers { for server in &mut elements.servers {
if let Some(ref icon) = server.icon_texture { if let Some(ref icon) = server.icon_texture {
tex.remove_dynamic(&icon); tex.remove_dynamic(&icon);
} }
server.collection.remove_all(ui_container);
} }
elements.servers.clear();
} }
self.elements = None self.elements = None
} }
@ -470,18 +441,18 @@ impl super::Screen for ServerList {
} }
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
elements.logo.tick(renderer, ui_container); elements.logo.tick(renderer);
for s in &mut elements.servers { for s in &mut elements.servers {
// Animate the entries // Animate the entries
{ {
let back = ui_container.get_mut(&s.back); let mut back = s.back.borrow_mut();
let dy = s.y - back.get_y(); let dy = s.y - back.y;
if dy * dy > 1.0 { if dy * dy > 1.0 {
let y = back.get_y(); let y = back.y;
back.set_y(y + delta * dy * 0.1); back.y = y + delta * dy * 0.1;
} else { } else {
back.set_y(s.y); back.y = s.y;
} }
} }
@ -491,45 +462,36 @@ impl super::Screen for ServerList {
match s.recv.try_recv() { match s.recv.try_recv() {
Ok(res) => { Ok(res) => {
s.done_ping = true; s.done_ping = true;
{ s.motd.borrow_mut().set_text(res.motd);
let motd = ui_container.get_mut(&s.motd); // Selects the icon for the given ping range
motd.set_component(renderer, res.motd); let y = match res.ping.num_milliseconds() {
} _x @ 0 ... 75 => 16.0 / 256.0,
{ _x @ 76 ... 150 => 24.0 / 256.0,
let ping = ui_container.get_mut(&s.ping); _x @ 151 ... 225 => 32.0 / 256.0,
// Selects the icon for the given ping range _x @ 226 ... 350 => 40.0 / 256.0,
let y = match res.ping.num_milliseconds() { _x @ 351 ... 999 => 48.0 / 256.0,
_x @ 0 ... 75 => 16.0 / 256.0, _ => 56.0 / 256.0,
_x @ 76 ... 150 => 24.0 / 256.0, };
_x @ 151 ... 225 => 32.0 / 256.0, s.ping.borrow_mut().texture_coords.1 = y;
_x @ 226 ... 350 => 40.0 / 256.0,
_x @ 351 ... 999 => 48.0 / 256.0,
_ => 56.0 / 256.0,
};
ping.set_t_y(y);
}
if res.exists { if res.exists {
{ {
let players = ui_container.get_mut(&s.players); let mut players = s.players.borrow_mut();
let txt = if res.protocol_version == protocol::SUPPORTED_PROTOCOL { let txt = if res.protocol_version == protocol::SUPPORTED_PROTOCOL {
players.set_g(255); players.colour.1 = 255;
players.set_b(255); players.colour.2 = 255;
format!("{}/{}", res.online, res.max) format!("{}/{}", res.online, res.max)
} else { } else {
players.set_g(85); players.colour.1 = 85;
players.set_b(85); players.colour.2 = 85;
format!("Out of date {}/{}", res.online, res.max) format!("Out of date {}/{}", res.online, res.max)
}; };
players.set_text(renderer, &txt); players.text = txt;
}
{
let version = ui_container.get_mut(&s.version);
let mut txt = TextComponent::new(&res.protocol_name);
txt.modifier.color = Some(format::Color::Yellow);
let mut msg = Component::Text(txt);
format::convert_legacy(&mut msg);
version.set_component(renderer, msg);
} }
let mut txt = TextComponent::new(&res.protocol_name);
txt.modifier.color = Some(format::Color::Yellow);
let mut msg = Component::Text(txt);
format::convert_legacy(&mut msg);
s.version.borrow_mut().set_text(msg);
} }
if let Some(favicon) = res.favicon { if let Some(favicon) = res.favicon {
let name: String = rand::thread_rng() let name: String = rand::thread_rng()
@ -541,16 +503,14 @@ impl super::Screen for ServerList {
let icon_tex = tex.write() let icon_tex = tex.write()
.unwrap() .unwrap()
.put_dynamic(&name, favicon); .put_dynamic(&name, favicon);
let icon = ui_container.get_mut(&s.icon); s.icon.borrow_mut().texture = icon_tex.name;
icon.set_texture(icon_tex);
} }
} }
Err(mpsc::TryRecvError::Disconnected) => { Err(mpsc::TryRecvError::Disconnected) => {
s.done_ping = true; s.done_ping = true;
let motd = ui_container.get_mut(&s.motd);
let mut txt = TextComponent::new("Channel dropped"); let mut txt = TextComponent::new("Channel dropped");
txt.modifier.color = Some(format::Color::Red); txt.modifier.color = Some(format::Color::Red);
motd.set_component(renderer, Component::Text(txt)); s.motd.borrow_mut().set_text(Component::Text(txt));
} }
_ => {} _ => {}
} }

View File

@ -5,49 +5,13 @@ use settings;
use std::rc::Rc; use std::rc::Rc;
pub fn new_submenu_button(text: &str, renderer: &mut render::Renderer, ui_container: &mut ui::Container, x: f64, y: f64) -> (ui::ElementRef<ui::Button>, ui::ElementRef<ui::Text>) {
let (mut btn, mut txt) = super::new_button_text(renderer, text, x, y, 300.0, 40.0);
btn.set_v_attach(ui::VAttach::Middle);
btn.set_h_attach(ui::HAttach::Center);
let ui_btn = ui_container.add(btn);
txt.set_parent(&ui_btn);
(ui_btn, ui_container.add(txt))
}
pub fn new_centered_button(text: &str, renderer: &mut render::Renderer, ui_container: &mut ui::Container, y: f64, vertical_attach: ui::VAttach) -> (ui::ElementRef<ui::Button>, ui::ElementRef<ui::Text>) {
let (mut btn, mut txt) = super::new_button_text(renderer, text, 0.0, y, 400.0, 40.0);
btn.set_v_attach(vertical_attach);
btn.set_h_attach(ui::HAttach::Center);
let ui_btn = ui_container.add(btn);
txt.set_parent(&ui_btn);
(ui_btn, ui_container.add(txt))
}
macro_rules! get_bool_str {
($fmt:expr, $val:expr, $val_true:expr, $val_false:expr) => (format!($fmt, if $val {
$val_true
} else {
$val_false
}).as_ref());
($fmt:expr, $val:expr) => (get_bool_string!($fmt, $val, "true", "false"));
}
macro_rules! get_matched_str {
($fmt:expr, $val:expr, $($to_match:expr => $result:expr),*) => (
format!($fmt, match $val {
$($to_match => $result.to_owned(), )*
_ => $val.to_string(),
}).as_ref()
)
}
pub struct UIElements { pub struct UIElements {
elements: ui::Collection, background: ui::ImageRef,
background: ui::ElementRef<ui::Image>, _buttons: Vec<ui::ButtonRef>,
} }
pub struct SettingsMenu { pub struct SettingsMenu {
vars: Rc<console::Vars>, _vars: Rc<console::Vars>,
elements: Option<UIElements>, elements: Option<UIElements>,
show_disconnect_button: bool show_disconnect_button: bool
} }
@ -55,7 +19,7 @@ pub struct SettingsMenu {
impl SettingsMenu { impl SettingsMenu {
pub fn new(vars: Rc<console::Vars>, show_disconnect_button: bool) -> SettingsMenu { pub fn new(vars: Rc<console::Vars>, show_disconnect_button: bool) -> SettingsMenu {
SettingsMenu { SettingsMenu {
vars: vars, _vars: vars,
elements: None, elements: None,
show_disconnect_button: show_disconnect_button show_disconnect_button: show_disconnect_button
} }
@ -63,77 +27,135 @@ impl SettingsMenu {
} }
impl super::Screen for SettingsMenu { impl super::Screen for SettingsMenu {
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_active(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
let mut elements = ui::Collection::new(); let background = ui::ImageBuilder::new()
.texture("steven:solid")
.position(0.0, 0.0)
.size(854.0, 480.0)
.colour((0, 0, 0, 100))
.create(ui_container);
let mut background = ui::Image::new( let mut buttons = vec![];
render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"),
0.0, 0.0, 854.0, 480.0,
0.0, 0.0, 1.0, 1.0,
0, 0, 0
);
background.set_a(100);
let background = elements.add(ui_container.add(background));
// From top and down // From top and down
let (btn_audio_settings, txt_audio_settings) = new_submenu_button("Audio settings...", renderer, ui_container, -160.0, -50.0); let audio_settings = ui::ButtonBuilder::new()
super::button_action(ui_container, btn_audio_settings.clone(), Some(txt_audio_settings.clone()), move |game, _| { .position(-160.0, -50.0)
game.screen_sys.add_screen(Box::new(AudioSettingsMenu::new(game.vars.clone()))); .size(300.0, 40.0)
}); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
elements.add(btn_audio_settings); .create(ui_container);
elements.add(txt_audio_settings); {
let mut audio_settings = audio_settings.borrow_mut();
let txt = ui::TextBuilder::new()
.text("Audio settings...")
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *audio_settings);
audio_settings.add_text(txt);
audio_settings.add_click_func(|_, game| {
game.screen_sys.add_screen(Box::new(AudioSettingsMenu::new(game.vars.clone())));
true
});
}
buttons.push(audio_settings);
let (btn_video_settings, txt_video_settings) = new_submenu_button("Video settings...", renderer, ui_container, 160.0, -50.0); let video_settings = ui::ButtonBuilder::new()
super::button_action(ui_container, btn_video_settings.clone(), Some(txt_video_settings.clone()), move |game, _| { .position(160.0, -50.0)
game.screen_sys.add_screen(Box::new(VideoSettingsMenu::new(game.vars.clone()))); .size(300.0, 40.0)
}); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
elements.add(btn_video_settings); .create(ui_container);
elements.add(txt_video_settings); {
let mut video_settings = video_settings.borrow_mut();
let txt = ui::TextBuilder::new()
.text("Video settings...")
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *video_settings);
video_settings.add_text(txt);
video_settings.add_click_func(|_, game| {
game.screen_sys.add_screen(Box::new(VideoSettingsMenu::new(game.vars.clone())));
true
});
}
buttons.push(video_settings);
let (btn_controls_settings, txt_controls_settings) = new_submenu_button("Controls...", renderer, ui_container, 160.0, 0.0); let controls_settings = ui::ButtonBuilder::new()
super::button_action(ui_container, btn_controls_settings.clone(), Some(txt_controls_settings.clone()), move |_, _| { .position(160.0, 0.0)
// TODO: Implement this... .size(300.0, 40.0)
}); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
elements.add(btn_controls_settings); .create(ui_container);
elements.add(txt_controls_settings); {
let mut controls_settings = controls_settings.borrow_mut();
let txt = ui::TextBuilder::new()
.text("Controls...")
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *controls_settings);
controls_settings.add_text(txt);
}
buttons.push(controls_settings);
let (btn_locale_settings, txt_locale_settings) = new_submenu_button("Language...", renderer, ui_container, -160.0, 0.0); let lang_settings = ui::ButtonBuilder::new()
super::button_action(ui_container, btn_locale_settings.clone(), Some(txt_locale_settings.clone()), move |_, _| { .position(-160.0, 0.0)
// TODO: Implement this... .size(300.0, 40.0)
}); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
elements.add(btn_locale_settings); .create(ui_container);
elements.add(txt_locale_settings); {
let mut lang_settings = lang_settings.borrow_mut();
let txt = ui::TextBuilder::new()
.text("Language...")
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *lang_settings);
lang_settings.add_text(txt);
}
buttons.push(lang_settings);
// Center bottom items // Center bottom items
let (btn_back_to_game, txt_back_to_game) = new_centered_button("Done", renderer, ui_container, 50.0, ui::VAttach::Bottom); let done_button = ui::ButtonBuilder::new()
super::button_action(ui_container, btn_back_to_game.clone(), Some(txt_back_to_game.clone()), move |game, _| { .position(0.0, 50.0)
game.screen_sys.pop_screen(); .size(300.0, 40.0)
game.focused = true; .alignment(ui::VAttach::Bottom, ui::HAttach::Center)
}); .create(ui_container);
elements.add(btn_back_to_game); {
elements.add(txt_back_to_game); let mut done_button = done_button.borrow_mut();
let txt = ui::TextBuilder::new()
.text("Done")
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *done_button);
done_button.add_text(txt);
done_button.add_click_func(|_, game| {
game.screen_sys.pop_screen();
game.focused = true;
true
});
}
buttons.push(done_button);
if self.show_disconnect_button { if self.show_disconnect_button {
let (btn_exit_game, txt_exit_game) = new_centered_button("Disconnect", renderer, ui_container, 100.0, ui::VAttach::Bottom); let disconnect_button = ui::ButtonBuilder::new()
super::button_action(ui_container, btn_exit_game.clone(), Some(txt_exit_game.clone()), move |game, _| { .position(0.0, 100.0)
game.server.disconnect(None); .size(300.0, 40.0)
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None))); .alignment(ui::VAttach::Bottom, ui::HAttach::Center)
}); .create(ui_container);
elements.add(btn_exit_game); {
elements.add(txt_exit_game); let mut disconnect_button = disconnect_button.borrow_mut();
let txt = ui::TextBuilder::new()
.text("Disconnect")
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *disconnect_button);
disconnect_button.add_text(txt);
disconnect_button.add_click_func(|_, game| {
game.server.disconnect(None);
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None)));
true
});
}
buttons.push(disconnect_button);
} }
self.elements = Some(UIElements { self.elements = Some(UIElements {
elements: elements,
background: background, background: background,
_buttons: buttons,
}); });
} }
fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
{
let elements = self.elements.as_mut().unwrap();
elements.elements.remove_all(ui_container);
}
self.elements = None; self.elements = None;
} }
@ -142,15 +164,15 @@ impl super::Screen for SettingsMenu {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
{ {
let mode = ui_container.mode; let mode = ui_container.mode;
let background = ui_container.get_mut(&elements.background); let mut background = elements.background.borrow_mut();
background.set_width(match mode { background.width = match mode {
ui::Mode::Unscaled(scale) => 854.0 / scale, ui::Mode::Unscaled(scale) => 854.0 / scale,
ui::Mode::Scaled => renderer.width as f64, ui::Mode::Scaled => renderer.width as f64,
}); };
background.set_height(match mode { background.height = match mode {
ui::Mode::Unscaled(scale) => 480.0 / scale, ui::Mode::Unscaled(scale) => 480.0 / scale,
ui::Mode::Scaled => renderer.height as f64, ui::Mode::Scaled => renderer.height as f64,
}); };
} }
None None
} }
@ -180,17 +202,15 @@ impl VideoSettingsMenu {
} }
impl super::Screen for VideoSettingsMenu { impl super::Screen for VideoSettingsMenu {
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_active(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
let mut elements = ui::Collection::new(); let background = ui::ImageBuilder::new()
.texture("steven:solid")
.position(0.0, 0.0)
.size(854.0, 480.0)
.colour((0, 0, 0, 100))
.create(ui_container);
let mut background = ui::Image::new( let mut buttons = vec![];
render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"),
0.0, 0.0, 854.0, 480.0,
0.0, 0.0, 1.0, 1.0,
0, 0, 0
);
background.set_a(100);
let background = elements.add(ui_container.add(background));
// Load defaults // Load defaults
let r_max_fps = *self.vars.get(settings::R_MAX_FPS); let r_max_fps = *self.vars.get(settings::R_MAX_FPS);
@ -199,42 +219,92 @@ impl super::Screen for VideoSettingsMenu {
// Setting buttons // Setting buttons
// TODO: Slider // TODO: Slider
let (btn_fov, txt_fov) = new_submenu_button(get_matched_str!("FOV: {}", r_fov, 90 => "Normal", 110 => "Quake pro"), renderer, ui_container, -160.0, -50.0); let fov_setting = ui::ButtonBuilder::new()
elements.add(btn_fov); .position(160.0, -50.0)
elements.add(txt_fov); .size(300.0, 40.0)
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.create(ui_container);
{
let mut fov_setting = fov_setting.borrow_mut();
let txt = ui::TextBuilder::new()
.text(format!("FOV: {}", match r_fov {
90 => "Normal".into(),
110 => "Quake pro".into(),
val => val.to_string(),
}))
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *fov_setting);
fov_setting.add_text(txt);
}
buttons.push(fov_setting);
let (btn_vsync, txt_vsync) = new_submenu_button(get_bool_str!("VSync: {}", r_vsync, "Enabled", "Disabled"), renderer, ui_container, -160.0, 0.0); let vsync_setting = ui::ButtonBuilder::new()
elements.add(txt_vsync.clone()); .position(-160.0, 0.0)
super::button_action(ui_container, btn_vsync.clone(), Some(txt_vsync.clone()), move | game, ui_container | { .size(300.0, 40.0)
let r_vsync = !*game.vars.get(settings::R_VSYNC); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
let txt_vsync = ui_container.get_mut(&txt_vsync); .create(ui_container);
txt_vsync.set_text(&game.renderer, get_bool_str!("VSync: {}", r_vsync, "Enabled", "Disabled")); {
game.vars.set(settings::R_VSYNC, r_vsync); let mut vsync_setting = vsync_setting.borrow_mut();
}); let txt = ui::TextBuilder::new()
elements.add(btn_vsync); .text(format!("VSync: {}", if r_vsync { "Enabled" } else { "Disabled" }))
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *vsync_setting);
let txt_vsync = txt.clone();
vsync_setting.add_text(txt);
vsync_setting.add_click_func(move |_, game| {
let r_vsync = !*game.vars.get(settings::R_VSYNC);
txt_vsync.borrow_mut().text = format!("VSync: {}", if r_vsync { "Enabled" } else { "Disabled" });
game.vars.set(settings::R_VSYNC, r_vsync);
true
});
}
buttons.push(vsync_setting);
// TODO: Slider // TODO: Slider
let (btn_fps_cap, txt_fps_cap) = new_submenu_button(get_matched_str!("FPS cap: {}", r_max_fps, 0 => "Unlimited", 15 => "Potato"), renderer, ui_container, 160.0, 0.0); let fps_setting = ui::ButtonBuilder::new()
elements.add(btn_fps_cap); .position(160.0, 0.0)
elements.add(txt_fps_cap); .size(300.0, 40.0)
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.create(ui_container);
{
let mut fps_setting = fps_setting.borrow_mut();
let txt = ui::TextBuilder::new()
.text(format!("FPS cap: {}", match r_max_fps {
0 => "Unlimited".into(),
val => val.to_string(),
}))
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *fps_setting);
fps_setting.add_text(txt);
}
buttons.push(fps_setting);
let (btn_done, txt_done) = new_centered_button("Done", renderer, ui_container, 50.0, ui::VAttach::Bottom); let done_button = ui::ButtonBuilder::new()
super::button_action(ui_container, btn_done.clone(), Some(txt_done.clone()), move | game, _ | { .position(0.0, 50.0)
game.screen_sys.pop_screen(); .size(300.0, 40.0)
}); .alignment(ui::VAttach::Bottom, ui::HAttach::Center)
elements.add(btn_done); .create(ui_container);
elements.add(txt_done); {
let mut done_button = done_button.borrow_mut();
let txt = ui::TextBuilder::new()
.text("Done")
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *done_button);
done_button.add_text(txt);
done_button.add_click_func(|_, game| {
game.screen_sys.pop_screen();
game.focused = true;
true
});
}
buttons.push(done_button);
self.elements = Some(UIElements { self.elements = Some(UIElements {
elements: elements,
background: background, background: background,
_buttons: buttons,
}); });
} }
fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
{
let elements = self.elements.as_mut().unwrap();
elements.elements.remove_all(ui_container);
}
self.elements = None; self.elements = None;
} }
@ -243,15 +313,15 @@ impl super::Screen for VideoSettingsMenu {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
{ {
let mode = ui_container.mode; let mode = ui_container.mode;
let background = ui_container.get_mut(&elements.background); let mut background = elements.background.borrow_mut();
background.set_width(match mode { background.width = match mode {
ui::Mode::Unscaled(scale) => 854.0 / scale, ui::Mode::Unscaled(scale) => 854.0 / scale,
ui::Mode::Scaled => renderer.width as f64, ui::Mode::Scaled => renderer.width as f64,
}); };
background.set_height(match mode { background.height = match mode {
ui::Mode::Unscaled(scale) => 480.0 / scale, ui::Mode::Unscaled(scale) => 480.0 / scale,
ui::Mode::Scaled => renderer.height as f64, ui::Mode::Scaled => renderer.height as f64,
}); };
} }
None None
} }
@ -267,56 +337,59 @@ impl super::Screen for VideoSettingsMenu {
} }
pub struct AudioSettingsMenu { pub struct AudioSettingsMenu {
vars: Rc<console::Vars>, _vars: Rc<console::Vars>,
elements: Option<UIElements> elements: Option<UIElements>
} }
impl AudioSettingsMenu { impl AudioSettingsMenu {
pub fn new(vars: Rc<console::Vars>) -> AudioSettingsMenu { pub fn new(vars: Rc<console::Vars>) -> AudioSettingsMenu {
AudioSettingsMenu { AudioSettingsMenu {
vars: vars, _vars: vars,
elements: None elements: None
} }
} }
} }
impl super::Screen for AudioSettingsMenu { impl super::Screen for AudioSettingsMenu {
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_active(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
let mut elements = ui::Collection::new(); let background = ui::ImageBuilder::new()
.texture("steven:solid")
.position(0.0, 0.0)
.size(854.0, 480.0)
.colour((0, 0, 0, 100))
.create(ui_container);
let mut background = ui::Image::new( let mut buttons = vec![];
render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"),
0.0, 0.0, 854.0, 480.0,
0.0, 0.0, 1.0, 1.0,
0, 0, 0
);
background.set_a(100);
let background = elements.add(ui_container.add(background));
let master_volume = *self.vars.get(settings::CL_MASTER_VOLUME); // TODO
let (btn_master_volume, txt_master_volume) = new_centered_button(&master_volume.to_string(), renderer, ui_container, -150.0, ui::VAttach::Middle); let done_button = ui::ButtonBuilder::new()
elements.add(btn_master_volume); .position(0.0, 50.0)
elements.add(txt_master_volume); .size(300.0, 40.0)
.alignment(ui::VAttach::Bottom, ui::HAttach::Center)
let (btn_done, txt_done) = new_centered_button("Done", renderer, ui_container, 50.0, ui::VAttach::Bottom); .create(ui_container);
super::button_action(ui_container, btn_done.clone(), Some(txt_done.clone()), move | game, _ | { {
game.screen_sys.pop_screen(); let mut done_button = done_button.borrow_mut();
}); let txt = ui::TextBuilder::new()
elements.add(btn_done); .text("Done")
elements.add(txt_done); .alignment(ui::VAttach::Middle, ui::HAttach::Center)
.attach(&mut *done_button);
done_button.add_text(txt);
done_button.add_click_func(|_, game| {
game.screen_sys.pop_screen();
game.focused = true;
true
});
}
buttons.push(done_button);
self.elements = Some(UIElements { self.elements = Some(UIElements {
elements: elements,
background: background, background: background,
_buttons: buttons,
}); });
} }
fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
{
let elements = self.elements.as_mut().unwrap();
elements.elements.remove_all(ui_container);
}
self.elements = None; self.elements = None;
} }
@ -325,15 +398,15 @@ impl super::Screen for AudioSettingsMenu {
let elements = self.elements.as_mut().unwrap(); let elements = self.elements.as_mut().unwrap();
{ {
let mode = ui_container.mode; let mode = ui_container.mode;
let background = ui_container.get_mut(&elements.background); let mut background = elements.background.borrow_mut();
background.set_width(match mode { background.width = match mode {
ui::Mode::Unscaled(scale) => 854.0 / scale, ui::Mode::Unscaled(scale) => 854.0 / scale,
ui::Mode::Scaled => renderer.width as f64, ui::Mode::Scaled => renderer.width as f64,
}); };
background.set_height(match mode { background.height = match mode {
ui::Mode::Unscaled(scale) => 480.0 / scale, ui::Mode::Unscaled(scale) => 480.0 / scale,
ui::Mode::Scaled => renderer.height as f64, ui::Mode::Scaled => renderer.height as f64,
}); };
} }
None None
} }

View File

@ -1,128 +0,0 @@
// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[derive(Clone, Copy)]
pub struct BatchRef<T: UIElement> {
index: usize,
ty: PhantomData<T>,
}
ui_element!(Batch {
width: f64,
height: f64,
elements: Vec<Element>,
});
impl Batch {
base_impl!();
pub fn new(x: f64, y: f64, w: f64, h: f64) -> Batch {
ui_create!(Batch {
x: x,
y: y,
width: w,
height: h,
elements: Vec::new(),
})
}
fn update(&mut self, _: &mut render::Renderer) {
}
fn draw(&mut self,
renderer: &mut render::Renderer,
r: &Region,
width: f64,
height: f64,
delta: f64)
-> &Vec<u8> {
if self.dirty {
self.dirty = false;
self.data.clear();
let sx = r.w / self.width;
let sy = r.h / self.height;
for e in &mut self.elements {
let reg = e.get_draw_region(sx, sy, r);
e.set_dirty(true);
self.data.extend(e.draw(renderer, &reg, width, height, delta));
}
}
&self.data
}
pub fn add<T: UIElement>(&mut self, e: T) -> BatchRef<T> {
self.elements.push(e.wrap());
BatchRef {
index: self.elements.len() - 1,
ty: PhantomData,
}
}
pub fn get<T: UIElement>(&self, r: BatchRef<T>) -> &T {
T::unwrap_ref(&self.elements[r.index])
}
pub fn get_mut<T: UIElement>(&mut self, r: BatchRef<T>) -> &mut T {
self.dirty = true;
T::unwrap_ref_mut(&mut self.elements[r.index])
}
pub fn get_mut_at<T: UIElement>(&mut self, index: usize) -> &mut T {
self.dirty = true;
T::unwrap_ref_mut(&mut self.elements[index])
}
pub fn len(&self) -> usize {
self.elements.len()
}
lazy_field!(width, f64, get_width, set_width);
lazy_field!(height, f64, get_height, set_height);
}
impl UIElement for Batch {
fn wrap(self) -> Element {
Element::Batch(self)
}
fn unwrap_ref<'a>(e: &'a Element) -> &'a Batch {
match e {
&Element::Batch(ref val) => val,
_ => panic!("Incorrect type"),
}
}
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Batch {
match e {
&mut Element::Batch(ref mut val) => val,
_ => panic!("Incorrect type"),
}
}
fn get_attachment(&self) -> (VAttach, HAttach) {
(self.v_attach, self.h_attach)
}
fn get_offset(&self) -> (f64, f64) {
(self.x, self.y)
}
fn get_size(&self) -> (f64, f64) {
(self.width, self.height)
}
}

View File

@ -1,144 +0,0 @@
// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
ui_element!(Button {
width: f64,
height: f64,
disabled: bool,
});
impl Button {
base_impl!();
pub fn new(x: f64, y: f64, w: f64, h: f64) -> Button {
let mut btn = ui_create!(Button {
x: x,
y: y,
width: w,
height: h,
disabled: false,
});
btn.add_hover_func(|_,_,_|{}); // Force hover events to be called
btn
}
fn update(&mut self, _renderer: &mut render::Renderer) {
}
fn draw(&mut self,
renderer: &mut render::Renderer,
r: &Region,
width: f64,
height: f64,
_delta: f64)
-> &Vec<u8> {
if self.dirty {
self.dirty = false;
let sx = r.w / self.width;
let sy = r.h / self.height;
let offset = match (self.disabled, self.hovered) {
(true, _) => 46.0,
(false, true) => 86.0,
(false, false) => 66.0,
};
let texture = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/widgets")
.relative(0.0, offset / 256.0, 200.0 / 256.0, 20.0 / 256.0);
self.data.clear();
self.data.extend(render::ui::UIElement::new(&texture, r.x, r.y, 4.0 * sx, 4.0 * sy, 0.0, 0.0, 2.0/200.0, 2.0/20.0).bytes(width, height));
self.data.extend(render::ui::UIElement::new(&texture, r.x + r.w - 4.0 * sx, r.y, 4.0 * sx, 4.0 * sy, 198.0/200.0, 0.0, 2.0/200.0, 2.0/20.0).bytes(width, height));
self.data.extend(render::ui::UIElement::new(&texture, r.x, r.y + r.h - 6.0 * sy, 4.0 * sx, 6.0 * sy, 0.0, 17.0/20.0, 2.0/200.0, 3.0/20.0).bytes(width, height));
self.data.extend(render::ui::UIElement::new(&texture, r.x + r.w - 4.0 * sx, r.y + r.h - 6.0 * sy, 4.0 * sx, 6.0 * sy, 198.0/200.0, 17.0/20.0, 2.0/200.0, 3.0/20.0).bytes(width, height));
let w = ((r.w / sx)/2.0) - 4.0;
self.data.extend(render::ui::UIElement::new(
&texture.relative(2.0/200.0, 0.0, 196.0/200.0, 2.0/20.0),
r.x+4.0*sx, r.y, r.w - 8.0 * sx, 4.0 * sy, 0.0, 0.0, w/196.0, 1.0).bytes(width, height)
);
self.data.extend(render::ui::UIElement::new(
&texture.relative(2.0/200.0, 17.0/20.0, 196.0/200.0, 3.0/20.0),
r.x+4.0*sx, r.y+r.h-6.0*sy, r.w - 8.0 * sx, 6.0 * sy, 0.0, 0.0, w/196.0, 1.0).bytes(width, height)
);
let h = ((r.h / sy)/2.0) - 5.0;
self.data.extend(render::ui::UIElement::new(
&texture.relative(0.0/200.0, 2.0/20.0, 2.0/200.0, 15.0/20.0),
r.x, r.y + 4.0*sy, 4.0 * sx, r.h - 10.0*sy, 0.0, 0.0, 1.0, h/16.0).bytes(width, height)
);
self.data.extend(render::ui::UIElement::new(
&texture.relative(198.0/200.0, 2.0/20.0, 2.0/200.0, 15.0/20.0),
r.x+r.w - 4.0 * sx, r.y + 4.0*sy, 4.0 * sx, r.h - 10.0*sy, 0.0, 0.0, 1.0, h/16.0).bytes(width, height)
);
self.data.extend(render::ui::UIElement::new(
&texture.relative(2.0/200.0, 2.0/20.0, 196.0/200.0, 15.0/20.0),
r.x+4.0*sx, r.y+4.0*sy, r.w - 8.0 * sx, r.h - 10.0 * sy, 0.0, 0.0, w/196.0, h/16.0).bytes(width, height)
);
}
&self.data
}
lazy_field!(width, f64, get_width, set_width);
lazy_field!(height, f64, get_height, set_height);
lazy_field!(disabled, bool, is_disabled, set_disabled);
}
impl UIElement for Button {
fn wrap(self) -> Element {
Element::Button(self)
}
fn unwrap_ref<'a>(e: &'a Element) -> &'a Button {
match e {
&Element::Button(ref val) => val,
_ => panic!("Incorrect type"),
}
}
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Button {
match e {
&mut Element::Button(ref mut val) => val,
_ => panic!("Incorrect type"),
}
}
fn get_attachment(&self) -> (VAttach, HAttach) {
(self.v_attach, self.h_attach)
}
fn get_offset(&self) -> (f64, f64) {
(self.x, self.y)
}
fn get_size(&self) -> (f64, f64) {
(self.width, self.height)
}
}

View File

@ -1,237 +0,0 @@
// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
ui_element!(Formatted {
val: format::Component,
width: f64,
height: f64,
scale_x: f64,
scale_y: f64,
text: Vec<Element>,
max_width: f64,
lines: usize,
});
impl Formatted {
base_impl!();
pub fn new(renderer: &mut render::Renderer,
val: format::Component,
x: f64,
y: f64)
-> Formatted {
let mut f = ui_create!(Formatted {
val: val,
x: x,
y: y,
width: 0.0,
height: 18.0,
scale_x: 1.0,
scale_y: 1.0,
text: Vec::new(),
max_width: -1.0,
lines: 0,
});
f.init_component(renderer);
f
}
pub fn with_width_limit(renderer: &mut render::Renderer,
val: format::Component,
x: f64,
y: f64,
max_width: f64)
-> Formatted {
let mut f = ui_create!(Formatted {
val: val,
x: x,
y: y,
width: 0.0,
height: 18.0,
scale_x: 1.0,
scale_y: 1.0,
text: Vec::new(),
max_width: max_width,
lines: 0,
});
f.init_component(renderer);
f
}
pub fn set_component(&mut self, renderer: &mut render::Renderer, val: format::Component) {
self.val = val;
self.init_component(renderer);
}
fn init_component(&mut self, renderer: &mut render::Renderer) {
self.text.clear();
let mut state = FormatState {
lines: 0,
width: 0.0,
offset: 0.0,
text: Vec::new(),
max_width: self.max_width,
renderer: &renderer,
};
state.build(&self.val, format::Color::White);
self.height = (state.lines + 1) as f64 * 18.0;
self.width = state.width;
self.lines = state.lines;
self.text = state.text;
self.dirty = true;
}
fn update(&mut self, renderer: &mut render::Renderer) {
self.init_component(renderer);
}
fn draw(&mut self,
renderer: &mut render::Renderer,
r: &Region,
width: f64,
height: f64,
delta: f64)
-> &Vec<u8> {
if self.dirty {
self.dirty = false;
self.data.clear();
let sx = r.w / self.width;
let sy = r.h / self.height;
for e in &mut self.text {
let reg = e.get_draw_region(sx, sy, r);
e.set_dirty(true);
self.data.extend(e.draw(renderer, &reg, width, height, delta));
}
}
&self.data
}
lazy_field!(width, f64, get_width, set_width);
lazy_field!(height, f64, get_height, set_height);
lazy_field!(scale_x, f64, get_scale_x, set_scale_x);
lazy_field!(scale_y, f64, get_scale_y, set_scale_y);
}
impl UIElement for Formatted {
fn wrap(self) -> Element {
Element::Formatted(self)
}
fn unwrap_ref<'a>(e: &'a Element) -> &'a Formatted {
match e {
&Element::Formatted(ref val) => val,
_ => panic!("Incorrect type"),
}
}
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Formatted {
match e {
&mut Element::Formatted(ref mut val) => val,
_ => panic!("Incorrect type"),
}
}
fn get_attachment(&self) -> (VAttach, HAttach) {
(self.v_attach, self.h_attach)
}
fn get_offset(&self) -> (f64, f64) {
(self.x, self.y)
}
fn get_size(&self) -> (f64, f64) {
((self.width + 2.0) * self.scale_x, self.height * self.scale_y)
}
}
struct FormatState<'a> {
max_width: f64,
lines: usize,
offset: f64,
width: f64,
text: Vec<Element>,
renderer: &'a render::Renderer,
}
impl <'a> FormatState<'a> {
fn build(&mut self, c: &format::Component, color: format::Color) {
match c {
&format::Component::Text(ref txt) => {
let col = FormatState::get_color(&txt.modifier, color);
self.append_text(&txt.text, col);
let modi = &txt.modifier;
if let Some(ref extra) = modi.extra {
for e in extra {
self.build(e, col);
}
}
}
}
}
fn append_text(&mut self, txt: &str, color: format::Color) {
let mut width = 0.0;
let mut last = 0;
for (i, c) in txt.char_indices() {
let size = self.renderer.ui.size_of_char(c) + 2.0;
if (self.max_width > 0.0 && self.offset + width + size > self.max_width) || c == '\n' {
let (rr, gg, bb) = color.to_rgb();
let text = Text::new(self.renderer,
&txt[last..i],
self.offset,
(self.lines * 18 + 1) as f64,
rr,
gg,
bb);
self.text.push(text.wrap());
last = i;
if c == '\n' {
last += 1;
}
self.offset = 0.0;
self.lines += 1;
width = 0.0;
}
width += size;
if self.offset + width > self.width {
self.width = self.offset + width;
}
}
if last != txt.len() {
let (rr, gg, bb) = color.to_rgb();
let text = Text::new(self.renderer,
&txt[last..],
self.offset,
(self.lines * 18 + 1) as f64,
rr,
gg,
bb);
self.offset += text.width + 4.0; // TODO Why is this 4 not 2?
self.text.push(text.wrap());
if self.offset > self.width {
self.width = self.offset;
}
}
}
fn get_color(modi: &format::Modifier, color: format::Color) -> format::Color {
modi.color.unwrap_or(color)
}
}

View File

@ -1,151 +0,0 @@
// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
ui_element!(Image {
texture: render::Texture,
width: f64,
height: f64,
t_x: f64,
t_y: f64,
t_width: f64,
t_height: f64,
r: u8,
g: u8,
b: u8,
a: u8,
});
impl Image {
base_impl!();
pub fn new(texture: render::Texture,
x: f64,
y: f64,
w: f64,
h: f64,
t_x: f64,
t_y: f64,
t_width: f64,
t_height: f64,
r: u8,
g: u8,
b: u8)
-> Image {
ui_create!(Image {
texture: texture,
x: x,
y: y,
width: w,
height: h,
t_x: t_x,
t_y: t_y,
t_width: t_width,
t_height: t_height,
r: r,
g: g,
b: b,
a: 255,
})
}
fn update(&mut self, _: &mut render::Renderer) {
}
fn draw(&mut self,
renderer: &mut render::Renderer,
r: &Region,
width: f64,
height: f64,
_: f64)
-> &Vec<u8> {
if self.dirty {
self.dirty = false;
self.texture = renderer.check_texture(self.texture.clone());
let mut e = render::ui::UIElement::new(&self.texture,
r.x,
r.y,
r.w,
r.h,
self.t_x,
self.t_y,
self.t_width,
self.t_height);
e.r = self.r;
e.g = self.g;
e.b = self.b;
e.a = self.a;
e.layer = self.layer;
self.data = e.bytes(width, height);
}
&self.data
}
pub fn get_texture(&self) -> render::Texture {
self.texture.clone()
}
pub fn set_texture(&mut self, val: render::Texture) {
self.texture = val;
self.dirty = true;
}
lazy_field!(width, f64, get_width, set_width);
lazy_field!(height, f64, get_height, set_height);
lazy_field!(t_x, f64, get_t_x, set_t_x);
lazy_field!(t_y, f64, get_t_y, set_t_y);
lazy_field!(t_width, f64, get_t_width, set_t_width);
lazy_field!(t_height, f64, get_t_height, set_t_height);
lazy_field!(r, u8, get_r, set_r);
lazy_field!(g, u8, get_g, set_g);
lazy_field!(b, u8, get_b, set_b);
lazy_field!(a, u8, get_a, set_a);
}
impl UIElement for Image {
fn wrap(self) -> Element {
Element::Image(self)
}
fn unwrap_ref<'a>(e: &'a Element) -> &'a Image {
match e {
&Element::Image(ref val) => val,
_ => panic!("Incorrect type"),
}
}
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Image {
match e {
&mut Element::Image(ref mut val) => val,
_ => panic!("Incorrect type"),
}
}
fn get_attachment(&self) -> (VAttach, HAttach) {
(self.v_attach, self.h_attach)
}
fn get_offset(&self) -> (f64, f64) {
(self.x, self.y)
}
fn get_size(&self) -> (f64, f64) {
(self.width, self.height)
}
}

View File

@ -9,12 +9,10 @@ use rand;
use rand::Rng; use rand::Rng;
pub struct Logo { pub struct Logo {
resources: Arc<RwLock<resources::Manager>>, _shadow: ui::BatchRef,
_layer0: ui::BatchRef,
shadow: ui::ElementRef<ui::Batch>, text: ui::TextRef,
layer0: ui::ElementRef<ui::Batch>,
text: ui::ElementRef<ui::Text>,
text_base_scale: f64, text_base_scale: f64,
text_orig_x: f64, text_orig_x: f64,
text_index: isize, text_index: isize,
@ -23,40 +21,27 @@ pub struct Logo {
impl Logo { impl Logo {
pub fn new(resources: Arc<RwLock<resources::Manager>>, pub fn new(resources: Arc<RwLock<resources::Manager>>,
renderer: &mut render::Renderer,
ui_container: &mut ui::Container) ui_container: &mut ui::Container)
-> Logo { -> Logo {
let mut l = Logo {
resources: resources,
shadow: Default::default(),
layer0: Default::default(),
text: Default::default(),
text_base_scale: 0.0,
text_orig_x: 0.0,
text_index: -1,
text_strings: Vec::new(),
};
l.init(renderer, ui_container);
l
}
fn init(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
let logo_str = { let logo_str = {
let res = self.resources.read().unwrap(); let res = resources.read().unwrap();
let mut logo = res.open("steven", "logo/logo.txt").unwrap(); let mut logo = res.open("steven", "logo/logo.txt").unwrap();
let mut logo_str = String::new(); let mut logo_str = String::new();
logo.read_to_string(&mut logo_str).unwrap(); logo.read_to_string(&mut logo_str).unwrap();
logo_str logo_str
}; };
let solid = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"); let shadow_batch = ui::BatchBuilder::new()
let front = render::Renderer::get_texture(renderer.get_textures_ref(), "blocks/planks_oak"); .position(0.0, 8.0)
.size(100.0, 100.0)
let mut shadow_batch = ui::Batch::new(0.0, 8.0, 100.0, 100.0); .alignment(ui::VAttach::Top, ui::HAttach::Center)
let mut layer0 = ui::Batch::new(0.0, 8.0, 100.0, 100.0); .create(ui_container);
let layer0 = ui::BatchBuilder::new()
shadow_batch.set_h_attach(ui::HAttach::Center); .position(0.0, 8.0)
layer0.set_h_attach(ui::HAttach::Center); .size(100.0, 100.0)
.draw_index(1)
.alignment(ui::VAttach::Top, ui::HAttach::Center)
.create(ui_container);
let mut row = 0; let mut row = 0;
for line in logo_str.lines() { for line in logo_str.lines() {
@ -74,96 +59,96 @@ impl Logo {
} else { } else {
(170, 170, 170) (170, 170, 170)
}; };
let mut shadow = ui::Image::new(solid.clone(), ui::ImageBuilder::new()
(x + 2) as f64, .texture("steven:solid")
(y + 4) as f64, .position((x + 2) as f64, (y + 4) as f64)
4.0, .size(4.0, 8.0)
8.0, .colour((0, 0, 0, 100))
0.0, .attach(&mut *shadow_batch.borrow_mut());
0.0,
1.0,
1.0,
0,
0,
0);
shadow.set_a(100);
shadow_batch.add(shadow);
let img = ui::Image::new(front.clone(), ui::ImageBuilder::new()
x as f64, .texture("minecraft:blocks/planks_oak")
y as f64, .position(x as f64, y as f64)
4.0, .size(4.0, 8.0)
8.0, .texture_coords((
(x % 16) as f64 / 16.0, (x % 16) as f64 / 16.0, (y % 16) as f64 / 16.0,
(y % 16) as f64 / 16.0, 4.0 / 16.0, 8.0 / 16.0
4.0 / 16.0, ))
8.0 / 16.0, .colour((r, g, b, 255))
r, .attach(&mut *layer0.borrow_mut());
g,
b);
layer0.add(img);
let width = (x + 4) as f64; let width = (x + 4) as f64;
if shadow_batch.get_width() < width { if shadow_batch.borrow().width < width {
shadow_batch.set_width(width); shadow_batch.borrow_mut().width = width;
layer0.set_width(width); layer0.borrow_mut().width = width;
} }
} }
row += 1; row += 1;
} }
shadow_batch.borrow_mut().height = row as f64 * 8.0;
layer0.borrow_mut().height = row as f64 * 8.0;
let mut text_strings = vec![];
{ {
let res = self.resources.read().unwrap(); let res = resources.read().unwrap();
let mut splashes = res.open_all("minecraft", "texts/splashes.txt"); let mut splashes = res.open_all("minecraft", "texts/splashes.txt");
for file in &mut splashes { for file in &mut splashes {
let mut texts = String::new(); let mut texts = String::new();
file.read_to_string(&mut texts).unwrap(); file.read_to_string(&mut texts).unwrap();
for line in texts.lines() { for line in texts.lines() {
self.text_strings.push(line.to_owned().replace("\r", "")); text_strings.push(line.to_owned().replace("\r", ""));
} }
} }
let mut r: rand::XorShiftRng = rand::SeedableRng::from_seed([45, 64, 32, 12]); let mut r: rand::XorShiftRng = rand::SeedableRng::from_seed([45, 64, 32, 12]);
r.shuffle(&mut self.text_strings[..]); r.shuffle(&mut text_strings[..]);
} }
shadow_batch.set_height(row as f64 * 8.0); let txt = ui::TextBuilder::new()
layer0.set_height(row as f64 * 8.0); .text("")
.position(0.0, -8.0)
.colour((255, 255, 0, 255))
.rotation(-consts::PI / 8.0)
.alignment(ui::VAttach::Bottom, ui::HAttach::Right)
.draw_index(1)
.create(&mut *layer0.borrow_mut());
self.shadow = ui_container.add(shadow_batch); let width = txt.borrow().width;
self.layer0 = ui_container.add(layer0); let mut text_base_scale = 300.0 / width;
if text_base_scale > 1.0 {
let mut txt = ui::Text::new(renderer, "", 0.0, -8.0, 255, 255, 0); text_base_scale = 1.0;
txt.set_h_attach(ui::HAttach::Right); }
txt.set_v_attach(ui::VAttach::Bottom); txt.borrow_mut().x = (-width / 2.0) * text_base_scale;
txt.set_parent(&self.shadow); let text_orig_x = txt.borrow().x;
txt.set_rotation(-consts::PI / 8.0);
Logo {
let width = txt.get_width(); _shadow: shadow_batch,
self.text_base_scale = 300.0 / width; _layer0: layer0,
if self.text_base_scale > 1.0 { text: txt,
self.text_base_scale = 1.0; text_base_scale: text_base_scale,
text_orig_x: text_orig_x,
text_index: -1,
text_strings: text_strings,
} }
txt.set_x((-width / 2.0) * self.text_base_scale);
self.text_orig_x = txt.get_x();
self.text = ui_container.add(txt);
} }
pub fn tick(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { pub fn tick(&mut self, renderer: &mut render::Renderer) {
let now = time::now().to_timespec(); let now = time::now().to_timespec();
// Splash text // Splash text
let text = ui_container.get_mut(&self.text);
let text_index = (now.sec / 15) as isize % self.text_strings.len() as isize; let text_index = (now.sec / 15) as isize % self.text_strings.len() as isize;
let mut text = self.text.borrow_mut();
if self.text_index != text_index { if self.text_index != text_index {
self.text_index = text_index; self.text_index = text_index;
text.set_text(renderer, &self.text_strings[text_index as usize]); text.text = self.text_strings[text_index as usize].clone();
let width = text.get_width(); let width = (renderer.ui.size_of_string(&text.text) + 2.0) * text.scale_x;
self.text_base_scale = 300.0 / width; self.text_base_scale = 300.0 / width;
if self.text_base_scale > 1.0 { if self.text_base_scale > 1.0 {
self.text_base_scale = 1.0; self.text_base_scale = 1.0;
} }
text.set_x((-width / 2.0) * self.text_base_scale); text.x =(-width / 2.0) * self.text_base_scale;
self.text_orig_x = text.get_x(); self.text_orig_x = text.x;
} }
let timer = now.nsec as f64 / 1000000000.0; let timer = now.nsec as f64 / 1000000000.0;
@ -172,15 +157,9 @@ impl Logo {
offset = 2.0 - offset; offset = 2.0 - offset;
} }
offset = ((offset * consts::PI).cos() + 1.0) / 2.0; offset = ((offset * consts::PI).cos() + 1.0) / 2.0;
text.set_scale_x((0.7 + (offset / 3.0)) * self.text_base_scale); text.scale_x = (0.7 + (offset / 3.0)) * self.text_base_scale;
text.set_scale_y((0.7 + (offset / 3.0)) * self.text_base_scale); text.scale_y = (0.7 + (offset / 3.0)) * self.text_base_scale;
let scale = text.get_scale_x(); let scale = text.scale_x;
text.set_x(self.text_orig_x * scale * self.text_base_scale); text.x =self.text_orig_x * scale * self.text_base_scale;
}
pub fn remove(&self, ui_container: &mut ui::Container) {
ui_container.remove(&self.shadow);
ui_container.remove(&self.layer0);
ui_container.remove(&self.text);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,156 +0,0 @@
// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
ui_element!(Text {
val: String,
width: f64,
height: f64,
scale_x: f64,
scale_y: f64,
rotation: f64,
r: u8,
g: u8,
b: u8,
a: u8,
});
impl Text {
base_impl!();
pub fn new(renderer: &render::Renderer,
val: &str,
x: f64,
y: f64,
r: u8,
g: u8,
b: u8)
-> Text {
ui_create!(Text {
val: val.to_owned(),
x: x,
y: y,
width: renderer.ui.size_of_string(val),
height: 18.0,
scale_x: 1.0,
scale_y: 1.0,
rotation: 0.0,
r: r,
g: g,
b: b,
a: 255,
})
}
fn update(&mut self, renderer: &mut render::Renderer) {
self.width = renderer.ui.size_of_string(&self.val);
}
fn draw(&mut self,
renderer: &mut render::Renderer,
r: &Region,
width: f64,
height: f64,
_: f64)
-> &Vec<u8> {
if self.dirty {
self.dirty = false;
let sx = r.w / self.width;
let sy = r.h / self.height;
let mut text = if self.rotation == 0.0 {
renderer.ui.new_text_scaled(&self.val,
r.x,
r.y,
sx * self.scale_x,
sy * self.scale_y,
self.r,
self.g,
self.b)
} else {
let c = self.rotation.cos();
let s = self.rotation.sin();
let tmpx = r.w / 2.0;
let tmpy = r.h / 2.0;
let w = (tmpx * c - tmpy * s).abs();
let h = (tmpy * c + tmpx * s).abs();
renderer.ui.new_text_rotated(&self.val,
r.x + w - (r.w / 2.0),
r.y + h - (r.h / 2.0),
sx * self.scale_x,
sy * self.scale_y,
self.rotation,
self.r,
self.g,
self.b)
};
for e in &mut text.elements {
e.a = self.a;
e.layer = self.layer;
}
self.data = text.bytes(width, height);
}
&self.data
}
pub fn get_text(&self) -> &str {
&self.val
}
pub fn set_text(&mut self, renderer: &render::Renderer, val: &str) {
self.dirty = true;
self.val = val.to_owned();
self.width = renderer.ui.size_of_string(val);
}
lazy_field!(width, f64, get_width, set_width);
lazy_field!(height, f64, get_height, set_height);
lazy_field!(scale_x, f64, get_scale_x, set_scale_x);
lazy_field!(scale_y, f64, get_scale_y, set_scale_y);
lazy_field!(rotation, f64, get_rotation, set_rotation);
lazy_field!(r, u8, get_r, set_r);
lazy_field!(g, u8, get_g, set_g);
lazy_field!(b, u8, get_b, set_b);
}
impl UIElement for Text {
fn wrap(self) -> Element {
Element::Text(self)
}
fn unwrap_ref<'a>(e: &'a Element) -> &'a Text {
match e {
&Element::Text(ref val) => val,
_ => panic!("Incorrect type"),
}
}
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Text {
match e {
&mut Element::Text(ref mut val) => val,
_ => panic!("Incorrect type"),
}
}
fn get_attachment(&self) -> (VAttach, HAttach) {
(self.v_attach, self.h_attach)
}
fn get_offset(&self) -> (f64, f64) {
(self.x, self.y)
}
fn get_size(&self) -> (f64, f64) {
((self.width + 2.0) * self.scale_x, self.height * self.scale_y)
}
}

View File

@ -1,181 +0,0 @@
// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
ui_element!(TextBox {
input: String,
width: f64,
height: f64,
password: bool,
button: Button,
text: Text,
cursor_tick: f64,
was_focused: bool,
submit_funcs: Vec<Rc<ClickFunc>>,
});
impl TextBox {
base_impl!();
pub fn new(renderer: &render::Renderer,
input: &str,
x: f64, y: f64, w: f64, h: f64
) -> TextBox {
let mut btn = Button::new(0.0, 0.0, w, h);
btn.set_disabled(true);
let mut txt = Text::new(renderer, input, 5.0, 0.0, 255, 255, 255);
txt.set_v_attach(VAttach::Middle);
let mut tbox = ui_create!(TextBox {
input: input.to_owned(),
x: x,
y: y,
width: w,
height: h,
password: false,
button: btn,
text: txt,
cursor_tick: 0.0,
was_focused: false,
submit_funcs: vec![],
});
tbox.can_focus = true;
tbox
}
fn update(&mut self, renderer: &mut render::Renderer) {
self.text.update(renderer);
}
fn draw(&mut self,
renderer: &mut render::Renderer,
r: &Region,
width: f64,
height: f64,
delta: f64)
-> &Vec<u8> {
if self.dirty || self.focused || self.was_focused {
self.was_focused = self.focused;
self.data.clear();
self.dirty = false;
self.cursor_tick += delta;
if self.cursor_tick > 3000.0 {
self.cursor_tick -= 3000.0;
}
let mut txt = self.transform_input();
if self.focused && ((self.cursor_tick / 30.0) as i32) % 2 == 0 {
txt.push('|');
}
self.text.set_text(renderer, &txt);
let sx = r.w / self.width;
let sy = r.h / self.height;
let reg = Container::get_draw_region_raw(&self.button, sx, sy, r);
self.button.dirty = true;
self.data.extend(self.button.draw(renderer, &reg, width, height, delta));
let reg = Container::get_draw_region_raw(&self.text, sx, sy, r);
self.text.dirty = true;
self.data.extend(self.text.draw(renderer, &reg, width, height, delta));
}
&self.data
}
pub fn get_input(&self) -> String {
self.input.clone()
}
pub fn set_input(&mut self, renderer: &render::Renderer, input: &str) {
self.dirty = true;
self.input = input.to_owned();
let txt = self.transform_input();
self.text.set_text(renderer, &txt);
}
pub fn add_submit_func<F: Fn(&mut ::Game, &mut Container) + 'static>(&mut self, f: F) {
self.submit_funcs.push(Rc::new(f));
}
fn transform_input(&self) -> String {
if self.password {
::std::iter::repeat('*').take(self.input.len()).collect()
} else {
self.input.clone()
}
}
lazy_field!(width, f64, get_width, set_width);
lazy_field!(height, f64, get_height, set_height);
lazy_field!(password, bool, is_password, set_password);
}
impl UIElement for TextBox {
fn key_press(&mut self, _game: &mut ::Game, key: Keycode, down: bool) -> Vec<Rc<ClickFunc>> {
match (key, down) {
(Keycode::Backspace, false) => {self.input.pop();},
(Keycode::Return, false) => return self.submit_funcs.clone(),
_ => {},
}
vec![]
}
fn key_type(&mut self, _game: &mut ::Game, c: char) -> Vec<Rc<ClickFunc>> {
self.input.push(c);
vec![]
}
fn wrap(self) -> Element {
Element::TextBox(self)
}
fn unwrap_ref<'a>(e: &'a Element) -> &'a TextBox {
match e {
&Element::TextBox(ref val) => val,
_ => panic!("Incorrect type"),
}
}
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut TextBox {
match e {
&mut Element::TextBox(ref mut val) => val,
_ => panic!("Incorrect type"),
}
}
fn get_attachment(&self) -> (VAttach, HAttach) {
(self.v_attach, self.h_attach)
}
fn get_offset(&self) -> (f64, f64) {
(self.x, self.y)
}
fn get_size(&self) -> (f64, f64) {
(self.width, self.height)
}
}