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 let wsize = w.size();
112 let process = match Command::new("dot")
114 .arg(format!("-Gsize={},{}!", wsize.width, wsize.height - 50))
116 .stdin(Stdio::piped())
117 .stdout(Stdio::piped())
120 Err(_) => return None,
122 process.stdin.unwrap().write_all(s.dot_graph_code()
124 .unwrap_or_else(|e| panic!("piping failed: {}", e));
125 let mut png = Vec::new();
126 process.stdout.unwrap().read_to_end(&mut png)
127 .unwrap_or_else(|_| panic!("final read failed"));
128 let rgba_img = load_from_memory_with_format(&png,
130 .unwrap_or_else(|e| panic!("PNG image loading failed: {}", e))
132 let factory = &mut w.factory;
133 let settings = piston_window::TextureSettings::new();
134 Some(Texture::from_image(factory, &rgba_img, &settings)
138 pub fn final_size(WSize { header_h: hh, side_w: _, w: ww, h: wh_ }: WSize,
139 (iw, ih): (f64, f64)) -> [f64; 4]
145 let w = iw * (wh / ih);
146 [(ww / 2.0) - (w / 2.0), hh, w, wh]
148 let h = ih * (ww / iw);
149 [0.0, (wh / 2.0) - (h / 2.0) + hh, ww, h]
154 ($color:expr, $c:expr, $gl:expr, ($x:expr, $z:expr),
155 ($ax:expr, $az:expr), ($bx:expr, $bz:expr)) => {
156 Line::new($color, 1.0)
157 .draw([$x + $ax, $z + $az,
159 &DrawState::default(),
165 macro_rules! black_line {
166 ($c:expr, $gl:expr, ($x:expr, $z:expr),
167 ($ax:expr, $az:expr), ($bx:expr, $bz:expr)) => {
168 line!(BLACK, $c, $gl, ($x, $z), ($ax, $az), ($bx, $bz))
172 macro_rules! red_line {
173 ($c:expr, $gl:expr, ($x:expr, $z:expr),
174 ($ax:expr, $az:expr), ($bx:expr, $bz:expr)) => {
175 line!(RED, $c, $gl, ($x, $z), ($ax, $az), ($bx, $bz))
179 pub fn show_space<G: graphics::Graphics>(s: &Space,
181 c: graphics::Context, gl: &mut G) {
182 let (xctr, zctr) = ((wsize.w - wsize.side_w) / 2.0, (wsize.h - wsize.header_h) / 2.0);
183 let (xcur, ycur, zcur) = (s.row_size_before_current(Axis::X) as f64,
184 (s.row_size_before_current(Axis::Y) / 2) as f64,
185 s.row_size_before_current(Axis::Z) as f64);
186 let (wshift, hshift) = (xctr - (xcur + ycur) + wsize.side_w,
187 zctr - (zcur + ycur) + wsize.header_h);
188 let mut wy = (s.row_size(Axis::Y) / 3) as f64;
189 for iy in (0..s.faces[0].len()).rev() {
190 let ysize = (s.size[Space::axis_idx(Axis::Y)][iy] / 3) as f64;
192 for ix in 0..s.faces.len() {
193 let xsize = s.size[Space::axis_idx(Axis::X)][ix] as f64;
195 for iz in 0..s.faces[0][0].len() {
196 let zsize = s.size[Space::axis_idx(Axis::Z)][iz] as f64;
197 match s.faces[ix][iy][iz] {
201 if let Some((r, g, b)) = ss[Space::ori_idx(Ori::Back)] {
202 Rectangle::new([r, g, b, 0.6])
203 .draw([0.0, 0.0, xsize, zsize],
204 &DrawState::default(),
205 c.transform.trans(x, z),
207 Rectangle::new_border(BLACK, 1.0)
208 .draw([0.0, 0.0, xsize, zsize],
209 &DrawState::default(),
210 c.transform.trans(x, z),
213 if let Some((r, g, b)) = ss[Space::ori_idx(Ori::Top)] {
214 Polygon::new([r, g, b, 0.6])
217 [x + xsize - ysize, z - ysize],
218 [x - ysize, z - ysize]],
219 &DrawState::default(),
222 black_line!(c, gl, (x, z), (0.0, 0.0), (xsize, 0.0));
223 black_line!(c, gl, (x, z), (xsize, 0.0), (xsize - ysize, -ysize));
224 black_line!(c, gl, (x, z), (xsize - ysize, -ysize), (-ysize, -ysize));
225 black_line!(c, gl, (x, z), (-ysize, -ysize), (0.0, 0.0));
227 if let Some((r, g, b)) = ss[Space::ori_idx(Ori::Side)] {
228 Polygon::new([r, g, b, 0.6])
229 .draw(&[[x, z + zsize],
231 [x - ysize, z - ysize],
232 [x - ysize, z + zsize - ysize]],
233 &DrawState::default(),
236 black_line!(c, gl, (x, z), (0.0, zsize), (0.0, 0.0));
237 black_line!(c, gl, (x, z), (0.0, 0.0), (-ysize, -ysize));
238 black_line!(c, gl, (x, z), (-ysize, -ysize), (-ysize, zsize - ysize));
239 black_line!(c, gl, (x, z), (-ysize, zsize - ysize), (0.0, zsize));
241 if (ix, iy, iz) == s.current_node_coord() {
243 .draw([-3.0, -3.0, 7.0, 7.0],
244 &DrawState::default(),
245 c.transform.trans(x, z),
248 Pos::E((_, a)) => match a {
249 Axis::X => Line::new(RED, 1.0)
250 .draw([x, z, x + xsize, z],
251 &DrawState::default(),
254 Axis::Y => Line::new(RED, 1.0)
255 .draw([x, z, x - ysize, z - ysize],
256 &DrawState::default(),
259 Axis::Z => Line::new(RED, 1.0)
260 .draw([x, z, x, z + zsize],
261 &DrawState::default(),
265 Pos::F((_, o)) => match o {
266 Ori::Back => Rectangle::new_border(RED, 1.0)
267 .draw([0.0, 0.0, xsize, zsize],
268 &DrawState::default(),
269 c.transform.trans(x, z),
272 red_line!(c, gl, (x, z), (0.0, 0.0), (xsize, 0.0));
273 red_line!(c, gl, (x, z), (xsize, 0.0), (xsize - ysize, -ysize));
274 red_line!(c, gl, (x, z), (xsize - ysize, -ysize), (-ysize, -ysize));
275 red_line!(c, gl, (x, z), (-ysize, -ysize), (0.0, 0.0));
278 red_line!(c, gl, (x, z), (0.0, zsize), (0.0, 0.0));
279 red_line!(c, gl, (x, z), (0.0, 0.0), (-ysize, -ysize));
280 red_line!(c, gl, (x, z), (-ysize, -ysize), (-ysize, zsize - ysize));
281 red_line!(c, gl, (x, z), (-ysize, zsize - ysize), (0.0, zsize));
297 pub fn set_ui(ui: &mut UiCell, s: &mut State,
298 d: &mut Data, c: &mut Colors, wsize: &WSize)
301 &mut State::Design => {
302 header_ui(ui, c, wsize);
303 side_ui(ui, c, wsize);
306 &mut State::Visual(_) => {
307 header_ui(ui, c, wsize);
310 &mut State::Extensions => /*extensions_ui(ui, s, c)*/ {},
311 &mut State::Err(_) => error_ui(ui, s, c),
315 fn error_ui(ui: &mut UiCell, gs: &mut State, c: &mut Colors)
321 Canvas::new().middle_of(C_MASTER)
322 .color(c.c1).frame_color(c.c2)
323 .w_h(400.0, 120.0).pad(20.0)
325 Text::new(match *gs {
326 State::Err(ref msg) => msg,
329 .color(c.font).mid_top_of(C_ERR)
333 .label("OK").mid_bottom_of(C_ERR)
337 .set(BTN_OK_ERR, ui);
340 fn header_ui(ui: &mut UiCell, c: &mut Colors, wsize: &WSize)
343 .color(c.c1).frame_color(c.c2)
344 .y((wsize.h/2.0)-(wsize.header_h/2.0)).h(wsize.header_h)
345 .pad_left(20.0).pad_right(20.0)
349 fn side_ui(ui: &mut UiCell, c: &mut Colors, wsize: &WSize)
351 Canvas::new().color(c.c1)
352 .color(c.c1).frame_color(c.c2)
353 .x_y(-((wsize.w/2.0)-(wsize.side_w/2.0)), -(wsize.header_h/2.0))
354 .w_h(wsize.side_w, wsize.h - wsize.header_h)
359 fn visual_ui(ui: &mut UiCell, gs: &mut State, c: &mut Colors)
362 .mid_right_of(C_HEADER)
363 .label("Extensions").mid_right_of(C_HEADER)
365 *gs = State::Extensions;
367 .set(BTN_EXTENSIONS, ui);
368 make_disable_button!(c)
369 .mid_right_of(C_HEADER)
370 .left_from(BTN_EXTENSIONS, 0.0)
372 .set(DBTN_VISUAL, ui);
374 .mid_right_of(C_HEADER)
375 .label("Design").left_from(DBTN_VISUAL, 0.0)
379 .set(BTN_DESIGN, ui);
381 fn std_ui(ui: &mut UiCell, gs: &mut State, d: &mut Data, c: &mut Colors)
383 let prev_id = if d.history.has_prev() {
385 .mid_left_of(C_HEADER).w_h(50.0, 30.0)
386 .color(c.c1).frame_color(c.c2)
388 .label("←").react(|| {
395 make_disable_button!(c)
397 .mid_left_of(C_HEADER).w_h(50.0, 30.0)
402 let next_id = if d.history.has_next() {
404 .mid_left_of(C_HEADER).right_from(prev_id, 30.0)
406 .color(c.c1).frame_color(c.c2)
408 .label("→").react(|| {
415 make_disable_button!(c)
417 .mid_left_of(C_HEADER).right_from(prev_id, 30.0)
424 let mut select = vec![String::from("Edge (E)"),
425 String::from("Face (F)")];
426 let mut select_idx = None;
427 DropDownList::new(&mut select, &mut select_idx)
428 .w_h(BUTTON_WIDTH, BUTTON_HEIGHT)
429 .mid_left_of(C_HEADER).right_from(next_id, 30.0)
430 .max_visible_items(2)
435 .react(|selected_idx: &mut Option<usize>, new_idx, string: &str| {
436 *selected_idx = Some(new_idx);
437 d.space.set_pos_kind(match string {
438 "Edge (E)" => PosKind::Edge,
442 .set(POS_KIND_SELECT, ui);
445 .mid_left_of(C_HEADER).right_from(POS_KIND_SELECT, 30.0)
449 }).set(BTN_ROTATE, ui);
451 .mid_right_of(C_HEADER)
454 *gs = State::Extensions;
455 }).set(BTN_EXTENSIONS, ui);
457 .mid_right_of(C_HEADER)
458 .left_from(BTN_EXTENSIONS, 0.0)
461 *gs = State::Visual(None);
462 }).set(BTN_VISUAL, ui);
463 make_disable_button!(c)
464 .mid_right_of(C_HEADER)
465 .label("Design").left_from(BTN_VISUAL, 0.0)
466 .set(DBTN_DESIGN, ui);
467 match d.space.current {
468 Pos::F(((x, y, z), o)) => {
469 if let Some(n) = d.space.faces[x][y][z] {
470 if let Some((r, g, b)) = n[Space::ori_idx(o)] {
471 make_disable_button!(c)
476 .down(20.0).label("Delete (D)")
478 d.space.remove_face(((x, y, z), o));
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(40.0) } else { slider.right(10.0) })
497 .label(&format!("{:.*}", 2, value))
498 .label_color(color.plain_contrast())
500 .react(|v| d.space.set_current_face_color_if_any(match i {
505 .set(COLOR_SLIDER + i, ui);
508 let color = color::rgb(r, g, b);
509 let mut colors = vec![
515 "Orange".to_string(),
516 "Yellow".to_string(),
521 let mut selected_idx = None;
522 DropDownList::new(&mut colors, &mut selected_idx)
523 .w_h(BUTTON_WIDTH, BUTTON_HEIGHT)
524 .mid_top_of(C_SIDE).down(20.0)
528 .label_color(color.plain_contrast())
529 .react(|selected_idx: &mut Option<usize>, new_idx, string: &str| {
530 *selected_idx = Some(new_idx);
531 d.space.set_current_face_color_if_any(match string {
532 "Black" => (0.0, 0.0, 0.0),
533 "White" => (1.0, 1.0, 1.0),
534 "Red" => (1.0, 0.0, 0.0),
535 "Green" => (0.0, 1.0, 0.0),
536 "Blue" => (0.0, 0.0, 1.0),
537 "Yellow" => (color::YELLOW.red(),
538 color::YELLOW.green(),
539 color::YELLOW.blue()),
540 "Purple" => (color::PURPLE.red(),
541 color::PURPLE.green(),
542 color::PURPLE.blue()),
543 "Orange" => (color::ORANGE.red(),
544 color::ORANGE.green(),
545 color::ORANGE.blue()),
546 "Gray" => (color::GRAY.red(),
549 "Brown" => (color::BROWN.red(),
550 color::BROWN.green(),
551 color::BROWN.blue()),
552 _ => (1.0, 1.0, 1.0),
555 .set(COLOR_SELECT, ui);
559 .mid_top_of(C_SIDE).label("Add (A)")
561 d.space.add_face(((x, y, z), o));
563 make_disable_button!(c)
564 .down(20.0).label("Delete (D)")
567 Slider::new(0.0, 0.0, 1.0)
568 .and(|slider| if i == 0 {
578 .set(DCOLOR_SLIDER + i, ui);
580 make_disable_button!(c)
581 .mid_top_of(C_SIDE).down(20.0)
583 .set(DBTN_SELECT_COLOR, ui);
593 .set(LENGTH_TXT, ui);
594 let length = d.space.get_edge_size(e) as f64;
595 Slider::new(length, 1.0, 1024.0)
596 .top_right_of(C_SIDE)
599 .label(&format!("{:.*}", 0, length))
602 .react(|v| d.space.edge_size(e, v as usize))
603 .set(SIZE_SLIDER, ui);