Base console implementation

This commit is contained in:
Thinkofdeath 2015-09-29 22:33:24 +01:00
parent 302af6393d
commit 12a88b07b9
5 changed files with 180 additions and 6 deletions

1
Cargo.lock generated
View File

@ -7,6 +7,7 @@ dependencies = [
"glfw 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -16,6 +16,7 @@ image = "0.3.12"
time = "0.1.32"
rand = "0.3.11"
rustc-serialize = "0.3"
log = "0.3.2"
[dependencies.steven_gl]
path = "./gl"

View File

@ -15,6 +15,12 @@
use std::marker::PhantomData;
use std::collections::HashMap;
use std::any::Any;
use std::sync::{Arc, Mutex};
use log;
use ui;
use render;
use format::{Component, TextComponent, Color};
pub struct CVar<T: Sized + Any + 'static> {
pub name: &'static str,
@ -34,14 +40,32 @@ pub trait Var {
pub struct Console {
vars: HashMap<&'static str, Box<Var>>,
var_values: HashMap<&'static str, Box<Any>>,
history: Vec<Component>,
collection: ui::Collection,
active: bool,
position: f64,
}
impl Console {
pub fn new() -> Console {
Console {
let mut con = Console {
vars: HashMap::new(),
var_values: HashMap::new(),
history: Vec::with_capacity(200),
collection: ui::Collection::new(),
active: false,
position: -220.0,
};
for _ in 0 .. 200 {
con.history.push(Component::Text(
TextComponent::new("")
));
}
con
}
pub fn register<T: Sized + Any>(&mut self, var: CVar<T>) where CVar<T> : Var {
@ -60,4 +84,133 @@ impl Console {
pub fn set<T: Sized + Any>(&mut self, var: CVar<T>, val: T) where CVar<T> : Var {
self.var_values.insert(var.name, Box::new(val));
}
}
pub fn is_active(&self) -> bool {
self.active
}
pub fn toggle(&mut self) {
self.active = !self.active;
}
pub fn tick(&mut self, ui_container: &mut ui::Container, 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.
self.collection.remove_all(ui_container);
if !self.active && self.position <= -220.0 {
return;
}
if self.active {
if self.position < 0.0 {
self.position += delta * 4.0;
} else {
self.position = 0.0;
}
} else {
if self.position > -220.0 {
self.position -= delta * 4.0;
} else {
self.position = -220.0;
}
}
let w = match ui_container.mode {
ui::Mode::Scaled => width,
ui::Mode::Unscaled(scale) => 854.0 / scale,
};
let mut background = ui::Image::new(
render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"),
0.0, self.position, w, 220.0,
0.0, 0.0, 1.0, 1.0,
0, 0, 0
);
background.set_a(180);
let background = self.collection.add(ui_container.add(background));
let mut lines = Vec::new();
let mut offset = 0.0;
for line in self.history.iter().rev() {
if offset >= 210.0 {
break;
}
let mut fmt = ui::Formatted::with_width_limit(renderer, line.clone(), 5.0, 5.0 + offset, w - 1.0);
fmt.set_parent(&background);
fmt.set_v_attach(ui::VAttach::Bottom);
offset += fmt.get_height();
lines.push(ui_container.add(fmt));
}
for fmt in lines {
self.collection.add(fmt);
}
}
fn log(&mut self, record: &log::LogRecord) {
let mut file = record.location().file();
if let Some(pos) = file.rfind("src/") {
file = &file[pos + 4..];
}
println!("[{}:{}][{}] {}", file, record.location().line(), record.level(), record.args());
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())))
]);
self.history.push(Component::Text(
msg
));
}
}
pub struct ConsoleProxy {
console: Arc<Mutex<Console>>,
}
impl ConsoleProxy {
pub fn new(con: Arc<Mutex<Console>>) -> ConsoleProxy {
ConsoleProxy {
console: con,
}
}
}
impl log::Log for ConsoleProxy {
fn enabled(&self, metadata: &log::LogMetadata) -> bool {
metadata.level() <= log::LogLevel::Trace
}
fn log(&self, record: &log::LogRecord) {
if self.enabled(record.metadata()) {
self.console.lock().unwrap().log(record);
}
}
}
unsafe impl Send for ConsoleProxy {}
unsafe impl Sync for ConsoleProxy {}

View File

@ -35,8 +35,10 @@ extern crate hyper;
extern crate flate2;
extern crate rand;
extern crate rustc_serialize;
#[macro_use]
extern crate log;
use std::sync::{Arc, RwLock};
use std::sync::{Arc, RwLock, Mutex};
use std::marker::PhantomData;
use glfw::{Action, Context, Key};
@ -53,12 +55,19 @@ pub struct Game {
renderer: render::Renderer,
screen_sys: screen::ScreenSystem,
resource_manager: Arc<RwLock<resources::Manager>>,
console: console::Console,
console: Arc<Mutex<console::Console>>,
}
fn main() {
let mut con = console::Console::new();
con.register(CL_BRAND);
let con = Arc::new(Mutex::new(console::Console::new()));
con.lock().unwrap().register(CL_BRAND);
let proxy = console::ConsoleProxy::new(con.clone());
log::set_logger(|max_log_level| {
max_log_level.set(log::LogLevelFilter::Trace);
Box::new(proxy)
}).unwrap();
info!("Starting steven");
let resource_manager = Arc::new(RwLock::new(resources::Manager::new()));
{ resource_manager.write().unwrap().tick(); }
@ -77,6 +86,7 @@ fn main() {
gl::init(&mut window);
window.set_key_polling(true);
window.set_char_polling(true);
window.set_scroll_polling(true);
window.set_mouse_button_polling(true);
window.set_cursor_pos_polling(true);
@ -109,6 +119,7 @@ fn main() {
game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
let (width, height) = window.get_framebuffer_size();
game.console.lock().unwrap().tick(&mut ui_container, &mut game.renderer, delta, width as f64);
ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
game.renderer.tick(delta, width as u32, height as u32);
@ -122,9 +133,16 @@ fn main() {
fn handle_window_event(window: &mut glfw::Window, game: &mut Game, ui_container: &mut ui::Container, event: glfw::WindowEvent) {
match event {
glfw::WindowEvent::Key(Key::GraveAccent, _, Action::Press, _) => {
game.console.lock().unwrap().toggle();
}
glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
window.set_should_close(true)
},
glfw::WindowEvent::Key(key, _, Action::Press, _) => {
println!("Key: {:?}", key);
},
glfw::WindowEvent::Scroll(x, y) => {
game.screen_sys.on_scroll(x, y);
},

View File

@ -248,6 +248,7 @@ impl Collection {
for e in &self.elements {
container.remove_raw(e);
}
self.elements.clear();
}
}