Work on login screen, added ui buttons and textboxes (plus tab fixes)
This commit is contained in:
parent
4524cb31e2
commit
b418625a48
|
@ -0,0 +1,63 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use console;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
pub const CL_USERNAME: console::CVar<String> = console::CVar {
|
||||||
|
ty: PhantomData,
|
||||||
|
name: "cl_username",
|
||||||
|
description: r#"cl_username is the username that the client will use to connect
|
||||||
|
to servers."#,
|
||||||
|
mutable: false,
|
||||||
|
serializable: true,
|
||||||
|
default: &|| "".to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const CL_UUID: console::CVar<String> = console::CVar {
|
||||||
|
ty: PhantomData,
|
||||||
|
name: "cl_uuid",
|
||||||
|
description: r#"cl_uuid is the uuid of the client. This is unique to a player
|
||||||
|
unlike their username."#,
|
||||||
|
mutable: false,
|
||||||
|
serializable: true,
|
||||||
|
default: &|| "".to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const AUTH_TOKEN: console::CVar<String> = console::CVar {
|
||||||
|
ty: PhantomData,
|
||||||
|
name: "auth_token",
|
||||||
|
description: r#"auth_token is the token used for this session to auth to servers
|
||||||
|
or relogin to this account."#,
|
||||||
|
mutable: false,
|
||||||
|
serializable: true,
|
||||||
|
default: &|| "".to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const AUTH_CLIENT_TOKEN: console::CVar<String> = console::CVar {
|
||||||
|
ty: PhantomData,
|
||||||
|
name: "auth_client_token",
|
||||||
|
description: r#"auth_client_token is a token that stays static between sessions.
|
||||||
|
Used to identify this client vs others."#,
|
||||||
|
mutable: false,
|
||||||
|
serializable: true,
|
||||||
|
default: &|| "".to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn register_vars(console: &mut console::Console) {
|
||||||
|
console.register(CL_USERNAME);
|
||||||
|
console.register(CL_UUID);
|
||||||
|
console.register(AUTH_TOKEN);
|
||||||
|
console.register(AUTH_CLIENT_TOKEN);
|
||||||
|
}
|
19
src/main.rs
19
src/main.rs
|
@ -49,6 +49,7 @@ pub mod console;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod world;
|
pub mod world;
|
||||||
pub mod chunk_builder;
|
pub mod chunk_builder;
|
||||||
|
pub mod auth;
|
||||||
|
|
||||||
use std::sync::{Arc, RwLock, Mutex};
|
use std::sync::{Arc, RwLock, Mutex};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -128,6 +129,7 @@ fn main() {
|
||||||
{
|
{
|
||||||
let mut con = con.lock().unwrap();
|
let mut con = con.lock().unwrap();
|
||||||
con.register(CL_BRAND);
|
con.register(CL_BRAND);
|
||||||
|
auth::register_vars(&mut con);
|
||||||
con.load_config();
|
con.load_config();
|
||||||
con.save_config();
|
con.save_config();
|
||||||
}
|
}
|
||||||
|
@ -170,7 +172,7 @@ fn main() {
|
||||||
let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;
|
let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;
|
||||||
|
|
||||||
let mut screen_sys = screen::ScreenSystem::new();
|
let mut screen_sys = screen::ScreenSystem::new();
|
||||||
screen_sys.add_screen(Box::new(screen::Login::new()));
|
screen_sys.add_screen(Box::new(screen::Login::new(con.clone())));
|
||||||
|
|
||||||
let textures = renderer.get_textures();
|
let textures = renderer.get_textures();
|
||||||
let mut game = Game {
|
let mut game = Game {
|
||||||
|
@ -240,14 +242,12 @@ fn handle_window_event(window: &glutin::Window,
|
||||||
|
|
||||||
ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64);
|
ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) => {
|
Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) => {
|
||||||
let (x, y) = game.mouse_pos;
|
let (x, y) = game.mouse_pos;
|
||||||
let (width, height) = window.get_inner_size_pixels().unwrap();
|
let (width, height) = window.get_inner_size_pixels().unwrap();
|
||||||
|
|
||||||
ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64);
|
ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::MouseWheel(delta) => {
|
Event::MouseWheel(delta) => {
|
||||||
let (x, y) = match delta {
|
let (x, y) = match delta {
|
||||||
glutin::MouseScrollDelta::LineDelta(x, y) => (x, y),
|
glutin::MouseScrollDelta::LineDelta(x, y) => (x, y),
|
||||||
|
@ -256,18 +256,15 @@ fn handle_window_event(window: &glutin::Window,
|
||||||
|
|
||||||
game.screen_sys.on_scroll(x as f64, y as f64);
|
game.screen_sys.on_scroll(x as f64, y as f64);
|
||||||
}
|
}
|
||||||
|
Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(VirtualKeyCode::Grave)) => {
|
||||||
Event::KeyboardInput(glutin::ElementState::Pressed, 41 /* ` GRAVE */, _)
|
|
||||||
| Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(VirtualKeyCode::Grave)) => {
|
|
||||||
game.console.lock().unwrap().toggle();
|
game.console.lock().unwrap().toggle();
|
||||||
}
|
}
|
||||||
Event::KeyboardInput(glutin::ElementState::Pressed, key, virt) => {
|
Event::KeyboardInput(state, key, virt) => {
|
||||||
println!("Key: {:?} {:?}", key, virt);
|
ui_container.key_press(game, virt, key, state == glutin::ElementState::Pressed);
|
||||||
if virt == Some(VirtualKeyCode::H) {
|
|
||||||
game.server.world.flag_dirty_all();
|
|
||||||
}
|
}
|
||||||
|
Event::ReceivedCharacter(c) => {
|
||||||
|
ui_container.key_type(game, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,15 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use ui;
|
use ui;
|
||||||
use render;
|
use render;
|
||||||
|
use console;
|
||||||
|
|
||||||
pub struct Login {
|
pub struct Login {
|
||||||
elements: Option<UIElements>,
|
elements: Option<UIElements>,
|
||||||
|
console: Arc<Mutex<console::Console>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UIElements {
|
struct UIElements {
|
||||||
|
@ -28,8 +30,8 @@ struct UIElements {
|
||||||
|
|
||||||
|
|
||||||
impl Login {
|
impl Login {
|
||||||
pub fn new() -> Login {
|
pub fn new(console: Arc<Mutex<console::Console>>) -> Login {
|
||||||
Login { elements: None }
|
Login { elements: None, console: console }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,12 +41,7 @@ impl super::Screen for Login {
|
||||||
let mut elements = ui::Collection::new();
|
let mut elements = ui::Collection::new();
|
||||||
|
|
||||||
// Login
|
// Login
|
||||||
let (mut login, mut txt) = super::new_button_text(renderer,
|
let (mut login, mut txt) = super::new_button_text(renderer, "Login", 0.0, 100.0, 400.0, 40.0);
|
||||||
"Login",
|
|
||||||
0.0,
|
|
||||||
100.0,
|
|
||||||
400.0,
|
|
||||||
40.0);
|
|
||||||
login.set_v_attach(ui::VAttach::Middle);
|
login.set_v_attach(ui::VAttach::Middle);
|
||||||
login.set_h_attach(ui::HAttach::Center);
|
login.set_h_attach(ui::HAttach::Center);
|
||||||
let re = ui_container.add(login);
|
let re = ui_container.add(login);
|
||||||
|
@ -53,13 +50,40 @@ impl super::Screen for Login {
|
||||||
super::button_action(ui_container,
|
super::button_action(ui_container,
|
||||||
re.clone(),
|
re.clone(),
|
||||||
Some(tre.clone()),
|
Some(tre.clone()),
|
||||||
Some(Rc::new(|game, _| {
|
|game, _| {
|
||||||
game.screen_sys
|
game.screen_sys
|
||||||
.replace_screen(Box::new(super::ServerList::new(None)));
|
.replace_screen(Box::new(super::ServerList::new(None)));
|
||||||
})));
|
});
|
||||||
elements.add(re);
|
elements.add(re);
|
||||||
elements.add(tre);
|
elements.add(tre);
|
||||||
|
|
||||||
|
// Username
|
||||||
|
let mut username = ui::TextBox::new(renderer, "", 0.0, -20.0, 400.0, 40.0);
|
||||||
|
username.set_v_attach(ui::VAttach::Middle);
|
||||||
|
username.set_h_attach(ui::HAttach::Center);
|
||||||
|
username.add_submit_func(|_, ui| {
|
||||||
|
ui.cycle_focus();
|
||||||
|
});
|
||||||
|
let ure = ui_container.add(username);
|
||||||
|
let mut username_label = ui::Text::new(renderer, "Username/Email:", 0.0, -18.0, 255, 255, 255);
|
||||||
|
username_label.set_parent(&ure);
|
||||||
|
elements.add(ure);
|
||||||
|
elements.add(ui_container.add(username_label));
|
||||||
|
|
||||||
|
// Password
|
||||||
|
let mut password = ui::TextBox::new(renderer, "", 0.0, 40.0, 400.0, 40.0);
|
||||||
|
password.set_v_attach(ui::VAttach::Middle);
|
||||||
|
password.set_h_attach(ui::HAttach::Center);
|
||||||
|
password.set_password(true);
|
||||||
|
password.add_submit_func(|_, _| {
|
||||||
|
println!("Submit!");
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
elements.add(pre);
|
||||||
|
elements.add(ui_container.add(password_label));
|
||||||
|
|
||||||
// Disclaimer
|
// Disclaimer
|
||||||
let mut warn = ui::Text::new(renderer,
|
let mut warn = ui::Text::new(renderer,
|
||||||
"Not affiliated with Mojang/Minecraft",
|
"Not affiliated with Mojang/Minecraft",
|
||||||
|
|
|
@ -18,8 +18,6 @@ mod login;
|
||||||
pub use self::login::*;
|
pub use self::login::*;
|
||||||
pub mod connecting;
|
pub mod connecting;
|
||||||
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use render;
|
use render;
|
||||||
use ui;
|
use ui;
|
||||||
|
|
||||||
|
@ -131,202 +129,26 @@ impl ScreenSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_button(renderer: &mut render::Renderer, x: f64, y: f64, w: f64, h: f64) -> ui::Batch {
|
|
||||||
let mut batch = ui::Batch::new(x, y, w, h);
|
|
||||||
|
|
||||||
let texture = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/widgets")
|
|
||||||
.relative(0.0, 66.0 / 256.0, 200.0 / 256.0, 20.0 / 256.0);
|
|
||||||
|
|
||||||
// Corners
|
|
||||||
batch.add(ui::Image::new(texture.clone(),
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
4.0,
|
|
||||||
4.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
2.0 / 200.0,
|
|
||||||
2.0 / 20.0,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255));
|
|
||||||
batch.add(ui::Image::new(texture.clone(),
|
|
||||||
w - 4.0,
|
|
||||||
0.0,
|
|
||||||
4.0,
|
|
||||||
4.0,
|
|
||||||
198.0 / 200.0,
|
|
||||||
0.0,
|
|
||||||
2.0 / 200.0,
|
|
||||||
2.0 / 20.0,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255));
|
|
||||||
batch.add(ui::Image::new(texture.clone(),
|
|
||||||
0.0,
|
|
||||||
h - 6.0,
|
|
||||||
4.0,
|
|
||||||
6.0,
|
|
||||||
0.0,
|
|
||||||
17.0 / 20.0,
|
|
||||||
2.0 / 200.0,
|
|
||||||
3.0 / 20.0,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255));
|
|
||||||
batch.add(ui::Image::new(texture.clone(),
|
|
||||||
w - 4.0,
|
|
||||||
h - 6.0,
|
|
||||||
4.0,
|
|
||||||
6.0,
|
|
||||||
198.0 / 200.0,
|
|
||||||
17.0 / 20.0,
|
|
||||||
2.0 / 200.0,
|
|
||||||
3.0 / 20.0,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255));
|
|
||||||
|
|
||||||
// Widths
|
|
||||||
batch.add(ui::Image::new(texture.clone()
|
|
||||||
.relative(2.0 / 200.0, 0.0, 196.0 / 200.0, 2.0 / 20.0),
|
|
||||||
4.0,
|
|
||||||
0.0,
|
|
||||||
w - 8.0,
|
|
||||||
4.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255));
|
|
||||||
batch.add(ui::Image::new(texture.clone().relative(2.0 / 200.0,
|
|
||||||
17.0 / 20.0,
|
|
||||||
196.0 / 200.0,
|
|
||||||
3.0 / 20.0),
|
|
||||||
4.0,
|
|
||||||
h - 6.0,
|
|
||||||
w - 8.0,
|
|
||||||
6.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255));
|
|
||||||
|
|
||||||
// Heights
|
|
||||||
batch.add(ui::Image::new(texture.clone().relative(0.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0),
|
|
||||||
0.0,
|
|
||||||
4.0,
|
|
||||||
4.0,
|
|
||||||
h - 10.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255));
|
|
||||||
batch.add(ui::Image::new(texture.clone().relative(198.0 / 200.0,
|
|
||||||
2.0 / 20.0,
|
|
||||||
2.0 / 200.0,
|
|
||||||
15.0 / 20.0),
|
|
||||||
w - 4.0,
|
|
||||||
4.0,
|
|
||||||
4.0,
|
|
||||||
h - 10.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255));
|
|
||||||
|
|
||||||
// Center
|
|
||||||
batch.add(ui::Image::new(texture.clone().relative(2.0 / 200.0,
|
|
||||||
2.0 / 20.0,
|
|
||||||
196.0 / 200.0,
|
|
||||||
15.0 / 20.0),
|
|
||||||
4.0,
|
|
||||||
4.0,
|
|
||||||
w - 8.0,
|
|
||||||
h - 10.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255));
|
|
||||||
|
|
||||||
batch
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_button_text(renderer: &mut render::Renderer,
|
pub fn new_button_text(renderer: &mut render::Renderer,
|
||||||
val: &str,
|
val: &str,
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
w: f64,
|
w: f64,
|
||||||
h: f64)
|
h: f64)
|
||||||
-> (ui::Batch, ui::Text) {
|
-> (ui::Button, ui::Text) {
|
||||||
let batch = new_button(renderer, x, y, w, h);
|
let btn = ui::Button::new(x, y, w, h);
|
||||||
let mut text = ui::Text::new(renderer, val, 0.0, 0.0, 255, 255, 255);
|
let mut text = ui::Text::new(renderer, val, 0.0, 0.0, 255, 255, 255);
|
||||||
text.set_v_attach(ui::VAttach::Middle);
|
text.set_v_attach(ui::VAttach::Middle);
|
||||||
text.set_h_attach(ui::HAttach::Center);
|
text.set_h_attach(ui::HAttach::Center);
|
||||||
(batch, text)
|
(btn, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn button_action(ui_container: &mut ui::Container,
|
pub fn button_action<F: Fn(&mut ::Game, &mut ui::Container) + 'static>(ui_container: &mut ui::Container,
|
||||||
btn: ui::ElementRef<ui::Batch>,
|
btn: ui::ElementRef<ui::Button>,
|
||||||
txt: Option<ui::ElementRef<ui::Text>>,
|
txt: Option<ui::ElementRef<ui::Text>>,
|
||||||
click: Option<ui::ClickFunc>) {
|
click: F) {
|
||||||
let batch = ui_container.get_mut(&btn);
|
let button = ui_container.get_mut(&btn);
|
||||||
batch.add_hover_func(Rc::new(move |over, game, ui_container| {
|
button.add_hover_func(move |over, _, ui_container| {
|
||||||
let texture = render::Renderer::get_texture(game.renderer.get_textures_ref(),
|
|
||||||
"gui/widgets")
|
|
||||||
.relative(0.0,
|
|
||||||
(if over {
|
|
||||||
86.0
|
|
||||||
} else {
|
|
||||||
66.0
|
|
||||||
}) / 256.0,
|
|
||||||
200.0 / 256.0,
|
|
||||||
20.0 / 256.0);
|
|
||||||
|
|
||||||
{
|
|
||||||
let batch = ui_container.get_mut(&btn);
|
|
||||||
for i in 0..batch.len() {
|
|
||||||
let img = batch.get_mut_at::<ui::Image>(i);
|
|
||||||
match i {
|
|
||||||
_i @ 0 ...3 => img.set_texture(texture.clone()),
|
|
||||||
4 => img.set_texture(texture.clone().relative(2.0 / 200.0,
|
|
||||||
0.0,
|
|
||||||
196.0 / 200.0,
|
|
||||||
2.0 / 20.0)),
|
|
||||||
5 => img.set_texture(texture.clone().relative(2.0 / 200.0,
|
|
||||||
17.0 / 20.0,
|
|
||||||
196.0 / 200.0,
|
|
||||||
3.0 / 20.0)),
|
|
||||||
6 => img.set_texture(texture.clone().relative(0.0,
|
|
||||||
2.0 / 20.0,
|
|
||||||
2.0 / 200.0,
|
|
||||||
15.0 / 20.0)),
|
|
||||||
7 => img.set_texture(texture.clone().relative(198.0 / 200.0,
|
|
||||||
2.0 / 20.0,
|
|
||||||
2.0 / 200.0,
|
|
||||||
15.0 / 20.0)),
|
|
||||||
8 => img.set_texture(texture.clone().relative(2.0 / 200.0,
|
|
||||||
2.0 / 20.0,
|
|
||||||
196.0 / 200.0,
|
|
||||||
15.0 / 20.0)),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let txt = txt.clone();
|
let txt = txt.clone();
|
||||||
if let Some(txt) = txt {
|
if let Some(txt) = txt {
|
||||||
let text = ui_container.get_mut(&txt);
|
let text = ui_container.get_mut(&txt);
|
||||||
|
@ -336,8 +158,6 @@ pub fn button_action(ui_container: &mut ui::Container,
|
||||||
255
|
255
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
if let Some(click) = click {
|
button.add_click_func(click);
|
||||||
batch.add_click_func(click);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,19 +170,19 @@ impl ServerList {
|
||||||
let back = ui_container.get_mut(&server.back);
|
let back = ui_container.get_mut(&server.back);
|
||||||
let back_ref = server.back.clone();
|
let back_ref = server.back.clone();
|
||||||
let address = address.clone();
|
let address = address.clone();
|
||||||
back.add_hover_func(Rc::new(move |over, _, ui_container| {
|
back.add_hover_func(move |over, _, ui_container| {
|
||||||
let back = ui_container.get_mut(&back_ref);
|
let back = ui_container.get_mut(&back_ref);
|
||||||
back.set_a(if over {
|
back.set_a(if over {
|
||||||
200
|
200
|
||||||
} else {
|
} else {
|
||||||
100
|
100
|
||||||
});
|
});
|
||||||
}));
|
});
|
||||||
|
|
||||||
back.add_click_func(Rc::new(move |game, _| {
|
back.add_click_func(move |game, _| {
|
||||||
game.screen_sys.replace_screen(Box::new(super::connecting::Connecting::new(&address)));
|
game.screen_sys.replace_screen(Box::new(super::connecting::Connecting::new(&address)));
|
||||||
game.connect_to(&address);
|
game.connect_to(&address);
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server name
|
// Server name
|
||||||
|
@ -259,7 +259,7 @@ impl ServerList {
|
||||||
let re = ui_container.add(del);
|
let re = ui_container.add(del);
|
||||||
txt.set_parent(&re);
|
txt.set_parent(&re);
|
||||||
let tre = ui_container.add(txt);
|
let tre = ui_container.add(txt);
|
||||||
super::button_action(ui_container, re.clone(), Some(tre.clone()), None);
|
super::button_action(ui_container, re.clone(), Some(tre.clone()), |_,_| {});
|
||||||
server.collection.add(re);
|
server.collection.add(re);
|
||||||
server.collection.add(tre);
|
server.collection.add(tre);
|
||||||
|
|
||||||
|
@ -271,7 +271,7 @@ impl ServerList {
|
||||||
let re = ui_container.add(edit);
|
let re = ui_container.add(edit);
|
||||||
txt.set_parent(&re);
|
txt.set_parent(&re);
|
||||||
let tre = ui_container.add(txt);
|
let tre = ui_container.add(txt);
|
||||||
super::button_action(ui_container, re.clone(), Some(tre.clone()), None);
|
super::button_action(ui_container, re.clone(), Some(tre.clone()), |_,_|{});
|
||||||
server.collection.add(re);
|
server.collection.add(re);
|
||||||
server.collection.add(tre);
|
server.collection.add(tre);
|
||||||
|
|
||||||
|
@ -345,9 +345,9 @@ impl super::Screen for ServerList {
|
||||||
super::button_action(ui_container,
|
super::button_action(ui_container,
|
||||||
re.clone(),
|
re.clone(),
|
||||||
Some(tre.clone()),
|
Some(tre.clone()),
|
||||||
Some(Rc::new(move |_, _| {
|
move |_, _| {
|
||||||
*nr.borrow_mut() = true;
|
*nr.borrow_mut() = true;
|
||||||
})));
|
});
|
||||||
elements.add(re);
|
elements.add(re);
|
||||||
elements.add(tre);
|
elements.add(tre);
|
||||||
|
|
||||||
|
@ -363,12 +363,12 @@ impl super::Screen for ServerList {
|
||||||
let re = ui_container.add(add);
|
let re = ui_container.add(add);
|
||||||
txt.set_parent(&re);
|
txt.set_parent(&re);
|
||||||
let tre = ui_container.add(txt);
|
let tre = ui_container.add(txt);
|
||||||
super::button_action(ui_container, re.clone(), Some(tre.clone()), None);
|
super::button_action(ui_container, re.clone(), Some(tre.clone()), |_, _|{});
|
||||||
elements.add(re);
|
elements.add(re);
|
||||||
elements.add(tre);
|
elements.add(tre);
|
||||||
|
|
||||||
// Options menu
|
// Options menu
|
||||||
let mut options = super::new_button(renderer, 5.0, 25.0, 40.0, 40.0);
|
let mut options = ui::Button::new(5.0, 25.0, 40.0, 40.0);
|
||||||
options.set_v_attach(ui::VAttach::Bottom);
|
options.set_v_attach(ui::VAttach::Bottom);
|
||||||
options.set_h_attach(ui::HAttach::Right);
|
options.set_h_attach(ui::HAttach::Right);
|
||||||
let re = ui_container.add(options);
|
let re = ui_container.add(options);
|
||||||
|
@ -388,7 +388,7 @@ impl super::Screen for ServerList {
|
||||||
cog.set_parent(&re);
|
cog.set_parent(&re);
|
||||||
cog.set_v_attach(ui::VAttach::Middle);
|
cog.set_v_attach(ui::VAttach::Middle);
|
||||||
cog.set_h_attach(ui::HAttach::Center);
|
cog.set_h_attach(ui::HAttach::Center);
|
||||||
super::button_action(ui_container, re.clone(), None, None);
|
super::button_action(ui_container, re.clone(), None, |_, _| {});
|
||||||
elements.add(re);
|
elements.add(re);
|
||||||
elements.add(ui_container.add(cog));
|
elements.add(ui_container.add(cog));
|
||||||
|
|
||||||
|
|
|
@ -47,10 +47,8 @@ impl Server {
|
||||||
|
|
||||||
let packet = match conn.read_packet().unwrap() {
|
let packet = match conn.read_packet().unwrap() {
|
||||||
protocol::packet::Packet::EncryptionRequest(val) => val,
|
protocol::packet::Packet::EncryptionRequest(val) => val,
|
||||||
protocol::packet::Packet::LoginDisconnect(val) => {
|
protocol::packet::Packet::LoginDisconnect(val) => return Err(protocol::Error::Disconnect(val.reason)),
|
||||||
return Err(protocol::Error::Disconnect(val.reason));
|
val => return Err(protocol::Error::Err(format!("Wrong packet: {:?}", val))),
|
||||||
},
|
|
||||||
val => panic!("Wrong packet: {:?}", val),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
|
|
|
@ -22,7 +22,7 @@ ui_element!(Batch {
|
||||||
width: f64,
|
width: f64,
|
||||||
height: f64,
|
height: f64,
|
||||||
|
|
||||||
elements: Vec<Element>
|
elements: Vec<Element>,
|
||||||
});
|
});
|
||||||
|
|
||||||
impl Batch {
|
impl Batch {
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_size(&self) -> (f64, f64) {
|
||||||
|
(self.width, self.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ ui_element!(Formatted {
|
||||||
|
|
||||||
text: Vec<Element>,
|
text: Vec<Element>,
|
||||||
max_width: f64,
|
max_width: f64,
|
||||||
lines: usize
|
lines: usize,
|
||||||
});
|
});
|
||||||
|
|
||||||
impl Formatted {
|
impl Formatted {
|
||||||
|
|
|
@ -25,7 +25,7 @@ ui_element!(Image {
|
||||||
r: u8,
|
r: u8,
|
||||||
g: u8,
|
g: u8,
|
||||||
b: u8,
|
b: u8,
|
||||||
a: u8
|
a: u8,
|
||||||
});
|
});
|
||||||
|
|
||||||
impl Image {
|
impl Image {
|
||||||
|
|
178
src/ui/mod.rs
178
src/ui/mod.rs
|
@ -20,6 +20,7 @@ use std::rc::Rc;
|
||||||
use rand;
|
use rand;
|
||||||
use render;
|
use render;
|
||||||
use format;
|
use format;
|
||||||
|
use glutin::VirtualKeyCode;
|
||||||
|
|
||||||
const SCALED_WIDTH: f64 = 854.0;
|
const SCALED_WIDTH: f64 = 854.0;
|
||||||
const SCALED_HEIGHT: f64 = 480.0;
|
const SCALED_HEIGHT: f64 = 480.0;
|
||||||
|
@ -29,16 +30,63 @@ pub enum Element {
|
||||||
Batch(Batch),
|
Batch(Batch),
|
||||||
Text(Text),
|
Text(Text),
|
||||||
Formatted(Formatted),
|
Formatted(Formatted),
|
||||||
|
TextBox(TextBox),
|
||||||
|
Button(Button),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ClickFunc = Rc<Fn(&mut ::Game, &mut Container)>;
|
pub type ClickFunc = Fn(&mut ::Game, &mut Container);
|
||||||
pub type HoverFunc = Rc<Fn(bool, &mut ::Game, &mut Container)>;
|
pub type HoverFunc = Fn(bool, &mut ::Game, &mut Container);
|
||||||
|
|
||||||
macro_rules! element_impl {
|
macro_rules! element_impl {
|
||||||
($($name:ident),+) => (
|
($($name:ident),+) => (
|
||||||
impl Element {
|
impl Element {
|
||||||
fn get_click_funcs(&self) -> Vec<ClickFunc> {
|
fn can_focus(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
$(
|
||||||
|
Element::$name(ref val) => val.can_focus,
|
||||||
|
)+
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_focused(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
$(
|
||||||
|
Element::$name(ref val) => val.focused,
|
||||||
|
)+
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_focused(&mut self, f: bool) {
|
||||||
|
match *self {
|
||||||
|
$(
|
||||||
|
Element::$name(ref mut val) => val.focused = f,
|
||||||
|
)+
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_press(&mut self, game: &mut ::Game, key: Option<VirtualKeyCode>, raw: u8, down: bool) -> Vec<Rc<ClickFunc>> {
|
||||||
|
match *self {
|
||||||
|
$(
|
||||||
|
Element::$name(ref mut val) => val.key_press(game, key, raw, down),
|
||||||
|
)+
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_type(&mut self, game: &mut ::Game, c: char) -> Vec<Rc<ClickFunc>> {
|
||||||
|
match *self {
|
||||||
|
$(
|
||||||
|
Element::$name(ref mut val) => val.key_type(game, c),
|
||||||
|
)+
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_click_funcs(&self) -> Vec<Rc<ClickFunc>> {
|
||||||
match *self {
|
match *self {
|
||||||
$(
|
$(
|
||||||
Element::$name(ref val) => val.click_funcs.clone(),
|
Element::$name(ref val) => val.click_funcs.clone(),
|
||||||
|
@ -47,7 +95,7 @@ impl Element {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_hover_funcs(&self) -> Vec<HoverFunc> {
|
fn get_hover_funcs(&self) -> Vec<Rc<HoverFunc>> {
|
||||||
match *self {
|
match *self {
|
||||||
$(
|
$(
|
||||||
Element::$name(ref val) => val.hover_funcs.clone(),
|
Element::$name(ref val) => val.hover_funcs.clone(),
|
||||||
|
@ -61,6 +109,7 @@ impl Element {
|
||||||
$(
|
$(
|
||||||
Element::$name(ref mut val) => {
|
Element::$name(ref mut val) => {
|
||||||
let ret = val.hovered != new;
|
let ret = val.hovered != new;
|
||||||
|
val.dirty = val.dirty || ret;
|
||||||
val.hovered = new;
|
val.hovered = new;
|
||||||
ret
|
ret
|
||||||
},
|
},
|
||||||
|
@ -157,7 +206,9 @@ element_impl!(
|
||||||
Image,
|
Image,
|
||||||
Batch,
|
Batch,
|
||||||
Text,
|
Text,
|
||||||
Formatted
|
Formatted,
|
||||||
|
TextBox,
|
||||||
|
Button
|
||||||
);
|
);
|
||||||
|
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
|
@ -337,6 +388,11 @@ impl Container {
|
||||||
self.version = renderer.ui.version;
|
self.version = renderer.ui.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to make sure we have a focus
|
||||||
|
if !self.elements.iter().any(|(_, ref e)| e.is_focused()) {
|
||||||
|
self.cycle_focus();
|
||||||
|
}
|
||||||
|
|
||||||
// Borrow rules seem to prevent us from doing this in the first pass
|
// Borrow rules seem to prevent us from doing this in the first pass
|
||||||
// so we split it.
|
// so we split it.
|
||||||
let regions = self.collect_elements(sw, sh);
|
let regions = self.collect_elements(sw, sh);
|
||||||
|
@ -433,6 +489,80 @@ impl Container {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn key_press(&mut self, game: &mut ::Game, key: Option<VirtualKeyCode>, raw: u8, down: bool) {
|
||||||
|
if key == Some(VirtualKeyCode::Tab) {
|
||||||
|
if !down {
|
||||||
|
self.cycle_focus();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut callbacks = None;
|
||||||
|
for (_, e) in &mut self.elements {
|
||||||
|
if e.is_focused() {
|
||||||
|
callbacks = Some(e.key_press(game, key, raw, down));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(callbacks) = callbacks {
|
||||||
|
for cb in callbacks {
|
||||||
|
cb(game, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn key_type(&mut self, game: &mut ::Game, c: char) {
|
||||||
|
if c < ' ' {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut callbacks = None;
|
||||||
|
for (_, e) in &mut self.elements {
|
||||||
|
if e.is_focused() {
|
||||||
|
callbacks = Some(e.key_type(game, c));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(callbacks) = callbacks {
|
||||||
|
for cb in callbacks {
|
||||||
|
cb(game, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_focused<T: UIElement>(&mut self, r: &ElementRef<T>) {
|
||||||
|
for (_, e) in &mut self.elements {
|
||||||
|
e.set_focused(false);
|
||||||
|
}
|
||||||
|
self.elements.get_mut(&r.inner).unwrap().set_focused(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cycle_focus(&mut self) {
|
||||||
|
// Find the last focused element
|
||||||
|
let i = self.elements_list.iter()
|
||||||
|
.map(|v| self.elements.get(v).unwrap())
|
||||||
|
.position(|v| v.is_focused());
|
||||||
|
let mut current = i.map(|v| v + 1).unwrap_or(0) % self.elements_list.len();
|
||||||
|
|
||||||
|
// Clear the old focus
|
||||||
|
if let Some(pos) = i {
|
||||||
|
let r = self.elements_list[pos];
|
||||||
|
self.elements.get_mut(&r).unwrap().set_focused(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut limit = 0;
|
||||||
|
while limit < self.elements_list.len() {
|
||||||
|
let r = self.elements_list[current];
|
||||||
|
let e = self.elements.get_mut(&r).unwrap();
|
||||||
|
if e.can_focus() {
|
||||||
|
e.set_focused(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
limit += 1;
|
||||||
|
current += 1;
|
||||||
|
current %= self.elements_list.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_draw_region(&self, e: &Element, sw: f64, sh: f64) -> Region {
|
fn get_draw_region(&self, e: &Element, sw: f64, sh: f64) -> Region {
|
||||||
let super_region = match e.get_parent() {
|
let super_region = match e.get_parent() {
|
||||||
Some(ref p) => self.get_draw_region(self.elements.get(p).unwrap(), sw, sh),
|
Some(ref p) => self.get_draw_region(self.elements.get(p).unwrap(), sw, sh),
|
||||||
|
@ -473,6 +603,14 @@ pub trait UIElement {
|
||||||
fn wrap(self) -> Element;
|
fn wrap(self) -> Element;
|
||||||
fn unwrap_ref(&Element) -> &Self;
|
fn unwrap_ref(&Element) -> &Self;
|
||||||
fn unwrap_ref_mut(&mut Element) -> &mut Self;
|
fn unwrap_ref_mut(&mut Element) -> &mut Self;
|
||||||
|
|
||||||
|
fn key_press(&mut self, _game: &mut ::Game, _key: Option<VirtualKeyCode>, _raw: u8, _down: bool) -> Vec<Rc<ClickFunc>> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_type(&mut self, _game: &mut ::Game, _c: char) -> Vec<Rc<ClickFunc>> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! lazy_field {
|
macro_rules! lazy_field {
|
||||||
|
@ -494,8 +632,8 @@ macro_rules! ui_element {
|
||||||
(
|
(
|
||||||
$name:ident {
|
$name:ident {
|
||||||
$(
|
$(
|
||||||
$field:ident : $field_ty:ty
|
$field:ident : $field_ty:ty,
|
||||||
),+
|
)*
|
||||||
}
|
}
|
||||||
) => (
|
) => (
|
||||||
pub struct $name {
|
pub struct $name {
|
||||||
|
@ -508,12 +646,14 @@ macro_rules! ui_element {
|
||||||
y: f64,
|
y: f64,
|
||||||
v_attach: VAttach,
|
v_attach: VAttach,
|
||||||
h_attach: HAttach,
|
h_attach: HAttach,
|
||||||
click_funcs: Vec<ClickFunc>,
|
click_funcs: Vec<Rc<ClickFunc>>,
|
||||||
hover_funcs: Vec<HoverFunc>,
|
hover_funcs: Vec<Rc<HoverFunc>>,
|
||||||
hovered: bool,
|
hovered: bool,
|
||||||
|
can_focus: bool,
|
||||||
|
focused: bool,
|
||||||
$(
|
$(
|
||||||
$field: $field_ty
|
$field: $field_ty,
|
||||||
),+
|
)*
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -525,12 +665,12 @@ macro_rules! base_impl {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_click_func(&mut self, f: ClickFunc) {
|
pub fn add_click_func<F: Fn(&mut ::Game, &mut Container) + 'static>(&mut self, f: F) {
|
||||||
self.click_funcs.push(f);
|
self.click_funcs.push(Rc::new(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_hover_func(&mut self, f: HoverFunc) {
|
pub fn add_hover_func<F: Fn(bool, &mut ::Game, &mut Container) + 'static>(&mut self, f: F) {
|
||||||
self.hover_funcs.push(f);
|
self.hover_funcs.push(Rc::new(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_field!(layer, isize, get_layer, set_layer);
|
lazy_field!(layer, isize, get_layer, set_layer);
|
||||||
|
@ -543,7 +683,7 @@ macro_rules! base_impl {
|
||||||
|
|
||||||
macro_rules! ui_create {
|
macro_rules! ui_create {
|
||||||
($name:ident {
|
($name:ident {
|
||||||
$($field:ident: $e:expr,)+
|
$($field:ident: $e:expr,)*
|
||||||
}) => (
|
}) => (
|
||||||
$name {
|
$name {
|
||||||
dirty: true,
|
dirty: true,
|
||||||
|
@ -557,7 +697,9 @@ macro_rules! ui_create {
|
||||||
click_funcs: Vec::new(),
|
click_funcs: Vec::new(),
|
||||||
hover_funcs: Vec::new(),
|
hover_funcs: Vec::new(),
|
||||||
hovered: false,
|
hovered: false,
|
||||||
$($field: $e),+
|
can_focus: false,
|
||||||
|
focused: false,
|
||||||
|
$($field: $e,)*
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -570,3 +712,5 @@ include!("image.rs");
|
||||||
include!("batch.rs");
|
include!("batch.rs");
|
||||||
include!("text.rs");
|
include!("text.rs");
|
||||||
include!("formatted.rs");
|
include!("formatted.rs");
|
||||||
|
include!("textbox.rs");
|
||||||
|
include!("button.rs");
|
||||||
|
|
|
@ -22,7 +22,7 @@ ui_element!(Text {
|
||||||
r: u8,
|
r: u8,
|
||||||
g: u8,
|
g: u8,
|
||||||
b: u8,
|
b: u8,
|
||||||
a: u8
|
a: u8,
|
||||||
});
|
});
|
||||||
|
|
||||||
impl Text {
|
impl Text {
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
// 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> {
|
||||||
|
use std::mem;
|
||||||
|
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 mut btn = mem::replace(&mut self.button, unsafe { mem::uninitialized() }).wrap();
|
||||||
|
let reg = Container::get_draw_region_raw(&btn, sx, sy, r);
|
||||||
|
btn.set_dirty(true);
|
||||||
|
self.data.extend(btn.draw(renderer, ®, width, height, delta));
|
||||||
|
mem::forget(mem::replace(&mut self.button, match btn {
|
||||||
|
Element::Button(btn)=> btn,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}));
|
||||||
|
let mut txt = mem::replace(&mut self.text, unsafe { mem::uninitialized() }).wrap();
|
||||||
|
let reg = Container::get_draw_region_raw(&txt, sx, sy, r);
|
||||||
|
txt.set_dirty(true);
|
||||||
|
self.data.extend(txt.draw(renderer, ®, width, height, delta));
|
||||||
|
mem::forget(mem::replace(&mut self.text, match txt {
|
||||||
|
Element::Text(txt)=> txt,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_size(&self) -> (f64, f64) {
|
||||||
|
(self.width, self.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_input(&self) -> &str {
|
||||||
|
&self.input
|
||||||
|
}
|
||||||
|
|
||||||
|
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: Option<VirtualKeyCode>, _raw: u8, down: bool) -> Vec<Rc<ClickFunc>> {
|
||||||
|
if let Some(key) = key {
|
||||||
|
match (key, down) {
|
||||||
|
(VirtualKeyCode::Back, false) => {self.input.pop();},
|
||||||
|
(VirtualKeyCode::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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue