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);
|
||||
}
|
|
@ -98,7 +98,7 @@ impl Console {
|
|||
pub fn get<T: Sized + Any>(&self, var: CVar<T>) -> &T
|
||||
where CVar<T>: Var
|
||||
{
|
||||
// Should never fail
|
||||
// Should never fail
|
||||
self.var_values.get(var.name).unwrap().downcast_ref::<T>().unwrap()
|
||||
}
|
||||
|
||||
|
@ -122,9 +122,9 @@ impl Console {
|
|||
renderer: &mut render::Renderer,
|
||||
delta: 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.
|
||||
// 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 {
|
||||
return;
|
||||
|
@ -238,34 +238,34 @@ impl Console {
|
|||
self.history.remove(0);
|
||||
let mut msg = TextComponent::new("");
|
||||
msg.modifier.extra = Some(vec![
|
||||
Component::Text(TextComponent::new("[")),
|
||||
{
|
||||
let mut msg = TextComponent::new(file);
|
||||
msg.modifier.color = Some(Color::Green);
|
||||
Component::Text(msg)
|
||||
},
|
||||
Component::Text(TextComponent::new(":")),
|
||||
{
|
||||
let mut msg = TextComponent::new(&format!("{}", record.location().line()));
|
||||
msg.modifier.color = Some(Color::Aqua);
|
||||
Component::Text(msg)
|
||||
},
|
||||
Component::Text(TextComponent::new("]")),
|
||||
Component::Text(TextComponent::new("[")),
|
||||
{
|
||||
let mut msg = TextComponent::new(&format!("{}", record.level()));
|
||||
msg.modifier.color = Some(match record.level() {
|
||||
log::LogLevel::Debug => Color::Green,
|
||||
log::LogLevel::Error => Color::Red,
|
||||
log::LogLevel::Warn => Color::Yellow,
|
||||
log::LogLevel::Info => Color::Aqua,
|
||||
log::LogLevel::Trace => Color::Blue,
|
||||
});
|
||||
Component::Text(msg)
|
||||
},
|
||||
Component::Text(TextComponent::new("] ")),
|
||||
Component::Text(TextComponent::new(&format!("{}", record.args())))
|
||||
]);
|
||||
Component::Text(TextComponent::new("[")),
|
||||
{
|
||||
let mut msg = TextComponent::new(file);
|
||||
msg.modifier.color = Some(Color::Green);
|
||||
Component::Text(msg)
|
||||
},
|
||||
Component::Text(TextComponent::new(":")),
|
||||
{
|
||||
let mut msg = TextComponent::new(&format!("{}", record.location().line()));
|
||||
msg.modifier.color = Some(Color::Aqua);
|
||||
Component::Text(msg)
|
||||
},
|
||||
Component::Text(TextComponent::new("]")),
|
||||
Component::Text(TextComponent::new("[")),
|
||||
{
|
||||
let mut msg = TextComponent::new(&format!("{}", record.level()));
|
||||
msg.modifier.color = Some(match record.level() {
|
||||
log::LogLevel::Debug => Color::Green,
|
||||
log::LogLevel::Error => Color::Red,
|
||||
log::LogLevel::Warn => Color::Yellow,
|
||||
log::LogLevel::Info => Color::Aqua,
|
||||
log::LogLevel::Trace => Color::Blue,
|
||||
});
|
||||
Component::Text(msg)
|
||||
},
|
||||
Component::Text(TextComponent::new("] ")),
|
||||
Component::Text(TextComponent::new(&format!("{}", record.args())))
|
||||
]);
|
||||
self.history.push(Component::Text(msg));
|
||||
}
|
||||
}
|
||||
|
|
21
src/main.rs
21
src/main.rs
|
@ -49,6 +49,7 @@ pub mod console;
|
|||
pub mod server;
|
||||
pub mod world;
|
||||
pub mod chunk_builder;
|
||||
pub mod auth;
|
||||
|
||||
use std::sync::{Arc, RwLock, Mutex};
|
||||
use std::marker::PhantomData;
|
||||
|
@ -128,6 +129,7 @@ fn main() {
|
|||
{
|
||||
let mut con = con.lock().unwrap();
|
||||
con.register(CL_BRAND);
|
||||
auth::register_vars(&mut con);
|
||||
con.load_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 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 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);
|
||||
}
|
||||
|
||||
Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) => {
|
||||
let (x, y) = game.mouse_pos;
|
||||
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);
|
||||
}
|
||||
|
||||
Event::MouseWheel(delta) => {
|
||||
let (x, y) = match delta {
|
||||
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);
|
||||
}
|
||||
|
||||
Event::KeyboardInput(glutin::ElementState::Pressed, 41 /* ` GRAVE */, _)
|
||||
| Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(VirtualKeyCode::Grave)) => {
|
||||
Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(VirtualKeyCode::Grave)) => {
|
||||
game.console.lock().unwrap().toggle();
|
||||
}
|
||||
Event::KeyboardInput(glutin::ElementState::Pressed, key, virt) => {
|
||||
println!("Key: {:?} {:?}", key, virt);
|
||||
if virt == Some(VirtualKeyCode::H) {
|
||||
game.server.world.flag_dirty_all();
|
||||
}
|
||||
Event::KeyboardInput(state, key, virt) => {
|
||||
ui_container.key_press(game, virt, key, state == glutin::ElementState::Pressed);
|
||||
}
|
||||
Event::ReceivedCharacter(c) => {
|
||||
ui_container.key_type(game, c);
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -511,20 +511,20 @@ state_packets!(
|
|||
// JoinGame is sent after completing the login process. This
|
||||
// sets the initial state for the client.
|
||||
JoinGame {
|
||||
// The entity id the client will be referenced by
|
||||
// The entity id the client will be referenced by
|
||||
entity_id: i32 =,
|
||||
// The starting gamemode of the client
|
||||
// The starting gamemode of the client
|
||||
gamemode: u8 =,
|
||||
// The dimension the client is starting in
|
||||
// The dimension the client is starting in
|
||||
dimension: i8 =,
|
||||
// The difficuilty setting for the server
|
||||
// The difficuilty setting for the server
|
||||
difficulty: u8 =,
|
||||
// The max number of players on the server
|
||||
// The max number of players on the server
|
||||
max_players: u8 =,
|
||||
// The level type of the server
|
||||
// The level type of the server
|
||||
level_type: String =,
|
||||
// Whether the client should reduce the amount of debug
|
||||
// information it displays in F3 mode
|
||||
// Whether the client should reduce the amount of debug
|
||||
// information it displays in F3 mode
|
||||
reduced_debug_info: bool =,
|
||||
}
|
||||
// Maps updates a single map's contents
|
||||
|
@ -879,21 +879,21 @@ state_packets!(
|
|||
// and optionally a favicon.
|
||||
//
|
||||
// The structure is as follows
|
||||
// {
|
||||
// "version": {
|
||||
// "name": "1.8.3",
|
||||
// "protocol": 47,
|
||||
// },
|
||||
// "players": {
|
||||
// "max": 20,
|
||||
// "online": 1,
|
||||
// "sample": [
|
||||
// {"name": "Thinkofdeath", "id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20"}
|
||||
// ]
|
||||
// },
|
||||
// "description": "Hello world",
|
||||
// "favicon": "data:image/png;base64,<data>"
|
||||
// }
|
||||
// {
|
||||
// "version": {
|
||||
// "name": "1.8.3",
|
||||
// "protocol": 47,
|
||||
// },
|
||||
// "players": {
|
||||
// "max": 20,
|
||||
// "online": 1,
|
||||
// "sample": [
|
||||
// {"name": "Thinkofdeath", "id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20"}
|
||||
// ]
|
||||
// },
|
||||
// "description": "Hello world",
|
||||
// "favicon": "data:image/png;base64,<data>"
|
||||
// }
|
||||
StatusResponse {
|
||||
status: String =,
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ impl Atlas {
|
|||
let mut priority = usize::max_value();
|
||||
let mut target: Option<Rect> = None;
|
||||
let mut target_index = 0;
|
||||
// Search through and find the best fit for this texture
|
||||
// Search through and find the best fit for this texture
|
||||
for (index, free) in self.free_space.iter().enumerate() {
|
||||
if free.width >= width && free.height >= height {
|
||||
let current_priority = (free.width - width) * (free.height - height);
|
||||
|
@ -49,7 +49,7 @@ impl Atlas {
|
|||
priority = current_priority;
|
||||
target_index = index;
|
||||
}
|
||||
// Perfect match, we can break early
|
||||
// Perfect match, we can break early
|
||||
if priority == 0 {
|
||||
break;
|
||||
}
|
||||
|
@ -70,14 +70,14 @@ impl Atlas {
|
|||
t.y += height;
|
||||
t.height -= height;
|
||||
if t.height == 0 {
|
||||
// Remove empty sections
|
||||
// Remove empty sections
|
||||
self.free_space.remove(target_index);
|
||||
} else {
|
||||
self.free_space[target_index] = t;
|
||||
}
|
||||
} else {
|
||||
if t.height > height {
|
||||
// Split by height
|
||||
// Split by height
|
||||
self.free_space.insert(0,
|
||||
Rect {
|
||||
x: t.x,
|
||||
|
|
|
@ -41,50 +41,50 @@ macro_rules! get_shader {
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! init_shader {
|
||||
(
|
||||
Program $name:ident {
|
||||
vert = $vert:expr, $(#$vdef:ident)*
|
||||
frag = $frag:expr, $(#$fdef:ident)*
|
||||
attribute = {
|
||||
$(
|
||||
$field:ident => $glname:expr,
|
||||
)*
|
||||
},
|
||||
uniform = {
|
||||
$(
|
||||
$ufield:ident => $uglname:expr,
|
||||
)*
|
||||
},
|
||||
}
|
||||
) => (
|
||||
(
|
||||
Program $name:ident {
|
||||
vert = $vert:expr, $(#$vdef:ident)*
|
||||
frag = $frag:expr, $(#$fdef:ident)*
|
||||
attribute = {
|
||||
$(
|
||||
$field:ident => $glname:expr,
|
||||
)*
|
||||
},
|
||||
uniform = {
|
||||
$(
|
||||
$ufield:ident => $uglname:expr,
|
||||
)*
|
||||
},
|
||||
}
|
||||
) => (
|
||||
#[allow(dead_code)]
|
||||
struct $name {
|
||||
program: gl::Program,
|
||||
$(
|
||||
$field: gl::Attribute,
|
||||
)+
|
||||
$(
|
||||
$ufield: gl::Uniform,
|
||||
)+
|
||||
}
|
||||
struct $name {
|
||||
program: gl::Program,
|
||||
$(
|
||||
$field: gl::Attribute,
|
||||
)+
|
||||
$(
|
||||
$ufield: gl::Uniform,
|
||||
)+
|
||||
}
|
||||
|
||||
impl $name {
|
||||
pub fn new(reg: &glsl::Registry) -> $name {
|
||||
let v = get_shader!(reg, $vert $(,stringify!($vdef))*);
|
||||
let f = get_shader!(reg, $frag $(,stringify!($fdef))*);
|
||||
let shader = shaders::create_program(&v, &f);
|
||||
$name {
|
||||
$(
|
||||
$field: shader.attribute_location($glname),
|
||||
)+
|
||||
$(
|
||||
$ufield: shader.uniform_location($uglname),
|
||||
)+
|
||||
program: shader,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
impl $name {
|
||||
pub fn new(reg: &glsl::Registry) -> $name {
|
||||
let v = get_shader!(reg, $vert $(,stringify!($vdef))*);
|
||||
let f = get_shader!(reg, $frag $(,stringify!($fdef))*);
|
||||
let shader = shaders::create_program(&v, &f);
|
||||
$name {
|
||||
$(
|
||||
$field: shader.attribute_location($glname),
|
||||
)+
|
||||
$(
|
||||
$ufield: shader.uniform_location($uglname),
|
||||
)+
|
||||
program: shader,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub fn create_program(vertex: &str, fragment: &str) -> gl::Program {
|
||||
|
|
|
@ -16,21 +16,21 @@ out float revealage;
|
|||
#include lookup_texture
|
||||
|
||||
void main() {
|
||||
vec4 col = atlasTexture();
|
||||
#ifndef alpha
|
||||
if (col.a < 0.5) discard;
|
||||
#endif
|
||||
col *= vec4(vColor, 1.0);
|
||||
col.rgb *= vLighting;
|
||||
vec4 col = atlasTexture();
|
||||
#ifndef alpha
|
||||
if (col.a < 0.5) discard;
|
||||
#endif
|
||||
col *= vec4(vColor, 1.0);
|
||||
col.rgb *= vLighting;
|
||||
|
||||
#ifndef alpha
|
||||
fragColor = col;
|
||||
#else
|
||||
float z = gl_FragCoord.z;
|
||||
float al = col.a;
|
||||
float weight = pow(al + 0.01f, 4.0f) +
|
||||
max(0.01f, min(3000.0f, 0.3f / (0.00001f + pow(abs(z) / 800.0f, 4.0f))));
|
||||
accum = vec4(col.rgb * al * weight, al);
|
||||
revealage = weight * al;
|
||||
#endif
|
||||
#ifndef alpha
|
||||
fragColor = col;
|
||||
#else
|
||||
float z = gl_FragCoord.z;
|
||||
float al = col.a;
|
||||
float weight = pow(al + 0.01f, 4.0f) +
|
||||
max(0.01f, min(3000.0f, 0.3f / (0.00001f + pow(abs(z) / 800.0f, 4.0f))));
|
||||
accum = vec4(col.rgb * al * weight, al);
|
||||
revealage = weight * al;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -19,14 +19,14 @@ out vec3 vLighting;
|
|||
#include get_light
|
||||
|
||||
void main() {
|
||||
vec3 pos = vec3(aPosition.x, -aPosition.y, aPosition.z);
|
||||
vec3 o = vec3(offset.x, -offset.y / 4096.0, offset.z);
|
||||
gl_Position = perspectiveMatrix * cameraMatrix * vec4(pos + o * 16.0, 1.0);
|
||||
vec3 pos = vec3(aPosition.x, -aPosition.y, aPosition.z);
|
||||
vec3 o = vec3(offset.x, -offset.y / 4096.0, offset.z);
|
||||
gl_Position = perspectiveMatrix * cameraMatrix * vec4(pos + o * 16.0, 1.0);
|
||||
|
||||
vColor = aColor;
|
||||
vTextureInfo = aTextureInfo;
|
||||
vTextureOffset = aTextureOffset.xy / 16.0;
|
||||
vAtlas = aTextureOffset.z;
|
||||
vColor = aColor;
|
||||
vTextureInfo = aTextureInfo;
|
||||
vTextureOffset = aTextureOffset.xy / 16.0;
|
||||
vAtlas = aTextureOffset.z;
|
||||
|
||||
vLighting = getLight(aLighting / (4000.0));
|
||||
vLighting = getLight(aLighting / (4000.0));
|
||||
}
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
|
||||
vec3 getLight(vec2 light) {
|
||||
vec2 li = pow(vec2(lightLevel), 15.0 - light);
|
||||
float skyTint = skyOffset * 0.95 + 0.05;
|
||||
float bl = li.x;
|
||||
float sk = li.y * skyTint;
|
||||
vec2 li = pow(vec2(lightLevel), 15.0 - light);
|
||||
float skyTint = skyOffset * 0.95 + 0.05;
|
||||
float bl = li.x;
|
||||
float sk = li.y * skyTint;
|
||||
|
||||
float skyRed = sk * (skyOffset * 0.65 + 0.35);
|
||||
float skyGreen = sk * (skyOffset * 0.65 + 0.35);
|
||||
float blockGreen = bl * ((bl * 0.6 + 0.4) * 0.6 + 0.4);
|
||||
float blockBlue = bl * (bl * bl * 0.6 + 0.4);
|
||||
float skyRed = sk * (skyOffset * 0.65 + 0.35);
|
||||
float skyGreen = sk * (skyOffset * 0.65 + 0.35);
|
||||
float blockGreen = bl * ((bl * 0.6 + 0.4) * 0.6 + 0.4);
|
||||
float blockBlue = bl * (bl * bl * 0.6 + 0.4);
|
||||
|
||||
vec3 col = vec3(
|
||||
skyRed + bl,
|
||||
skyGreen + blockGreen,
|
||||
sk + blockBlue
|
||||
);
|
||||
vec3 col = vec3(
|
||||
skyRed + bl,
|
||||
skyGreen + blockGreen,
|
||||
sk + blockBlue
|
||||
);
|
||||
|
||||
col = col * 0.96 + 0.03;
|
||||
col = col * 0.96 + 0.03;
|
||||
|
||||
float gamma = 0.0;
|
||||
vec3 invCol = 1.0 - col;
|
||||
invCol = 1.0 - invCol * invCol * invCol * invCol;
|
||||
col = col * (1.0 - gamma) + invCol * gamma;
|
||||
col = col * 0.96 + 0.03;
|
||||
float gamma = 0.0;
|
||||
vec3 invCol = 1.0 - col;
|
||||
invCol = 1.0 - invCol * invCol * invCol * invCol;
|
||||
col = col * (1.0 - gamma) + invCol * gamma;
|
||||
col = col * 0.96 + 0.03;
|
||||
|
||||
return clamp(col, 0.0, 1.0);
|
||||
}
|
||||
return clamp(col, 0.0, 1.0);
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
const float invAtlasSize = 1.0 / 1024;
|
||||
vec4 atlasTexture() {
|
||||
vec2 tPos = vTextureOffset;
|
||||
tPos = mod(tPos, vTextureInfo.zw);
|
||||
tPos += vTextureInfo.xy;
|
||||
tPos *= invAtlasSize;
|
||||
return texture(textures, vec3(tPos, vAtlas));
|
||||
}
|
||||
vec2 tPos = vTextureOffset;
|
||||
tPos = mod(tPos, vTextureInfo.zw);
|
||||
tPos += vTextureInfo.xy;
|
||||
tPos *= invAtlasSize;
|
||||
return texture(textures, vec3(tPos, vAtlas));
|
||||
}
|
|
@ -7,22 +7,22 @@ uniform int samples;
|
|||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
ivec2 C = ivec2(gl_FragCoord.xy);
|
||||
vec4 accum = texelFetch(taccum, C, 0);
|
||||
float aa = texelFetch(trevealage, C, 0).r;
|
||||
vec4 col = texelFetch(tcolor, C, 0);
|
||||
ivec2 C = ivec2(gl_FragCoord.xy);
|
||||
vec4 accum = texelFetch(taccum, C, 0);
|
||||
float aa = texelFetch(trevealage, C, 0).r;
|
||||
vec4 col = texelFetch(tcolor, C, 0);
|
||||
|
||||
for (int i = 1; i < samples; i++) {
|
||||
col += texelFetch(tcolor, C, i);
|
||||
}
|
||||
col /= float(samples);
|
||||
for (int i = 1; i < samples; i++) {
|
||||
col += texelFetch(tcolor, C, i);
|
||||
}
|
||||
col /= float(samples);
|
||||
|
||||
float r = accum.a;
|
||||
accum.a = aa;
|
||||
if (r >= 1.0) {
|
||||
fragColor = vec4(col.rgb, 0.0);
|
||||
} else {
|
||||
vec3 alp = clamp(accum.rgb / clamp(accum.a, 1e-4, 5e4), 0.0, 1.0);
|
||||
fragColor = vec4(col.rgb * r + alp * (1.0 - r), 0.0);
|
||||
}
|
||||
float r = accum.a;
|
||||
accum.a = aa;
|
||||
if (r >= 1.0) {
|
||||
fragColor = vec4(col.rgb, 0.0);
|
||||
} else {
|
||||
vec3 alp = clamp(accum.rgb / clamp(accum.a, 1e-4, 5e4), 0.0, 1.0);
|
||||
fragColor = vec4(col.rgb * r + alp * (1.0 - r), 0.0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ out vec4 fragColor;
|
|||
#include lookup_texture
|
||||
|
||||
void main() {
|
||||
vec4 col = atlasTexture();
|
||||
col *= vColor;
|
||||
if (col.a == 0.0) discard;
|
||||
fragColor = col;
|
||||
vec4 col = atlasTexture();
|
||||
col *= vColor;
|
||||
if (col.a == 0.0) discard;
|
||||
fragColor = col;
|
||||
}
|
|
@ -11,10 +11,10 @@ out float vAtlas;
|
|||
uniform vec2 screenSize;
|
||||
|
||||
void main() {
|
||||
vec2 pos = aPosition.xy / screenSize;
|
||||
gl_Position = vec4((pos.x-0.5)*2.0, -(pos.y-0.5)*2.0, float(-aPosition.z) / float(0xFFFF-1), 1.0);
|
||||
vColor = aColor;
|
||||
vTextureInfo = aTextureInfo;
|
||||
vTextureOffset = aTextureOffset.xy / 16.0;
|
||||
vAtlas = aTextureOffset.z;
|
||||
vec2 pos = aPosition.xy / screenSize;
|
||||
gl_Position = vec4((pos.x-0.5)*2.0, -(pos.y-0.5)*2.0, float(-aPosition.z) / float(0xFFFF-1), 1.0);
|
||||
vColor = aColor;
|
||||
vTextureInfo = aTextureInfo;
|
||||
vTextureOffset = aTextureOffset.xy / 16.0;
|
||||
vAtlas = aTextureOffset.z;
|
||||
}
|
|
@ -53,20 +53,20 @@ pub struct UIState {
|
|||
}
|
||||
|
||||
init_shader! {
|
||||
Program UIShader {
|
||||
vert = "ui_vertex",
|
||||
frag = "ui_frag",
|
||||
attribute = {
|
||||
position => "aPosition",
|
||||
texture_info => "aTextureInfo",
|
||||
texture_offset => "aTextureOffset",
|
||||
color => "aColor",
|
||||
},
|
||||
uniform = {
|
||||
texture => "textures",
|
||||
screensize => "screenSize",
|
||||
},
|
||||
}
|
||||
Program UIShader {
|
||||
vert = "ui_vertex",
|
||||
frag = "ui_frag",
|
||||
attribute = {
|
||||
position => "aPosition",
|
||||
texture_info => "aTextureInfo",
|
||||
texture_offset => "aTextureOffset",
|
||||
color => "aColor",
|
||||
},
|
||||
uniform = {
|
||||
texture => "textures",
|
||||
screensize => "screenSize",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl UIState {
|
||||
|
@ -143,7 +143,7 @@ impl UIState {
|
|||
self.load_font();
|
||||
}
|
||||
}
|
||||
// Prevent clipping with the world
|
||||
// Prevent clipping with the world
|
||||
gl::clear(gl::ClearFlags::Depth);
|
||||
gl::depth_func(gl::LESS_OR_EQUAL);
|
||||
gl::enable(gl::BLEND);
|
||||
|
@ -187,7 +187,7 @@ impl UIState {
|
|||
pub fn character_texture(&mut self, c: char) -> render::Texture {
|
||||
let raw = c as u32;
|
||||
let page = raw >> 8;
|
||||
// Lazy load fonts to size memory
|
||||
// Lazy load fonts to size memory
|
||||
if self.font_pages[page as usize].is_none() {
|
||||
let name = if page == 0 {
|
||||
"font/ascii".to_owned()
|
||||
|
@ -254,8 +254,8 @@ impl UIState {
|
|||
let mut data = Vec::with_capacity(0x10000);
|
||||
info.read_to_end(&mut data).unwrap();
|
||||
for (i, info) in self.font_character_info.iter_mut().enumerate() {
|
||||
// Top nibble - start position
|
||||
// Bottom nibble - end position
|
||||
// Top nibble - start position
|
||||
// Bottom nibble - end position
|
||||
info.0 = (data[i] >> 4) as i32;
|
||||
info.1 = (data[i] & 0xF) as i32 + 1;
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ impl super::Screen for Connecting {
|
|||
server_msg.set_h_attach(ui::HAttach::Center);
|
||||
elements.add(ui_container.add(server_msg));
|
||||
|
||||
// Disclaimer
|
||||
// Disclaimer
|
||||
let mut warn = ui::Text::new(renderer,
|
||||
"Not affiliated with Mojang/Minecraft",
|
||||
5.0,
|
||||
|
@ -81,7 +81,7 @@ impl super::Screen for Connecting {
|
|||
});
|
||||
}
|
||||
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);
|
||||
|
|
|
@ -12,13 +12,15 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use ui;
|
||||
use render;
|
||||
use console;
|
||||
|
||||
pub struct Login {
|
||||
elements: Option<UIElements>,
|
||||
console: Arc<Mutex<console::Console>>,
|
||||
}
|
||||
|
||||
struct UIElements {
|
||||
|
@ -28,8 +30,8 @@ struct UIElements {
|
|||
|
||||
|
||||
impl Login {
|
||||
pub fn new() -> Login {
|
||||
Login { elements: None }
|
||||
pub fn new(console: Arc<Mutex<console::Console>>) -> Login {
|
||||
Login { elements: None, console: console }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,13 +40,8 @@ impl super::Screen for Login {
|
|||
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container);
|
||||
let mut elements = ui::Collection::new();
|
||||
|
||||
// Login
|
||||
let (mut login, mut txt) = super::new_button_text(renderer,
|
||||
"Login",
|
||||
0.0,
|
||||
100.0,
|
||||
400.0,
|
||||
40.0);
|
||||
// Login
|
||||
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_h_attach(ui::HAttach::Center);
|
||||
let re = ui_container.add(login);
|
||||
|
@ -53,14 +50,41 @@ impl super::Screen for Login {
|
|||
super::button_action(ui_container,
|
||||
re.clone(),
|
||||
Some(tre.clone()),
|
||||
Some(Rc::new(|game, _| {
|
||||
|game, _| {
|
||||
game.screen_sys
|
||||
.replace_screen(Box::new(super::ServerList::new(None)));
|
||||
})));
|
||||
});
|
||||
elements.add(re);
|
||||
elements.add(tre);
|
||||
|
||||
// Disclaimer
|
||||
// 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
|
||||
let mut warn = ui::Text::new(renderer,
|
||||
"Not affiliated with Mojang/Minecraft",
|
||||
5.0,
|
||||
|
@ -78,7 +102,7 @@ impl super::Screen for Login {
|
|||
});
|
||||
}
|
||||
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);
|
||||
|
|
|
@ -18,30 +18,28 @@ mod login;
|
|||
pub use self::login::*;
|
||||
pub mod connecting;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use render;
|
||||
use ui;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub trait Screen {
|
||||
// Called once
|
||||
// Called once
|
||||
fn init(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||
}
|
||||
fn deinit(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||
}
|
||||
|
||||
// May be called multiple times
|
||||
// May be called multiple times
|
||||
fn on_active(&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);
|
||||
|
||||
// Called every frame the screen is active
|
||||
// Called every frame the screen is active
|
||||
fn tick(&mut self,
|
||||
delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container);
|
||||
|
||||
// Events
|
||||
// Events
|
||||
fn on_scroll(&mut self, x: f64, y: f64) {
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +98,7 @@ impl ScreenSystem {
|
|||
if self.screens.is_empty() {
|
||||
return;
|
||||
}
|
||||
// Update state for screens
|
||||
// Update state for screens
|
||||
let len = self.screens.len();
|
||||
for screen in &mut self.screens[..len - 1] {
|
||||
if screen.active {
|
||||
|
@ -118,7 +116,7 @@ impl ScreenSystem {
|
|||
current.screen.on_active(renderer, ui_container);
|
||||
}
|
||||
|
||||
// Handle current
|
||||
// Handle current
|
||||
current.screen.tick(delta, renderer, ui_container);
|
||||
}
|
||||
|
||||
|
@ -131,213 +129,35 @@ 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,
|
||||
val: &str,
|
||||
x: f64,
|
||||
y: f64,
|
||||
w: f64,
|
||||
h: f64)
|
||||
-> (ui::Batch, ui::Text) {
|
||||
let batch = new_button(renderer, x, y, w, h);
|
||||
-> (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);
|
||||
(batch, text)
|
||||
(btn, text)
|
||||
}
|
||||
|
||||
pub fn button_action(ui_container: &mut ui::Container,
|
||||
btn: ui::ElementRef<ui::Batch>,
|
||||
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: Option<ui::ClickFunc>) {
|
||||
let batch = ui_container.get_mut(&btn);
|
||||
batch.add_hover_func(Rc::new(move |over, game, 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();
|
||||
if let Some(txt) = txt {
|
||||
let text = ui_container.get_mut(&txt);
|
||||
text.set_b(if over {
|
||||
160
|
||||
} else {
|
||||
255
|
||||
});
|
||||
}
|
||||
}));
|
||||
if let Some(click) = click {
|
||||
batch.add_click_func(click);
|
||||
}
|
||||
click: F) {
|
||||
let button = ui_container.get_mut(&btn);
|
||||
button.add_hover_func(move |over, _, ui_container| {
|
||||
let txt = txt.clone();
|
||||
if let Some(txt) = txt {
|
||||
let text = ui_container.get_mut(&txt);
|
||||
text.set_b(if over {
|
||||
160
|
||||
} else {
|
||||
255
|
||||
});
|
||||
}
|
||||
});
|
||||
button.add_click_func(click);
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ impl ServerList {
|
|||
let elements = self.elements.as_mut().unwrap();
|
||||
*self.needs_reload.borrow_mut() = false;
|
||||
{
|
||||
// Clean up previous list entries and icons.
|
||||
// Clean up previous list entries and icons.
|
||||
let mut tex = renderer.get_textures_ref().write().unwrap();
|
||||
for server in &mut elements.servers {
|
||||
server.collection.remove_all(ui_container);
|
||||
|
@ -117,10 +117,10 @@ impl ServerList {
|
|||
let servers = servers_info.find("servers").unwrap().as_array().unwrap();
|
||||
let mut offset = 0.0;
|
||||
|
||||
// Default icon whilst we ping the servers or if the server doesn't provide one
|
||||
// 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
|
||||
// General gui icons
|
||||
let icons = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/icons");
|
||||
|
||||
for svr in servers {
|
||||
|
@ -129,7 +129,7 @@ impl ServerList {
|
|||
|
||||
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,
|
||||
0.0,
|
||||
offset * 100.0,
|
||||
|
@ -165,32 +165,32 @@ impl ServerList {
|
|||
};
|
||||
server.collection.add(server.back.clone());
|
||||
server.update_position();
|
||||
// Make whole entry interactable
|
||||
// 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(Rc::new(move |over, _, ui_container| {
|
||||
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(Rc::new(move |game, _| {
|
||||
back.add_click_func(move |game, _| {
|
||||
game.screen_sys.replace_screen(Box::new(super::connecting::Connecting::new(&address)));
|
||||
game.connect_to(&address);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
// Server name
|
||||
// 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
|
||||
// Server icon
|
||||
let mut icon = ui::Image::new(default_icon.clone(),
|
||||
5.0,
|
||||
5.0,
|
||||
|
@ -206,7 +206,7 @@ impl ServerList {
|
|||
icon.set_parent(&server.back);
|
||||
server.icon = server.collection.add(ui_container.add(icon));
|
||||
|
||||
// Ping indicator
|
||||
// Ping indicator
|
||||
let mut ping = ui::Image::new(icons.clone(),
|
||||
5.0,
|
||||
5.0,
|
||||
|
@ -223,13 +223,13 @@ impl ServerList {
|
|||
ping.set_parent(&server.back);
|
||||
server.ping = server.collection.add(ui_container.add(ping));
|
||||
|
||||
// Player count
|
||||
// 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
|
||||
// Server's message of the day
|
||||
let mut motd =
|
||||
ui::Formatted::with_width_limit(renderer,
|
||||
Component::Text(TextComponent::new("Connecting.\
|
||||
|
@ -240,7 +240,7 @@ impl ServerList {
|
|||
motd.set_parent(&server.back);
|
||||
server.motd = server.collection.add(ui_container.add(motd));
|
||||
|
||||
// Version information
|
||||
// Version information
|
||||
let mut version =
|
||||
ui::Formatted::with_width_limit(renderer,
|
||||
Component::Text(TextComponent::new("")),
|
||||
|
@ -251,7 +251,7 @@ impl ServerList {
|
|||
version.set_parent(&server.back);
|
||||
server.version = server.collection.add(ui_container.add(version));
|
||||
|
||||
// Delete entry button
|
||||
// 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);
|
||||
|
@ -259,11 +259,11 @@ impl ServerList {
|
|||
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()), None);
|
||||
super::button_action(ui_container, re.clone(), Some(tre.clone()), |_,_| {});
|
||||
server.collection.add(re);
|
||||
server.collection.add(tre);
|
||||
|
||||
// Edit entry button
|
||||
// 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);
|
||||
|
@ -271,14 +271,14 @@ impl ServerList {
|
|||
let re = ui_container.add(edit);
|
||||
txt.set_parent(&re);
|
||||
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(tre);
|
||||
|
||||
elements.servers.push(server);
|
||||
offset += 1.0;
|
||||
|
||||
// Don't block the main thread whilst pinging the server
|
||||
// Don't block the main thread whilst pinging the server
|
||||
thread::spawn(move || {
|
||||
match protocol::Conn::new(&address).and_then(|conn| conn.do_status()) {
|
||||
Ok(res) => {
|
||||
|
@ -329,7 +329,7 @@ impl super::Screen for ServerList {
|
|||
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, 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,
|
||||
"Refresh",
|
||||
300.0,
|
||||
|
@ -345,13 +345,13 @@ impl super::Screen for ServerList {
|
|||
super::button_action(ui_container,
|
||||
re.clone(),
|
||||
Some(tre.clone()),
|
||||
Some(Rc::new(move |_, _| {
|
||||
move |_, _| {
|
||||
*nr.borrow_mut() = 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(renderer,
|
||||
"Add",
|
||||
200.0,
|
||||
|
@ -363,12 +363,12 @@ impl super::Screen for ServerList {
|
|||
let re = ui_container.add(add);
|
||||
txt.set_parent(&re);
|
||||
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(tre);
|
||||
|
||||
// Options menu
|
||||
let mut options = super::new_button(renderer, 5.0, 25.0, 40.0, 40.0);
|
||||
// Options menu
|
||||
let mut options = ui::Button::new(5.0, 25.0, 40.0, 40.0);
|
||||
options.set_v_attach(ui::VAttach::Bottom);
|
||||
options.set_h_attach(ui::HAttach::Right);
|
||||
let re = ui_container.add(options);
|
||||
|
@ -388,11 +388,11 @@ impl super::Screen for ServerList {
|
|||
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, None);
|
||||
super::button_action(ui_container, re.clone(), None, |_, _| {});
|
||||
elements.add(re);
|
||||
elements.add(ui_container.add(cog));
|
||||
|
||||
// Disclaimer
|
||||
// Disclaimer
|
||||
let mut warn = ui::Text::new(renderer,
|
||||
"Not affiliated with Mojang/Minecraft",
|
||||
5.0,
|
||||
|
@ -404,7 +404,7 @@ impl super::Screen for ServerList {
|
|||
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 mut dis_msg = ui::Text::new(renderer, "Disconnected", 0.0, 32.0, 255, 0, 0);
|
||||
dis_msg.set_h_attach(ui::HAttach::Center);
|
||||
|
@ -443,7 +443,7 @@ impl super::Screen for ServerList {
|
|||
self.reload_server_list(renderer, 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);
|
||||
|
@ -468,7 +468,7 @@ impl super::Screen for ServerList {
|
|||
elements.logo.tick(renderer, ui_container);
|
||||
|
||||
for s in &mut elements.servers {
|
||||
// Animate the entries
|
||||
// Animate the entries
|
||||
{
|
||||
let back = ui_container.get_mut(&s.back);
|
||||
let dy = s.y - back.get_y();
|
||||
|
@ -480,8 +480,8 @@ impl super::Screen for ServerList {
|
|||
}
|
||||
}
|
||||
|
||||
// Keep checking to see if the server has finished being
|
||||
// pinged
|
||||
// Keep checking to see if the server has finished being
|
||||
// pinged
|
||||
if !s.done_ping {
|
||||
match s.recv.try_recv() {
|
||||
Ok(res) => {
|
||||
|
@ -492,7 +492,7 @@ impl super::Screen for ServerList {
|
|||
}
|
||||
{
|
||||
let ping = ui_container.get_mut(&s.ping);
|
||||
// Selects the icon for the given ping range
|
||||
// Selects the icon for the given ping range
|
||||
let y = match res.ping.num_milliseconds() {
|
||||
_x @ 0 ... 75 => 16.0 / 256.0,
|
||||
_x @ 76 ... 150 => 24.0 / 256.0,
|
||||
|
|
|
@ -47,10 +47,8 @@ impl Server {
|
|||
|
||||
let packet = match conn.read_packet().unwrap() {
|
||||
protocol::packet::Packet::EncryptionRequest(val) => val,
|
||||
protocol::packet::Packet::LoginDisconnect(val) => {
|
||||
return Err(protocol::Error::Disconnect(val.reason));
|
||||
},
|
||||
val => panic!("Wrong packet: {:?}", val),
|
||||
protocol::packet::Packet::LoginDisconnect(val) => return Err(protocol::Error::Disconnect(val.reason)),
|
||||
val => return Err(protocol::Error::Err(format!("Wrong packet: {:?}", val))),
|
||||
};
|
||||
|
||||
unimplemented!();
|
||||
|
|
|
@ -19,14 +19,14 @@ pub struct BatchRef<T: UIElement> {
|
|||
}
|
||||
|
||||
ui_element!(Batch {
|
||||
width: f64,
|
||||
height: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
|
||||
elements: Vec<Element>
|
||||
elements: Vec<Element>,
|
||||
});
|
||||
|
||||
impl Batch {
|
||||
base_impl!();
|
||||
base_impl!();
|
||||
|
||||
pub fn new(x: f64, y: f64, w: f64, h: f64) -> Batch {
|
||||
ui_create!(Batch {
|
||||
|
@ -95,8 +95,8 @@ impl Batch {
|
|||
self.elements.len()
|
||||
}
|
||||
|
||||
lazy_field!(width, f64, get_width, set_width);
|
||||
lazy_field!(height, f64, get_height, set_height);
|
||||
lazy_field!(width, f64, get_width, set_width);
|
||||
lazy_field!(height, f64, get_height, set_height);
|
||||
}
|
||||
|
||||
impl UIElement for 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"),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,19 +13,19 @@
|
|||
// limitations under the License.
|
||||
|
||||
ui_element!(Formatted {
|
||||
val: format::Component,
|
||||
width: f64,
|
||||
height: f64,
|
||||
scale_x: f64,
|
||||
scale_y: f64,
|
||||
val: format::Component,
|
||||
width: f64,
|
||||
height: f64,
|
||||
scale_x: f64,
|
||||
scale_y: f64,
|
||||
|
||||
text: Vec<Element>,
|
||||
max_width: f64,
|
||||
lines: usize
|
||||
text: Vec<Element>,
|
||||
max_width: f64,
|
||||
lines: usize,
|
||||
});
|
||||
|
||||
impl Formatted {
|
||||
base_impl!();
|
||||
base_impl!();
|
||||
|
||||
pub fn new(renderer: &mut render::Renderer,
|
||||
val: format::Component,
|
||||
|
@ -126,10 +126,10 @@ impl Formatted {
|
|||
self.height * self.scale_y)
|
||||
}
|
||||
|
||||
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!(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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -13,23 +13,23 @@
|
|||
// limitations under the License.
|
||||
|
||||
ui_element!(Image {
|
||||
texture: render::Texture,
|
||||
width: f64,
|
||||
height: f64,
|
||||
texture: render::Texture,
|
||||
width: f64,
|
||||
height: f64,
|
||||
|
||||
t_x: f64,
|
||||
t_y: f64,
|
||||
t_width: f64,
|
||||
t_height: f64,
|
||||
t_x: f64,
|
||||
t_y: f64,
|
||||
t_width: f64,
|
||||
t_height: f64,
|
||||
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
a: u8
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
a: u8,
|
||||
});
|
||||
|
||||
impl Image {
|
||||
base_impl!();
|
||||
base_impl!();
|
||||
|
||||
pub fn new(texture: render::Texture,
|
||||
x: f64,
|
||||
|
@ -108,18 +108,18 @@ impl Image {
|
|||
self.dirty = true;
|
||||
}
|
||||
|
||||
lazy_field!(width, f64, get_width, set_width);
|
||||
lazy_field!(height, f64, get_height, set_height);
|
||||
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!(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);
|
||||
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 {
|
||||
|
|
|
@ -148,7 +148,7 @@ impl Logo {
|
|||
pub fn tick(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||
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;
|
||||
if self.text_index != text_index {
|
||||
|
|
508
src/ui/mod.rs
508
src/ui/mod.rs
|
@ -20,6 +20,7 @@ use std::rc::Rc;
|
|||
use rand;
|
||||
use render;
|
||||
use format;
|
||||
use glutin::VirtualKeyCode;
|
||||
|
||||
const SCALED_WIDTH: f64 = 854.0;
|
||||
const SCALED_HEIGHT: f64 = 480.0;
|
||||
|
@ -29,135 +30,185 @@ pub enum Element {
|
|||
Batch(Batch),
|
||||
Text(Text),
|
||||
Formatted(Formatted),
|
||||
TextBox(TextBox),
|
||||
Button(Button),
|
||||
None,
|
||||
}
|
||||
|
||||
pub type ClickFunc = Rc<Fn(&mut ::Game, &mut Container)>;
|
||||
pub type HoverFunc = Rc<Fn(bool, &mut ::Game, &mut Container)>;
|
||||
pub type ClickFunc = Fn(&mut ::Game, &mut Container);
|
||||
pub type HoverFunc = Fn(bool, &mut ::Game, &mut Container);
|
||||
|
||||
macro_rules! element_impl {
|
||||
($($name:ident),+) => (
|
||||
($($name:ident),+) => (
|
||||
impl Element {
|
||||
fn get_click_funcs(&self) -> Vec<ClickFunc> {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.click_funcs.clone(),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn can_focus(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.can_focus,
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_hover_funcs(&self) -> Vec<HoverFunc> {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.hover_funcs.clone(),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn is_focused(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.focused,
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn should_call_hover(&mut self, new: bool) -> bool{
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref mut val) => {
|
||||
let ret = val.hovered != new;
|
||||
val.hovered = new;
|
||||
ret
|
||||
},
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn set_focused(&mut self, f: bool) {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref mut val) => val.focused = f,
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn should_draw(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.should_draw,
|
||||
)+
|
||||
_ => 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 get_parent(&self) -> Option<ElementRefInner> {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.parent,
|
||||
)+
|
||||
_ => 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_attachment(&self) -> (VAttach, HAttach) {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => (val.v_attach, val.h_attach),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn get_click_funcs(&self) -> Vec<Rc<ClickFunc>> {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.click_funcs.clone(),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_offset(&self) -> (f64, f64) {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => (val.x, val.y),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn get_hover_funcs(&self) -> Vec<Rc<HoverFunc>> {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.hover_funcs.clone(),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_size(&self) -> (f64, f64) {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.get_size(),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn should_call_hover(&mut self, new: bool) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref mut val) => {
|
||||
let ret = val.hovered != new;
|
||||
val.dirty = val.dirty || ret;
|
||||
val.hovered = new;
|
||||
ret
|
||||
},
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_dirty(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.dirty,
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn should_draw(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.should_draw,
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_dirty(&mut self, dirty: bool) {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref mut val) => val.dirty = dirty,
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn get_parent(&self) -> Option<ElementRefInner> {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.parent,
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, renderer: &mut render::Renderer) {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref mut val) => val.update(renderer),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn get_attachment(&self) -> (VAttach, HAttach) {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => (val.v_attach, val.h_attach),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8> {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref mut val) => val.draw(renderer, r, width, height, delta),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn get_offset(&self) -> (f64, f64) {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => (val.x, val.y),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_size(&self) -> (f64, f64) {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.get_size(),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_dirty(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref val) => val.dirty,
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_dirty(&mut self, dirty: bool) {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref mut val) => val.dirty = dirty,
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, renderer: &mut render::Renderer) {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref mut val) => val.update(renderer),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8> {
|
||||
match *self {
|
||||
$(
|
||||
Element::$name(ref mut val) => val.draw(renderer, r, width, height, delta),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
element_impl!(
|
||||
Image,
|
||||
Batch,
|
||||
Text,
|
||||
Formatted
|
||||
Image,
|
||||
Batch,
|
||||
Text,
|
||||
Formatted,
|
||||
TextBox,
|
||||
Button
|
||||
);
|
||||
|
||||
pub enum Mode {
|
||||
|
@ -337,8 +388,13 @@ impl Container {
|
|||
self.version = renderer.ui.version;
|
||||
}
|
||||
|
||||
// Borrow rules seem to prevent us from doing this in the first pass
|
||||
// so we split it.
|
||||
// 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
|
||||
// so we split it.
|
||||
let regions = self.collect_elements(sw, sh);
|
||||
for re in &self.elements_list {
|
||||
let mut e = self.elements.get_mut(re).unwrap();
|
||||
|
@ -361,8 +417,8 @@ impl Container {
|
|||
}
|
||||
let r = self.get_draw_region(e, sw, sh);
|
||||
if r.intersects(&SCREEN) {
|
||||
// Mark this as dirty if any of its
|
||||
// parents are dirty too.
|
||||
// Mark this as dirty if any of its
|
||||
// parents are dirty too.
|
||||
let mut dirty = e.is_dirty();
|
||||
let mut parent = e.get_parent();
|
||||
while !dirty && parent.is_some() {
|
||||
|
@ -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 {
|
||||
let super_region = match e.get_parent() {
|
||||
Some(ref p) => self.get_draw_region(self.elements.get(p).unwrap(), sw, sh),
|
||||
|
@ -473,93 +603,105 @@ pub trait UIElement {
|
|||
fn wrap(self) -> Element;
|
||||
fn unwrap_ref(&Element) -> &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 {
|
||||
($name:ident, $t:ty, $get:ident, $set:ident) => (
|
||||
pub fn $get(&self) -> $t {
|
||||
self.$name
|
||||
}
|
||||
($name:ident, $t:ty, $get:ident, $set:ident) => (
|
||||
pub fn $get(&self) -> $t {
|
||||
self.$name
|
||||
}
|
||||
|
||||
pub fn $set(&mut self, val: $t) {
|
||||
if self.$name != val {
|
||||
self.$name = val;
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
)
|
||||
pub fn $set(&mut self, val: $t) {
|
||||
if self.$name != val {
|
||||
self.$name = val;
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! ui_element {
|
||||
(
|
||||
$name:ident {
|
||||
$(
|
||||
$field:ident : $field_ty:ty
|
||||
),+
|
||||
}
|
||||
) => (
|
||||
pub struct $name {
|
||||
dirty: bool,
|
||||
data: Vec<u8>,
|
||||
parent: Option<ElementRefInner>,
|
||||
should_draw: bool,
|
||||
layer: isize,
|
||||
x: f64,
|
||||
y: f64,
|
||||
v_attach: VAttach,
|
||||
h_attach: HAttach,
|
||||
click_funcs: Vec<ClickFunc>,
|
||||
hover_funcs: Vec<HoverFunc>,
|
||||
hovered: bool,
|
||||
$(
|
||||
$field: $field_ty
|
||||
),+
|
||||
}
|
||||
)
|
||||
(
|
||||
$name:ident {
|
||||
$(
|
||||
$field:ident : $field_ty:ty,
|
||||
)*
|
||||
}
|
||||
) => (
|
||||
pub struct $name {
|
||||
dirty: bool,
|
||||
data: Vec<u8>,
|
||||
parent: Option<ElementRefInner>,
|
||||
should_draw: bool,
|
||||
layer: isize,
|
||||
x: f64,
|
||||
y: f64,
|
||||
v_attach: VAttach,
|
||||
h_attach: HAttach,
|
||||
click_funcs: Vec<Rc<ClickFunc>>,
|
||||
hover_funcs: Vec<Rc<HoverFunc>>,
|
||||
hovered: bool,
|
||||
can_focus: bool,
|
||||
focused: bool,
|
||||
$(
|
||||
$field: $field_ty,
|
||||
)*
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! base_impl {
|
||||
() => (
|
||||
pub fn set_parent<T: UIElement>(&mut self, other: &ElementRef<T>) {
|
||||
self.parent = Some(other.inner);
|
||||
self.dirty = true;
|
||||
}
|
||||
() => (
|
||||
pub fn set_parent<T: UIElement>(&mut self, other: &ElementRef<T>) {
|
||||
self.parent = Some(other.inner);
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
pub fn add_click_func(&mut self, f: ClickFunc) {
|
||||
self.click_funcs.push(f);
|
||||
}
|
||||
pub fn add_click_func<F: Fn(&mut ::Game, &mut Container) + 'static>(&mut self, f: F) {
|
||||
self.click_funcs.push(Rc::new(f));
|
||||
}
|
||||
|
||||
pub fn add_hover_func(&mut self, f: HoverFunc) {
|
||||
self.hover_funcs.push(f);
|
||||
}
|
||||
pub fn add_hover_func<F: Fn(bool, &mut ::Game, &mut Container) + 'static>(&mut self, f: F) {
|
||||
self.hover_funcs.push(Rc::new(f));
|
||||
}
|
||||
|
||||
lazy_field!(layer, isize, get_layer, set_layer);
|
||||
lazy_field!(x, f64, get_x, set_x);
|
||||
lazy_field!(y, f64, get_y, set_y);
|
||||
lazy_field!(v_attach, VAttach, get_v_attach, set_v_attach);
|
||||
lazy_field!(h_attach, HAttach, get_h_attach, set_h_attach);
|
||||
)
|
||||
lazy_field!(layer, isize, get_layer, set_layer);
|
||||
lazy_field!(x, f64, get_x, set_x);
|
||||
lazy_field!(y, f64, get_y, set_y);
|
||||
lazy_field!(v_attach, VAttach, get_v_attach, set_v_attach);
|
||||
lazy_field!(h_attach, HAttach, get_h_attach, set_h_attach);
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! ui_create {
|
||||
($name:ident {
|
||||
$($field:ident: $e:expr,)+
|
||||
}) => (
|
||||
$name {
|
||||
dirty: true,
|
||||
data: Vec::new(),
|
||||
($name:ident {
|
||||
$($field:ident: $e:expr,)*
|
||||
}) => (
|
||||
$name {
|
||||
dirty: true,
|
||||
data: Vec::new(),
|
||||
|
||||
parent: None,
|
||||
should_draw: true,
|
||||
layer: 0,
|
||||
v_attach: VAttach::Top,
|
||||
h_attach: HAttach::Left,
|
||||
click_funcs: Vec::new(),
|
||||
hover_funcs: Vec::new(),
|
||||
hovered: false,
|
||||
$($field: $e),+
|
||||
}
|
||||
)
|
||||
parent: None,
|
||||
should_draw: true,
|
||||
layer: 0,
|
||||
v_attach: VAttach::Top,
|
||||
h_attach: HAttach::Left,
|
||||
click_funcs: Vec::new(),
|
||||
hover_funcs: Vec::new(),
|
||||
hovered: false,
|
||||
can_focus: false,
|
||||
focused: false,
|
||||
$($field: $e,)*
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Include instead of mod so we can access private parts.
|
||||
|
@ -570,3 +712,5 @@ include!("image.rs");
|
|||
include!("batch.rs");
|
||||
include!("text.rs");
|
||||
include!("formatted.rs");
|
||||
include!("textbox.rs");
|
||||
include!("button.rs");
|
||||
|
|
|
@ -13,20 +13,20 @@
|
|||
// 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
|
||||
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!();
|
||||
base_impl!();
|
||||
|
||||
pub fn new(renderer: &render::Renderer,
|
||||
val: &str,
|
||||
|
@ -117,14 +117,14 @@ impl Text {
|
|||
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);
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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