Rewrite the UI system (Closes #12)
This commit is contained in:
parent
b0c54a3561
commit
a7caa50b6f
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
128
src/ui/batch.rs
128
src/ui/batch.rs
|
@ -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, ®, 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)
|
|
||||||
}
|
|
||||||
}
|
|
144
src/ui/button.rs
144
src/ui/button.rs
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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, ®, 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)
|
|
||||||
}
|
|
||||||
}
|
|
151
src/ui/image.rs
151
src/ui/image.rs
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
173
src/ui/logo.rs
173
src/ui/logo.rs
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1712
src/ui/mod.rs
1712
src/ui/mod.rs
File diff suppressed because it is too large
Load Diff
156
src/ui/text.rs
156
src/ui/text.rs
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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, ®, 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, ®, 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)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue