#![allow(dead_code, unused_variables)]
use glium_text::{self, TextSystem, FontTexture, TextDisplay};
use glium::backend::glutin_backend::GlutinFacade;
use glium::{self, VertexBuffer, IndexBuffer, Program, DrawParameters, Surface};
use glium::vertex::{EmptyInstanceAttributes as EIAttribs};
use glium::glutin::{ElementState, MouseButton, Event, VirtualKeyCode};
use ui::{self, Vertex, Element, MouseState, KeyboardState, UiRequest, EventRemainder};
const TWOSR3: f32 = 1.15470053838;
const DEFAULT_UI_SCALE: f32 = 0.9;
pub struct Pane<'d, R> where R: EventRemainder {
vbo: Option<VertexBuffer<Vertex>>,
ibo: Option<IndexBuffer<u16>>,
elements: Vec<Element<R>>,
program: Program,
params: DrawParameters<'d>,
display: &'d GlutinFacade,
scale: f32,
text_system: TextSystem,
font_texture: FontTexture,
mouse_state: MouseState,
keybd_state: KeyboardState,
mouse_focused: Option<usize>,
keybd_focused: Option<usize>,
surface_dims: (u32, u32),
}
impl<'d, R> Pane<'d, R> where R: EventRemainder {
pub fn new(display: &'d GlutinFacade) -> Pane<'d, R> {
let scale = DEFAULT_UI_SCALE;
let vbo = None;
let ibo = None;
let program = Program::from_source(display, vertex_shader_src, fragment_shader_src, None).unwrap();
let params = DrawParameters {
depth: glium::Depth {
test: glium::DepthTest::IfLessOrEqual,
write: true,
.. Default::default()
},
.. Default::default()
};
let text_system = TextSystem::new(display);
let font_size = 24;
let font_texture = FontTexture::new(display, &include_bytes!(
"assets/fonts/NotoSans/NotoSans-Bold.ttf"
)[..], font_size).unwrap();
Pane {
vbo: vbo,
ibo: ibo,
elements: Vec::new(),
program: program,
params: params,
display: display,
scale: scale,
text_system: text_system,
font_texture: font_texture,
mouse_state: MouseState::new(),
keybd_state: KeyboardState::new(),
mouse_focused: None,
keybd_focused: None,
surface_dims: display.get_framebuffer_dimensions(),
}
}
pub fn element(mut self, element: Element<R>) -> Pane<'d, R> {
if self.vbo.is_some() || self.ibo.is_some() {
panic!("Ui::element(): [FIXME]: Cannot [yet] add element after initialization.")
}
self.elements.push(element);
self
}
pub fn init(mut self) -> Pane<'d, R> {
let mut vertices: Vec<Vertex> = Vec::new();
let mut indices: Vec<u16> = Vec::new();
for element in self.elements.iter_mut() {
element.set_text_width(&self.text_system, &self.font_texture);
indices.extend_from_slice(&element.indices(vertices.len() as u16));
vertices.extend_from_slice(&element.vertices(
self.display.get_framebuffer_dimensions(), self.scale,
));
}
self.vbo = Some(VertexBuffer::dynamic(self.display, &vertices).unwrap());
self.ibo = Some(IndexBuffer::new(self.display, glium::index::PrimitiveType::TrianglesList,
&indices).unwrap());
self
}
pub fn draw<S>(&mut self, target: &mut S)
where S: Surface
{
if self.vbo.is_none() || self.ibo.is_none() {
panic!("Ui::draw(): Buffers not initialized.")
}
let model_color = ui::C_ORANGE;
let uniforms = uniform! {
u_model_color: model_color,
};
self.surface_dims = target.get_dimensions();
self.update_mouse_focus();
target.draw((self.vbo.as_ref().unwrap(), EIAttribs { len: 1 }), self.ibo.as_ref().unwrap(),
&self.program, &uniforms, &self.params).unwrap();
for element in self.elements.iter() {
element.draw_text(&self.text_system, target, &self.font_texture);
let text_display = TextDisplay::new(&self.text_system, &self.font_texture,
element.get_text());
glium_text::draw(&text_display, &self.text_system, target,
element.text_matrix(), element.text().get_color());
}
}
pub fn handle_event(&mut self, event: Event) -> R {
match event.clone() {
Event::Resized(..) => {
self.refresh_vertices();
R::event(event)
},
Event::KeyboardInput(key_state, _, vk_code) => {
self.handle_keyboard_input(key_state, vk_code, event)
},
Event::MouseInput(state, button) => {
self.mouse_state.set_button(button, state);
self.update_mouse_focus();
self.handle_mouse_input(state, button, event)
},
Event::MouseMoved(p_x, p_y) => {
self.mouse_state.update_position((p_x, p_y));
R::event(event)
},
Event::MouseWheel(delta, _) => {
R::event(event)
},
_ => R::event(event)
}
}
fn handle_keyboard_input(&mut self, key_state: ElementState, vk_code: Option<VirtualKeyCode>,
event: Event) -> R
{
self.keybd_state.update(key_state, vk_code);
if self.keybd_state.control {
match key_state {
ElementState::Pressed => { match vk_code {
Some(vkc) => { match vkc {
VirtualKeyCode::Q => R::event(Event::Closed),
_ => R::event(event),
} },
None => R::event(event),
} },
_ => R::event(event),
}
} else {
if let Some(ele_idx) = self.keybd_focused {
let (request, remainder) = self.elements[ele_idx].handle_keyboard_input(
key_state, vk_code, &self.keybd_state, event);
remainder
} else {
R::event(event)
}
}
}
fn handle_mouse_input(&mut self, state: ElementState, button: MouseButton, event: Event) -> R {
match self.mouse_focused {
Some(ele_idx) => {
let (request, remainder) = self.elements[ele_idx]
.handle_mouse_input(state, button, event);
match request {
UiRequest::KeyboardFocus(on) => {
if on {
self.keybd_focused = Some(ele_idx);
self.elements[ele_idx].set_keybd_focus(true);
} else {
self.keybd_focused = None;
self.elements[ele_idx].set_keybd_focus(false);
}
},
UiRequest::Refresh => (),
_ => (),
}
self.refresh_vertices();
remainder
},
None => {
self.keybd_focused = match self.keybd_focused {
Some(ele_idx) => {
self.elements[ele_idx].set_keybd_focus(false);
self.refresh_vertices();
None
},
None => None,
};
R::event(event)
}
}
}
pub fn update_mouse_focus(&mut self) {
if self.mouse_state.any_pressed() { return; }
if !self.mouse_state.is_stale() {
let newly_focused = self.focused_element_idx();
if newly_focused != self.mouse_focused {
match self.mouse_focused {
Some(idx) => self.elements[idx].set_mouse_focus(false),
None => (),
}
match newly_focused {
Some(idx) => self.elements[idx].set_mouse_focus(true),
None => (),
}
self.mouse_focused = newly_focused;
self.refresh_vertices();
}
}
}
fn focused_element_idx(&mut self) -> Option<usize> {
let mut idx = 0;
for element in self.elements.iter_mut() {
if element.has_mouse_focus(self.mouse_state.surface_position(self.surface_dims)) {
return Some(idx);
}
idx += 1;
}
None
}
pub fn refresh_vertices(&mut self) {
match self.vbo {
Some(ref mut vbo) => {
let mut vertices: Vec<Vertex> = Vec::with_capacity(vbo.len());
for element in self.elements.iter_mut() {
vertices.extend_from_slice(&element.vertices(
self.display.get_framebuffer_dimensions(), self.scale,
));
}
vbo.write(&vertices);
},
None => panic!("Ui::resize(): Cannot refresh until Ui has been \
initialized with .init()"),
}
}
pub fn mouse_state(&self) -> &MouseState {
&self.mouse_state
}
pub fn set_input_stale(&mut self) {
self.mouse_state.set_stale();
}
pub fn input_is_stale(&self) -> bool {
self.mouse_state.is_stale()
}
}
#[allow(non_upper_case_globals)]
static vertex_shader_src: &'static str = r#"
#version 330
in vec3 position;
in vec4 color;
in vec2 xy_normal;
out vec4 v_color;
void main() {
gl_Position = vec4(position, 1.0);
v_color = color;
};
"#;
#[allow(non_upper_case_globals)]
static fragment_shader_src: &'static str = r#"
#version 330
in vec4 v_color;
out vec4 color;
void main() {
color = v_color;
};
"#;