Fully implement the login screen (Closes #6)
This commit is contained in:
parent
b418625a48
commit
ae2703418b
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
use openssl;
|
use openssl;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
use hyper;
|
||||||
|
|
||||||
pub mod mojang;
|
pub mod mojang;
|
||||||
|
|
||||||
|
@ -633,6 +634,8 @@ pub enum Error {
|
||||||
Err(String),
|
Err(String),
|
||||||
Disconnect(format::Component),
|
Disconnect(format::Component),
|
||||||
IOError(io::Error),
|
IOError(io::Error),
|
||||||
|
Json(serde_json::Error),
|
||||||
|
Hyper(hyper::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl convert::From<io::Error> for Error {
|
impl convert::From<io::Error> for Error {
|
||||||
|
@ -641,12 +644,26 @@ impl convert::From<io::Error> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl convert::From<serde_json::Error> for Error {
|
||||||
|
fn from(e: serde_json::Error) -> Error {
|
||||||
|
Error::Json(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl convert::From<hyper::Error> for Error {
|
||||||
|
fn from(e: hyper::Error) -> Error {
|
||||||
|
Error::Hyper(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ::std::error::Error for Error {
|
impl ::std::error::Error for Error {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Err(ref val) => &val[..],
|
Error::Err(ref val) => &val[..],
|
||||||
Error::Disconnect(_) => "Disconnect",
|
Error::Disconnect(_) => "Disconnect",
|
||||||
Error::IOError(ref e) => e.description(),
|
Error::IOError(ref e) => e.description(),
|
||||||
|
Error::Json(ref e) => e.description(),
|
||||||
|
Error::Hyper(ref e) => e.description(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -657,6 +674,8 @@ impl ::std::fmt::Display for Error {
|
||||||
Error::Err(ref val) => write!(f, "protocol error: {}", val),
|
Error::Err(ref val) => write!(f, "protocol error: {}", val),
|
||||||
Error::Disconnect(ref val) => write!(f, "{}", val),
|
Error::Disconnect(ref val) => write!(f, "{}", val),
|
||||||
Error::IOError(ref e) => e.fmt(f),
|
Error::IOError(ref e) => e.fmt(f),
|
||||||
|
Error::Json(ref e) => e.fmt(f),
|
||||||
|
Error::Hyper(ref e) => e.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,10 @@
|
||||||
|
|
||||||
use openssl;
|
use openssl;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
use serde_json::builder::ObjectBuilder;
|
||||||
use hyper;
|
use hyper;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Profile {
|
pub struct Profile {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
@ -23,9 +25,85 @@ pub struct Profile {
|
||||||
}
|
}
|
||||||
|
|
||||||
const JOIN_URL: &'static str = "https://sessionserver.mojang.com/session/minecraft/join";
|
const JOIN_URL: &'static str = "https://sessionserver.mojang.com/session/minecraft/join";
|
||||||
|
const LOGIN_URL: &'static str = "https://authserver.mojang.com/authenticate";
|
||||||
|
const REFRESH_URL: &'static str = "https://authserver.mojang.com/refresh";
|
||||||
|
const VALIDATE_URL: &'static str = "https://authserver.mojang.com/validate";
|
||||||
|
|
||||||
impl Profile {
|
impl Profile {
|
||||||
pub fn join_server(&self, server_id: &String, shared_key: &Vec<u8>, public_key: &Vec<u8>) {
|
pub fn login(username: &str, password: &str, token: &str) -> Result<Profile, super::Error> {
|
||||||
|
let req_msg = ObjectBuilder::new()
|
||||||
|
.insert("username", username)
|
||||||
|
.insert("password", password)
|
||||||
|
.insert("clientToken", token)
|
||||||
|
.insert_object("agent", |b| b
|
||||||
|
.insert("name", "Minecraft")
|
||||||
|
.insert("version", 1)
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let req = try!(serde_json::to_string(&req_msg));
|
||||||
|
|
||||||
|
let client = hyper::Client::new();
|
||||||
|
let res = try!(client.post(LOGIN_URL)
|
||||||
|
.body(&req)
|
||||||
|
.header(hyper::header::ContentType("application/json".parse().unwrap()))
|
||||||
|
.send());
|
||||||
|
|
||||||
|
let ret: serde_json::Value = try!(serde_json::from_reader(res));
|
||||||
|
if let Some(error) = ret.find("error").and_then(|v| v.as_string()) {
|
||||||
|
return Err(super::Error::Err(format!(
|
||||||
|
"{}: {}",
|
||||||
|
error,
|
||||||
|
ret.find("errorMessage").and_then(|v| v.as_string()).unwrap())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(Profile {
|
||||||
|
username: ret.lookup("selectedProfile.name").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
id: ret.lookup("selectedProfile.id").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
access_token: ret.find("accessToken").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn refresh(self, token: &str) -> Result<Profile, super::Error> {
|
||||||
|
let req_msg = ObjectBuilder::new()
|
||||||
|
.insert("accessToken", self.access_token.clone())
|
||||||
|
.insert("clientToken", token)
|
||||||
|
.unwrap();
|
||||||
|
let req = try!(serde_json::to_string(&req_msg));
|
||||||
|
|
||||||
|
let client = hyper::Client::new();
|
||||||
|
let res = try!(client.post(VALIDATE_URL)
|
||||||
|
.body(&req)
|
||||||
|
.header(hyper::header::ContentType("application/json".parse().unwrap()))
|
||||||
|
.send());
|
||||||
|
|
||||||
|
if res.status != hyper::status::StatusCode::NoContent {
|
||||||
|
println!("Rerefeshing");
|
||||||
|
// Refresh needed
|
||||||
|
let res = try!(client.post(REFRESH_URL)
|
||||||
|
.body(&req)
|
||||||
|
.header(hyper::header::ContentType("application/json".parse().unwrap()))
|
||||||
|
.send());
|
||||||
|
|
||||||
|
let ret: serde_json::Value = try!(serde_json::from_reader(res));
|
||||||
|
if let Some(error) = ret.find("error").and_then(|v| v.as_string()) {
|
||||||
|
return Err(super::Error::Err(format!(
|
||||||
|
"{}: {}",
|
||||||
|
error,
|
||||||
|
ret.find("errorMessage").and_then(|v| v.as_string()).unwrap())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return Ok(Profile {
|
||||||
|
username: ret.lookup("selectedProfile.name").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
id: ret.lookup("selectedProfile.id").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
access_token: ret.find("accessToken").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
println!("Reuse");
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
pub fn join_server(&self, server_id: &str, shared_key: &Vec<u8>, public_key: &Vec<u8>) {
|
||||||
let mut sha1 = openssl::SHA1::new();
|
let mut sha1 = openssl::SHA1::new();
|
||||||
sha1.update(server_id.as_bytes());
|
sha1.update(server_id.as_bytes());
|
||||||
sha1.update(&shared_key[..]);
|
sha1.update(&shared_key[..]);
|
||||||
|
@ -46,7 +124,7 @@ impl Profile {
|
||||||
hash_val.to_owned()
|
hash_val.to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
let join_msg = serde_json::builder::ObjectBuilder::new()
|
let join_msg = ObjectBuilder::new()
|
||||||
.insert("accessToken", &self.access_token)
|
.insert("accessToken", &self.access_token)
|
||||||
.insert("selectedProfile", &self.id)
|
.insert("selectedProfile", &self.id)
|
||||||
.insert("serverId", hash_str)
|
.insert("serverId", hash_str)
|
||||||
|
@ -66,6 +144,10 @@ impl Profile {
|
||||||
};
|
};
|
||||||
panic!("{:?}", ret);
|
panic!("{:?}", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_complete(&self) -> bool {
|
||||||
|
!self.username.is_empty() && !self.id.is_empty() && !self.access_token.is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn twos_compliment(data: &mut Vec<u8>) {
|
fn twos_compliment(data: &mut Vec<u8>) {
|
||||||
|
|
|
@ -93,9 +93,10 @@ impl super::Screen for Connecting {
|
||||||
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) {
|
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, ui_container);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,19 @@
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
use rand::{self, Rng};
|
||||||
|
|
||||||
use ui;
|
use ui;
|
||||||
use render;
|
use render;
|
||||||
use console;
|
use console;
|
||||||
|
use protocol;
|
||||||
|
use protocol::mojang;
|
||||||
|
use auth;
|
||||||
|
|
||||||
pub struct Login {
|
pub struct Login {
|
||||||
elements: Option<UIElements>,
|
elements: Option<UIElements>,
|
||||||
|
@ -26,6 +36,17 @@ pub struct Login {
|
||||||
struct UIElements {
|
struct UIElements {
|
||||||
logo: ui::logo::Logo,
|
logo: ui::logo::Logo,
|
||||||
elements: ui::Collection,
|
elements: ui::Collection,
|
||||||
|
|
||||||
|
login_btn: ui::ElementRef<ui::Button>,
|
||||||
|
login_btn_text: ui::ElementRef<ui::Text>,
|
||||||
|
login_error: ui::ElementRef<ui::Text>,
|
||||||
|
username_txt: ui::ElementRef<ui::TextBox>,
|
||||||
|
password_txt: ui::ElementRef<ui::TextBox>,
|
||||||
|
try_login: Rc<Cell<bool>>,
|
||||||
|
refresh: bool,
|
||||||
|
login_res: Option<mpsc::Receiver<Result<mojang::Profile, protocol::Error>>>,
|
||||||
|
|
||||||
|
profile: mojang::Profile,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,6 +61,8 @@ impl super::Screen for Login {
|
||||||
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container);
|
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container);
|
||||||
let mut elements = ui::Collection::new();
|
let mut elements = ui::Collection::new();
|
||||||
|
|
||||||
|
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 (mut login, mut txt) = super::new_button_text(renderer, "Login", 0.0, 100.0, 400.0, 40.0);
|
||||||
login.set_v_attach(ui::VAttach::Middle);
|
login.set_v_attach(ui::VAttach::Middle);
|
||||||
|
@ -47,15 +70,21 @@ impl super::Screen for Login {
|
||||||
let re = ui_container.add(login);
|
let re = ui_container.add(login);
|
||||||
txt.set_parent(&re);
|
txt.set_parent(&re);
|
||||||
let tre = ui_container.add(txt);
|
let tre = ui_container.add(txt);
|
||||||
|
let tl = try_login.clone();
|
||||||
super::button_action(ui_container,
|
super::button_action(ui_container,
|
||||||
re.clone(),
|
re.clone(),
|
||||||
Some(tre.clone()),
|
Some(tre.clone()),
|
||||||
|game, _| {
|
move |_, _| {
|
||||||
game.screen_sys
|
tl.set(true);
|
||||||
.replace_screen(Box::new(super::ServerList::new(None)));
|
});
|
||||||
});
|
let login_btn = elements.add(re);
|
||||||
elements.add(re);
|
let login_btn_text = elements.add(tre);
|
||||||
elements.add(tre);
|
|
||||||
|
// Login Error
|
||||||
|
let mut login_error = ui::Text::new(renderer, "", 0.0, 150.0, 255, 50, 50);
|
||||||
|
login_error.set_v_attach(ui::VAttach::Middle);
|
||||||
|
login_error.set_h_attach(ui::HAttach::Center);
|
||||||
|
let login_error = elements.add(ui_container.add(login_error));
|
||||||
|
|
||||||
// Username
|
// Username
|
||||||
let mut username = ui::TextBox::new(renderer, "", 0.0, -20.0, 400.0, 40.0);
|
let mut username = ui::TextBox::new(renderer, "", 0.0, -20.0, 400.0, 40.0);
|
||||||
|
@ -67,7 +96,7 @@ impl super::Screen for Login {
|
||||||
let ure = ui_container.add(username);
|
let ure = ui_container.add(username);
|
||||||
let mut username_label = ui::Text::new(renderer, "Username/Email:", 0.0, -18.0, 255, 255, 255);
|
let mut username_label = ui::Text::new(renderer, "Username/Email:", 0.0, -18.0, 255, 255, 255);
|
||||||
username_label.set_parent(&ure);
|
username_label.set_parent(&ure);
|
||||||
elements.add(ure);
|
let username_txt = elements.add(ure);
|
||||||
elements.add(ui_container.add(username_label));
|
elements.add(ui_container.add(username_label));
|
||||||
|
|
||||||
// Password
|
// Password
|
||||||
|
@ -75,13 +104,14 @@ impl super::Screen for Login {
|
||||||
password.set_v_attach(ui::VAttach::Middle);
|
password.set_v_attach(ui::VAttach::Middle);
|
||||||
password.set_h_attach(ui::HAttach::Center);
|
password.set_h_attach(ui::HAttach::Center);
|
||||||
password.set_password(true);
|
password.set_password(true);
|
||||||
password.add_submit_func(|_, _| {
|
let tl = try_login.clone();
|
||||||
println!("Submit!");
|
password.add_submit_func(move |_, _| {
|
||||||
|
tl.set(true);
|
||||||
});
|
});
|
||||||
let pre = ui_container.add(password);
|
let pre = ui_container.add(password);
|
||||||
let mut password_label = ui::Text::new(renderer, "Password:", 0.0, -18.0, 255, 255, 255);
|
let mut password_label = ui::Text::new(renderer, "Password:", 0.0, -18.0, 255, 255, 255);
|
||||||
password_label.set_parent(&pre);
|
password_label.set_parent(&pre);
|
||||||
elements.add(pre);
|
let password_txt = elements.add(pre);
|
||||||
elements.add(ui_container.add(password_label));
|
elements.add(ui_container.add(password_label));
|
||||||
|
|
||||||
// Disclaimer
|
// Disclaimer
|
||||||
|
@ -96,9 +126,28 @@ impl super::Screen for Login {
|
||||||
warn.set_h_attach(ui::HAttach::Right);
|
warn.set_h_attach(ui::HAttach::Right);
|
||||||
elements.add(ui_container.add(warn));
|
elements.add(ui_container.add(warn));
|
||||||
|
|
||||||
|
let console = self.console.lock().unwrap();
|
||||||
|
let profile = mojang::Profile {
|
||||||
|
username: console.get(auth::CL_USERNAME).clone(),
|
||||||
|
id: console.get(auth::CL_UUID).clone(),
|
||||||
|
access_token: console.get(auth::AUTH_TOKEN).clone(),
|
||||||
|
};
|
||||||
|
let refresh = profile.is_complete();
|
||||||
|
try_login.set(refresh);
|
||||||
|
|
||||||
self.elements = Some(UIElements {
|
self.elements = Some(UIElements {
|
||||||
logo: logo,
|
logo: logo,
|
||||||
elements: elements,
|
elements: elements,
|
||||||
|
profile: profile,
|
||||||
|
login_btn: login_btn,
|
||||||
|
login_btn_text: login_btn_text,
|
||||||
|
login_error: login_error,
|
||||||
|
try_login: try_login,
|
||||||
|
refresh: refresh,
|
||||||
|
login_res: None,
|
||||||
|
|
||||||
|
username_txt: username_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) {
|
||||||
|
@ -114,9 +163,79 @@ impl super::Screen for Login {
|
||||||
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) {
|
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() {
|
||||||
|
elements.try_login.set(false);
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
elements.login_res = Some(rx);
|
||||||
|
{
|
||||||
|
let btn = ui_container.get_mut(&elements.login_btn);
|
||||||
|
btn.set_disabled(true);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let txt = ui_container.get_mut(&elements.login_btn_text);
|
||||||
|
txt.set_text(renderer, "Logging in...");
|
||||||
|
}
|
||||||
|
let mut console = self.console.lock().unwrap();
|
||||||
|
let mut client_token = console.get(auth::AUTH_CLIENT_TOKEN).clone();
|
||||||
|
if client_token.is_empty() {
|
||||||
|
client_token = rand::thread_rng().gen_ascii_chars().take(20).collect::<String>();
|
||||||
|
console.set(auth::AUTH_CLIENT_TOKEN, client_token);
|
||||||
|
}
|
||||||
|
let client_token = console.get(auth::AUTH_CLIENT_TOKEN).clone();
|
||||||
|
let username = {
|
||||||
|
let txt = ui_container.get(&elements.username_txt);
|
||||||
|
txt.get_input()
|
||||||
|
};
|
||||||
|
let password = {
|
||||||
|
let txt = ui_container.get(&elements.password_txt);
|
||||||
|
txt.get_input()
|
||||||
|
};
|
||||||
|
let refresh = elements.refresh;
|
||||||
|
let profile = elements.profile.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
if refresh {
|
||||||
|
tx.send(profile.refresh(&client_token)).unwrap();
|
||||||
|
} else {
|
||||||
|
tx.send(mojang::Profile::login(&username, &password, &client_token)).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let mut done = false;
|
||||||
|
if let Some(rx) = elements.login_res.as_ref() {
|
||||||
|
if let Ok(res) = rx.try_recv() {
|
||||||
|
done = true;
|
||||||
|
{
|
||||||
|
let btn = ui_container.get_mut(&elements.login_btn);
|
||||||
|
btn.set_disabled(false);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let txt = ui_container.get_mut(&elements.login_btn_text);
|
||||||
|
txt.set_text(renderer, "Login");
|
||||||
|
}
|
||||||
|
match res {
|
||||||
|
Ok(val) => {
|
||||||
|
let mut console = self.console.lock().unwrap();
|
||||||
|
console.set(auth::CL_USERNAME, val.username.clone());
|
||||||
|
console.set(auth::CL_UUID, val.id.clone());
|
||||||
|
console.set(auth::AUTH_TOKEN, val.access_token.clone());
|
||||||
|
elements.profile = val;
|
||||||
|
return Some(Box::new(super::ServerList::new(None)));
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
let login_error = ui_container.get_mut(&elements.login_error);
|
||||||
|
login_error.set_text(renderer, &format!("{}", err));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if done {
|
||||||
|
elements.login_res = None;
|
||||||
|
}
|
||||||
|
|
||||||
elements.logo.tick(renderer, ui_container);
|
elements.logo.tick(renderer, ui_container);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub trait Screen {
|
||||||
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);
|
ui_container: &mut ui::Container) -> Option<Box<Screen>>;
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
fn on_scroll(&mut self, x: f64, y: f64) {
|
fn on_scroll(&mut self, x: f64, y: f64) {
|
||||||
|
@ -106,18 +106,22 @@ impl ScreenSystem {
|
||||||
screen.screen.on_deactive(renderer, ui_container);
|
screen.screen.on_deactive(renderer, ui_container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let current = self.screens.last_mut().unwrap();
|
let swap = {
|
||||||
if !current.init {
|
let current = self.screens.last_mut().unwrap();
|
||||||
current.init = true;
|
if !current.init {
|
||||||
current.screen.init(renderer, ui_container);
|
current.init = true;
|
||||||
}
|
current.screen.init(renderer, ui_container);
|
||||||
if !current.active {
|
}
|
||||||
current.active = true;
|
if !current.active {
|
||||||
current.screen.on_active(renderer, ui_container);
|
current.active = true;
|
||||||
}
|
current.screen.on_active(renderer, ui_container);
|
||||||
|
}
|
||||||
|
current.screen.tick(delta, renderer, ui_container)
|
||||||
|
};
|
||||||
// Handle current
|
// Handle current
|
||||||
current.screen.tick(delta, renderer, ui_container);
|
if let Some(swap) = swap {
|
||||||
|
self.replace_screen(swap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_scroll(&mut self, x: f64, y: f64) {
|
pub fn on_scroll(&mut self, x: f64, y: f64) {
|
||||||
|
@ -149,15 +153,19 @@ pub fn button_action<F: Fn(&mut ::Game, &mut ui::Container) + 'static>(ui_contai
|
||||||
click: F) {
|
click: F) {
|
||||||
let button = ui_container.get_mut(&btn);
|
let button = ui_container.get_mut(&btn);
|
||||||
button.add_hover_func(move |over, _, ui_container| {
|
button.add_hover_func(move |over, _, ui_container| {
|
||||||
let txt = txt.clone();
|
let disabled = {
|
||||||
if let Some(txt) = txt {
|
let button = ui_container.get_mut(&btn);
|
||||||
let text = ui_container.get_mut(&txt);
|
button.is_disabled()
|
||||||
text.set_b(if over {
|
};
|
||||||
160
|
let txt = txt.clone();
|
||||||
} else {
|
if let Some(txt) = txt {
|
||||||
255
|
let text = ui_container.get_mut(&txt);
|
||||||
});
|
text.set_b(if over && !disabled {
|
||||||
}
|
160
|
||||||
|
} else {
|
||||||
|
255
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
button.add_click_func(click);
|
button.add_click_func(click);
|
||||||
}
|
}
|
||||||
|
|
|
@ -459,7 +459,7 @@ impl super::Screen for ServerList {
|
||||||
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) {
|
ui_container: &mut ui::Container) -> Option<Box<super::Screen>> {
|
||||||
if *self.needs_reload.borrow() {
|
if *self.needs_reload.borrow() {
|
||||||
self.reload_server_list(renderer, ui_container);
|
self.reload_server_list(renderer, ui_container);
|
||||||
}
|
}
|
||||||
|
@ -551,6 +551,7 @@ impl super::Screen for ServerList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_scroll(&mut self, _: f64, y: f64) {
|
fn on_scroll(&mut self, _: f64, y: f64) {
|
||||||
|
|
|
@ -119,8 +119,8 @@ impl TextBox {
|
||||||
(self.width, self.height)
|
(self.width, self.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_input(&self) -> &str {
|
pub fn get_input(&self) -> String {
|
||||||
&self.input
|
self.input.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_input(&mut self, renderer: &render::Renderer, input: &str) {
|
pub fn set_input(&mut self, renderer: &render::Renderer, input: &str) {
|
||||||
|
|
Loading…
Reference in New Issue