center and adapt faces map image
[lp74.git] / src / main.rs
blob482cdcb0ed0c164cf81cacd9e38f1c88f0529028
1 //#![feature(slice_patterns)]
2 #[macro_use] extern crate conrod;
3 extern crate find_folder;
4 extern crate piston_window;
5 extern crate graphics;
6 extern crate rand;
7 extern crate input;
8 extern crate image;
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};
14 use conrod::color;
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};
21 use view::WSize;
24 use std::io;
25 use std::process::{Command, Output, Stdio, ChildStdin, ChildStdout};
26 use image::{ImageFormat, load_from_memory_with_format};
27 use std::sync::Arc;
28 use graphics::{Transformed, Image, DrawState};
29 use std::io::Write;
30 use std::io::Read;
31 use gfx_device_gl::Resources;
34 mod data;
35 mod view;
37 type Backend = (
38     <piston_window::G2d<'static> as Graphics>::Texture,
39     Glyphs
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;
47 widget_ids! {
48     C_MASTER,
49     C_HEADER,
50     C_SIDE,
51     C_MAIN,
52     BTN1,
53     BTN2,
54     BTN3,
55     BTN_PREV,
56     DBTN_PREV,
57     BTN_NEXT,
58     DBTN_NEXT,
59     CIRCLE1,
60     CIRCLE2,
61     C_ERR,
62     TXT_ERR,
63     BTN_OK_ERR,
64     BTN_CANCEL_ERR,
65     BTN_DESIGN,
66     DBTN_DESIGN,
67     BTN_VISUAL,
68     DBTN_VISUAL,
69         COLOR_SLIDER with 3,
72 struct Colors {
73     c1: Color,
74     c2: Color,
75     font: Color,
76     main: Color,
77     hide: Color,
80 #[derive(Clone)]
81 struct ErrState {
82     msg: String,
85 #[derive(Clone)]
86 enum DesignState {
87     Std,
88     Add,
91 //#[derive(Clone)]
92 enum State {
93     Design(DesignState),
94     Visual(Option<Texture<gfx_device_gl::Resources>>),
95     Err(ErrState),
98 fn make_button<'a, F>(c: &Colors) -> Button<'a, F>
99     where F: FnOnce()
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 {
106     ($c:ident) => {
107         DButton::new()
108             .color($c.c1).w_h(BUTTON_WIDTH, BUTTON_HEIGHT).frame_color($c.c2)
109     }
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")
119         .arg("-Tpng")
120         .arg(format!("-Gsize={},{}!", wsize.width, wsize.height - 50))
121         .arg("-Gdpi=2")
122         .stdin(Stdio::piped())
123         .stdout(Stdio::piped())
124         .spawn()
125         .unwrap_or_else(|e| panic!("system call failed: {}", e));
126     process.stdin.unwrap().write_all(s.dot_graph_code()
127                                      .as_bytes())
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,
133                                                 ImageFormat::PNG)
134         .unwrap_or_else(|e| panic!("PNG image loading failed: {}", e))
135         .to_rgba();
136     //assert!(output.status.success());
137     let factory = &mut w.factory;
138     let settings = piston_window::TextureSettings::new();
139     println!("done");
140     Texture::from_image(factory, &rgba_img, &settings)
141              .unwrap()
144 fn final_size(WSize { header_h: hh, side_w: _, w: ww, h: wh_ }: WSize,
145               (iw, ih): (f64, f64)) -> [f64; 4]
147     let wh = wh_ - hh;
148     let wr = ww / wh;
149     let ir = iw / ih;
150     if wr > ir {
151         let w = iw * (wh / ih);
152         [(ww / 2.0) - (w / 2.0), hh, w, wh]
153     } else {
154         let h = ih * (ww / iw);
155         [0.0, (wh / 2.0) - (h / 2.0) + hh, ww, h]
156     }
159 fn main() {
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();
164         let mut ui = {
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)
171     };
173     window.set_ups(120);
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),
179         font: color::WHITE,
180         main: color::WHITE,
181         hide: color::rgba_bytes(57, 63, 63, 0.4),
182     };
184     let mut state = State::Design(DesignState::Std);
185     let mut data = Data::new();
187     while let Some(event) = window.next() {
188         let wsize = WSize {
189             header_h: 50.0,
190             side_w: 150.0,
191             w: window.size().width as f64,
192             h: window.size().height as f64
193         };
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|
198                                         set_ui(uicell,
199                                                &mut state,
200                                                &mut data,
201                                                &mut colors,
202                                                &wsize)));
203         match state {
204             State::Visual(ref mut faces_map) => match *faces_map {
205                 None => {
206                     *faces_map = Some(generate_faces_map(&mut window, &data.space));
207                 },
208                 _ => {},
209             },
210             _ => {},
211         }
212         window.draw_2d(&event, |c, g| {
213             match &state {
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);
221                         ui.needs_redraw();
222                     }
223                     data.save_if_changed();
224                 },
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);
235                             ui.needs_redraw();
236                         }
237                     }
238                 },
239                 &State::Err(_) => {},
240             }
241             ui.draw_if_changed(c, g);
242         });
243     }
246 fn draw_model<G: graphics::Graphics>(wsize: &WSize, d: &Data, c: graphics::Context, g: &mut G) {
247     use graphics::*;
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<_>>();
254     keys.dedup();
255     for k in keys {
256         println!("{:?}", k);
257         match k {
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(),
266                     _ => match a {
267                         Axis::X => match k {
268                             Key::Right => d.space.inc_pos(),
269                             Key::Left => d.space.dec_pos(),
270                             _ => {},
271                         },
272                         Axis::Y => match k {
273                             Key::Up => d.space.dec_pos(),
274                             Key::Down => d.space.inc_pos(),
275                             _ => {},
276                         },
277                         Axis::Z => match k {
278                             Key::Up => d.space.dec_pos(),
279                             Key::Down => d.space.inc_pos(),
280                             _ => {},
281                         },
282                     },
283                 },
284                 Pos::F((_, o)) => match k {
285                         Key::A => d.space.set_current_face_if_none(),
286                         _ => match o {
287                             Ori::Top => match k {
288                                 Key::Up => d.space.dec_pos(),
289                                 Key::Down => d.space.inc_pos(),
290                                 _ => {},
291                             },
292                             Ori::Back => match k {
293                                 Key::Down => d.space.dec_pos(),
294                                 Key::Up => d.space.inc_pos(),
295                                 _ => {},
296                             },
297                             Ori::Side => match k {
298                                 Key::Left => d.space.dec_pos(),
299                                 Key::Right => d.space.inc_pos(),
300                                 _ => {},
301                         },
302                     },
303                 },
304             },
305         };
306     }
309 fn set_ui(ui: &mut UiCell, s: &mut State,
310           d: &mut Data, c: &mut Colors, wsize: &WSize)
312     match s {
313         &mut State::Design(DesignState::Std) => {
314             header_ui(ui, s, d, c, wsize);
315             side_ui(ui, s, d, c, wsize);
316             std_ui(ui, s, d, c);
317         },
318         &mut State::Design(DesignState::Add) => {
319             header_ui(ui, s, d, c, wsize);
320             side_ui(ui, s, d, c, wsize);
321             add_ui(ui, s, d, c)
322         },
323         &mut State::Visual(_) => {
324             header_ui(ui, s, d, c, wsize);
325             visual_ui(ui, s, d, c);
326         },
327         &mut State::Err(_) => error_ui(ui, s, d, c),
328     }
331 fn error_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
333     {
334         let s = match *gs {
335             State::Err(ref mut s) => s,
336             _ => panic!("non Err state"),
337         };
338         Canvas::new()
339             .color(c.hide)
340             .set(C_MASTER, ui);
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)
344             .set(C_ERR, ui);
345         Text::new(&s.msg)
346             .color(c.font).mid_top_of(C_ERR)
347             .set(TXT_ERR, ui);
348         make_button(c)
349             .label("Cancel").bottom_right_of(C_ERR)
350             .react(|| {
351                 println!("Cancel");
352                 s.msg = String::from("Cannot cancel");
353             })
354             .set(BTN_CANCEL_ERR, ui);
355     }
356     make_button(c)
357         .label("OK").bottom_left_of(C_ERR)
358         .react(|| {
359             println!("OK");
360             *gs = State::Design(DesignState::Std);
361         })
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)
372     Canvas::new()
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)
376         .set(C_HEADER, ui);
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)
386         .pad(20.0)
387         .set(C_SIDE, ui);
390 fn add_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
392     make_button(c)
393         .mid_top_of(C_SIDE).label("Exit")
394         .react(|| {
395             println!("Add");
396             *gs = State::Design(DesignState::Std);
397         }).set(BTN1, ui);
400 fn visual_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
402     make_button(c)
403         .mid_left_of(C_HEADER).label("Design")
404         .react(|| {
405             println!("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() {
412         Button::new()
413             .mid_left_of(C_HEADER).w_h(50.0, 30.0)
414             .color(c.c1).frame_color(c.c2)
415             .label_color(c.font)
416             .label("<").react(|| {
417                 println!("prev");
418                 d.load_prev();
419             })
420             .set(BTN_PREV, ui);
421         BTN_PREV
422     } else {
423         make_disable_button!(c)
424             .label("<")
425             .mid_left_of(C_HEADER).w_h(50.0, 30.0)
426             .set(DBTN_PREV, ui);
427         DBTN_PREV
428     };
429     let next_id = if d.history.has_next() {
430         Button::new()
431             .mid_left_of(C_HEADER).right_from(prev_id, 30.0)
432             .w_h(50.0, 30.0)
433             .color(c.c1).frame_color(c.c2)
434             .label_color(c.font)
435             .label(">").react(|| {
436                 println!("next");
437                 d.load_next();
438             })
439             .set(BTN_NEXT, ui);
440         BTN_NEXT
441     } else {
442         make_disable_button!(c)
443             .label(">")
444             .mid_left_of(C_HEADER).right_from(prev_id, 30.0)
445             .w_h(50.0, 30.0)
446             .set(DBTN_NEXT, ui);
447         DBTN_NEXT
448     };
449     make_button(c)
450         .mid_right_of(C_HEADER).label("Visual")
451         .react(|| {
452             println!("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);
459     make_button(c)
460         .mid_top_of(C_SIDE).label("Add")
461         .react(|| {
462             println!("Add");
463             *gs = State::Design(DesignState::Add);
464         }).set(BTN1, ui);
465     make_button(c)
466         .mid_top_of(C_SIDE).down_from(BTN1, 20.0).label("Err")
467         .react(|| {
468             println!("Err");
469             *gs = State::Err(ErrState {
470                 msg: String::from("Error!")
471             });
472         }).set(BTN2, ui);
473     //make_button(c)
474     //    .mid_top_of(C_SIDE).down_from(BTN2, 20.0).label("þê¿ â€ŀï ¿»")
475     //    .react(|| {
476     //        println!("þê¿ â€ŀï ¿»");
477     //    }).set(BTN3, ui);
478         if let Some((r, g, b)) = d.space.get_current_face_color_if_any() {
479         for i in 0..3 {
480         
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),
485             };
486         
487             let value = match i {
488                 0 => r,
489                 1 => g,
490                 _ => b,
491             };
492         
493             Slider::new(value, 0.0, 1.0)
494                 .and(|slider| if i == 0 { slider.down(25.0) } else { slider.right(10.0) })
495                 .w_h(30.0, 80.0)
496                 .color(color)
497                 //.frame(app.frame_width)
498                 .label(&format!("{:.*}", 2, value))
499                 .label_color(c.font)
500                 .frame_color(c.c2)
501                 .react(|v| match i {
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)),
505                 })
506                 .set(COLOR_SLIDER + i, ui);
507                 }
508         }