Base of server list

This commit is contained in:
Thinkofdeath 2015-09-23 20:16:25 +01:00
parent 876e88ec95
commit 93edfa3828
9 changed files with 705 additions and 71 deletions

View File

@ -15,26 +15,27 @@
use serde_json;
use std::fmt;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Component {
Text(TextComponent)
}
impl Component {
pub fn from_value(v: &serde_json::Value) -> Self {
let modifier = Modifier::from_value(v);
if let Some(val) = v.as_string() {
Component::Text(TextComponent{text: val.to_owned(), modifier: modifier})
} else if v.find("text").is_some(){
Component::Text(TextComponent::from_value(v, modifier))
} else {
Component::Text(TextComponent{text: "".to_owned(), modifier: modifier})
}
pub fn from_value(v: &serde_json::Value) -> Self {
let mut modifier = Modifier::from_value(v);
if let Some(val) = v.as_string() {
Component::Text(TextComponent{text: val.to_owned(), modifier: modifier})
} else if v.find("text").is_some(){
Component::Text(TextComponent::from_value(v, modifier))
} else {
modifier.color = Some(Color::RGB(255, 0, 0));
Component::Text(TextComponent{text: "UNHANDLED".to_owned(), modifier: modifier})
}
}
pub fn to_value(&self) -> serde_json::Value {
unimplemented!()
}
pub fn to_value(&self) -> serde_json::Value {
unimplemented!()
}
}
impl fmt::Display for Component {
@ -51,7 +52,7 @@ impl Default for Component {
}
}
#[derive(Debug, Default)]
#[derive(Debug, Default, Clone)]
pub struct Modifier {
pub extra: Option<Vec<Component>>,
pub bold: Option<bool>,
@ -67,50 +68,59 @@ pub struct Modifier {
}
impl Modifier {
pub fn from_value(v: &serde_json::Value) -> Self {
let mut m = Modifier {
bold: v.find("bold").map_or(Option::None, |v| v.as_boolean()),
italic: v.find("italic").map_or(Option::None, |v| v.as_boolean()),
underlined: v.find("underlined").map_or(Option::None, |v| v.as_boolean()),
strikethrough: v.find("strikethrough").map_or(Option::None, |v| v.as_boolean()),
obfuscated: v.find("obfuscated").map_or(Option::None, |v| v.as_boolean()),
color: v.find("color").map_or(Option::None, |v| v.as_string()).map(|v| Color::from_string(&v.to_owned())),
extra: Option::None,
};
if let Some(extra) = v.find("extra") {
if let Some(data) = extra.as_array() {
let mut ex = Vec::new();
for e in data {
ex.push(Component::from_value(e));
}
m.extra = Some(ex);
pub fn from_value(v: &serde_json::Value) -> Self {
let mut m = Modifier {
bold: v.find("bold").map_or(Option::None, |v| v.as_boolean()),
italic: v.find("italic").map_or(Option::None, |v| v.as_boolean()),
underlined: v.find("underlined").map_or(Option::None, |v| v.as_boolean()),
strikethrough: v.find("strikethrough").map_or(Option::None, |v| v.as_boolean()),
obfuscated: v.find("obfuscated").map_or(Option::None, |v| v.as_boolean()),
color: v.find("color").map_or(Option::None, |v| v.as_string()).map(|v| Color::from_string(&v.to_owned())),
extra: Option::None,
};
if let Some(extra) = v.find("extra") {
if let Some(data) = extra.as_array() {
let mut ex = Vec::new();
for e in data {
ex.push(Component::from_value(e));
}
m.extra = Some(ex);
}
m
}
m
}
pub fn to_value(&self) -> serde_json::Value {
unimplemented!()
}
pub fn to_value(&self) -> serde_json::Value {
unimplemented!()
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct TextComponent {
pub text: String,
pub modifier: Modifier,
pub modifier: Modifier,
}
impl TextComponent {
pub fn from_value(v: &serde_json::Value, modifier: Modifier) -> Self {
TextComponent {
text: v.find("text").unwrap().as_string().unwrap_or("").to_owned(),
modifier: modifier,
pub fn new(val: &str) -> TextComponent {
TextComponent {
text: val.to_owned(),
modifier: Modifier {
.. Default::default()
}
}
}
pub fn to_value(&self) -> serde_json::Value {
unimplemented!()
pub fn from_value(v: &serde_json::Value, modifier: Modifier) -> Self {
TextComponent {
text: v.find("text").unwrap().as_string().unwrap_or("").to_owned(),
modifier: modifier,
}
}
pub fn to_value(&self) -> serde_json::Value {
unimplemented!()
}
}
impl fmt::Display for TextComponent {
@ -125,7 +135,7 @@ impl fmt::Display for TextComponent {
}
}
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub enum Color {
Black,
DarkBlue,
@ -194,7 +204,7 @@ impl Color {
}
}
fn to_string(&self) -> String {
pub fn to_string(&self) -> String {
match *self {
Color::Black => "black".to_owned(),
Color::DarkBlue => "dark_blue".to_owned(),
@ -216,8 +226,7 @@ impl Color {
}
}
#[allow(dead_code)]
fn to_rgb(&self) -> (u8, u8, u8) {
pub fn to_rgb(&self) -> (u8, u8, u8) {
match *self {
Color::Black =>(0, 0, 0),
Color::DarkBlue =>(0, 0, 170),

View File

@ -21,6 +21,7 @@ pub mod types;
pub mod resources;
pub mod render;
pub mod ui;
pub mod screen;
extern crate glfw;
extern crate image;
@ -53,6 +54,7 @@ fn main() {
gl::init(&mut window);
window.set_key_polling(true);
window.set_scroll_polling(true);
window.make_current();
glfw.set_swap_interval(1);
@ -62,7 +64,8 @@ fn main() {
let mut last_frame = time::now();
let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;
let mut logo = ui::logo::Logo::new(resource_manager.clone(), &mut renderer, &mut ui_container);
let mut screen_sys = screen::ScreenSystem::new();
screen_sys.add_screen(Box::new(screen::ServerList::new(None)));
while !window.should_close() {
{ resource_manager.write().unwrap().tick(); }
@ -71,7 +74,7 @@ fn main() {
last_frame = now;
let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
logo.tick(&mut renderer, &mut ui_container);
screen_sys.tick(delta, &mut renderer, &mut ui_container);
let (width, height) = window.get_framebuffer_size();
ui_container.tick(&mut renderer, delta, width as f64, height as f64);
@ -80,16 +83,19 @@ fn main() {
window.swap_buffers();
glfw.poll_events();
for (_, event) in glfw::flush_messages(&events) {
handle_window_event(&mut window, event);
handle_window_event(&mut window, &mut screen_sys, event);
}
}
}
fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
fn handle_window_event(window: &mut glfw::Window, screen_sys: &mut screen::ScreenSystem, event: glfw::WindowEvent) {
match event {
glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
window.set_should_close(true)
}
},
glfw::WindowEvent::Scroll(x, y) => {
screen_sys.on_scroll(x, y);
},
_ => {}
}
}

View File

@ -30,7 +30,7 @@ const ATLAS_SIZE: usize = 1024;
pub struct Renderer {
resource_version: usize,
resources: Arc<RwLock<resources::Manager>>,
pub resources: Arc<RwLock<resources::Manager>>,
textures: Arc<RwLock<TextureManager>>,
glsl: glsl::Registry,
pub ui: ui::UIState,

View File

@ -312,19 +312,7 @@ impl UIState {
continue;
}
let texture = self.character_texture(ch);
let mut raw = ch as u32;
let page = raw >> 8;
if page == 0 {
raw = (*self.char_map.get(&ch).unwrap_or(&ch)) as u32;
}
let info = self.font_character_info[raw as usize];
let w = if page == 0 {
let sw = self.page_width / 16.0;
((info.1 - info.0) as f64 / sw) * 16.0
} else {
(info.1 - info.0) as f64
};
let w = self.size_of_char(ch);
let mut dsx = offset + 2.0;
let mut dsy = 2.0;

144
src/screen/mod.rs Normal file
View File

@ -0,0 +1,144 @@
mod server_list;
pub use self::server_list::*;
use render;
use ui;
pub trait Screen {
// 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
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
fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container);
// Events
fn on_scroll(&mut self, x: f64, y: f64) {}
}
struct ScreenInfo {
screen: Box<Screen>,
init: bool,
active: bool,
}
pub struct ScreenSystem {
screens: Vec<ScreenInfo>,
remove_queue: Vec<ScreenInfo>,
}
impl ScreenSystem {
pub fn new() -> ScreenSystem {
ScreenSystem {
screens: Vec::new(),
remove_queue: Vec::new(),
}
}
pub fn add_screen(&mut self, screen: Box<Screen>) {
self.screens.push(ScreenInfo {
screen: screen,
init: false,
active: false,
});
}
pub fn pop_screen(&mut self) {
if let Some(screen) = self.screens.pop() {
self.remove_queue.push(screen);
}
}
pub fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
for screen in &mut self.remove_queue {
if screen.active {
screen.screen.on_deactive(renderer, ui_container);
}
if screen.init {
screen.screen.deinit(renderer, ui_container);
}
}
self.remove_queue.clear();
if self.screens.is_empty() {
return;
}
// Update state for screens
let len = self.screens.len();
for screen in &mut self.screens[..len - 1] {
if screen.active {
screen.active = false;
screen.screen.on_deactive(renderer, ui_container);
}
}
let current = self.screens.last_mut().unwrap();
if !current.init {
current.init = true;
current.screen.init(renderer, ui_container);
}
if !current.active {
current.active = true;
current.screen.on_active(renderer, ui_container);
}
// Handle current
current.screen.tick(delta, renderer, ui_container);
}
pub fn on_scroll(&mut self, x: f64, y: f64) {
if self.screens.is_empty() {
return;
}
let current = self.screens.last_mut().unwrap();
current.screen.on_scroll(x, y);
}
}
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);
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)
}

224
src/screen/server_list.rs Normal file
View File

@ -0,0 +1,224 @@
use std::fs;
use ui;
use render;
use format;
use serde_json;
use std::cmp::max;
pub struct ServerList {
elements: Option<UIElements>,
disconnect_reason: Option<format::Component>,
}
struct UIElements {
logo: ui::logo::Logo,
elements: ui::Collection,
servers: Vec<Server>,
}
struct Server {
collection: ui::Collection,
back: ui::ElementRef<ui::Image>,
offset: f64,
y: f64,
}
impl Server {
fn update_position(&mut self) {
if self.offset < 0.0 {
self.y = self.offset * 200.0;
} else {
self.y = self.offset * 100.0;
}
}
}
impl ServerList {
pub fn new(disconnect_reason: Option<format::Component>) -> ServerList {
ServerList {
elements: None,
disconnect_reason: disconnect_reason,
}
}
fn reload_server_list(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
let elements = self.elements.as_mut().unwrap();
for server in &mut elements.servers {
server.collection.remove_all(ui_container);
}
elements.servers.clear();
let file = match fs::File::open("servers.json") {
Ok(val) => val,
Err(e) => return,
};
let servers_info: serde_json::Value = serde_json::from_reader(file).unwrap();
let servers = servers_info.find("servers").unwrap().as_array().unwrap();
let mut offset = 0.0;
let default_icon = render::Renderer::get_texture(renderer.get_textures_ref(), "misc/unknown_server");
let icons = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/icons");
for svr in servers {
let name = svr.find("name").unwrap().as_string().unwrap();
let address = svr.find("address").unwrap().as_string().unwrap();
let solid = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid");
let mut back = ui::Image::new(solid, 0.0, offset * 100.0, 700.0, 100.0, 0.0, 0.0, 1.0, 1.0, 0, 0, 0);
back.set_a(100);
back.set_v_attach(ui::VAttach::Middle);
back.set_h_attach(ui::HAttach::Center);
let mut server = Server {
collection: ui::Collection::new(),
back: ui_container.add(back),
offset: offset,
y: 0.0,
};
server.collection.add(server.back.clone());
server.update_position();
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));
let mut icon = ui::Image::new(default_icon.clone(), 5.0, 5.0, 90.0, 90.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255);
icon.set_parent(&server.back);
server.collection.add(ui_container.add(icon));
let mut ping = ui::Image::new(icons.clone(), 5.0, 5.0, 20.0, 16.0, 0.0, 56.0/256.0, 10.0/256.0, 8.0/256.0, 255, 255, 255);
ping.set_h_attach(ui::HAttach::Right);
ping.set_parent(&server.back);
server.collection.add(ui_container.add(ping));
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.collection.add(ui_container.add(players));
elements.servers.push(server);
offset += 1.0;
}
}
}
impl super::Screen for ServerList {
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) {}
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container);
let mut elements = ui::Collection::new();
let (mut refresh, mut txt) = super::new_button_text(renderer, "Refresh", 300.0, -50.0-15.0, 100.0, 30.0);
refresh.set_v_attach(ui::VAttach::Middle);
refresh.set_h_attach(ui::HAttach::Center);
let re = ui_container.add(refresh);
txt.set_parent(&re);
elements.add(re);
elements.add(ui_container.add(txt));
let (mut add, mut txt) = super::new_button_text(renderer, "Add", 200.0, -50.0-15.0, 100.0, 30.0);
add.set_v_attach(ui::VAttach::Middle);
add.set_h_attach(ui::HAttach::Center);
let re = ui_container.add(add);
txt.set_parent(&re);
elements.add(re);
elements.add(ui_container.add(txt));
let mut options = super::new_button(renderer, 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);
let mut cog = ui::Image::new(render::Renderer::get_texture(renderer.get_textures_ref(), "steven:gui/cog"), 0.0, 0.0, 40.0, 40.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255);
cog.set_parent(&re);
cog.set_v_attach(ui::VAttach::Middle);
cog.set_h_attach(ui::HAttach::Center);
elements.add(re);
elements.add(ui_container.add(cog));
let mut warn = ui::Text::new(renderer, "Not affiliated with Mojang/Minecraft", 5.0, 5.0, 255, 200, 200);
warn.set_v_attach(ui::VAttach::Bottom);
warn.set_h_attach(ui::HAttach::Right);
elements.add(ui_container.add(warn));
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);
let mut dis = ui::Formatted::with_width_limit(renderer, disconnect_reason.clone(), 0.0, 48.0, 600.0);
dis.set_h_attach(ui::HAttach::Center);
let mut back = ui::Image::new(
render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"),
0.0, 30.0,
dis.get_width().max(dis_msg.get_width()) + 4.0, dis.get_height() + 4.0 + 16.0,
0.0, 0.0, 1.0, 1.0,
0, 0, 0
);
back.set_a(100);
back.set_h_attach(ui::HAttach::Center);
elements.add(ui_container.add(back));
elements.add(ui_container.add(dis));
elements.add(ui_container.add(dis_msg));
}
self.elements = Some(UIElements {
logo: logo,
elements: elements,
servers: Vec::new(),
});
self.reload_server_list(renderer, ui_container);
}
fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
{
let elements = self.elements.as_mut().unwrap();
elements.logo.remove(ui_container);
elements.elements.remove_all(ui_container);
for server in &mut elements.servers {
server.collection.remove_all(ui_container);
}
elements.servers.clear();
}
self.elements = None
}
fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
let elements = self.elements.as_mut().unwrap();
elements.logo.tick(renderer, ui_container);
for s in &mut elements.servers {
let back = ui_container.get_mut(&s.back);
let dy = s.y - back.get_y();
if dy*dy > 1.0 {
let y = back.get_y();
back.set_y(y + delta * dy * 0.1);
} else {
back.set_y(s.y);
}
}
}
fn on_scroll(&mut self, x: f64, y: f64) {
let elements = self.elements.as_mut().unwrap();
if elements.servers.is_empty() {
return;
}
let mut diff = y / 1.0;
{
let last = elements.servers.last().unwrap();
if last.offset+diff <= 2.0 {
diff = 2.0 - last.offset;
}
let first = elements.servers.first().unwrap();
if first.offset + diff >= 0.0 {
diff = -first.offset;
}
}
for s in &mut elements.servers {
s.offset += diff;
s.update_position();
}
}
}

220
src/ui/formatted.rs Normal file
View File

@ -0,0 +1,220 @@
pub struct Formatted {
dirty: bool,
data: Vec<u8>,
parent: Option<ElementRefInner>,
should_draw: bool,
layer: isize,
val: format::Component,
x: f64,
y: f64,
width: f64,
height: f64,
v_attach: VAttach,
h_attach: HAttach,
scale_x: f64,
scale_y: f64,
text: Vec<Element>,
max_width: f64,
lines: usize,
}
impl Formatted {
pub fn new(renderer: &mut render::Renderer, val: format::Component, x: f64, y: f64) -> Formatted {
let mut f = Formatted {
dirty: true,
data: Vec::new(),
parent: None,
should_draw: true,
layer: 0,
val: val,
x: x,
y: y,
width: 0.0,
height: 18.0,
v_attach: VAttach::Top,
h_attach: HAttach::Left,
scale_x: 1.0,
scale_y: 1.0,
text: Vec::new(),
max_width: -1.0,
lines: 0,
};
f.set_component(renderer);
f
}
pub fn with_width_limit(renderer: &mut render::Renderer, val: format::Component, x: f64, y: f64, max_width: f64) -> Formatted {
let mut f = Formatted {
dirty: true,
data: Vec::new(),
parent: None,
should_draw: true,
layer: 0,
val: val,
x: x,
y: y,
width: 0.0,
height: 18.0,
v_attach: VAttach::Top,
h_attach: HAttach::Left,
scale_x: 1.0,
scale_y: 1.0,
text: Vec::new(),
max_width: max_width,
lines: 0,
};
f.set_component(renderer);
f
}
fn set_component(&mut self, renderer: &mut render::Renderer) {
self.text.clear();
let mut state = FormatState {
lines: 0,
width: 0.0,
offset: 0.0,
text: Vec::new(),
max_width: self.max_width,
renderer: &renderer,
};
state.build(&self.val, format::Color::White);
self.height = (state.lines + 1) as f64 * 18.0;
self.width = state.width;
self.lines = state.lines;
self.text = state.text;
self.dirty = true;
}
fn update(&mut self, renderer: &mut render::Renderer) {
self.set_component(renderer);
}
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8> {
if self.dirty {
self.dirty = false;
self.data.clear();
let sx = r.w / self.width;
let sy = r.h / self.height;
for e in &mut self.text {
let reg = Container::get_draw_region_raw(e, sx, sy, r);
e.set_dirty(true);
self.data.extend(e.draw(renderer, &reg, width, height, delta));
}
}
&self.data
}
pub fn get_size(&self) -> (f64, f64) {
((self.width + 2.0) * self.scale_x, self.height * self.scale_y)
}
pub fn set_parent<T: UIElement>(&mut self, other: &ElementRef<T>) {
self.parent = Some(other.inner);
self.dirty = true;
}
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!(width, f64, get_width, set_width);
lazy_field!(height, f64, get_height, set_height);
lazy_field!(v_attach, VAttach, get_v_attach, set_v_attach);
lazy_field!(h_attach, HAttach, get_h_attach, set_h_attach);
lazy_field!(scale_x, f64, get_scale_x, set_scale_x);
lazy_field!(scale_y, f64, get_scale_y, set_scale_y);
}
impl UIElement for Formatted {
fn wrap(self) -> Element {
Element::Formatted(self)
}
fn unwrap_ref<'a>(e: &'a Element) -> &'a Formatted {
match e {
&Element::Formatted(ref val) => val,
_ => panic!("Incorrect type"),
}
}
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Formatted {
match e {
&mut Element::Formatted(ref mut val) => val,
_ => panic!("Incorrect type"),
}
}
}
struct FormatState<'a> {
max_width: f64,
lines: usize,
offset: f64,
width: f64,
text: Vec<Element>,
renderer: &'a render::Renderer,
}
type GetColorFn = Fn() -> format::Color;
impl <'a> FormatState<'a> {
fn build(&mut self, c: &format::Component, color: format::Color) {
match c {
&format::Component::Text(ref txt) => {
let col = FormatState::get_color(&txt.modifier, color);
self.append_text(&txt.text, col);
let modi = &txt.modifier;
if let Some(ref extra) = modi.extra {
for e in extra {
self.build(e, col);
}
}
},
}
}
fn append_text(&mut self, txt: &str, color: format::Color) {
let mut width = 0.0;
let mut last = 0;
for (i, c) in txt.chars().enumerate() {
let size = self.renderer.ui.size_of_char(c) + 2.0;
if (self.max_width > 0.0 && self.offset + width + size > self.max_width) || c == '\n' {
let (rr, gg, bb) = color.to_rgb();
let text = Text::new(self.renderer, &txt[last .. i], self.offset, (self.lines*18 + 1) as f64, rr, gg, bb);
self.text.push(text.wrap());
last = i;
if c == '\n' {
last += 1;
}
self.offset = 0.0;
self.lines += 1;
width = 0.0;
}
width += size;
if self.offset + width > self.width {
self.width = self.offset + width;
}
}
if last != txt.len() {
let (rr, gg, bb) = color.to_rgb();
let text = Text::new(self.renderer, &txt[last..], self.offset, (self.lines*18 + 1) as f64, rr, gg, bb);
self.offset += text.width + 4.0; // TODO Why is this 4 not 2?
self.text.push(text.wrap());
if self.offset > self.width {
self.width = self.offset;
}
}
}
fn get_color(modi: &format::Modifier, color: format::Color) -> format::Color {
modi.color.unwrap_or(color)
}
}

