2019-01-12 22:07:30 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
|
|
use crate::{
|
2019-01-21 07:48:32 +00:00
|
|
|
label, layout,
|
2019-03-11 14:39:54 +00:00
|
|
|
layout::{show_popup, Region},
|
2019-01-17 23:33:20 +00:00
|
|
|
math::{clamp, remap_clamp, vec2},
|
2019-02-24 16:18:30 +00:00
|
|
|
mesher::{Mesher, Vertex},
|
2019-03-11 14:39:54 +00:00
|
|
|
style::Style,
|
2019-03-11 14:59:49 +00:00
|
|
|
types::{Color, GuiInput, PaintCmd},
|
2019-01-12 22:07:30 +00:00
|
|
|
widgets::*,
|
2019-03-10 20:00:28 +00:00
|
|
|
FontSizes, Fonts, Mesh, RawInput, Texture,
|
2019-01-12 22:07:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Default)]
|
|
|
|
struct Stats {
|
|
|
|
num_vertices: usize,
|
|
|
|
num_triangles: usize,
|
|
|
|
}
|
|
|
|
|
2019-03-11 14:39:54 +00:00
|
|
|
fn show_style(style: &mut Style, gui: &mut Region) {
|
|
|
|
if gui.add(Button::new("Reset style")).clicked {
|
2019-01-12 22:07:30 +00:00
|
|
|
*style = Default::default();
|
|
|
|
}
|
2019-03-11 14:39:54 +00:00
|
|
|
gui.add(Slider::f32(&mut style.item_spacing.x, 0.0, 10.0).text("item_spacing.x"));
|
|
|
|
gui.add(Slider::f32(&mut style.item_spacing.y, 0.0, 10.0).text("item_spacing.y"));
|
|
|
|
gui.add(Slider::f32(&mut style.window_padding.x, 0.0, 10.0).text("window_padding.x"));
|
|
|
|
gui.add(Slider::f32(&mut style.window_padding.y, 0.0, 10.0).text("window_padding.y"));
|
|
|
|
gui.add(Slider::f32(&mut style.indent, 0.0, 100.0).text("indent"));
|
|
|
|
gui.add(Slider::f32(&mut style.button_padding.x, 0.0, 20.0).text("button_padding.x"));
|
|
|
|
gui.add(Slider::f32(&mut style.button_padding.y, 0.0, 20.0).text("button_padding.y"));
|
|
|
|
gui.add(Slider::f32(&mut style.clickable_diameter, 0.0, 60.0).text("clickable_diameter"));
|
|
|
|
gui.add(Slider::f32(&mut style.start_icon_width, 0.0, 60.0).text("start_icon_width"));
|
2019-02-10 15:10:08 +00:00
|
|
|
gui.add(Slider::f32(&mut style.line_width, 0.0, 10.0).text("line_width"));
|
2019-01-12 22:07:30 +00:00
|
|
|
}
|
|
|
|
|
2019-01-17 17:03:39 +00:00
|
|
|
fn show_font_sizes(font_sizes: &mut FontSizes, gui: &mut Region) {
|
|
|
|
for (text_style, mut size) in font_sizes {
|
2019-02-10 15:10:08 +00:00
|
|
|
gui.add(Slider::f32(&mut size, 4.0, 40.0).text(format!("{:?}", text_style)));
|
2019-01-17 17:03:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-17 23:33:20 +00:00
|
|
|
fn show_font_texture(texture: &Texture, gui: &mut Region) {
|
2019-01-21 07:48:32 +00:00
|
|
|
gui.add(label!(
|
2019-01-17 23:33:20 +00:00
|
|
|
"Font texture size: {} x {} (hover to zoom)",
|
2019-01-21 07:48:32 +00:00
|
|
|
texture.width,
|
|
|
|
texture.height
|
|
|
|
));
|
2019-01-19 16:10:28 +00:00
|
|
|
let mut size = vec2(texture.width as f32, texture.height as f32);
|
|
|
|
if size.x > gui.width() {
|
|
|
|
size *= gui.width() / size.x;
|
|
|
|
}
|
2019-01-17 23:33:20 +00:00
|
|
|
let interact = gui.reserve_space(size, None);
|
|
|
|
let rect = interact.rect;
|
|
|
|
let top_left = Vertex {
|
|
|
|
pos: rect.min(),
|
|
|
|
uv: (0, 0),
|
|
|
|
color: Color::WHITE,
|
|
|
|
};
|
|
|
|
let bottom_right = Vertex {
|
|
|
|
pos: rect.max(),
|
|
|
|
uv: (texture.width as u16 - 1, texture.height as u16 - 1),
|
|
|
|
color: Color::WHITE,
|
|
|
|
};
|
2019-03-10 20:00:28 +00:00
|
|
|
let mut mesh = Mesh::default();
|
|
|
|
mesh.add_rect(top_left, bottom_right);
|
2019-03-11 14:59:49 +00:00
|
|
|
gui.add_paint_cmd(PaintCmd::Mesh(mesh));
|
2019-01-17 23:33:20 +00:00
|
|
|
|
2019-02-10 14:30:48 +00:00
|
|
|
if let Some(mouse_pos) = gui.input().mouse_pos {
|
|
|
|
if interact.hovered {
|
|
|
|
show_popup(gui.data(), mouse_pos, |gui| {
|
|
|
|
let zoom_rect = gui.reserve_space(vec2(128.0, 128.0), None).rect;
|
|
|
|
let u = remap_clamp(
|
|
|
|
mouse_pos.x,
|
|
|
|
rect.min().x,
|
|
|
|
rect.max().x,
|
|
|
|
0.0,
|
|
|
|
texture.width as f32 - 1.0,
|
|
|
|
)
|
|
|
|
.round();
|
|
|
|
let v = remap_clamp(
|
|
|
|
mouse_pos.y,
|
|
|
|
rect.min().y,
|
|
|
|
rect.max().y,
|
|
|
|
0.0,
|
|
|
|
texture.height as f32 - 1.0,
|
|
|
|
)
|
|
|
|
.round();
|
|
|
|
|
|
|
|
let texel_radius = 32.0;
|
|
|
|
let u = clamp(u, texel_radius, texture.width as f32 - 1.0 - texel_radius);
|
|
|
|
let v = clamp(v, texel_radius, texture.height as f32 - 1.0 - texel_radius);
|
|
|
|
|
|
|
|
let top_left = Vertex {
|
|
|
|
pos: zoom_rect.min(),
|
|
|
|
uv: ((u - texel_radius) as u16, (v - texel_radius) as u16),
|
|
|
|
color: Color::WHITE,
|
|
|
|
};
|
|
|
|
let bottom_right = Vertex {
|
|
|
|
pos: zoom_rect.max(),
|
|
|
|
uv: ((u + texel_radius) as u16, (v + texel_radius) as u16),
|
|
|
|
color: Color::WHITE,
|
|
|
|
};
|
2019-03-10 20:00:28 +00:00
|
|
|
let mut mesh = Mesh::default();
|
|
|
|
mesh.add_rect(top_left, bottom_right);
|
2019-03-11 14:59:49 +00:00
|
|
|
gui.add_paint_cmd(PaintCmd::Mesh(mesh));
|
2019-02-10 14:30:48 +00:00
|
|
|
});
|
|
|
|
}
|
2019-01-17 23:33:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-12 22:07:30 +00:00
|
|
|
/// Encapsulates input, layout and painting for ease of use.
|
|
|
|
pub struct Emigui {
|
|
|
|
pub last_input: RawInput,
|
|
|
|
pub data: Arc<layout::Data>,
|
|
|
|
stats: Stats,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Emigui {
|
2019-01-19 16:10:28 +00:00
|
|
|
pub fn new(pixels_per_point: f32) -> Emigui {
|
2019-01-12 22:07:30 +00:00
|
|
|
Emigui {
|
|
|
|
last_input: Default::default(),
|
2019-01-19 16:10:28 +00:00
|
|
|
data: Arc::new(layout::Data::new(pixels_per_point)),
|
2019-01-12 22:07:30 +00:00
|
|
|
stats: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-16 23:09:12 +00:00
|
|
|
pub fn texture(&self) -> &Texture {
|
2019-01-12 23:55:56 +00:00
|
|
|
self.data.fonts.texture()
|
|
|
|
}
|
|
|
|
|
2019-01-12 22:07:30 +00:00
|
|
|
pub fn new_frame(&mut self, new_input: RawInput) {
|
|
|
|
let gui_input = GuiInput::from_last_and_new(&self.last_input, &new_input);
|
|
|
|
self.last_input = new_input;
|
|
|
|
|
2019-01-12 23:55:56 +00:00
|
|
|
// TODO: avoid this clone
|
2019-01-12 22:07:30 +00:00
|
|
|
let mut new_data = (*self.data).clone();
|
|
|
|
new_data.new_frame(gui_input);
|
|
|
|
self.data = Arc::new(new_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn whole_screen_region(&mut self) -> layout::Region {
|
|
|
|
let size = self.data.input.screen_size;
|
|
|
|
layout::Region {
|
|
|
|
data: self.data.clone(),
|
2019-03-11 14:39:54 +00:00
|
|
|
style: self.data.style(),
|
2019-01-12 22:07:30 +00:00
|
|
|
id: Default::default(),
|
|
|
|
dir: layout::Direction::Vertical,
|
2019-01-14 13:54:06 +00:00
|
|
|
align: layout::Align::Center,
|
2019-01-12 22:07:30 +00:00
|
|
|
cursor: Default::default(),
|
|
|
|
bounding_size: Default::default(),
|
|
|
|
available_space: size,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-10 20:00:28 +00:00
|
|
|
pub fn paint(&mut self) -> Mesh {
|
2019-03-11 14:59:49 +00:00
|
|
|
let paint_commands: Vec<PaintCmd> = self.data.graphics.lock().unwrap().drain().collect();
|
2019-02-24 16:18:30 +00:00
|
|
|
let mut mesher = Mesher::new(self.last_input.pixels_per_point);
|
|
|
|
mesher.paint(&self.data.fonts, &paint_commands);
|
2019-03-10 20:00:28 +00:00
|
|
|
let mesh = mesher.mesh;
|
|
|
|
self.stats.num_vertices = mesh.vertices.len();
|
|
|
|
self.stats.num_triangles = mesh.indices.len() / 3;
|
|
|
|
mesh
|
2019-01-12 22:07:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn example(&mut self, region: &mut Region) {
|
|
|
|
region.foldable("Style", |gui| {
|
2019-03-11 14:39:54 +00:00
|
|
|
let mut style = self.data.style();
|
|
|
|
show_style(&mut style, gui);
|
|
|
|
self.data.set_style(style);
|
2019-01-12 22:07:30 +00:00
|
|
|
});
|
|
|
|
|
2019-01-17 17:03:39 +00:00
|
|
|
region.foldable("Fonts", |gui| {
|
|
|
|
let old_font_sizes = self.data.fonts.sizes();
|
|
|
|
let mut new_font_sizes = old_font_sizes.clone();
|
|
|
|
show_font_sizes(&mut new_font_sizes, gui);
|
2019-01-19 16:09:00 +00:00
|
|
|
show_font_texture(self.texture(), gui);
|
2019-01-17 17:03:39 +00:00
|
|
|
if *old_font_sizes != new_font_sizes {
|
|
|
|
let mut new_data = (*self.data).clone();
|
2019-01-19 16:10:28 +00:00
|
|
|
let fonts = Fonts::from_sizes(new_font_sizes, self.data.input.pixels_per_point);
|
2019-01-17 17:03:39 +00:00
|
|
|
new_data.fonts = Arc::new(fonts);
|
|
|
|
self.data = Arc::new(new_data);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-01-12 22:07:30 +00:00
|
|
|
region.foldable("Stats", |gui| {
|
2019-01-21 07:48:32 +00:00
|
|
|
gui.add(label!(
|
|
|
|
"Screen size: {} x {} points, pixels_per_point: {}",
|
|
|
|
gui.input().screen_size.x,
|
|
|
|
gui.input().screen_size.y,
|
|
|
|
gui.input().pixels_per_point,
|
|
|
|
));
|
2019-02-10 14:30:48 +00:00
|
|
|
if let Some(mouse_pos) = gui.input().mouse_pos {
|
|
|
|
gui.add(label!("mouse_pos: {} x {}", mouse_pos.x, mouse_pos.y,));
|
|
|
|
} else {
|
|
|
|
gui.add(label!("mouse_pos: None"));
|
|
|
|
}
|
2019-01-21 07:48:32 +00:00
|
|
|
gui.add(label!(
|
|
|
|
"gui cursor: {} x {}",
|
|
|
|
gui.cursor().x,
|
|
|
|
gui.cursor().y,
|
|
|
|
));
|
|
|
|
gui.add(label!("num_vertices: {}", self.stats.num_vertices));
|
|
|
|
gui.add(label!("num_triangles: {}", self.stats.num_triangles));
|
2019-01-12 22:07:30 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|