1 //#![feature(slice_patterns)]
2 #[macro_use] extern crate conrod;
3 extern crate find_folder;
4 extern crate piston_window;
9 extern crate gfx_device_gl;
11 use conrod::{Theme, Color, Button, Colorable, Labelable, Frameable,
12 Positionable, Sizeable, Graphics, Canvas, Widget, Tabs,
13 Circle, Text, DButton, Slider};
15 use conrod::events::input_provider::InputProvider;
16 use piston_window::{Glyphs, OpenGL, PistonWindow, WindowSettings, UpdateEvent,
17 EventLoop, Window, Texture, Flip, ImageSize};
18 use input::keyboard::{Key};
20 use data::{Data, Space, Axis, Ori, Pos, Change};
25 use std::process::{Command, Output, Stdio, ChildStdin, ChildStdout};
26 use image::{ImageFormat, load_from_memory_with_format};
28 use graphics::{Transformed, Image, DrawState};
31 use gfx_device_gl::Resources;
38 <piston_window::G2d<'static> as Graphics>::Texture,
41 type Ui = conrod::Ui<Backend>;
42 type UiCell<'a> = conrod::UiCell<'a, Backend>;
44 const BUTTON_WIDTH: f64 = 110.0;
45 const BUTTON_HEIGHT: f64 = 35.0;
94 Visual(Option<Texture<gfx_device_gl::Resources>>),
98 fn make_button<'a, F>(c: &Colors) -> Button<'a, F>
101 Button::new().w_h(BUTTON_WIDTH, BUTTON_HEIGHT).color(c.c1)
102 .label_color(c.font).frame_color(c.c2)
105 macro_rules! make_disable_button {
108 .color($c.c1).w_h(BUTTON_WIDTH, BUTTON_HEIGHT).frame_color($c.c2)
112 fn generate_faces_map(w: &mut PistonWindow,s: &Space) ->
113 Texture<gfx_device_gl::Resources>
115 println!("Generating graph... ");
116 let wsize = w.size();
117 println!("-Gsize={},{}!", wsize.width, wsize.height - 50);
118 let process = Command::new("dot")
120 .arg(format!("-Gsize={},{}!", wsize.width, wsize.height - 50))
122 .stdin(Stdio::piped())
123 .stdout(Stdio::piped())
125 .unwrap_or_else(|e| panic!("system call failed: {}", e));
126 process.stdin.unwrap().write_all(s.dot_graph_code()
128 .unwrap_or_else(|e| panic!("piping failed: {}", e));
129 let mut png = Vec::new();
130 process.stdout.unwrap().read_to_end(&mut png)
131 .unwrap_or_else(|e| panic!("final read failed: {}"));
132 let rgba_img = load_from_memory_with_format(&png,
134 .unwrap_or_else(|e| panic!("PNG image loading failed: {}", e))
136 //assert!(output.status.success());
137 let factory = &mut w.factory;
138 let settings = piston_window::TextureSettings::new();
140 Texture::from_image(factory, &rgba_img, &settings)
144 fn final_size(WSize { header_h: hh, side_w: _, w: ww, h: wh_ }: WSize,
145 (iw, ih): (f64, f64)) -> [f64; 4]
151 let w = iw * (wh / ih);
152 [(ww / 2.0) - (w / 2.0), hh, w, wh]
154 let h = ih * (ww / iw);
155 [0.0, (wh / 2.0) - (h / 2.0) + hh, ww, h]
160 let opengl = OpenGL::V3_2;
161 let mut window: PistonWindow = WindowSettings::new("LP74", [800, 500])
162 .opengl(opengl).exit_on_esc(true).build().unwrap();
165 let assets = find_folder::Search::KidsThenParents(3, 5)
166 .for_folder("assets").expect("Cannot find assets folder");
167 let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
168 let theme = Theme::default();
169 let glyph_cache = Glyphs::new(&font_path, window.factory.clone());
170 Ui::new(glyph_cache.unwrap(), theme)
174 window.set_max_fps(60);
176 let mut colors = Colors {
177 c1: color::rgb_bytes(57, 63, 63),
178 c2: color::rgb_bytes(30, 34, 34),
181 hide: color::rgba_bytes(57, 63, 63, 0.4),
184 let mut state = State::Design(DesignState::Std);
185 let mut data = Data::new();
187 while let Some(event) = window.next() {
191 w: window.size().width as f64,
192 h: window.size().height as f64
195 handle_keys(&ui, &mut data); //must be before handle_event()
196 ui.handle_event(&event);
197 event.update(|_| ui.set_widgets(|ref mut uicell|
204 State::Visual(ref mut faces_map) => match *faces_map {
206 *faces_map = Some(generate_faces_map(&mut window, &data.space));
212 window.draw_2d(&event, |c, g| {
214 &State::Design(_) => {
215 if data.space.change != Change::None
216 || data.history.change
217 || ui.will_redraw() {
218 data.history.change = false;
219 piston_window::clear([0.0, 0.0, 0.0, 0.0], g);
220 draw_model(&wsize, &data, c, g);
223 data.save_if_changed();
225 &State::Visual(ref faces_map) => {
226 if ui.will_redraw() {
227 if let &Some(ref m) = faces_map {
228 piston_window::clear([1.0, 1.0, 1.0, 1.0], g);
229 let image = Image::new()
230 .rect(final_size(wsize,
231 (m.get_width() as f64,
232 (m.get_height()) as f64)));
233 image.draw(m, &DrawState::default(),
234 c.transform.trans(0.0, 0.0), g);
239 &State::Err(_) => {},
241 ui.draw_if_changed(c, g);
246 fn draw_model<G: graphics::Graphics>(wsize: &WSize, d: &Data, c: graphics::Context, g: &mut G) {
248 //rectangle([rand::random(), rand::random(), rand::random(), 1.0], [0.0, 0.0, 200.0, 200.0], c.transform.trans(100.0, 100.0), g);
249 view::view_space(&d.space, wsize, c, g);
252 fn handle_keys(ui: &Ui, d: &mut Data) {
253 let mut keys = ui.global_input.keys_just_pressed().collect::<Vec<_>>();
258 Key::R => d.space.rotate(),
259 Key::S => d.space.switch_pos_type(),
260 Key::N => d.load_next_if_any(),
261 Key::P => d.load_prev_if_any(),
262 _ => match d.space.current {
263 Pos::E((_, a)) => match k {
264 Key::PageUp => d.space.inc_size(),
265 Key::PageDown => d.space.dec_size(),
268 Key::Right => d.space.inc_pos(),
269 Key::Left => d.space.dec_pos(),
273 Key::Up => d.space.dec_pos(),
274 Key::Down => d.space.inc_pos(),
278 Key::Up => d.space.dec_pos(),
279 Key::Down => d.space.inc_pos(),
284 Pos::F((_, o)) => match k {
285 Key::A => d.space.set_current_face_if_none(),
287 Ori::Top => match k {
288 Key::Up => d.space.dec_pos(),
289 Key::Down => d.space.inc_pos(),
292 Ori::Back => match k {
293 Key::Down => d.space.dec_pos(),
294 Key::Up => d.space.inc_pos(),
297 Ori::Side => match k {
298 Key::Left => d.space.dec_pos(),
299 Key::Right => d.space.inc_pos(),
309 fn set_ui(ui: &mut UiCell, s: &mut State,
310 d: &mut Data, c: &mut Colors, wsize: &WSize)
313 &mut State::Design(DesignState::Std) => {
314 header_ui(ui, s, d, c, wsize);
315 side_ui(ui, s, d, c, wsize);
318 &mut State::Design(DesignState::Add) => {
319 header_ui(ui, s, d, c, wsize);
320 side_ui(ui, s, d, c, wsize);
323 &mut State::Visual(_) => {
324 header_ui(ui, s, d, c, wsize);
325 visual_ui(ui, s, d, c);
327 &mut State::Err(_) => error_ui(ui, s, d, c),
331 fn error_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
335 State::Err(ref mut s) => s,
336 _ => panic!("non Err state"),
341 Canvas::new().middle_of(C_MASTER)
342 .color(c.c1).frame_color(c.c2)
343 .w_h(400.0, 120.0).pad(20.0)
346 .color(c.font).mid_top_of(C_ERR)
349 .label("Cancel").bottom_right_of(C_ERR)
352 s.msg = String::from("Cannot cancel");
354 .set(BTN_CANCEL_ERR, ui);
357 .label("OK").bottom_left_of(C_ERR)
360 *gs = State::Design(DesignState::Std);
362 .set(BTN_OK_ERR, ui);
365 fn get_win_dim(ui: &UiCell) -> (f64, f64) {
366 (ui.window_dim()[0], ui.window_dim()[1])
369 fn header_ui(ui: &mut UiCell, gs: &mut State,
370 d: &mut Data, c: &mut Colors, wsize: &WSize)
373 .color(c.c1).frame_color(c.c2)
374 .y((wsize.h/2.0)-(wsize.header_h/2.0)).h(wsize.header_h)
375 .pad_left(20.0).pad_right(20.0)
379 fn side_ui(ui: &mut UiCell, gs: &mut State,
380 d: &mut Data, c: &mut Colors, wsize: &WSize)
382 Canvas::new().color(c.c1)
383 .color(c.c1).frame_color(c.c2)
384 .x_y(-((wsize.w/2.0)-(wsize.side_w/2.0)), -(wsize.header_h/2.0))
385 .w_h(wsize.side_w, wsize.h - wsize.header_h)
390 fn add_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
393 .mid_top_of(C_SIDE).label("Exit")
396 *gs = State::Design(DesignState::Std);
400 fn visual_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
403 .mid_left_of(C_HEADER).label("Design")
406 *gs = State::Design(DesignState::Std);
407 }).set(BTN_DESIGN, ui);
409 fn std_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
411 let prev_id = if d.history.has_prev() {
413 .mid_left_of(C_HEADER).w_h(50.0, 30.0)
414 .color(c.c1).frame_color(c.c2)
416 .label("<").react(|| {
423 make_disable_button!(c)
425 .mid_left_of(C_HEADER).w_h(50.0, 30.0)
429 let next_id = if d.history.has_next() {
431 .mid_left_of(C_HEADER).right_from(prev_id, 30.0)
433 .color(c.c1).frame_color(c.c2)
435 .label(">").react(|| {
442 make_disable_button!(c)
444 .mid_left_of(C_HEADER).right_from(prev_id, 30.0)
450 .mid_right_of(C_HEADER).label("Visual")
453 *gs = State::Visual(None);
454 }).set(BTN_VISUAL, ui);
455 make_disable_button!(c)
456 .mid_right_of(C_HEADER)
457 .label("Design").left_from(BTN_VISUAL, 0.0)
458 .set(DBTN_DESIGN, ui);
460 .mid_top_of(C_SIDE).label("Add")
463 *gs = State::Design(DesignState::Add);
466 .mid_top_of(C_SIDE).down_from(BTN1, 20.0).label("Err")
469 *gs = State::Err(ErrState {
470 msg: String::from("Error!")
474 // .mid_top_of(C_SIDE).down_from(BTN2, 20.0).label("þê¿ â€ŀï ¿»")
476 // println!("þê¿ â€ŀï ¿»");
478 if let Some((r, g, b)) = d.space.get_current_face_color_if_any() {
481 let color = match i {
482 0 => color::rgb(r, 0.0, 0.0),
483 1 => color::rgb(0.0, g, 0.0),
484 _ => color::rgb(0.0, 0.0, b),
487 let value = match i {
493 Slider::new(value, 0.0, 1.0)
494 .and(|slider| if i == 0 { slider.down(25.0) } else { slider.right(10.0) })
497 //.frame(app.frame_width)
498 .label(&format!("{:.*}", 2, value))
502 0 => d.space.set_current_face_color_if_any((v, g, b)),
503 1 => d.space.set_current_face_color_if_any((r, v, b)),
504 _ => d.space.set_current_face_color_if_any((r, g, v)),
506 .set(COLOR_SLIDER + i, ui);