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, DropDownList};
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, PosKind};
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;
97 Visual(Option<Texture<gfx_device_gl::Resources>>),
101 fn make_button<'a, F>(c: &Colors) -> Button<'a, F>
104 Button::new().w_h(BUTTON_WIDTH, BUTTON_HEIGHT).color(c.c1)
105 .label_color(c.font).frame_color(c.c2)
108 macro_rules! make_disable_button {
111 .color($c.c1).w_h(BUTTON_WIDTH, BUTTON_HEIGHT).frame_color($c.c2)
115 fn generate_faces_map(w: &mut PistonWindow,s: &Space) ->
116 Texture<gfx_device_gl::Resources>
118 println!("Generating graph... ");
119 let wsize = w.size();
120 println!("-Gsize={},{}!", wsize.width, wsize.height - 50);
121 let process = Command::new("dot")
123 .arg(format!("-Gsize={},{}!", wsize.width, wsize.height - 50))
125 .stdin(Stdio::piped())
126 .stdout(Stdio::piped())
128 .unwrap_or_else(|e| panic!("system call failed: {}", e));
129 process.stdin.unwrap().write_all(s.dot_graph_code()
131 .unwrap_or_else(|e| panic!("piping failed: {}", e));
132 let mut png = Vec::new();
133 process.stdout.unwrap().read_to_end(&mut png)
134 .unwrap_or_else(|e| panic!("final read failed: {}"));
135 let rgba_img = load_from_memory_with_format(&png,
137 .unwrap_or_else(|e| panic!("PNG image loading failed: {}", e))
139 //assert!(output.status.success());
140 let factory = &mut w.factory;
141 let settings = piston_window::TextureSettings::new();
143 Texture::from_image(factory, &rgba_img, &settings)
147 fn final_size(WSize { header_h: hh, side_w: _, w: ww, h: wh_ }: WSize,
148 (iw, ih): (f64, f64)) -> [f64; 4]
154 let w = iw * (wh / ih);
155 [(ww / 2.0) - (w / 2.0), hh, w, wh]
157 let h = ih * (ww / iw);
158 [0.0, (wh / 2.0) - (h / 2.0) + hh, ww, h]
163 let opengl = OpenGL::V3_2;
164 let mut window: PistonWindow = WindowSettings::new("LP74", [800, 500])
165 .opengl(opengl).exit_on_esc(true).build().unwrap();
168 let assets = find_folder::Search::KidsThenParents(3, 5)
169 .for_folder("assets").expect("Cannot find assets folder");
170 let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
171 let theme = Theme::default();
172 let glyph_cache = Glyphs::new(&font_path, window.factory.clone());
173 Ui::new(glyph_cache.unwrap(), theme)
177 window.set_max_fps(60);
179 let mut colors = Colors {
180 c1: color::rgb_bytes(57, 63, 63),
181 c2: color::rgb_bytes(30, 34, 34),
184 hide: color::rgba_bytes(57, 63, 63, 0.4),
187 let mut state = State::Design(DesignState::Std);
188 let mut data = Data::new();
190 while let Some(event) = window.next() {
194 w: window.size().width as f64,
195 h: window.size().height as f64
198 handle_keys(&ui, &mut data); //must be before handle_event()
199 ui.handle_event(&event);
200 event.update(|_| ui.set_widgets(|ref mut uicell|
207 State::Visual(ref mut faces_map) => match *faces_map {
209 *faces_map = Some(generate_faces_map(&mut window, &data.space));
215 window.draw_2d(&event, |c, g| {
217 &State::Design(_) => {
218 if data.space.change != Change::None
219 || data.history.change
220 || ui.will_redraw() {
221 data.history.change = false;
222 piston_window::clear([0.0, 0.0, 0.0, 0.0], g);
223 draw_model(&wsize, &data, c, g);
226 data.save_if_changed();
228 &State::Visual(ref faces_map) => {
229 if ui.will_redraw() {
230 if let &Some(ref m) = faces_map {
231 piston_window::clear([1.0, 1.0, 1.0, 1.0], g);
232 let image = Image::new()
233 .rect(final_size(wsize,
234 (m.get_width() as f64,
235 (m.get_height()) as f64)));
236 image.draw(m, &DrawState::default(),
237 c.transform.trans(0.0, 0.0), g);
242 &State::Err(_) => {},
244 ui.draw_if_changed(c, g);
249 fn draw_model<G: graphics::Graphics>(wsize: &WSize, d: &Data, c: graphics::Context, g: &mut G) {
251 //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);
252 view::view_space(&d.space, wsize, c, g);
255 fn handle_keys(ui: &Ui, d: &mut Data) {
256 let mut keys = ui.global_input.keys_just_pressed().collect::<Vec<_>>();
261 Key::R => d.space.rotate(),
262 Key::S => d.space.switch_pos_type(),
263 Key::N => d.load_next_if_any(),
264 Key::P => d.load_prev_if_any(),
265 _ => match d.space.current {
266 Pos::E((_, a)) => match k {
267 Key::PageUp => d.space.inc_size(),
268 Key::PageDown => d.space.dec_size(),
271 Key::Right => d.space.inc_pos(),
272 Key::Left => d.space.dec_pos(),
276 Key::Up => d.space.dec_pos(),
277 Key::Down => d.space.inc_pos(),
281 Key::Up => d.space.dec_pos(),
282 Key::Down => d.space.inc_pos(),
287 Pos::F((_, o)) => match k {
288 Key::A => d.space.set_current_face_if_none(),
290 Ori::Top => match k {
291 Key::Up => d.space.dec_pos(),
292 Key::Down => d.space.inc_pos(),
295 Ori::Back => match k {
296 Key::Down => d.space.dec_pos(),
297 Key::Up => d.space.inc_pos(),
300 Ori::Side => match k {
301 Key::Left => d.space.dec_pos(),
302 Key::Right => d.space.inc_pos(),
312 fn set_ui(ui: &mut UiCell, s: &mut State,
313 d: &mut Data, c: &mut Colors, wsize: &WSize)
316 &mut State::Design(DesignState::Std) => {
317 header_ui(ui, s, d, c, wsize);
318 side_ui(ui, s, d, c, wsize);
321 //&mut State::Design(DesignState::Add) => {
322 // header_ui(ui, s, d, c, wsize);
323 // side_ui(ui, s, d, c, wsize);
324 // add_ui(ui, s, d, c)
326 &mut State::Visual(_) => {
327 header_ui(ui, s, d, c, wsize);
328 visual_ui(ui, s, d, c);
330 &mut State::Err(_) => error_ui(ui, s, d, c),
334 fn error_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
338 State::Err(ref mut s) => s,
339 _ => panic!("non Err state"),
344 Canvas::new().middle_of(C_MASTER)
345 .color(c.c1).frame_color(c.c2)
346 .w_h(400.0, 120.0).pad(20.0)
349 .color(c.font).mid_top_of(C_ERR)
352 .label("Cancel").bottom_right_of(C_ERR)
355 s.msg = String::from("Cannot cancel");
357 .set(BTN_CANCEL_ERR, ui);
360 .label("OK").bottom_left_of(C_ERR)
363 *gs = State::Design(DesignState::Std);
365 .set(BTN_OK_ERR, ui);
368 fn get_win_dim(ui: &UiCell) -> (f64, f64) {
369 (ui.window_dim()[0], ui.window_dim()[1])
372 fn header_ui(ui: &mut UiCell, gs: &mut State,
373 d: &mut Data, c: &mut Colors, wsize: &WSize)
376 .color(c.c1).frame_color(c.c2)
377 .y((wsize.h/2.0)-(wsize.header_h/2.0)).h(wsize.header_h)
378 .pad_left(20.0).pad_right(20.0)
382 fn side_ui(ui: &mut UiCell, gs: &mut State,
383 d: &mut Data, c: &mut Colors, wsize: &WSize)
385 Canvas::new().color(c.c1)
386 .color(c.c1).frame_color(c.c2)
387 .x_y(-((wsize.w/2.0)-(wsize.side_w/2.0)), -(wsize.header_h/2.0))
388 .w_h(wsize.side_w, wsize.h - wsize.header_h)
393 fn visual_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
395 make_disable_button!(c)
396 .mid_right_of(C_HEADER).label("Visual")
397 .set(DBTN_VISUAL, ui);
399 .mid_right_of(C_HEADER)
400 .label("Design").left_from(DBTN_VISUAL, 0.0)
403 *gs = State::Design(DesignState::Std);
405 .set(BTN_DESIGN, ui);
407 fn std_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
409 let prev_id = if d.history.has_prev() {
411 .mid_left_of(C_HEADER).w_h(50.0, 30.0)
412 .color(c.c1).frame_color(c.c2)
414 .label("<").react(|| {
421 make_disable_button!(c)
423 .mid_left_of(C_HEADER).w_h(50.0, 30.0)
427 let next_id = if d.history.has_next() {
429 .mid_left_of(C_HEADER).right_from(prev_id, 30.0)
431 .color(c.c1).frame_color(c.c2)
433 .label(">").react(|| {
440 make_disable_button!(c)
442 .mid_left_of(C_HEADER).right_from(prev_id, 30.0)
448 let mut select = vec![String::from("Edge"),
449 String::from("Face")];
450 let mut select_idx = None;
451 DropDownList::new(&mut select, &mut select_idx)
452 .w_h(BUTTON_WIDTH, BUTTON_HEIGHT)
453 .mid_left_of(C_HEADER).right_from(next_id, 30.0)
454 .max_visible_items(2)
459 .react(|selected_idx: &mut Option<usize>, new_idx, string: &str| {
460 *selected_idx = Some(new_idx);
461 d.space.set_pos_kind(match string {
462 "Edge" => PosKind::Edge,
466 .set(POS_KIND_SELECT, ui);
469 .mid_right_of(C_HEADER).label("Visual")
472 *gs = State::Visual(None);
473 }).set(BTN_VISUAL, ui);
474 make_disable_button!(c)
475 .mid_right_of(C_HEADER)
476 .label("Design").left_from(BTN_VISUAL, 0.0)
477 .set(DBTN_DESIGN, ui);
479 // .mid_top_of(C_SIDE).down_from(BTN1, 20.0).label("Err")
482 // *gs = State::Err(ErrState {
483 // msg: String::from("Error!")
486 match d.space.current {
487 Pos::F(((x, y, z), o)) => {
488 if let Some(n) = d.space.faces[x][y][z] {
489 if let Some((r, g, b)) = n[Space::ori_idx(o)] {
490 make_disable_button!(c)
495 .down(20.0).label("Remove")
498 d.space.remove_face(((x, y, z), o));
501 let color = match i {
502 0 => color::rgb(r, 0.0, 0.0),
503 1 => color::rgb(0.0, g, 0.0),
504 _ => color::rgb(0.0, 0.0, b),
507 let value = match i {
513 Slider::new(value, 0.0, 1.0)
514 .and(|slider| if i == 0 { slider.down(20.0) } else { slider.right(10.0) })
517 //.frame(app.frame_width)
518 .label(&format!("{:.*}", 2, value))
522 0 => d.space.set_current_face_color_if_any((v, g, b)),
523 1 => d.space.set_current_face_color_if_any((r, v, b)),
524 _ => d.space.set_current_face_color_if_any((r, g, v)),
526 .set(COLOR_SLIDER + i, ui);
530 .mid_top_of(C_SIDE).label("Add")
533 d.space.add_face(((x, y, z), o));
535 make_disable_button!(c)
536 .down(20.0).label("Remove")
539 Slider::new(0.0, 0.0, 1.0)
540 .and(|slider| if i == 0 {
550 .set(DCOLOR_SLIDER + i, ui);
554 panic!("no node here");
558 let value = d.space.get_edge_size(e) as f64;
559 Slider::new(value, 1.0, 1024.0)
563 //.frame(app.frame_width)
564 .label(&format!("{:.*}", 0, value))
567 .react(|v| d.space.edge_size(e, v as usize))
568 .set(SIZE_SLIDER, ui);