1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
use amethyst::ecs::prelude::*;
use amethyst_imgui::imgui;
use imgui::im_str;

#[derive(Default, Clone, Copy)]
pub struct InspectorHierarchy {
	dragging: Option<Entity>,
	hovering: Option<Entity>,
}

impl InspectorHierarchy {
	fn render_boy(
		&mut self,
		entity: Entity,
		hierarchy: &amethyst::core::ParentHierarchy,
		names: &ReadStorage<'_, amethyst::core::Named>,
		ui: &imgui::Ui<'_>,
		inspector_state: &mut crate::InspectorState,
		entities: &amethyst::ecs::world::EntitiesRes,
		lazy: &LazyUpdate,
	) {
		let children = hierarchy.children(entity);

		let label: String = if let Some(name) = names.get(entity) {
			name.name.to_string()
		} else {
			format!("Entity {}/{}", entity.id(), entity.gen().id())
		};

		macro_rules! tree_node_buttons {
			() => {
				if ui.is_item_hovered_with_flags(imgui::ImGuiHoveredFlags::AllowWhenBlockedByActiveItem) {
					self.hovering = Some(entity);

					if ui.imgui().is_mouse_clicked(imgui::ImMouseButton::Left) && self.dragging.is_none() {
						self.dragging = Some(entity);
					}
				}
				ui.same_line(0.);
				if ui.small_button(im_str!("inspect##selector{:?}", entity)) {
					inspector_state.selected = Some(entity);
				}
			};
		}

		let mut opened = false;
		ui.tree_node(im_str!("{:?}", entity))
			.label(im_str!("{}", label))
			.allow_item_overlap(true)
			.selected(
				inspector_state.selected == Some(entity) ||
				self.dragging == Some(entity)
			)
			.leaf(children.is_empty())
			.build(|| {
				opened = true;
				tree_node_buttons!();
				for child in children {
					self.render_boy(*child, hierarchy, names, ui, inspector_state, &entities, &lazy);
				}
			});

		if !opened {
			tree_node_buttons!();
		}
	}
}

impl<'s> System<'s> for InspectorHierarchy {
	type SystemData = (
		Write<'s, crate::InspectorState>,
		ReadStorage<'s, amethyst::core::Named>,
		ReadStorage<'s, amethyst::core::Parent>,
		ReadExpect<'s, amethyst::core::ParentHierarchy>,
		Entities<'s>,
		Read<'s, LazyUpdate>,
	);

	fn run(&mut self, (mut inspector_state, names, parents, hierarchy, entities, lazy): Self::SystemData) {
		amethyst_imgui::with(move |ui| {
			ui.window(im_str!("Hierarchy"))
				.size((300.0, 500.0), imgui::ImGuiCond::FirstUseEver)
				.build(move || {
					self.hovering = None;

					if ui.small_button(im_str!("new entity##hierarchy")) {
						lazy.create_entity(&entities).build();
					}
					ui.separator();
					for (entity, _) in (&entities, !&parents).join() {
						self.render_boy(entity, &hierarchy, &names, &ui, &mut inspector_state, &entities, &lazy);
					}

					let is_dragging = ui.imgui().is_mouse_dragging(imgui::ImMouseButton::Left);
					let is_mouse_down = ui.imgui().is_mouse_down(imgui::ImMouseButton::Left);
					if let Some(dragged) = self.dragging {
						if !is_dragging && !is_mouse_down {
							if let Some(hover) = self.hovering {
								if dragged != hover {
									lazy.insert(dragged, amethyst::core::Parent::new(hover));
								}
							} else {
								// TODO: bugged in amethyst
								// lazy.remove::<amethyst::core::Parent>(dragged);
							}
							self.dragging = None;
						}
					}
				});
		});
	}
}