void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) {

	Ref<InputEventKey> k = p_event;
	if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) {
		if (selected_node != StringName() || selected_transition_to != StringName() || selected_transition_from != StringName()) {
			_erase_selected();
			accept_event();
		}
	}

	Ref<InputEventMouseButton> mb = p_event;

	//Add new node
	if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == BUTTON_LEFT))) {
		menu->clear();
		animations_menu->clear();
		animations_to_add.clear();
		List<StringName> classes;
		classes.sort_custom<StringName::AlphCompare>();

		ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
		menu->add_submenu_item(TTR("Add Animation"), "animations");

		AnimationTree *gp = state_machine->get_tree();
		ERR_FAIL_COND(!gp);
		if (gp && gp->has_node(gp->get_animation_player())) {
			AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
			if (ap) {
				List<StringName> names;
				ap->get_animation_list(&names);
				for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
					animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get());
					animations_to_add.push_back(E->get());
				}
			}
		}

		for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {

			String name = String(E->get()).replace_first("AnimationNode", "");
			if (name == "Animation")
				continue; // nope
			int idx = menu->get_item_count();
			menu->add_item(vformat("Add %s", name));
			menu->set_item_metadata(idx, E->get());
		}

		menu->set_global_position(state_machine_draw->get_global_transform().xform(mb->get_position()));
		menu->popup();
		add_node_pos = mb->get_position() / EDSCALE + state_machine->get_graph_offset();
	}

	// select node or push a field inside
	if (mb.is_valid() && !mb->get_shift() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {

		selected_transition_from = StringName();
		selected_transition_to = StringName();
		selected_node = StringName();

		for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order

			if (node_rects[i].play.has_point(mb->get_position())) { //edit name
				if (play_mode->get_selected() == 1 || !state_machine->is_playing()) {
					//start
					state_machine->start(node_rects[i].node_name);
				} else {
					//travel
					if (!state_machine->travel(node_rects[i].node_name)) {

						state_machine->start(node_rects[i].node_name);
						//removing this due to usability..
						//error_time = 5;
						//error_text = vformat(TTR("No path found from '%s' to '%s'."), state_machine->get_current_node(), node_rects[i].node_name);
					}
				}
				state_machine_draw->update();
				return;
			}

			if (node_rects[i].name.has_point(mb->get_position())) { //edit name

				Ref<StyleBox> line_sb = get_stylebox("normal", "LineEdit");

				Rect2 edit_rect = node_rects[i].name;
				edit_rect.position -= line_sb->get_offset();
				edit_rect.size += line_sb->get_minimum_size();

				name_edit->set_global_position(state_machine_draw->get_global_transform().xform(edit_rect.position));
				name_edit->set_size(edit_rect.size);
				name_edit->set_text(node_rects[i].node_name);
				name_edit->show_modal();
				name_edit->grab_focus();
				name_edit->select_all();

				prev_name = node_rects[i].node_name;
				return;
			}

			if (node_rects[i].edit.has_point(mb->get_position())) { //edit name
				call_deferred("_open_editor", node_rects[i].node_name);
				return;
			}

			if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected
				selected_node = node_rects[i].node_name;

				Ref<AnimationNode> anode = state_machine->get_node(selected_node);
				EditorNode::get_singleton()->push_item(anode.ptr(), "", true);
				state_machine_draw->update();
				dragging_selected_attempt = true;
				dragging_selected = false;
				drag_from = mb->get_position();
				snap_x = StringName();
				snap_y = StringName();
				_update_mode();
				return;
			}
		}

		//test the lines now
		int closest = -1;
		float closest_d = 1e20;
		for (int i = 0; i < transition_lines.size(); i++) {

			Vector2 s[2] = {
				transition_lines[i].from,
				transition_lines[i].to
			};
			Vector2 cpoint = Geometry::get_closest_point_to_segment_2d(mb->get_position(), s);
			float d = cpoint.distance_to(mb->get_position());
			if (d > transition_lines[i].width) {
				continue;
			}

			if (d < closest_d) {
				closest = i;
				closest_d = d;
			}
		}

		if (closest >= 0) {
			selected_transition_from = transition_lines[closest].from_node;
			selected_transition_to = transition_lines[closest].to_node;

			Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(closest);
			EditorNode::get_singleton()->push_item(tr.ptr(), "", true);
		}

		state_machine_draw->update();
		_update_mode();
	}

	//end moving node
	if (mb.is_valid() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {

		if (dragging_selected) {

			Ref<AnimationNode> an = state_machine->get_node(selected_node);
			updating = true;
			undo_redo->create_action("Move Node");
			undo_redo->add_do_method(an.ptr(), "set_position", an->get_position() + drag_ofs / EDSCALE);
			undo_redo->add_undo_method(an.ptr(), "set_position", an->get_position());
			undo_redo->add_do_method(this, "_update_graph");
			undo_redo->add_undo_method(this, "_update_graph");
			undo_redo->commit_action();
			updating = false;
		}
		snap_x = StringName();
		snap_y = StringName();

		dragging_selected_attempt = false;
		dragging_selected = false;
		state_machine_draw->update();
	}

	//connect nodes
	if (mb.is_valid() && ((tool_select->is_pressed() && mb->get_shift()) || tool_connect->is_pressed()) && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {

		for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
			if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected
				connecting = true;
				connecting_from = node_rects[i].node_name;
				connecting_to = mb->get_position();
				connecting_to_node = StringName();
				return;
			}
		}
	}

	//end connecting nodes
	if (mb.is_valid() && connecting && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {

		if (connecting_to_node != StringName()) {

			if (state_machine->has_transition(connecting_from, connecting_to_node)) {
				EditorNode::get_singleton()->show_warning("Transition exists!");

			} else {

				Ref<AnimationNodeStateMachineTransition> tr;
				tr.instance();
				tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()));

				updating = true;
				undo_redo->create_action("Add Transition");
				undo_redo->add_do_method(state_machine.ptr(), "add_transition", connecting_from, connecting_to_node, tr);
				undo_redo->add_undo_method(state_machine.ptr(), "remove_transition", connecting_from, connecting_to_node);
				undo_redo->add_do_method(this, "_update_graph");
				undo_redo->add_undo_method(this, "_update_graph");
				undo_redo->commit_action();
				updating = false;

				selected_transition_from = connecting_from;
				selected_transition_to = connecting_to_node;

				EditorNode::get_singleton()->push_item(tr.ptr(), "", true);
				_update_mode();
			}
		}
		connecting_to_node = StringName();
		connecting = false;
		state_machine_draw->update();
	}

	Ref<InputEventMouseMotion> mm = p_event;

	//pan window
	if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) {

		h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x);
		v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y);
	}

	//move mouse while connecting
	if (mm.is_valid() && connecting) {

		connecting_to = mm->get_position();
		connecting_to_node = StringName();
		state_machine_draw->update();

		for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
			if (node_rects[i].node_name != connecting_from && node_rects[i].node.has_point(connecting_to)) { //select node since nothing else was selected
				connecting_to_node = node_rects[i].node_name;
				return;
			}
		}
	}

	//move mouse while moving a node
	if (mm.is_valid() && dragging_selected_attempt) {

		dragging_selected = true;
		drag_ofs = mm->get_position() - drag_from;
		snap_x = StringName();
		snap_y = StringName();
		{
			//snap
			Vector2 cpos = state_machine->get_node(selected_node)->get_position() + drag_ofs / EDSCALE;
			List<StringName> nodes;
			state_machine->get_node_list(&nodes);

			float best_d_x = 1e20;
			float best_d_y = 1e20;

			for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) {
				if (E->get() == selected_node)
					continue;
				Vector2 npos = state_machine->get_node(E->get())->get_position();

				float d_x = ABS(npos.x - cpos.x);
				if (d_x < MIN(5, best_d_x)) {
					drag_ofs.x -= cpos.x - npos.x;
					best_d_x = d_x;
					snap_x = E->get();
				}

				float d_y = ABS(npos.y - cpos.y);
				if (d_y < MIN(5, best_d_y)) {
					drag_ofs.y -= cpos.y - npos.y;
					best_d_y = d_y;
					snap_y = E->get();
				}
			}
		}

		state_machine_draw->update();
	}

	//put ibeam (text cursor) over names to make it clearer that they are editable
	if (mm.is_valid()) {

		state_machine_draw->grab_focus();

		bool over_text_now = false;
		String new_over_node = StringName();
		int new_over_node_what = -1;
		if (tool_select->is_pressed()) {

			for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order

				if (node_rects[i].name.has_point(mm->get_position())) {
					over_text_now = true;
					break;
				}

				if (node_rects[i].node.has_point(mm->get_position())) {
					new_over_node = node_rects[i].node_name;
					if (node_rects[i].play.has_point(mm->get_position())) {
						new_over_node_what = 0;
					}
					if (node_rects[i].edit.has_point(mm->get_position())) {
						new_over_node_what = 1;
					}
				}
			}
		}

		if (new_over_node != over_node || new_over_node_what != over_node_what) {
			over_node = new_over_node;
			over_node_what = new_over_node_what;
			state_machine_draw->update();
		}

		if (over_text != over_text_now) {

			if (over_text_now) {
				state_machine_draw->set_default_cursor_shape(CURSOR_IBEAM);
			} else {
				state_machine_draw->set_default_cursor_shape(CURSOR_ARROW);
			}

			over_text = over_text_now;
		}
	}
}
void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) {
	Ref<InputEventKey> k = p_event;

	if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) {
		if (selected_point != -1) {
			_erase_selected();
			accept_event();
		}
	}

	Ref<InputEventMouseButton> mb = p_event;

	if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (mb->get_button_index() == BUTTON_LEFT && tool_create->is_pressed()))) {
		menu->clear();
		animations_menu->clear();
		animations_to_add.clear();

		List<StringName> classes;
		ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
		classes.sort_custom<StringName::AlphCompare>();

		menu->add_submenu_item(TTR("Add Animation"), "animations");

		AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
		ERR_FAIL_COND(!gp);

		if (gp->has_node(gp->get_animation_player())) {
			AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));

			if (ap) {
				List<StringName> names;
				ap->get_animation_list(&names);

				for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
					animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get());
					animations_to_add.push_back(E->get());
				}
			}
		}

		for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
			String name = String(E->get()).replace_first("AnimationNode", "");
			if (name == "Animation")
				continue;

			int idx = menu->get_item_count();
			menu->add_item(vformat("Add %s", name), idx);
			menu->set_item_metadata(idx, E->get());
		}

		Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
		if (clipb.is_valid()) {
			menu->add_separator();
			menu->add_item(TTR("Paste"), MENU_PASTE);
		}
		menu->add_separator();
		menu->add_item(TTR("Load.."), MENU_LOAD_FILE);

		menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position()));
		menu->popup();

		add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
		add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
		add_point_pos += blend_space->get_min_space();

		if (snap->is_pressed()) {
			add_point_pos = Math::stepify(add_point_pos, blend_space->get_snap());
		}
	}

	if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
		blend_space_draw->update(); // why not

		// try to see if a point can be selected
		selected_point = -1;
		_update_tool_erase();

		for (int i = 0; i < points.size(); i++) {

			if (Math::abs(float(points[i] - mb->get_position().x)) < 10 * EDSCALE) {
				selected_point = i;

				Ref<AnimationNode> node = blend_space->get_blend_point_node(i);
				EditorNode::get_singleton()->push_item(node.ptr(), "", true);
				dragging_selected_attempt = true;
				drag_from = mb->get_position();
				_update_tool_erase();
				_update_edited_point_pos();
				return;
			}
		}
	}

	if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT) {
		if (dragging_selected) {
			// move
			float point = blend_space->get_blend_point_position(selected_point);
			point += drag_ofs.x;

			if (snap->is_pressed()) {
				point = Math::stepify(point, blend_space->get_snap());
			}

			updating = true;
			undo_redo->create_action("Move Node Point");
			undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
			undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
			undo_redo->add_do_method(this, "_update_space");
			undo_redo->add_undo_method(this, "_update_space");
			undo_redo->add_do_method(this, "_update_edited_point_pos");
			undo_redo->add_undo_method(this, "_update_edited_point_pos");
			undo_redo->commit_action();
			updating = false;
			_update_edited_point_pos();
		}

		dragging_selected_attempt = false;
		dragging_selected = false;
		blend_space_draw->update();
	}

	// *set* the blend
	if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
		float blend_pos = mb->get_position().x / blend_space_draw->get_size().x;
		blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
		blend_pos += blend_space->get_min_space();

		AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
		blend_space_draw->update();
	}

	Ref<InputEventMouseMotion> mm = p_event;

	if (mm.is_valid() && !blend_space_draw->has_focus()) {
		blend_space_draw->grab_focus();
		blend_space_draw->update();
	}

	if (mm.is_valid() && dragging_selected_attempt) {
		dragging_selected = true;
		drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * ((blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, 0));
		blend_space_draw->update();
		_update_edited_point_pos();
	}

	if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
		float blend_pos = mm->get_position().x / blend_space_draw->get_size().x;
		blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
		blend_pos += blend_space->get_min_space();

		AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);

		blend_space_draw->update();
	}
}