2 extern crate find_folder;
3 extern crate piston_window;
8 extern crate gfx_device_gl;
12 use graphics::{Line, Rectangle, Polygon, Ellipse, DrawState, Transformed};
14 Color, Button, Colorable, Labelable, Frameable, Positionable,
15 Sizeable, Graphics, Canvas, Widget, Text, DButton, Slider, DropDownList
22 use std::process::{Command, Stdio};
23 use image::{ImageFormat, load_from_memory_with_format};
29 <piston_window::G2d<'static> as Graphics>::Texture,
32 pub type Ui = conrod::Ui<Backend>;
33 pub type UiCell<'a> = conrod::UiCell<'a, Backend>;
35 const BUTTON_WIDTH: f64 = 110.0;
36 const BUTTON_HEIGHT: f64 = 35.0;
38 const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
39 const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
89 Visual(Option<Texture<gfx_device_gl::Resources>>),
94 fn make_button<'a, F>(c: &Colors) -> Button<'a, F>
97 Button::new().w_h(BUTTON_WIDTH, BUTTON_HEIGHT).color(c.c1)
98 .label_color(c.font).frame_color(c.c2)
101 macro_rules! make_disable_button {
104 .color($c.c1).w_h(BUTTON_WIDTH, BUTTON_HEIGHT).frame_color($c.c2)
108 pub fn generate_faces_map(w: &mut PistonWindow,s: &Space) ->
109 Option<Texture<gfx_device_gl::Resources>>
111 println!("Generating graph... ");
112 let wsize = w.size();
113 println!("-Gsize={},{}!", wsize.width, wsize.height - 50);
114 let process = match Command::new("dot")
116 .arg(format!("-Gsize={},{}!", wsize.width, wsize.height - 50))
118 .stdin(Stdio::piped())
119 .stdout(Stdio::piped())
122 Err(_) => return None,
124 process.stdin.unwrap().write_all(s.dot_graph_code()
126 .unwrap_or_else(|e| panic!("piping failed: {}", e));
127 let mut png = Vec::new();
128 process.stdout.unwrap().read_to_end(&mut png)
129 .unwrap_or_else(|_| panic!("final read failed"));
130 let rgba_img = load_from_memory_with_format(&png,
132 .unwrap_or_else(|e| panic!("PNG image loading failed: {}", e))
134 let factory = &mut w.factory;
135 let settings = piston_window::TextureSettings::new();
137 Some(Texture::from_image(factory, &rgba_img, &settings)
141 pub fn final_size(WSize { header_h: hh, side_w: _, w: ww, h: wh_ }: WSize,
142 (iw, ih): (f64, f64)) -> [f64; 4]
148 let w = iw * (wh / ih);
149 [(ww / 2.0) - (w / 2.0), hh, w, wh]
151 let h = ih * (ww / iw);
152 [0.0, (wh / 2.0) - (h / 2.0) + hh, ww, h]
157 ($color:expr, $c:expr, $gl:expr, ($x:expr, $z:expr),
158 ($ax:expr, $az:expr), ($bx:expr, $bz:expr)) => {
159 Line::new($color, 1.0)
160 .draw([$x + $ax, $z + $az,
162 &DrawState::default(),
168 macro_rules! black_line {
169 ($c:expr, $gl:expr, ($x:expr, $z:expr),
170 ($ax:expr, $az:expr), ($bx:expr, $bz:expr)) => {
171 line!(BLACK, $c, $gl, ($x, $z), ($ax, $az), ($bx, $bz))
175 macro_rules! red_line {
176 ($c:expr, $gl:expr, ($x:expr, $z:expr),
177 ($ax:expr, $az:expr), ($bx:expr, $bz:expr)) => {
178 line!(RED, $c, $gl, ($x, $z), ($ax, $az), ($bx, $bz))
182 pub fn show_space<G: graphics::Graphics>(s: &Space,
184 c: graphics::Context, gl: &mut G) {
185 let (xctr, zctr) = ((wsize.w - wsize.side_w) / 2.0, (wsize.h - wsize.header_h) / 2.0);
186 let (xcur, ycur, zcur) = (s.row_size_before_current(Axis::X) as f64,
187 (s.row_size_before_current(Axis::Y) / 2) as f64,
188 s.row_size_before_current(Axis::Z) as f64);
189 let (wshift, hshift) = (xctr - (xcur + ycur) + wsize.side_w,
190 zctr - (zcur + ycur) + wsize.header_h);
191 let mut wy = (s.row_size(Axis::Y) / 3) as f64;
192 for iy in (0..s.faces[0].len()).rev() {
193 let ysize = (s.size[Space::axis_idx(Axis::Y)][iy] / 3) as f64;
195 for ix in 0..s.faces.len() {
196 let xsize = s.size[Space::axis_idx(Axis::X)][ix] as f64;
198 for iz in 0..s.faces[0][0].len() {
199 let zsize = s.size[Space::axis_idx(Axis::Z)][iz] as f64;
200 match s.faces[ix][iy][iz] {
204 if let Some((r, g, b)) = ss[Space::ori_idx(Ori::Back)] {
205 Rectangle::new([r, g, b, 0.6])
206 .draw([0.0, 0.0, xsize, zsize],
207 &DrawState::default(),
208 c.transform.trans(x, z),
210 Rectangle::new_border(BLACK, 1.0)
211 .draw([0.0, 0.0, xsize, zsize],
212 &DrawState::default(),
213 c.transform.trans(x, z),
216 if let Some((r, g, b)) = ss[Space::ori_idx(Ori::Top)] {
217 Polygon::new([r, g, b, 0.6])
220 [x + xsize - ysize, z - ysize],
221 [x - ysize, z - ysize]],
222 &DrawState::default(),
225 black_line!(c, gl, (x, z), (0.0, 0.0), (xsize, 0.0));
226 black_line!(c, gl, (x, z), (xsize, 0.0), (xsize - ysize, -ysize));
227 black_line!(c, gl, (x, z), (xsize - ysize, -ysize), (-ysize, -ysize));
228 black_line!(c, gl, (x, z), (-ysize, -ysize), (0.0, 0.0));
230 if let Some((r, g, b)) = ss[Space::ori_idx(Ori::Side)] {
231 Polygon::new([r, g, b, 0.6])
232 .draw(&[[x, z + zsize],
234 [x - ysize, z - ysize],
235 [x - ysize, z + zsize - ysize]],
236 &DrawState::default(),
239 black_line!(c, gl, (x, z), (0.0, zsize), (0.0, 0.0));
240 black_line!(c, gl, (x, z), (0.0, 0.0), (-ysize, -ysize));
241 black_line!(c, gl, (x, z), (-ysize, -ysize), (-ysize, zsize - ysize));
242 black_line!(c, gl, (x, z), (-ysize, zsize - ysize), (0.0, zsize));
244 if (ix, iy, iz) == s.current_node_coord() {
246 .draw([-3.0, -3.0, 7.0, 7.0],
247 &DrawState::default(),
248 c.transform.trans(x, z),
251 Pos::E((_, a)) => match a {
252 Axis::X => Line::new(RED, 1.0)
253 .draw([x, z, x + xsize, z],
254 &DrawState::default(),
257 Axis::Y => Line::new(RED, 1.0)
258 .draw([x, z, x - ysize, z - ysize],
259 &DrawState::default(),
262 Axis::Z => Line::new(RED, 1.0)
263 .draw([x, z, x, z + zsize],
264 &DrawState::default(),
268 Pos::F((_, o)) => match o {
269 Ori::Back => Rectangle::new_border(RED, 1.0)
270 .draw([0.0, 0.0, xsize, zsize],
271 &DrawState::default(),
272 c.transform.trans(x, z),
275 red_line!(c, gl, (x, z), (0.0, 0.0), (xsize, 0.0));
276 red_line!(c, gl, (x, z), (xsize, 0.0), (xsize - ysize, -ysize));
277 red_line!(c, gl, (x, z), (xsize - ysize, -ysize), (-ysize, -ysize));
278 red_line!(c, gl, (x, z), (-ysize, -ysize), (0.0, 0.0));
281 red_line!(c, gl, (x, z), (0.0, zsize), (0.0, 0.0));
282 red_line!(c, gl, (x, z), (0.0, 0.0), (-ysize, -ysize));
283 red_line!(c, gl, (x, z), (-ysize, -ysize), (-ysize, zsize - ysize));
284 red_line!(c, gl, (x, z), (-ysize, zsize - ysize), (0.0, zsize));
300 pub fn set_ui(ui: &mut UiCell, s: &mut State,
301 d: &mut Data, c: &mut Colors, wsize: &WSize)
304 &mut State::Design => {
305 header_ui(ui, c, wsize);
306 side_ui(ui, c, wsize);
309 &mut State::Visual(_) => {
310 header_ui(ui, c, wsize);
313 &mut State::Extensions => /*extensions_ui(ui, s, c)*/ {},
314 &mut State::Err(_) => error_ui(ui, s, c),
318 fn error_ui(ui: &mut UiCell, gs: &mut State, c: &mut Colors)
324 Canvas::new().middle_of(C_MASTER)
325 .color(c.c1).frame_color(c.c2)
326 .w_h(400.0, 120.0).pad(20.0)
328 Text::new(match *gs {
329 State::Err(ref msg) => msg,
332 .color(c.font).mid_top_of(C_ERR)
336 .label("OK").mid_bottom_of(C_ERR)
341 .set(BTN_OK_ERR, ui);
344 fn header_ui(ui: &mut UiCell, c: &mut Colors, wsize: &WSize)
347 .color(c.c1).frame_color(c.c2)
348 .y((wsize.h/2.0)-(wsize.header_h/2.0)).h(wsize.header_h)
349 .pad_left(20.0).pad_right(20.0)
353 fn side_ui(ui: &mut UiCell, c: &mut Colors, wsize: &WSize)
355 Canvas::new().color(c.c1)
356 .color(c.c1).frame_color(c.c2)
357 .x_y(-((wsize.w/2.0)-(wsize.side_w/2.0)), -(wsize.header_h/2.0))
358 .w_h(wsize.side_w, wsize.h - wsize.header_h)
363 fn visual_ui(ui: &mut UiCell, gs: &mut State, c: &mut Colors)
366 .mid_right_of(C_HEADER)
367 .label("Extensions").mid_right_of(C_HEADER)
369 println!("Extensions");
370 *gs = State::Extensions;
372 .set(BTN_EXTENSIONS, ui);
373 make_disable_button!(c)
374 .mid_right_of(C_HEADER)
375 .left_from(BTN_EXTENSIONS, 0.0)
377 .set(DBTN_VISUAL, ui);
379 .mid_right_of(C_HEADER)
380 .label("Design").left_from(DBTN_VISUAL, 0.0)
385 .set(BTN_DESIGN, ui);
387 fn std_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
389 let prev_id = if d.history.has_prev() {
391 .mid_left_of(C_HEADER).w_h(50.0, 30.0)
392 .color(c.c1).frame_color(c.c2)
394 .label("<").react(|| {
401 make_disable_button!(c)
403 .mid_left_of(C_HEADER).w_h(50.0, 30.0)
407 let next_id = if d.history.has_next() {
409 .mid_left_of(C_HEADER).right_from(prev_id, 30.0)
411 .color(c.c1).frame_color(c.c2)
413 .label(">").react(|| {
420 make_disable_button!(c)
422 .mid_left_of(C_HEADER).right_from(prev_id, 30.0)
428 let mut select = vec![String::from("Edge (E)"),
429 String::from("Face (F)")];
430 let mut select_idx = None;
431 DropDownList::new(&mut select, &mut select_idx)
432 .w_h(BUTTON_WIDTH, BUTTON_HEIGHT)
433 .mid_left_of(C_HEADER).right_from(next_id, 30.0)
434 .max_visible_items(2)
439 .react(|selected_idx: &mut Option<usize>, new_idx, string: &str| {
440 *selected_idx = Some(new_idx);
441 d.space.set_pos_kind(match string {
442 "Edge (E)" => PosKind::Edge,
446 .set(POS_KIND_SELECT, ui);
449 .mid_left_of(C_HEADER).right_from(POS_KIND_SELECT, 30.0)
454 }).set(BTN_ROTATE, ui);
456 .mid_right_of(C_HEADER)
459 println!("Extensions");
460 *gs = State::Extensions;
461 }).set(BTN_EXTENSIONS, ui);
463 .mid_right_of(C_HEADER)
464 .left_from(BTN_EXTENSIONS, 0.0)
468 *gs = State::Visual(None);
469 }).set(BTN_VISUAL, ui);
470 make_disable_button!(c)
471 .mid_right_of(C_HEADER)
472 .label("Design").left_from(BTN_VISUAL, 0.0)
473 .set(DBTN_DESIGN, ui);
475 // .mid_top_of(C_SIDE).down_from(BTN1, 20.0).label("Err")
478 // *gs = State::Err(ErrState {
479 // msg: String::from("Error!")
482 match d.space.current {
483 Pos::F(((x, y, z), o)) => {
484 if let Some(n) = d.space.faces[x][y][z] {
485 if let Some((r, g, b)) = n[Space::ori_idx(o)] {
486 make_disable_button!(c)
491 .down(20.0).label("Delete (D)")
494 d.space.remove_face(((x, y, z), o));
497 let color = match i {
498 0 => color::rgb(r, 0.0, 0.0),
499 1 => color::rgb(0.0, g, 0.0),
500 _ => color::rgb(0.0, 0.0, b),
503 let value = match i {
509 Slider::new(value, 0.0, 1.0)
510 .and(|slider| if i == 0 { slider.down(40.0) } else { slider.right(10.0) })
513 .label(&format!("{:.*}", 2, value))
514 .label_color(color.plain_contrast())
516 .react(|v| d.space.set_current_face_color_if_any(match i {
521 .set(COLOR_SLIDER + i, ui);
524 let color = color::rgb(r, g, b);
525 let mut colors = vec![
529 "Orange".to_string(),
534 "Yellow".to_string(),
537 let mut selected_idx = None;
538 DropDownList::new(&mut colors, &mut selected_idx)
539 .w_h(BUTTON_WIDTH, BUTTON_HEIGHT)
540 .mid_top_of(C_SIDE).down(20.0)
544 .label_color(color.plain_contrast())
545 .react(|selected_idx: &mut Option<usize>, new_idx, string: &str| {
546 *selected_idx = Some(new_idx);
547 d.space.set_current_face_color_if_any(match string {
548 "Black" => (0.0, 0.0, 0.0),
549 "White" => (1.0, 1.0, 1.0),
550 "Red" => (1.0, 0.0, 0.0),
551 "Green" => (0.0, 1.0, 0.0),
552 "Blue" => (0.0, 0.0, 1.0),
553 "Yellow" => (color::YELLOW.red(),
554 color::YELLOW.green(),
555 color::YELLOW.blue()),
556 "Purple" => (color::PURPLE.red(),
557 color::PURPLE.green(),
558 color::PURPLE.blue()),
559 "Orange" => (color::ORANGE.red(),
560 color::ORANGE.green(),
561 color::ORANGE.blue()),
562 "Gray" => (color::GRAY.red(),
565 "Brown" => (color::BROWN.red(),
566 color::BROWN.green(),
567 color::BROWN.blue()),
568 _ => (1.0, 1.0, 1.0),
571 .set(COLOR_SELECT, ui);
575 .mid_top_of(C_SIDE).label("Add (A)")
578 d.space.add_face(((x, y, z), o));
580 make_disable_button!(c)
581 .down(20.0).label("Delete (D)")
584 Slider::new(0.0, 0.0, 1.0)
585 .and(|slider| if i == 0 {
595 .set(DCOLOR_SLIDER + i, ui);
597 make_disable_button!(c)
598 .mid_top_of(C_SIDE).down(20.0)
600 .set(DBTN_SELECT_COLOR, ui);
610 .set(LENGTH_TXT, ui);
611 let length = d.space.get_edge_size(e) as f64;
612 Slider::new(length, 1.0, 1024.0)
613 .top_right_of(C_SIDE)
616 .label(&format!("{:.*}", 0, length))
619 .react(|v| d.space.edge_size(e, v as usize))
620 .set(SIZE_SLIDER, ui);