View File

@ -162,7 +162,7 @@ impl Logo {
text.set_x(self.text_orig_x * scale * self.text_base_scale);
}
pub fn remove(self, ui_container: &mut ui::Container) {
pub fn remove(&self, ui_container: &mut ui::Container) {
ui_container.remove(&self.shadow);
ui_container.remove(&self.layer0);
ui_container.remove(&self.text);

View File

@ -18,6 +18,7 @@ use std::collections::HashMap;
use std::marker::PhantomData;
use rand;
use render;
use format;
const SCALED_WIDTH: f64 = 854.0;
const SCALED_HEIGHT: f64 = 480.0;
@ -26,6 +27,7 @@ pub enum Element {
Image(Image),
Batch(Batch),
Text(Text),
Formatted(Formatted),
None,
}
@ -119,7 +121,8 @@ impl Element {
element_impl!(
Image,
Batch,
Text
Text,
Formatted
);
pub enum Mode {
@ -160,12 +163,21 @@ impl Region {
/// Reference to an element currently attached to a
/// container.
#[derive(Clone, Copy)]
#[derive(Copy)]
pub struct ElementRef<T> {
inner: ElementRefInner,
ty: PhantomData<T>,
}
impl <T> Clone for ElementRef<T> {
fn clone(&self) -> Self {
ElementRef {
inner: self.inner,
ty: PhantomData,
}
}
}
#[derive(Hash, PartialEq, Eq, Clone, Copy)]
struct ElementRefInner {
index: usize,
@ -180,6 +192,29 @@ impl <T> Default for ElementRef<T> {
}
}
/// Allows for easy cleanup
pub struct Collection {
elements: Vec<ElementRefInner>,
}
impl Collection {
pub fn new() -> Collection {
Collection {
elements: Vec::new(),
}
}
pub fn add<T: UIElement>(&mut self, element: ElementRef<T>) {
self.elements.push(element.inner);
}
pub fn remove_all(&mut self, container: &mut Container) {
for e in &self.elements {
container.remove_raw(e);
}
}
}
const SCREEN: Region = Region{x: 0.0, y: 0.0, w: SCALED_WIDTH, h: SCALED_HEIGHT};
pub struct Container {
@ -228,9 +263,13 @@ impl Container {
}
pub fn remove<T: UIElement>(&mut self, r: &ElementRef<T>) {
self.elements.remove(&r.inner);
self.remove_raw(&r.inner);
}
fn remove_raw(&mut self, r: &ElementRefInner) {
self.elements.remove(&r);
self.elements_list.iter()
.position(|&e| e.index == r.inner.index)
.position(|&e| e.index == r.index)
.map(|e| self.elements_list.remove(e))
.unwrap();
}
@ -477,6 +516,7 @@ impl UIElement for Image {
}
}
// TODO Getting values out?
pub struct Batch {
dirty: bool,
@ -711,3 +751,6 @@ impl UIElement for Text {
}
}
}
// Include instead of mod so we can access private parts
include!("formatted.rs");