summaryrefslogtreecommitdiff
path: root/editor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins')
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp440
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.h41
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp441
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h36
-rw-r--r--[-rwxr-xr-x]editor/plugins/collision_polygon_2d_editor_plugin.cpp0
-rw-r--r--[-rwxr-xr-x]editor/plugins/collision_polygon_2d_editor_plugin.h0
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp44
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.h7
-rw-r--r--editor/plugins/gi_probe_editor_plugin.cpp26
-rw-r--r--editor/plugins/gi_probe_editor_plugin.h5
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.cpp27
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.h7
-rw-r--r--editor/plugins/line_2d_editor_plugin.cpp24
-rw-r--r--editor/plugins/line_2d_editor_plugin.h37
-rw-r--r--editor/plugins/material_editor_plugin.cpp47
-rw-r--r--editor/plugins/material_editor_plugin.h8
-rw-r--r--editor/plugins/navigation_mesh_generator.cpp2
-rw-r--r--[-rwxr-xr-x]editor/plugins/navigation_polygon_editor_plugin.cpp0
-rw-r--r--[-rwxr-xr-x]editor/plugins/navigation_polygon_editor_plugin.h0
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp19
-rw-r--r--editor/plugins/path_2d_editor_plugin.h5
-rw-r--r--[-rwxr-xr-x]editor/plugins/polygon_2d_editor_plugin.cpp8
-rw-r--r--[-rwxr-xr-x]editor/plugins/polygon_2d_editor_plugin.h0
-rw-r--r--editor/plugins/script_editor_plugin.cpp4
-rw-r--r--editor/plugins/shader_editor_plugin.cpp1
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp68
-rw-r--r--editor/plugins/spatial_editor_plugin.h4
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp27
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h2
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp107
-rw-r--r--editor/plugins/texture_region_editor_plugin.h4
-rw-r--r--editor/plugins/theme_editor_plugin.cpp6
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp54
-rw-r--r--editor/plugins/tile_map_editor_plugin.h6
34 files changed, 1024 insertions, 483 deletions
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 2fd74d529e..2f839b96cf 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -30,6 +30,49 @@
#include "abstract_polygon_2d_editor.h"
#include "canvas_item_editor_plugin.h"
+#include "core/os/keyboard.h"
+
+AbstractPolygon2DEditor::Vertex::Vertex()
+ : polygon(-1), vertex(-1) {
+ // invalid vertex
+}
+
+AbstractPolygon2DEditor::Vertex::Vertex(int p_vertex)
+ : polygon(-1), vertex(p_vertex) {
+ // vertex p_vertex of current wip polygon
+}
+
+AbstractPolygon2DEditor::Vertex::Vertex(int p_polygon, int p_vertex)
+ : polygon(p_polygon), vertex(p_vertex) {
+ // vertex p_vertex of polygon p_polygon
+}
+
+bool AbstractPolygon2DEditor::Vertex::operator==(const AbstractPolygon2DEditor::Vertex &p_vertex) const {
+
+ return polygon == p_vertex.polygon && vertex == p_vertex.vertex;
+}
+
+bool AbstractPolygon2DEditor::Vertex::operator!=(const AbstractPolygon2DEditor::Vertex &p_vertex) const {
+
+ return !(*this == p_vertex);
+}
+
+bool AbstractPolygon2DEditor::Vertex::valid() const {
+
+ return vertex >= 0;
+}
+
+AbstractPolygon2DEditor::PosVertex::PosVertex() {
+ // invalid vertex
+}
+
+AbstractPolygon2DEditor::PosVertex::PosVertex(const Vertex &p_vertex, const Vector2 &p_pos)
+ : Vertex(p_vertex.polygon, p_vertex.vertex), pos(p_pos) {
+}
+
+AbstractPolygon2DEditor::PosVertex::PosVertex(int p_polygon, int p_vertex, const Vector2 &p_pos)
+ : Vertex(p_polygon, p_vertex), pos(p_pos) {
+}
bool AbstractPolygon2DEditor::_is_empty() const {
@@ -171,7 +214,10 @@ void AbstractPolygon2DEditor::_wip_close() {
wip.clear();
wip_active = false;
- edited_point = -1;
+
+ edited_point = PosVertex();
+ hover_point = Vertex();
+ selected_point = Vertex();
}
bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
@@ -195,12 +241,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform();
Vector2 gpoint = mb->get_position();
- Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
- cpoint = canvas_item_editor->snap_point(cpoint);
- cpoint = _get_node()->get_global_transform().affine_inverse().xform(cpoint);
-
- //first check if a point is to be added (segment split)
- real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
+ Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position())));
if (mode == MODE_CREATE) {
@@ -211,13 +252,16 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
wip.clear();
wip.push_back(cpoint);
wip_active = true;
- edited_point_pos = cpoint;
- edited_polygon = -1;
- edited_point = 1;
+ edited_point = PosVertex(-1, 1, cpoint);
canvas_item_editor->get_viewport_control()->update();
+ hover_point = Vertex();
+ selected_point = Vertex(0);
+ edge_point = PosVertex();
return true;
} else {
+ const real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
+
if (wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) {
//wip closed
_wip_close();
@@ -226,7 +270,8 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
} else {
wip.push_back(cpoint);
- edited_point = wip.size();
+ edited_point = PosVertex(-1, wip.size(), cpoint);
+ selected_point = Vertex(wip.size() - 1);
canvas_item_editor->get_viewport_control()->update();
return true;
@@ -242,66 +287,31 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
if (mb->is_pressed()) {
- if (mb->get_control()) {
-
- const int n_polygons = _get_polygon_count();
-
- if (n_polygons >= 1) {
-
- Vector<Vector2> vertices = _get_polygon(n_polygons - 1);
+ const PosVertex insert = closest_edge_point(gpoint);
- if (vertices.size() < 3) {
+ if (insert.valid()) {
- vertices.push_back(cpoint);
- undo_redo->create_action(TTR("Edit Poly"));
- _action_set_polygon(n_polygons - 1, vertices);
- _commit_action();
- return true;
- }
- }
-
- //search edges
- int closest_poly = -1;
- int closest_idx = -1;
- Vector2 closest_pos;
- real_t closest_dist = 1e10;
-
- for (int j = 0; j < n_polygons; j++) {
-
- PoolVector<Vector2> points = _get_polygon(j);
- const Vector2 offset = _get_offset(j);
- const int n_points = points.size();
-
- for (int i = 0; i < n_points; i++) {
+ Vector<Vector2> vertices = _get_polygon(insert.polygon);
- Vector2 p[2] = { xform.xform(points[i] + offset),
- xform.xform(points[(i + 1) % n_points] + offset) };
+ if (vertices.size() < 3) {
- Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint, p);
- if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2)
- continue; //not valid to reuse point
-
- real_t d = cp.distance_to(gpoint);
- if (d < closest_dist && d < grab_threshold) {
- closest_poly = j;
- closest_dist = d;
- closest_pos = cp;
- closest_idx = i;
- }
- }
- }
-
- if (closest_idx >= 0) {
+ vertices.push_back(cpoint);
+ undo_redo->create_action(TTR("Edit Poly"));
+ selected_point = Vertex(insert.polygon, vertices.size());
+ _action_set_polygon(insert.polygon, vertices);
+ _commit_action();
+ return true;
+ } else {
- Vector<Vector2> vertices = _get_polygon(closest_poly);
+ Vector<Vector2> vertices = _get_polygon(insert.polygon);
pre_move_edit = vertices;
- vertices.insert(closest_idx + 1, xform.affine_inverse().xform(closest_pos));
- edited_point = closest_idx + 1;
- edited_polygon = closest_poly;
- edited_point_pos = xform.affine_inverse().xform(closest_pos);
+ edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos));
+ vertices.insert(edited_point.vertex, edited_point.pos);
+ selected_point = edited_point;
+ edge_point = PosVertex();
undo_redo->create_action(TTR("Insert Point"));
- _action_set_polygon(closest_poly, vertices);
+ _action_set_polygon(insert.polygon, vertices);
_commit_action();
return true;
@@ -309,150 +319,137 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
} else {
//look for points to move
- int closest_poly = -1;
- int closest_idx = -1;
- Vector2 closest_pos;
- real_t closest_dist = 1e10;
-
- const int n_polygons = _get_polygon_count();
-
- for (int j = 0; j < n_polygons; j++) {
-
- PoolVector<Vector2> points = _get_polygon(j);
- const Vector2 offset = _get_offset(j);
- const int n_points = points.size();
-
- for (int i = 0; i < n_points; i++) {
+ const PosVertex closest = closest_point(gpoint);
- Vector2 cp = xform.xform(points[i] + offset);
+ if (closest.valid()) {
- real_t d = cp.distance_to(gpoint);
- if (d < closest_dist && d < grab_threshold) {
- closest_poly = j;
- closest_dist = d;
- closest_pos = cp;
- closest_idx = i;
- }
- }
- }
-
- if (closest_idx >= 0) {
-
- pre_move_edit = _get_polygon(closest_poly);
- edited_polygon = closest_poly;
- edited_point = closest_idx;
- edited_point_pos = xform.affine_inverse().xform(closest_pos);
+ pre_move_edit = _get_polygon(closest.polygon);
+ edited_point = PosVertex(closest, xform.affine_inverse().xform(closest.pos));
+ selected_point = closest;
+ edge_point = PosVertex();
canvas_item_editor->get_viewport_control()->update();
return true;
+ } else {
+
+ selected_point = Vertex();
}
}
} else {
- if (edited_point != -1) {
+ if (edited_point.valid()) {
//apply
- Vector<Vector2> vertices = _get_polygon(edited_polygon);
- ERR_FAIL_INDEX_V(edited_point, vertices.size(), false);
- vertices[edited_point] = edited_point_pos - _get_offset(edited_polygon);
+ Vector<Vector2> vertices = _get_polygon(edited_point.polygon);
+ ERR_FAIL_INDEX_V(edited_point.vertex, vertices.size(), false);
+ vertices[edited_point.vertex] = edited_point.pos - _get_offset(edited_point.polygon);
undo_redo->create_action(TTR("Edit Poly"));
- _action_set_polygon(edited_polygon, pre_move_edit, vertices);
+ _action_set_polygon(edited_point.polygon, pre_move_edit, vertices);
_commit_action();
- edited_point = -1;
+ edited_point = PosVertex();
return true;
}
}
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && edited_point == -1) {
+ } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && !edited_point.valid()) {
- int closest_poly = -1;
- int closest_idx = -1;
- Vector2 closest_pos;
- real_t closest_dist = 1e10;
- const int n_polygons = _get_polygon_count();
+ const PosVertex closest = closest_point(gpoint);
- for (int j = 0; j < n_polygons; j++) {
+ if (closest.valid()) {
- PoolVector<Vector2> points = _get_polygon(j);
- const int n_points = points.size();
- const Vector2 offset = _get_offset(j);
+ remove_point(closest);
+ return true;
+ }
+ }
+ }
+ }
- for (int i = 0; i < n_points; i++) {
+ Ref<InputEventMouseMotion> mm = p_event;
- Vector2 cp = xform.xform(points[i] + offset);
+ if (mm.is_valid()) {
- real_t d = cp.distance_to(gpoint);
- if (d < closest_dist && d < grab_threshold) {
- closest_poly = j;
- closest_dist = d;
- closest_pos = cp;
- closest_idx = i;
- }
- }
- }
+ Vector2 gpoint = mm->get_position();
- if (closest_idx >= 0) {
+ if (edited_point.valid() && (wip_active || (mm->get_button_mask() & BUTTON_MASK_LEFT))) {
- PoolVector<Vector2> vertices = _get_polygon(closest_poly);
+ Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)));
+ edited_point = PosVertex(edited_point, cpoint);
- if (vertices.size() > 3) {
+ if (!wip_active) {
- vertices.remove(closest_idx);
+ Vector<Vector2> vertices = _get_polygon(edited_point.polygon);
+ ERR_FAIL_INDEX_V(edited_point.vertex, vertices.size(), false);
+ vertices[edited_point.vertex] = cpoint - _get_offset(edited_point.polygon);
+ _set_polygon(edited_point.polygon, vertices);
+ }
- undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
- _action_set_polygon(closest_poly, vertices);
- _commit_action();
- } else {
+ canvas_item_editor->get_viewport_control()->update();
+ } else if (mode == MODE_EDIT) {
- undo_redo->create_action(TTR("Remove Poly And Point"));
- _action_remove_polygon(closest_poly);
- _commit_action();
- }
+ const PosVertex onEdgeVertex = closest_edge_point(gpoint);
- if (_is_empty())
- _menu_option(MODE_CREATE);
- return true;
+ if (onEdgeVertex.valid()) {
+
+ hover_point = Vertex();
+ edge_point = onEdgeVertex;
+ canvas_item_editor->get_viewport_control()->update();
+ } else {
+
+ if (edge_point.valid()) {
+
+ edge_point = PosVertex();
+ canvas_item_editor->get_viewport_control()->update();
+ }
+
+ const PosVertex new_hover_point = closest_point(gpoint);
+ if (hover_point != new_hover_point) {
+
+ hover_point = new_hover_point;
+ canvas_item_editor->get_viewport_control()->update();
}
}
}
}
- Ref<InputEventMouseMotion> mm = p_event;
+ Ref<InputEventKey> k = p_event;
- if (mm.is_valid()) {
+ if (k.is_valid() && k->is_pressed() && (k->get_scancode() == KEY_DELETE || k->get_scancode() == KEY_BACKSPACE)) {
+ if (wip_active && selected_point.polygon == -1) {
- if (edited_point != -1 && (wip_active || (mm->get_button_mask() & BUTTON_MASK_LEFT))) {
+ if (wip.size() > selected_point.vertex) {
- Vector2 gpoint = mm->get_position();
- Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
- cpoint = canvas_item_editor->snap_point(cpoint);
- edited_point_pos = _get_node()->get_global_transform().affine_inverse().xform(cpoint);
+ wip.remove(selected_point.vertex);
+ selected_point = wip.size() - 1;
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+ }
+ } else {
- if (!wip_active) {
+ const Vertex active_point = get_active_point();
- Vector<Vector2> vertices = _get_polygon(edited_polygon);
- ERR_FAIL_INDEX_V(edited_point, vertices.size(), false);
- vertices[edited_point] = edited_point_pos - _get_offset(edited_polygon);
- _set_polygon(edited_polygon, vertices);
- }
+ if (active_point.valid()) {
- canvas_item_editor->get_viewport_control()->update();
+ remove_point(active_point);
+ return true;
+ }
}
}
return false;
}
-void AbstractPolygon2DEditor::_canvas_draw() {
-
+void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) {
if (!_get_node())
return;
Control *vpc = canvas_item_editor->get_viewport_control();
Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform();
- Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons");
+ Ref<Texture> default_handle = get_icon("EditorHandle", "EditorIcons");
+ Ref<Texture> selected_handle = get_icon("EditorHandleSelected", "EditorIcons");
+
+ const Vertex active_point = get_active_point();
const int n_polygons = _get_polygon_count();
for (int j = -1; j < n_polygons; j++) {
@@ -463,7 +460,7 @@ void AbstractPolygon2DEditor::_canvas_draw() {
PoolVector<Vector2> points;
Vector2 offset;
- if (wip_active && j == edited_polygon) {
+ if (wip_active && j == edited_point.polygon) {
points = Variant(wip);
offset = Vector2(0, 0);
@@ -475,7 +472,7 @@ void AbstractPolygon2DEditor::_canvas_draw() {
offset = _get_offset(j);
}
- if (!wip_active && j == edited_polygon && edited_point >= 0 && EDITOR_DEF("editors/poly_editor/show_previous_outline", true)) {
+ if (!wip_active && j == edited_point.polygon && EDITOR_DEF("editors/poly_editor/show_previous_outline", true)) {
const Color col = Color(0.5, 0.5, 0.5); // FIXME polygon->get_outline_color();
const int n = pre_move_edit.size();
@@ -497,10 +494,12 @@ void AbstractPolygon2DEditor::_canvas_draw() {
for (int i = 0; i < n_points; i++) {
+ const Vertex vertex(j, i);
+
Vector2 p, p2;
- p = (j == edited_polygon && i == edited_point) ? edited_point_pos : (points[i] + offset);
- if (j == edited_polygon && ((wip_active && i == n_points - 1) || (((i + 1) % n_points) == edited_point)))
- p2 = edited_point_pos;
+ p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset);
+ if (j == edited_point.polygon && ((wip_active && i == n_points - 1) || (((i + 1) % n_points) == edited_point.vertex)))
+ p2 = edited_point.pos;
else
p2 = points[(i + 1) % n_points] + offset;
@@ -508,9 +507,16 @@ void AbstractPolygon2DEditor::_canvas_draw() {
Vector2 next_point = xform.xform(p2);
vpc->draw_line(point, next_point, col, 2);
+ Ref<Texture> handle = vertex == active_point ? selected_handle : default_handle;
vpc->draw_texture(handle, point - handle->get_size() * 0.5);
}
}
+
+ if (edge_point.valid()) {
+
+ Ref<Texture> add_handle = get_icon("EditorHandleAdd", "EditorIcons");
+ vpc->draw_texture(add_handle, edge_point.pos - add_handle->get_size() * 0.5);
+ }
}
void AbstractPolygon2DEditor::edit(Node *p_polygon) {
@@ -527,32 +533,128 @@ void AbstractPolygon2DEditor::edit(Node *p_polygon) {
if (_is_empty())
_menu_option(MODE_CREATE);
- if (!canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->get_viewport_control()->connect("draw", this, "_canvas_draw");
-
wip.clear();
wip_active = false;
- edited_point = -1;
+ edited_point = PosVertex();
+ hover_point = Vertex();
+ selected_point = Vertex();
canvas_item_editor->get_viewport_control()->update();
} else {
_set_node(NULL);
-
- if (canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->get_viewport_control()->disconnect("draw", this, "_canvas_draw");
}
}
void AbstractPolygon2DEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_canvas_draw"), &AbstractPolygon2DEditor::_canvas_draw);
ClassDB::bind_method(D_METHOD("_node_removed"), &AbstractPolygon2DEditor::_node_removed);
ClassDB::bind_method(D_METHOD("_menu_option"), &AbstractPolygon2DEditor::_menu_option);
ClassDB::bind_method(D_METHOD("_create_resource"), &AbstractPolygon2DEditor::_create_resource);
}
+void AbstractPolygon2DEditor::remove_point(const Vertex &p_vertex) {
+
+ PoolVector<Vector2> vertices = _get_polygon(p_vertex.polygon);
+
+ if (vertices.size() > 3) {
+
+ vertices.remove(p_vertex.vertex);
+
+ undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
+ _action_set_polygon(p_vertex.polygon, vertices);
+ _commit_action();
+ } else {
+
+ undo_redo->create_action(TTR("Remove Poly And Point"));
+ _action_remove_polygon(p_vertex.polygon);
+ _commit_action();
+ }
+
+ if (_is_empty())
+ _menu_option(MODE_CREATE);
+
+ hover_point = Vertex();
+ if (selected_point == p_vertex)
+ selected_point = Vertex();
+}
+
+AbstractPolygon2DEditor::Vertex AbstractPolygon2DEditor::get_active_point() const {
+
+ return hover_point.valid() ? hover_point : selected_point;
+}
+
+AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_point(const Vector2 &p_pos) const {
+
+ const real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
+
+ const int n_polygons = _get_polygon_count();
+ const Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform();
+
+ PosVertex closest;
+ real_t closest_dist = 1e10;
+
+ for (int j = 0; j < n_polygons; j++) {
+
+ PoolVector<Vector2> points = _get_polygon(j);
+ const Vector2 offset = _get_offset(j);
+ const int n_points = points.size();
+
+ for (int i = 0; i < n_points; i++) {
+
+ Vector2 cp = xform.xform(points[i] + offset);
+
+ real_t d = cp.distance_to(p_pos);
+ if (d < closest_dist && d < grab_threshold) {
+ closest_dist = d;
+ closest = PosVertex(j, i, cp);
+ }
+ }
+ }
+
+ return closest;
+}
+
+AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_edge_point(const Vector2 &p_pos) const {
+
+ const real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
+ const real_t eps = grab_threshold * 2;
+ const real_t eps2 = eps * eps;
+
+ const int n_polygons = _get_polygon_count();
+ const Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform();
+
+ PosVertex closest;
+ real_t closest_dist = 1e10;
+
+ for (int j = 0; j < n_polygons; j++) {
+
+ PoolVector<Vector2> points = _get_polygon(j);
+ const Vector2 offset = _get_offset(j);
+ const int n_points = points.size();
+
+ for (int i = 0; i < n_points; i++) {
+
+ Vector2 segment[2] = { xform.xform(points[i] + offset),
+ xform.xform(points[(i + 1) % n_points] + offset) };
+
+ Vector2 cp = Geometry::get_closest_point_to_segment_2d(p_pos, segment);
+
+ if (cp.distance_squared_to(segment[0]) < eps2 || cp.distance_squared_to(segment[1]) < eps2)
+ continue; //not valid to reuse point
+
+ real_t d = cp.distance_to(p_pos);
+ if (d < closest_dist && d < grab_threshold) {
+ closest_dist = d;
+ closest = PosVertex(j, i, cp);
+ }
+ }
+ }
+
+ return closest;
+}
+
AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wip_destructive) {
canvas_item_editor = NULL;
@@ -560,9 +662,13 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wi
undo_redo = editor->get_undo_redo();
wip_active = false;
- edited_polygon = -1;
+ edited_point = PosVertex();
wip_destructive = p_wip_destructive;
+ hover_point = Vertex();
+ selected_point = Vertex();
+ edge_point = PosVertex();
+
add_child(memnew(VSeparator));
button_create = memnew(ToolButton);
add_child(button_create);
diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h
index 86e14694da..8dd22958db 100644
--- a/editor/plugins/abstract_polygon_2d_editor.h
+++ b/editor/plugins/abstract_polygon_2d_editor.h
@@ -47,9 +47,33 @@ class AbstractPolygon2DEditor : public HBoxContainer {
ToolButton *button_create;
ToolButton *button_edit;
- int edited_polygon;
- int edited_point;
- Vector2 edited_point_pos;
+ struct Vertex {
+ Vertex();
+ Vertex(int p_vertex);
+ Vertex(int p_polygon, int p_vertex);
+
+ bool operator==(const Vertex &p_vertex) const;
+ bool operator!=(const Vertex &p_vertex) const;
+
+ bool valid() const;
+
+ int polygon;
+ int vertex;
+ };
+
+ struct PosVertex : public Vertex {
+ PosVertex();
+ PosVertex(const Vertex &p_vertex, const Vector2 &p_pos);
+ PosVertex(int p_polygon, int p_vertex, const Vector2 &p_pos);
+
+ Vector2 pos;
+ };
+
+ PosVertex edited_point;
+ Vertex hover_point; // point under mouse cursor
+ Vertex selected_point; // currently selected
+ PosVertex edge_point; // adding an edge point?
+
Vector<Vector2> pre_move_edit;
Vector<Vector2> wip;
bool wip_active;
@@ -75,12 +99,16 @@ protected:
virtual void _menu_option(int p_option);
void _wip_close();
- void _canvas_draw();
void _notification(int p_what);
void _node_removed(Node *p_node);
static void _bind_methods();
+ void remove_point(const Vertex &p_vertex);
+ Vertex get_active_point() const;
+ PosVertex closest_point(const Vector2 &p_pos) const;
+ PosVertex closest_edge_point(const Vector2 &p_pos) const;
+
bool _is_empty() const;
void _commit_action();
@@ -103,6 +131,8 @@ protected:
public:
bool forward_gui_input(const Ref<InputEvent> &p_event);
+ void forward_draw_over_canvas(Control *p_canvas);
+
void edit(Node *p_polygon);
AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wip_destructive = true);
};
@@ -116,7 +146,8 @@ class AbstractPolygon2DEditorPlugin : public EditorPlugin {
String klass;
public:
- virtual bool forward_canvas_gui_input(const Transform2D &p_canvas_xform, const Ref<InputEvent> &p_event) { return polygon_editor->forward_gui_input(p_event); }
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return polygon_editor->forward_gui_input(p_event); }
+ virtual void forward_draw_over_canvas(Control *p_canvas) { polygon_editor->forward_draw_over_canvas(p_canvas); }
bool has_main_screen() const { return false; }
virtual String get_name() const { return klass; }
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 3f64e75bc8..3807c8961a 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -45,7 +45,7 @@
#include "scene/2d/screen_button.h"
#include "scene/2d/sprite.h"
#include "scene/gui/grid_container.h"
-#include "scene/gui/patch_9_rect.h"
+#include "scene/gui/nine_patch_rect.h"
#include "scene/main/canvas_layer.h"
#include "scene/main/viewport.h"
#include "scene/resources/packed_scene.h"
@@ -222,41 +222,38 @@ void CanvasItemEditor::_edit_set_pivot(const Vector2 &mouse_pos) {
undo_redo->commit_action();
}
-void CanvasItemEditor::_snap_if_closer(Point2 p_value, Point2 p_target_snap, Point2 &r_current_snap, bool (&r_snapped)[2], real_t rotation, float p_radius) {
+void CanvasItemEditor::_snap_if_closer_float(float p_value, float p_target_snap, float &r_current_snap, bool &r_snapped, float p_radius) {
float radius = p_radius / zoom;
- float dist;
+ float dist = Math::abs(p_value - p_target_snap);
+ if (p_radius < 0 || dist < radius && (!r_snapped || dist < Math::abs(r_current_snap - p_value))) {
+ r_current_snap = p_target_snap;
+ r_snapped = true;
+ }
+}
+void CanvasItemEditor::_snap_if_closer_point(Point2 p_value, Point2 p_target_snap, Point2 &r_current_snap, bool (&r_snapped)[2], real_t rotation, float p_radius) {
Transform2D rot_trans = Transform2D(rotation, Point2());
p_value = rot_trans.inverse().xform(p_value);
p_target_snap = rot_trans.inverse().xform(p_target_snap);
r_current_snap = rot_trans.inverse().xform(r_current_snap);
- dist = Math::abs(p_value.x - p_target_snap.x);
- if (p_radius < 0 || dist < radius && (!r_snapped[0] || dist < Math::abs(r_current_snap.x - p_value.x))) {
- r_current_snap.x = p_target_snap.x;
- r_snapped[0] = true;
- }
-
- dist = Math::abs(p_value.y - p_target_snap.y);
- if (p_radius < 0 || dist < radius && (!r_snapped[1] || dist < Math::abs(r_current_snap.y - p_value.y))) {
- r_current_snap.y = p_target_snap.y;
- r_snapped[1] = true;
- }
+ _snap_if_closer_float(p_value.x, p_target_snap.x, r_current_snap.x, r_snapped[0], p_radius);
+ _snap_if_closer_float(p_value.y, p_target_snap.y, r_current_snap.y, r_snapped[1], p_radius);
r_current_snap = rot_trans.xform(r_current_snap);
}
void CanvasItemEditor::_snap_other_nodes(Point2 p_value, Point2 &r_current_snap, bool (&r_snapped)[2], const Node *p_current, const CanvasItem *p_to_snap) {
const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_current);
- if (canvas_item && p_current != p_to_snap) {
+ if (canvas_item && (!p_to_snap || p_current != p_to_snap)) {
Transform2D ci_transform = canvas_item->get_global_transform_with_canvas();
- Transform2D to_snap_transform = p_to_snap->get_global_transform_with_canvas();
- if (ci_transform.get_rotation() == to_snap_transform.get_rotation()) {
+ Transform2D to_snap_transform = p_to_snap ? p_to_snap->get_global_transform_with_canvas() : Transform2D();
+ if (fmod(ci_transform.get_rotation() - to_snap_transform.get_rotation(), (real_t)360.0) == 0.0) {
Point2 begin = ci_transform.xform(canvas_item->get_item_rect().get_position());
Point2 end = ci_transform.xform(canvas_item->get_item_rect().get_position() + canvas_item->get_item_rect().get_size());
- _snap_if_closer(p_value, begin, r_current_snap, r_snapped, ci_transform.get_rotation());
- _snap_if_closer(p_value, end, r_current_snap, r_snapped, ci_transform.get_rotation());
+ _snap_if_closer_point(p_value, begin, r_current_snap, r_snapped, ci_transform.get_rotation());
+ _snap_if_closer_point(p_value, end, r_current_snap, r_snapped, ci_transform.get_rotation());
}
}
for (int i = 0; i < p_current->get_child_count(); i++) {
@@ -291,9 +288,9 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
}
if (can_snap) {
- _snap_if_closer(p_target, begin, output, snapped, rotation);
- _snap_if_closer(p_target, (begin + end) / 2.0, output, snapped, rotation);
- _snap_if_closer(p_target, end, output, snapped, rotation);
+ _snap_if_closer_point(p_target, begin, output, snapped, rotation);
+ _snap_if_closer_point(p_target, (begin + end) / 2.0, output, snapped, rotation);
+ _snap_if_closer_point(p_target, end, output, snapped, rotation);
}
}
@@ -302,8 +299,8 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
if (const Control *c = Object::cast_to<Control>(p_canvas_item)) {
begin = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(MARGIN_LEFT), c->get_anchor(MARGIN_TOP))));
end = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(MARGIN_RIGHT), c->get_anchor(MARGIN_BOTTOM))));
- _snap_if_closer(p_target, begin, output, snapped, rotation);
- _snap_if_closer(p_target, end, output, snapped, rotation);
+ _snap_if_closer_point(p_target, begin, output, snapped, rotation);
+ _snap_if_closer_point(p_target, end, output, snapped, rotation);
}
}
@@ -311,17 +308,34 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
if ((snap_active && snap_node_sides && (p_modes & SNAP_NODE_SIDES)) || (p_forced_modes & SNAP_NODE_SIDES)) {
begin = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->get_item_rect().get_position());
end = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->get_item_rect().get_position() + p_canvas_item->get_item_rect().get_size());
- _snap_if_closer(p_target, begin, output, snapped, rotation);
- _snap_if_closer(p_target, end, output, snapped, rotation);
+ _snap_if_closer_point(p_target, begin, output, snapped, rotation);
+ _snap_if_closer_point(p_target, end, output, snapped, rotation);
+ }
+ }
+
+ // Other nodes sides
+ if ((snap_active && snap_other_nodes && (p_modes & SNAP_OTHER_NODES)) || (p_forced_modes & SNAP_OTHER_NODES)) {
+ _snap_other_nodes(p_target, output, snapped, get_tree()->get_edited_scene_root(), p_canvas_item);
+ }
+
+ if (((snap_active && snap_guides && (p_modes & SNAP_GUIDES)) || (p_forced_modes & SNAP_GUIDES)) && fmod(rotation, (real_t)360.0) == 0.0) {
+ // Guides
+ if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) {
+ Array vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_");
+ for (int i = 0; i < vguides.size(); i++) {
+ _snap_if_closer_float(p_target.x, vguides[i], output.x, snapped[0]);
+ }
}
- // Other nodes sides
- if ((snap_active && snap_other_nodes && (p_modes & SNAP_OTHER_NODES)) || (p_forced_modes & SNAP_OTHER_NODES)) {
- _snap_other_nodes(p_target, output, snapped, get_tree()->get_edited_scene_root(), p_canvas_item);
+ if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) {
+ Array hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_");
+ for (int i = 0; i < hguides.size(); i++) {
+ _snap_if_closer_float(p_target.y, hguides[i], output.y, snapped[1]);
+ }
}
}
- if (((snap_active && snap_grid && (p_modes & SNAP_GRID)) || (p_forced_modes & SNAP_GRID)) && rotation == 0.0) {
+ if (((snap_active && snap_grid && (p_modes & SNAP_GRID)) || (p_forced_modes & SNAP_GRID)) && fmod(rotation, (real_t)360.0) == 0.0) {
// Grid
Point2 offset = grid_offset;
if (snap_relative) {
@@ -335,7 +349,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
Point2 grid_output;
grid_output.x = Math::stepify(p_target.x - offset.x, grid_step.x * Math::pow(2.0, grid_step_multiplier)) + offset.x;
grid_output.y = Math::stepify(p_target.y - offset.y, grid_step.y * Math::pow(2.0, grid_step_multiplier)) + offset.y;
- _snap_if_closer(p_target, grid_output, output, snapped, 0.0, -1.0);
+ _snap_if_closer_point(p_target, grid_output, output, snapped, 0.0, -1.0);
}
if (((snap_pixel && (p_modes & SNAP_PIXEL)) || (p_forced_modes & SNAP_PIXEL)) && rotation == 0.0) {
@@ -429,8 +443,10 @@ Dictionary CanvasItemEditor::get_state() const {
state["snap_node_sides"] = snap_node_sides;
state["snap_other_nodes"] = snap_other_nodes;
state["snap_grid"] = snap_grid;
+ state["snap_guides"] = snap_guides;
state["show_grid"] = show_grid;
state["show_rulers"] = show_rulers;
+ state["show_guides"] = show_guides;
state["show_helpers"] = show_helpers;
state["snap_rotation"] = snap_rotation;
state["snap_relative"] = snap_relative;
@@ -497,6 +513,12 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
smartsnap_config_popup->set_item_checked(idx, snap_other_nodes);
}
+ if (state.has("snap_guides")) {
+ snap_guides = state["snap_guides"];
+ int idx = smartsnap_config_popup->get_item_index(SNAP_USE_GUIDES);
+ smartsnap_config_popup->set_item_checked(idx, snap_guides);
+ }
+
if (state.has("snap_grid")) {
snap_grid = state["snap_grid"];
int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_GRID);
@@ -515,6 +537,12 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
view_menu->get_popup()->set_item_checked(idx, show_rulers);
}
+ if (state.has("show_guides")) {
+ show_guides = state["show_guides"];
+ int idx = view_menu->get_popup()->get_item_index(SHOW_GUIDES);
+ view_menu->get_popup()->set_item_checked(idx, show_guides);
+ }
+
if (state.has("show_helpers")) {
show_helpers = state["show_helpers"];
int idx = view_menu->get_popup()->get_item_index(SHOW_HELPERS);
@@ -1198,14 +1226,215 @@ void CanvasItemEditor::_update_cursor() {
viewport->set_default_cursor_shape(c);
}
-void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event) {
+void CanvasItemEditor::_gui_input_viewport_base(const Ref<InputEvent> &p_event) {
+
+ Ref<InputEventMouseButton> b = p_event;
+ if (b.is_valid()) {
+ if (b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
+ if (show_guides && show_rulers && EditorNode::get_singleton()->get_edited_scene()) {
+ Transform2D xform = viewport_scrollable->get_transform() * transform;
+ // Retreive the guide lists
+ Array vguides;
+ if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) {
+ vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_");
+ }
+ Array hguides;
+ if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) {
+ hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_");
+ }
+
+ // Press button
+ if (b->get_position().x < RULER_WIDTH && b->get_position().y < RULER_WIDTH) {
+ // Drag a new double guide
+ drag = DRAG_DOUBLE_GUIDE;
+ edited_guide_index = -1;
+ } else if (b->get_position().x < RULER_WIDTH) {
+ // Check if we drag an existing horizontal guide
+ float minimum = 1e20;
+ edited_guide_index = -1;
+ for (int i = 0; i < hguides.size(); i++) {
+ if (ABS(xform.xform(Point2(0, hguides[i])).y - b->get_position().y) < MIN(minimum, 8)) {
+ edited_guide_index = i;
+ }
+ }
+
+ if (edited_guide_index >= 0) {
+ // Drag an existing horizontal guide
+ drag = DRAG_H_GUIDE;
+ } else {
+ // Drag a new vertical guide
+ drag = DRAG_V_GUIDE;
+ }
+ } else if (b->get_position().y < RULER_WIDTH) {
+ // Check if we drag an existing vertical guide
+ float minimum = 1e20;
+ edited_guide_index = -1;
+ for (int i = 0; i < vguides.size(); i++) {
+ if (ABS(xform.xform(Point2(vguides[i], 0)).x - b->get_position().x) < MIN(minimum, 8)) {
+ edited_guide_index = i;
+ }
+ }
+
+ if (edited_guide_index >= 0) {
+ // Drag an existing vertical guide
+ drag = DRAG_V_GUIDE;
+ } else {
+ // Drag a new vertical guide
+ drag = DRAG_H_GUIDE;
+ }
+ }
+ }
+ }
+
+ if (b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
+ // Release button
+ if (show_guides && EditorNode::get_singleton()->get_edited_scene()) {
+ Transform2D xform = viewport_scrollable->get_transform() * transform;
+
+ // Retreive the guide lists
+ Array vguides;
+ if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) {
+ vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_");
+ }
+ Array hguides;
+ if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) {
+ hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_");
+ }
+
+ Point2 edited = snap_point(xform.affine_inverse().xform(b->get_position()), SNAP_GRID | SNAP_PIXEL | SNAP_OTHER_NODES);
+ if (drag == DRAG_V_GUIDE) {
+ Array prev_vguides = vguides.duplicate();
+ if (b->get_position().x > RULER_WIDTH) {
+ // Adds a new vertical guide
+ if (edited_guide_index >= 0) {
+ vguides[edited_guide_index] = edited.x;
+ undo_redo->create_action(TTR("Move vertical guide"));
+ undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
+ undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
+ undo_redo->add_undo_method(viewport_base, "update");
+ undo_redo->commit_action();
+ } else {
+ vguides.push_back(edited.x);
+ undo_redo->create_action(TTR("Create new vertical guide"));
+ undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
+ undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
+ undo_redo->add_undo_method(viewport_base, "update");
+ undo_redo->commit_action();
+ }
+ } else {
+ if (edited_guide_index >= 0) {
+ vguides.remove(edited_guide_index);
+ undo_redo->create_action(TTR("Remove vertical guide"));
+ undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
+ undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
+ undo_redo->add_undo_method(viewport_base, "update");
+ undo_redo->commit_action();
+ }
+ }
+ } else if (drag == DRAG_H_GUIDE) {
+ Array prev_hguides = hguides.duplicate();
+ if (b->get_position().y > RULER_WIDTH) {
+ // Adds a new horizontal guide
+ if (edited_guide_index >= 0) {
+ hguides[edited_guide_index] = edited.y;
+ undo_redo->create_action(TTR("Move horizontal guide"));
+ undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
+ undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
+ undo_redo->add_undo_method(viewport_base, "update");
+ undo_redo->commit_action();
+ } else {
+ hguides.push_back(edited.y);
+ undo_redo->create_action(TTR("Create new horizontal guide"));
+ undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
+ undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
+ undo_redo->add_undo_method(viewport_base, "update");
+ undo_redo->commit_action();
+ }
+ } else {
+ if (edited_guide_index >= 0) {
+ hguides.remove(edited_guide_index);
+ undo_redo->create_action(TTR("Remove horizontal guide"));
+ undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
+ undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
+ undo_redo->add_undo_method(viewport_base, "update");
+ undo_redo->commit_action();
+ }
+ }
+ } else if (drag == DRAG_DOUBLE_GUIDE) {
+ Array prev_hguides = hguides.duplicate();
+ Array prev_vguides = vguides.duplicate();
+ if (b->get_position().x > RULER_WIDTH && b->get_position().y > RULER_WIDTH) {
+ // Adds a new horizontal guide a new vertical guide
+ vguides.push_back(edited.x);
+ hguides.push_back(edited.y);
+ undo_redo->create_action(TTR("Create new horizontal and vertical guides"));
+ undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
+ undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
+ undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
+ undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
+ undo_redo->add_undo_method(viewport_base, "update");
+ undo_redo->commit_action();
+ }
+ }
+ }
+ if (drag == DRAG_DOUBLE_GUIDE || drag == DRAG_V_GUIDE || drag == DRAG_H_GUIDE) {
+ drag = DRAG_NONE;
+ viewport_base->update();
+ }
+ }
+ }
+
+ Ref<InputEventMouseMotion> m = p_event;
+ if (m.is_valid()) {
+ if (!viewport_base->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) {
+ viewport_base->call_deferred("grab_focus");
+ }
+ if (drag == DRAG_DOUBLE_GUIDE || drag == DRAG_H_GUIDE || drag == DRAG_V_GUIDE) {
+ Transform2D xform = viewport_scrollable->get_transform() * transform;
+ Point2 mouse_pos = m->get_position();
+ mouse_pos = xform.affine_inverse().xform(mouse_pos);
+ mouse_pos = xform.xform(snap_point(mouse_pos, SNAP_GRID | SNAP_PIXEL | SNAP_OTHER_NODES));
+
+ edited_guide_pos = mouse_pos;
+ viewport_base->update();
+ }
+ }
+
+ Ref<InputEventKey> k = p_event;
+ if (k.is_valid()) {
+ if (k->is_pressed() && drag == DRAG_NONE) {
+ // Move the object with the arrow keys
+ KeyMoveMODE move_mode = MOVE_VIEW_BASE;
+ if (k->get_alt()) move_mode = MOVE_LOCAL_BASE;
+ if (k->get_control() || k->get_metakey()) move_mode = MOVE_LOCAL_WITH_ROT;
+
+ if (k->get_scancode() == KEY_UP)
+ _key_move(Vector2(0, -1), k->get_shift(), move_mode);
+ else if (k->get_scancode() == KEY_DOWN)
+ _key_move(Vector2(0, 1), k->get_shift(), move_mode);
+ else if (k->get_scancode() == KEY_LEFT)
+ _key_move(Vector2(-1, 0), k->get_shift(), move_mode);
+ else if (k->get_scancode() == KEY_RIGHT)
+ _key_move(Vector2(1, 0), k->get_shift(), move_mode);
+ else if (k->get_scancode() == KEY_ESCAPE) {
+ editor_selection->clear();
+ viewport->update();
+ } else
+ return;
+
+ accept_event();
+ }
+ }
+}
+
+void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
{
EditorNode *en = editor;
EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
if (!over_plugin_list->empty()) {
- bool discard = over_plugin_list->forward_gui_input(transform, p_event);
+ bool discard = over_plugin_list->forward_gui_input(p_event);
if (discard) {
accept_event();
return;
@@ -1224,7 +1453,7 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
_update_scroll(0);
viewport->update();
} else {
- _zoom_on_position(zoom * (1 - (0.05 * b->get_factor())), viewport_scrollable->get_transform().affine_inverse().xform(b->get_position()));
+ _zoom_on_position(zoom * (1 - (0.05 * b->get_factor())), b->get_position());
}
return;
@@ -1237,7 +1466,7 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
_update_scroll(0);
viewport->update();
} else {
- _zoom_on_position(zoom * ((0.95 + (0.05 * b->get_factor())) / 0.95), viewport_scrollable->get_transform().affine_inverse().xform(b->get_position()));
+ _zoom_on_position(zoom * ((0.95 + (0.05 * b->get_factor())) / 0.95), b->get_position());
}
return;
@@ -1320,7 +1549,7 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
if (b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) {
if (b->is_pressed()) {
// Set the pivot point
- Point2 mouse_pos = viewport_scrollable->get_transform().affine_inverse().xform(b->get_position());
+ Point2 mouse_pos = b->get_position();
mouse_pos = transform.affine_inverse().xform(mouse_pos);
mouse_pos = snap_point(mouse_pos, SNAP_DEFAULT, _get_single_item());
_edit_set_pivot(mouse_pos);
@@ -1443,8 +1672,8 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
E->get().to
};
- Vector2 p = Geometry::get_closest_point_to_segment_2d(viewport_scrollable->get_transform().affine_inverse().xform(b->get_position()), s);
- float d = p.distance_to(viewport_scrollable->get_transform().affine_inverse().xform(b->get_position()));
+ Vector2 p = Geometry::get_closest_point_to_segment_2d(b->get_position(), s);
+ float d = p.distance_to(b->get_position());
if (d < bone_width && d < closest_dist) {
Cbone = E;
closest_dist = d;
@@ -1506,7 +1735,7 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
ERR_FAIL_COND(!se);
- Point2 click = viewport_scrollable->get_transform().affine_inverse().xform(b->get_position());
+ Point2 click = b->get_position();
// Rotation
if ((b->get_control() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
@@ -1561,7 +1790,7 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
}
// Multiple selected items
- Point2 click = viewport_scrollable->get_transform().affine_inverse().xform(b->get_position());
+ Point2 click = b->get_position();
if ((b->get_alt() || tool == TOOL_MOVE) && get_item_count()) {
// Drag the nodes
@@ -1621,12 +1850,9 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
// Mouse motion event
_update_cursor();
- if (!viewport_base->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
- viewport_base->call_deferred("grab_focus");
-
if (box_selecting) {
// Update box selection
- box_selecting_to = transform.affine_inverse().xform(viewport_scrollable->get_transform().affine_inverse().xform(m->get_position()));
+ box_selecting_to = transform.affine_inverse().xform(m->get_position());
viewport->update();
return;
}
@@ -1672,7 +1898,7 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
}
Vector2 dfrom = drag_from;
- Vector2 dto = transform.affine_inverse().xform(viewport_scrollable->get_transform().affine_inverse().xform(m->get_position()));
+ Vector2 dto = transform.affine_inverse().xform(m->get_position());
if (canvas_item->has_meta("_edit_lock_"))
continue;
@@ -1735,7 +1961,7 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
Vector2 anchor = c_trans_rev.xform(dto - drag_from + drag_point_from);
anchor = _position_to_anchor(control, anchor);
- Vector2 anchor_snapped = c_trans_rev.xform(snap_point(dto - drag_from + drag_point_from, SNAP_GRID | SNAP_OTHER_NODES, _get_single_item(), SNAP_NODE_PARENT | SNAP_NODE_SIDES));
+ Vector2 anchor_snapped = c_trans_rev.xform(snap_point(dto - drag_from + drag_point_from, SNAP_GRID | SNAP_GUIDES | SNAP_OTHER_NODES, _get_single_item(), SNAP_NODE_PARENT | SNAP_NODE_SIDES));
anchor_snapped = _position_to_anchor(control, anchor_snapped).snapped(Vector2(0.00001, 0.00001));
bool use_y = Math::abs(drag_vector.y) > Math::abs(drag_vector.x);
@@ -1771,7 +1997,7 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
}
dfrom = drag_point_from;
- dto = snap_point(dto, SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, _get_single_item());
+ dto = snap_point(dto, SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL, _get_single_item());
drag_vector =
canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dto) -
@@ -1995,32 +2221,6 @@ void CanvasItemEditor::_viewport_base_gui_input(const Ref<InputEvent> &p_event)
}
}
}
-
- Ref<InputEventKey> k = p_event;
- if (k.is_valid()) {
- if (k->is_pressed() && drag == DRAG_NONE) {
- // Move the object with the arrow keys
- KeyMoveMODE move_mode = MOVE_VIEW_BASE;
- if (k->get_alt()) move_mode = MOVE_LOCAL_BASE;
- if (k->get_control() || k->get_metakey()) move_mode = MOVE_LOCAL_WITH_ROT;
-
- if (k->get_scancode() == KEY_UP)
- _key_move(Vector2(0, -1), k->get_shift(), move_mode);
- else if (k->get_scancode() == KEY_DOWN)
- _key_move(Vector2(0, 1), k->get_shift(), move_mode);
- else if (k->get_scancode() == KEY_LEFT)
- _key_move(Vector2(-1, 0), k->get_shift(), move_mode);
- else if (k->get_scancode() == KEY_RIGHT)
- _key_move(Vector2(1, 0), k->get_shift(), move_mode);
- else if (k->get_scancode() == KEY_ESCAPE) {
- editor_selection->clear();
- viewport->update();
- } else
- return;
-
- accept_event();
- }
- }
}
void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string, Margin p_side) {
@@ -2059,6 +2259,58 @@ void CanvasItemEditor::_draw_percentage_at_position(float p_value, Point2 p_posi
}
}
+void CanvasItemEditor::_draw_focus() {
+ // Draw the focus around the base viewport
+ if (viewport_base->has_focus()) {
+ get_stylebox("Focus", "EditorStyles")->draw(viewport_base->get_canvas_item(), Rect2(Point2(), viewport_base->get_size()));
+ }
+}
+
+void CanvasItemEditor::_draw_guides() {
+
+ Color guide_color = Color(0.6, 0.0, 0.8);
+ Transform2D xform = viewport_scrollable->get_transform() * transform;
+
+ // Guides already there
+ if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) {
+ Array vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_");
+ for (int i = 0; i < vguides.size(); i++) {
+ if (drag == DRAG_V_GUIDE && i == edited_guide_index)
+ continue;
+ float x = xform.xform(Point2(vguides[i], 0)).x;
+ viewport_base->draw_line(Point2(x, 0), Point2(x, viewport_base->get_size().y), guide_color);
+ }
+ }
+
+ if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) {
+ Array hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_");
+ for (int i = 0; i < hguides.size(); i++) {
+ if (drag == DRAG_H_GUIDE && i == edited_guide_index)
+ continue;
+ float y = xform.xform(Point2(0, hguides[i])).y;
+ viewport_base->draw_line(Point2(0, y), Point2(viewport_base->get_size().x, y), guide_color);
+ }
+ }
+
+ // Dragged guide
+ Color text_color = get_color("font_color", "Editor");
+ text_color.a = 0.5;
+ if (drag == DRAG_DOUBLE_GUIDE || drag == DRAG_V_GUIDE) {
+ String str = vformat("%d px", xform.affine_inverse().xform(edited_guide_pos).x);
+ Ref<Font> font = get_font("font", "Label");
+ Size2 text_size = font->get_string_size(str);
+ viewport_base->draw_string(font, Point2(edited_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, text_color);
+ viewport_base->draw_line(Point2(edited_guide_pos.x, 0), Point2(edited_guide_pos.x, viewport_base->get_size().y), guide_color);
+ }
+ if (drag == DRAG_DOUBLE_GUIDE || drag == DRAG_H_GUIDE) {
+ String str = vformat("%d px", xform.affine_inverse().xform(edited_guide_pos).y);
+ Ref<Font> font = get_font("font", "Label");
+ Size2 text_size = font->get_string_size(str);
+ viewport_base->draw_string(font, Point2(RULER_WIDTH + 10, edited_guide_pos.y + text_size.y / 2 + 10), str, text_color);
+ viewport_base->draw_line(Point2(0, edited_guide_pos.y), Point2(viewport_base->get_size().x, edited_guide_pos.y), guide_color);
+ }
+}
+
void CanvasItemEditor::_draw_rulers() {
Color graduation_color = get_color("font_color", "Editor");
graduation_color.a = 0.5;
@@ -2143,12 +2395,6 @@ void CanvasItemEditor::_draw_rulers() {
viewport_base->draw_rect(Rect2(Point2(), Size2(RULER_WIDTH, RULER_WIDTH)), graduation_color);
}
-void CanvasItemEditor::_draw_focus() {
- if (viewport_base->has_focus()) {
- get_stylebox("Focus", "EditorStyles")->draw(viewport_base->get_canvas_item(), Rect2(Point2(), viewport_base->get_size()));
- }
-}
-
void CanvasItemEditor::_draw_grid() {
if (show_grid) {
//Draw the grid
@@ -2159,8 +2405,8 @@ void CanvasItemEditor::_draw_grid() {
Vector2 real_grid_offset;
if (snap_relative && get_item_count() > 0) {
Vector2 topleft = _find_topleftmost_point();
- real_grid_offset.x = fmod(topleft.x, grid_step.x * Math::pow(2.0, grid_step_multiplier));
- real_grid_offset.y = fmod(topleft.y, grid_step.y * Math::pow(2.0, grid_step_multiplier));
+ real_grid_offset.x = fmod(topleft.x, grid_step.x * (real_t)Math::pow(2.0, grid_step_multiplier));
+ real_grid_offset.y = fmod(topleft.y, grid_step.y * (real_t)Math::pow(2.0, grid_step_multiplier));
} else {
real_grid_offset = grid_offset;
}
@@ -2634,6 +2880,8 @@ void CanvasItemEditor::_get_encompassing_rect(Node *p_node, Rect2 &r_rect, const
void CanvasItemEditor::_draw_viewport_base() {
if (show_rulers)
_draw_rulers();
+ if (show_guides)
+ _draw_guides();
_draw_focus();
}
@@ -2681,9 +2929,8 @@ void CanvasItemEditor::_draw_viewport() {
EditorPluginList *over_plugin_list = editor->get_editor_plugins_over();
if (!over_plugin_list->empty()) {
- over_plugin_list->forward_draw_over_canvas(transform, viewport);
+ over_plugin_list->forward_draw_over_canvas(viewport);
}
- _draw_focus();
_draw_bones();
}
@@ -3121,6 +3368,11 @@ void CanvasItemEditor::_popup_callback(int p_op) {
int idx = smartsnap_config_popup->get_item_index(SNAP_USE_OTHER_NODES);
smartsnap_config_popup->set_item_checked(idx, snap_other_nodes);
} break;
+ case SNAP_USE_GUIDES: {
+ snap_guides = !snap_guides;
+ int idx = smartsnap_config_popup->get_item_index(SNAP_USE_GUIDES);
+ smartsnap_config_popup->set_item_checked(idx, snap_guides);
+ } break;
case SNAP_USE_GRID: {
snap_grid = !snap_grid;
int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_GRID);
@@ -3166,6 +3418,13 @@ void CanvasItemEditor::_popup_callback(int p_op) {
viewport->update();
viewport_base->update();
} break;
+ case SHOW_GUIDES: {
+ show_guides = !show_guides;
+ int idx = view_menu->get_popup()->get_item_index(SHOW_GUIDES);
+ view_menu->get_popup()->set_item_checked(idx, show_guides);
+ viewport->update();
+ viewport_base->update();
+ } break;
case LOCK_SELECTED: {
@@ -3433,7 +3692,6 @@ void CanvasItemEditor::_popup_callback(int p_op) {
case ANIM_INSERT_POS_SCALE:
case ANIM_INSERT_ROT_SCALE:
case ANIM_INSERT_POS_ROT_SCALE: {
-
static const bool key_toggles[7][3]={
{true,false,false},
{false,true,false},
@@ -3446,12 +3704,10 @@ void CanvasItemEditor::_popup_callback(int p_op) {
key_pos=key_toggles[p_op-ANIM_INSERT_POS][0];
key_rot=key_toggles[p_op-ANIM_INSERT_POS][1];
key_scale=key_toggles[p_op-ANIM_INSERT_POS][2];
-
for(int i=ANIM_INSERT_POS;i<=ANIM_INSERT_POS_ROT_SCALE;i++) {
int idx = animation_menu->get_popup()->get_item_index(i);
animation_menu->get_popup()->set_item_checked(idx,i==p_op);
}
-
} break;*/
case ANIM_COPY_POSE: {
@@ -3694,7 +3950,8 @@ void CanvasItemEditor::_bind_methods() {
ClassDB::bind_method("_unhandled_key_input", &CanvasItemEditor::_unhandled_key_input);
ClassDB::bind_method("_draw_viewport", &CanvasItemEditor::_draw_viewport);
ClassDB::bind_method("_draw_viewport_base", &CanvasItemEditor::_draw_viewport_base);
- ClassDB::bind_method("_viewport_base_gui_input", &CanvasItemEditor::_viewport_base_gui_input);
+ ClassDB::bind_method("_gui_input_viewport", &CanvasItemEditor::_gui_input_viewport);
+ ClassDB::bind_method("_gui_input_viewport_base", &CanvasItemEditor::_gui_input_viewport_base);
ClassDB::bind_method("_snap_changed", &CanvasItemEditor::_snap_changed);
ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &CanvasItemEditor::_selection_result_pressed);
ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &CanvasItemEditor::_selection_menu_hide);
@@ -3747,7 +4004,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
palette_split->add_child(viewport_base);
viewport_base->set_clip_contents(true);
viewport_base->connect("draw", this, "_draw_viewport_base");
- viewport_base->connect("gui_input", this, "_viewport_base_gui_input");
+ viewport_base->connect("gui_input", this, "_gui_input_viewport_base");
viewport_base->set_focus_mode(FOCUS_ALL);
viewport_base->set_v_size_flags(SIZE_EXPAND_FILL);
viewport_base->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -3771,6 +4028,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
viewport->set_anchors_and_margins_preset(Control::PRESET_WIDE);
viewport->set_clip_contents(true);
viewport->connect("draw", this, "_draw_viewport");
+ viewport->connect("gui_input", this, "_gui_input_viewport");
h_scroll = memnew(HScrollBar);
viewport->add_child(h_scroll);
@@ -3880,6 +4138,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_anchors", TTR("Snap to node anchor")), SNAP_USE_NODE_ANCHORS);
smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_sides", TTR("Snap to node sides")), SNAP_USE_NODE_SIDES);
smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_other_nodes", TTR("Snap to other nodes")), SNAP_USE_OTHER_NODES);
+ smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_guides", TTR("Snap to guides")), SNAP_USE_GUIDES);
hb->add_child(memnew(VSeparator));
@@ -3931,6 +4190,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Show Grid"), KEY_G), SHOW_GRID);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show helpers"), KEY_H), SHOW_HELPERS);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show rulers"), KEY_R), SHOW_RULERS);
+ p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_guides", TTR("Show guides"), KEY_Y), SHOW_GUIDES);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), KEY_F), VIEW_CENTER_TO_SELECTION);
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/frame_selection", TTR("Frame Selection"), KEY_MASK_SHIFT | KEY_F), VIEW_FRAME_TO_SELECTION);
@@ -4018,9 +4278,13 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
key_rot = true;
key_scale = false;
+ edited_guide_pos = Point2();
+ edited_guide_index = -1;
+
show_grid = false;
show_helpers = false;
show_rulers = false;
+ show_guides = true;
zoom = 1;
grid_offset = Point2();
grid_step = Point2(10, 10);
@@ -4033,6 +4297,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
snap_node_sides = true;
snap_other_nodes = true;
snap_grid = true;
+ snap_guides = true;
snap_rotation = false;
snap_pixel = false;
skeleton_show_bones = true;
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 69dc25d180..97e3b03569 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -87,6 +87,7 @@ class CanvasItemEditor : public VBoxContainer {
SNAP_USE_NODE_SIDES,
SNAP_USE_OTHER_NODES,
SNAP_USE_GRID,
+ SNAP_USE_GUIDES,
SNAP_USE_ROTATION,
SNAP_RELATIVE,
SNAP_CONFIGURE,
@@ -94,6 +95,7 @@ class CanvasItemEditor : public VBoxContainer {
SHOW_GRID,
SHOW_HELPERS,
SHOW_RULERS,
+ SHOW_GUIDES,
LOCK_SELECTED,
UNLOCK_SELECTED,
GROUP_SELECTED,
@@ -183,6 +185,9 @@ class CanvasItemEditor : public VBoxContainer {
DRAG_ROTATE,
DRAG_PIVOT,
DRAG_NODE_2D,
+ DRAG_V_GUIDE,
+ DRAG_H_GUIDE,
+ DRAG_DOUBLE_GUIDE,
};
enum KeyMoveMODE {
@@ -213,6 +218,7 @@ class CanvasItemEditor : public VBoxContainer {
Transform2D transform;
bool show_grid;
bool show_rulers;
+ bool show_guides;
bool show_helpers;
float zoom;
@@ -228,6 +234,7 @@ class CanvasItemEditor : public VBoxContainer {
bool snap_node_sides;
bool snap_other_nodes;
bool snap_grid;
+ bool snap_guides;
bool snap_rotation;
bool snap_relative;
bool snap_pixel;
@@ -333,6 +340,9 @@ class CanvasItemEditor : public VBoxContainer {
Point2 display_rotate_from;
Point2 display_rotate_to;
+ int edited_guide_index;
+ Point2 edited_guide_pos;
+
Ref<StyleBoxTexture> select_sb;
Ref<Texture> select_handle;
Ref<Texture> anchor_handle;
@@ -402,6 +412,7 @@ class CanvasItemEditor : public VBoxContainer {
void _draw_percentage_at_position(float p_value, Point2 p_position, Margin p_side);
void _draw_rulers();
+ void _draw_guides();
void _draw_focus();
void _draw_grid();
void _draw_selection();
@@ -410,14 +421,16 @@ class CanvasItemEditor : public VBoxContainer {
void _draw_locks_and_groups(Node *p_node, const Transform2D &p_xform);
void _draw_viewport();
-
- void _viewport_base_gui_input(const Ref<InputEvent> &p_event);
void _draw_viewport_base();
+ void _gui_input_viewport(const Ref<InputEvent> &p_event);
+ void _gui_input_viewport_base(const Ref<InputEvent> &p_event);
+
void _focus_selection(int p_op);
- void _snap_if_closer(Point2 p_value, Point2 p_target_snap, Point2 &r_current_snap, bool (&r_snapped)[2], real_t rotation = 0.0, float p_radius = 10.0);
- void _snap_other_nodes(Point2 p_value, Point2 &r_current_snap, bool (&r_snapped)[2], const Node *p_current, const CanvasItem *p_to_snap);
+ void _snap_if_closer_float(float p_value, float p_target_snap, float &r_current_snap, bool &r_snapped, float p_radius = 10.0);
+ void _snap_if_closer_point(Point2 p_value, Point2 p_target_snap, Point2 &r_current_snap, bool (&r_snapped)[2], real_t rotation = 0.0, float p_radius = 10.0);
+ void _snap_other_nodes(Point2 p_value, Point2 &r_current_snap, bool (&r_snapped)[2], const Node *p_current, const CanvasItem *p_to_snap = NULL);
void _set_anchors_preset(Control::LayoutPreset p_preset);
void _set_margins_preset(Control::LayoutPreset p_preset);
@@ -475,13 +488,14 @@ protected:
public:
enum SnapMode {
SNAP_GRID = 1 << 0,
- SNAP_PIXEL = 1 << 1,
- SNAP_NODE_PARENT = 1 << 2,
- SNAP_NODE_ANCHORS = 1 << 3,
- SNAP_NODE_SIDES = 1 << 4,
- SNAP_OTHER_NODES = 1 << 5,
-
- SNAP_DEFAULT = 0x03,
+ SNAP_GUIDES = 1 << 1,
+ SNAP_PIXEL = 1 << 2,
+ SNAP_NODE_PARENT = 1 << 3,
+ SNAP_NODE_ANCHORS = 1 << 4,
+ SNAP_NODE_SIDES = 1 << 5,
+ SNAP_OTHER_NODES = 1 << 6,
+
+ SNAP_DEFAULT = 0x07,
};
Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, const CanvasItem *p_canvas_item = NULL, unsigned int p_forced_modes = 0);
diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/editor/plugins/collision_polygon_2d_editor_plugin.cpp
index 00e6d617a1..00e6d617a1 100755..100644
--- a/editor/plugins/collision_polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_polygon_2d_editor_plugin.cpp
diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.h b/editor/plugins/collision_polygon_2d_editor_plugin.h
index edf3bbcc08..edf3bbcc08 100755..100644
--- a/editor/plugins/collision_polygon_2d_editor_plugin.h
+++ b/editor/plugins/collision_polygon_2d_editor_plugin.h
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index 3e6165e552..005de096cd 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -302,7 +302,7 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
undo_redo->commit_action();
}
-bool CollisionShape2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
+bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
if (!node) {
return false;
@@ -317,17 +317,17 @@ bool CollisionShape2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mb = p_event;
+ Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
if (mb.is_valid()) {
- Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
-
- Point2 gpoint(mb->get_position().x, mb->get_position().y);
+ Vector2 gpoint = mb->get_position();
+ Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position())));
if (mb->get_button_index() == BUTTON_LEFT) {
if (mb->is_pressed()) {
for (int i = 0; i < handles.size(); i++) {
- if (gt.xform(handles[i]).distance_to(gpoint) < 8) {
+ if (xform.xform(handles[i]).distance_to(gpoint) < 8) {
edit_handle = i;
break;
@@ -368,9 +368,7 @@ bool CollisionShape2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
- Point2 gpoint = mm->get_position();
- Point2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
- cpoint = canvas_item_editor->snap_point(cpoint);
+ Vector2 cpoint = canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mm->get_position()));
cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
set_handle(edit_handle, cpoint);
@@ -416,7 +414,7 @@ void CollisionShape2DEditor::_get_current_shape_type() {
canvas_item_editor->get_viewport_control()->update();
}
-void CollisionShape2DEditor::_canvas_draw() {
+void CollisionShape2DEditor::forward_draw_over_canvas(Control *p_canvas) {
if (!node) {
return;
@@ -432,7 +430,6 @@ void CollisionShape2DEditor::_canvas_draw() {
return;
}
- Control *c = canvas_item_editor->get_viewport_control();
Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
Ref<Texture> h = get_icon("EditorHandle", "EditorIcons");
@@ -451,8 +448,8 @@ void CollisionShape2DEditor::_canvas_draw() {
handles[0] = Point2(radius, -height);
handles[1] = Point2(0, -(height + radius));
- c->draw_texture(h, gt.xform(handles[0]) - size);
- c->draw_texture(h, gt.xform(handles[1]) - size);
+ p_canvas->draw_texture(h, gt.xform(handles[0]) - size);
+ p_canvas->draw_texture(h, gt.xform(handles[1]) - size);
} break;
@@ -462,7 +459,7 @@ void CollisionShape2DEditor::_canvas_draw() {
handles.resize(1);
handles[0] = Point2(shape->get_radius(), 0);
- c->draw_texture(h, gt.xform(handles[0]) - size);
+ p_canvas->draw_texture(h, gt.xform(handles[0]) - size);
} break;
@@ -481,8 +478,8 @@ void CollisionShape2DEditor::_canvas_draw() {
handles[0] = shape->get_normal() * shape->get_d();
handles[1] = shape->get_normal() * (shape->get_d() + 30.0);
- c->draw_texture(h, gt.xform(handles[0]) - size);
- c->draw_texture(h, gt.xform(handles[1]) - size);
+ p_canvas->draw_texture(h, gt.xform(handles[0]) - size);
+ p_canvas->draw_texture(h, gt.xform(handles[1]) - size);
} break;
@@ -492,7 +489,7 @@ void CollisionShape2DEditor::_canvas_draw() {
handles.resize(1);
handles[0] = Point2(0, shape->get_length());
- c->draw_texture(h, gt.xform(handles[0]) - size);
+ p_canvas->draw_texture(h, gt.xform(handles[0]) - size);
} break;
@@ -504,8 +501,8 @@ void CollisionShape2DEditor::_canvas_draw() {
handles[0] = Point2(ext.x, 0);
handles[1] = Point2(0, -ext.y);
- c->draw_texture(h, gt.xform(handles[0]) - size);
- c->draw_texture(h, gt.xform(handles[1]) - size);
+ p_canvas->draw_texture(h, gt.xform(handles[0]) - size);
+ p_canvas->draw_texture(h, gt.xform(handles[1]) - size);
} break;
@@ -516,8 +513,8 @@ void CollisionShape2DEditor::_canvas_draw() {
handles[0] = shape->get_a();
handles[1] = shape->get_b();
- c->draw_texture(h, gt.xform(handles[0]) - size);
- c->draw_texture(h, gt.xform(handles[1]) - size);
+ p_canvas->draw_texture(h, gt.xform(handles[0]) - size);
+ p_canvas->draw_texture(h, gt.xform(handles[1]) - size);
} break;
}
@@ -532,18 +529,12 @@ void CollisionShape2DEditor::edit(Node *p_node) {
if (p_node) {
node = Object::cast_to<CollisionShape2D>(p_node);
- if (!canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->get_viewport_control()->connect("draw", this, "_canvas_draw");
-
_get_current_shape_type();
} else {
edit_handle = -1;
shape_type = -1;
- if (canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->get_viewport_control()->disconnect("draw", this, "_canvas_draw");
-
node = NULL;
}
@@ -552,7 +543,6 @@ void CollisionShape2DEditor::edit(Node *p_node) {
void CollisionShape2DEditor::_bind_methods() {
- ClassDB::bind_method("_canvas_draw", &CollisionShape2DEditor::_canvas_draw);
ClassDB::bind_method("_get_current_shape_type", &CollisionShape2DEditor::_get_current_shape_type);
}
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h
index ffa91952e0..d4fbe87fb3 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.h
+++ b/editor/plugins/collision_shape_2d_editor_plugin.h
@@ -68,13 +68,13 @@ class CollisionShape2DEditor : public Control {
void commit_handle(int idx, Variant &p_org);
void _get_current_shape_type();
- void _canvas_draw();
protected:
static void _bind_methods();
public:
- bool forward_gui_input(const Ref<InputEvent> &p_event);
+ bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
+ void forward_draw_over_canvas(Control *p_canvas);
void edit(Node *p_node);
CollisionShape2DEditor(EditorNode *p_editor);
@@ -87,7 +87,8 @@ class CollisionShape2DEditorPlugin : public EditorPlugin {
EditorNode *editor;
public:
- virtual bool forward_canvas_gui_input(const Transform2D &p_canvas_xform, const Ref<InputEvent> &p_event) { return collision_shape_2d_editor->forward_gui_input(p_event); }
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return collision_shape_2d_editor->forward_canvas_gui_input(p_event); }
+ virtual void forward_draw_over_canvas(Control *p_canvas) { return collision_shape_2d_editor->forward_draw_over_canvas(p_canvas); }
virtual String get_name() const { return "CollisionShape2D"; }
bool has_main_screen() const { return false; }
diff --git a/editor/plugins/gi_probe_editor_plugin.cpp b/editor/plugins/gi_probe_editor_plugin.cpp
index fcbf282758..443cd2e41f 100644
--- a/editor/plugins/gi_probe_editor_plugin.cpp
+++ b/editor/plugins/gi_probe_editor_plugin.cpp
@@ -60,6 +60,27 @@ void GIProbeEditorPlugin::make_visible(bool p_visible) {
}
}
+EditorProgress *GIProbeEditorPlugin::tmp_progress = NULL;
+
+void GIProbeEditorPlugin::bake_func_begin(int p_steps) {
+
+ ERR_FAIL_COND(tmp_progress != NULL);
+
+ tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake GI Probe"), p_steps));
+}
+
+void GIProbeEditorPlugin::bake_func_step(int p_step, const String &p_description) {
+
+ ERR_FAIL_COND(tmp_progress == NULL);
+ tmp_progress->step(p_description, p_step);
+}
+
+void GIProbeEditorPlugin::bake_func_end() {
+ ERR_FAIL_COND(tmp_progress == NULL);
+ memdelete(tmp_progress);
+ tmp_progress = NULL;
+}
+
void GIProbeEditorPlugin::_bind_methods() {
ClassDB::bind_method("_bake", &GIProbeEditorPlugin::_bake);
@@ -70,10 +91,15 @@ GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) {
editor = p_node;
bake = memnew(Button);
bake->set_icon(editor->get_gui_base()->get_icon("BakedLight", "EditorIcons"));
+ bake->set_text(TTR("Bake GI Probe"));
bake->hide();
bake->connect("pressed", this, "_bake");
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake);
gi_probe = NULL;
+
+ GIProbe::bake_begin_function = bake_func_begin;
+ GIProbe::bake_step_function = bake_func_step;
+ GIProbe::bake_end_function = bake_func_end;
}
GIProbeEditorPlugin::~GIProbeEditorPlugin() {
diff --git a/editor/plugins/gi_probe_editor_plugin.h b/editor/plugins/gi_probe_editor_plugin.h
index a1fecd2911..527f420510 100644
--- a/editor/plugins/gi_probe_editor_plugin.h
+++ b/editor/plugins/gi_probe_editor_plugin.h
@@ -44,6 +44,11 @@ class GIProbeEditorPlugin : public EditorPlugin {
Button *bake;
EditorNode *editor;
+ static EditorProgress *tmp_progress;
+ static void bake_func_begin(int p_steps);
+ static void bake_func_step(int p_step, const String &p_description);
+ static void bake_func_end();
+
void _bake();
protected:
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp
index ed0bc60d2f..485657d2c9 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.cpp
+++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp
@@ -119,9 +119,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
Vector2 gpoint = mb->get_position();
- Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
- cpoint = canvas_item_editor->snap_point(cpoint);
- cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
+ Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position())));
Vector<Vector2> poly = Variant(node->get_occluder_polygon()->get_polygon());
@@ -319,7 +317,8 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
-void LightOccluder2DEditor::_canvas_draw() {
+
+void LightOccluder2DEditor::forward_draw_over_canvas(Control *p_canvas) {
if (!node || !node->get_occluder_polygon().is_valid())
return;
@@ -368,17 +367,12 @@ void LightOccluder2DEditor::edit(Node *p_collision_polygon) {
if (p_collision_polygon) {
node = Object::cast_to<LightOccluder2D>(p_collision_polygon);
- if (!canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->get_viewport_control()->connect("draw", this, "_canvas_draw");
wip.clear();
wip_active = false;
edited_point = -1;
canvas_item_editor->get_viewport_control()->update();
} else {
node = NULL;
-
- if (canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->get_viewport_control()->disconnect("draw", this, "_canvas_draw");
}
}
@@ -395,7 +389,6 @@ void LightOccluder2DEditor::_create_poly() {
void LightOccluder2DEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_menu_option"), &LightOccluder2DEditor::_menu_option);
- ClassDB::bind_method(D_METHOD("_canvas_draw"), &LightOccluder2DEditor::_canvas_draw);
ClassDB::bind_method(D_METHOD("_node_removed"), &LightOccluder2DEditor::_node_removed);
ClassDB::bind_method(D_METHOD("_create_poly"), &LightOccluder2DEditor::_create_poly);
}
@@ -430,7 +423,7 @@ LightOccluder2DEditor::LightOccluder2DEditor(EditorNode *p_editor) {
void LightOccluder2DEditorPlugin::edit(Object *p_object) {
- collision_polygon_editor->edit(Object::cast_to<Node>(p_object));
+ light_occluder_editor->edit(Object::cast_to<Node>(p_object));
}
bool LightOccluder2DEditorPlugin::handles(Object *p_object) const {
@@ -441,21 +434,21 @@ bool LightOccluder2DEditorPlugin::handles(Object *p_object) const {
void LightOccluder2DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- collision_polygon_editor->show();
+ light_occluder_editor->show();
} else {
- collision_polygon_editor->hide();
- collision_polygon_editor->edit(NULL);
+ light_occluder_editor->hide();
+ light_occluder_editor->edit(NULL);
}
}
LightOccluder2DEditorPlugin::LightOccluder2DEditorPlugin(EditorNode *p_node) {
editor = p_node;
- collision_polygon_editor = memnew(LightOccluder2DEditor(p_node));
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
+ light_occluder_editor = memnew(LightOccluder2DEditor(p_node));
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(light_occluder_editor);
- collision_polygon_editor->hide();
+ light_occluder_editor->hide();
}
LightOccluder2DEditorPlugin::~LightOccluder2DEditorPlugin() {
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.h b/editor/plugins/light_occluder_2d_editor_plugin.h
index b270dcb6e5..068832d8ed 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.h
+++ b/editor/plugins/light_occluder_2d_editor_plugin.h
@@ -72,7 +72,6 @@ class LightOccluder2DEditor : public HBoxContainer {
ConfirmationDialog *create_poly;
void _wip_close(bool p_closed);
- void _canvas_draw();
void _menu_option(int p_option);
void _create_poly();
@@ -83,6 +82,7 @@ protected:
public:
Vector2 snap_point(const Vector2 &p_point) const;
+ void forward_draw_over_canvas(Control *p_canvas);
bool forward_gui_input(const Ref<InputEvent> &p_event);
void edit(Node *p_collision_polygon);
LightOccluder2DEditor(EditorNode *p_editor);
@@ -92,11 +92,12 @@ class LightOccluder2DEditorPlugin : public EditorPlugin {
GDCLASS(LightOccluder2DEditorPlugin, EditorPlugin);
- LightOccluder2DEditor *collision_polygon_editor;
+ LightOccluder2DEditor *light_occluder_editor;
EditorNode *editor;
public:
- virtual bool forward_canvas_gui_input(const Transform2D &p_canvas_xform, const Ref<InputEvent> &p_event) { return collision_polygon_editor->forward_gui_input(p_event); }
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return light_occluder_editor->forward_gui_input(p_event); }
+ virtual void forward_draw_over_canvas(Control *p_canvas) { return light_occluder_editor->forward_draw_over_canvas(p_canvas); }
virtual String get_name() const { return "LightOccluder2D"; }
bool has_main_screen() const { return false; }
diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp
index ef3ee6a78f..0533aaa9c0 100644
--- a/editor/plugins/line_2d_editor_plugin.cpp
+++ b/editor/plugins/line_2d_editor_plugin.cpp
@@ -54,16 +54,10 @@ void Line2DEditor::_notification(int p_what) {
}
}
-Vector2 Line2DEditor::mouse_to_local_pos(Vector2 gpos, bool alt) {
- Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
- return !alt ? canvas_item_editor->snap_point(xform.affine_inverse().xform(gpos)) : node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpos)));
-}
-
-int Line2DEditor::get_point_index_at(Vector2 gpos) {
+int Line2DEditor::get_point_index_at(const Transform2D &xform, Vector2 gpos) {
ERR_FAIL_COND_V(node == 0, -1);
real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
- Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
for (int i = 0; i < node->get_point_count(); ++i) {
Point2 p = xform.xform(node->get_point_position(i));
@@ -75,7 +69,7 @@ int Line2DEditor::get_point_index_at(Vector2 gpos) {
return -1;
}
-bool Line2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
+bool Line2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
if (!node)
return false;
@@ -88,10 +82,10 @@ bool Line2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid()) {
Vector2 gpoint = mb->get_position();
- Vector2 cpoint = mouse_to_local_pos(gpoint, mb->get_alt());
+ Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position())));
if (mb->is_pressed() && _dragging == false) {
- int i = get_point_index_at(gpoint);
+ int i = get_point_index_at(canvas_item_editor->get_canvas_transform() * node->get_global_transform(), gpoint);
if (i != -1) {
if (mb->get_button_index() == BUTTON_LEFT && !mb->get_shift() && mode == MODE_EDIT) {
_dragging = true;
@@ -146,7 +140,8 @@ bool Line2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid()) {
if (_dragging) {
- Vector2 cpoint = mouse_to_local_pos(mm->get_position(), mm->get_alt());
+ Vector2 gpoint = mm->get_position();
+ Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mm->get_position())));
node->set_point_position(action_point, cpoint);
canvas_item_editor->get_viewport_control()->update();
return true;
@@ -156,7 +151,7 @@ bool Line2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
-void Line2DEditor::_canvas_draw() {
+void Line2DEditor::forward_draw_over_canvas(Control *p_canvas) {
if (!node)
return;
@@ -190,13 +185,9 @@ void Line2DEditor::edit(Node *p_line2d) {
if (p_line2d) {
node = Object::cast_to<Line2D>(p_line2d);
- if (!canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->get_viewport_control()->connect("draw", this, "_canvas_draw");
if (!node->is_connected("visibility_changed", this, "_node_visibility_changed"))
node->connect("visibility_changed", this, "_node_visibility_changed");
} else {
- if (canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->get_viewport_control()->disconnect("draw", this, "_canvas_draw");
// node may have been deleted at this point
if (node && node->is_connected("visibility_changed", this, "_node_visibility_changed"))
node->disconnect("visibility_changed", this, "_node_visibility_changed");
@@ -205,7 +196,6 @@ void Line2DEditor::edit(Node *p_line2d) {
}
void Line2DEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_canvas_draw"), &Line2DEditor::_canvas_draw);
ClassDB::bind_method(D_METHOD("_node_visibility_changed"), &Line2DEditor::_node_visibility_changed);
ClassDB::bind_method(D_METHOD("_mode_selected"), &Line2DEditor::_mode_selected);
}
diff --git a/editor/plugins/line_2d_editor_plugin.h b/editor/plugins/line_2d_editor_plugin.h
index dea0433084..6858680aed 100644
--- a/editor/plugins/line_2d_editor_plugin.h
+++ b/editor/plugins/line_2d_editor_plugin.h
@@ -40,27 +40,11 @@ class CanvasItemEditor;
class Line2DEditor : public HBoxContainer {
GDCLASS(Line2DEditor, HBoxContainer)
-
-public:
- bool forward_gui_input(const Ref<InputEvent> &p_event);
- void edit(Node *p_line2d);
- Line2DEditor(EditorNode *p_editor);
-
-protected:
- void _node_removed(Node *p_node);
- void _notification(int p_what);
-
- Vector2 mouse_to_local_pos(Vector2 mpos);
-
- static void _bind_methods();
-
private:
void _mode_selected(int p_mode);
- void _canvas_draw();
void _node_visibility_changed();
- int get_point_index_at(Vector2 gpos);
- Vector2 mouse_to_local_pos(Vector2 gpos, bool alt);
+ int get_point_index_at(const Transform2D &xform, Vector2 gpos);
UndoRedo *undo_redo;
@@ -86,17 +70,26 @@ private:
int action_point;
Point2 moving_from;
Point2 moving_screen_from;
+
+protected:
+ void _node_removed(Node *p_node);
+ void _notification(int p_what);
+
+ static void _bind_methods();
+
+public:
+ bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
+ void forward_draw_over_canvas(Control *p_canvas);
+ void edit(Node *p_line2d);
+ Line2DEditor(EditorNode *p_editor);
};
class Line2DEditorPlugin : public EditorPlugin {
GDCLASS(Line2DEditorPlugin, EditorPlugin)
public:
- virtual bool forward_canvas_gui_input(
- const Transform2D &p_canvas_xform,
- const Ref<InputEvent> &p_event) {
- return line2d_editor->forward_gui_input(p_event);
- }
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return line2d_editor->forward_canvas_gui_input(p_event); }
+ virtual void forward_draw_over_canvas(Control *p_canvas) { return line2d_editor->forward_draw_over_canvas(p_canvas); }
virtual String get_name() const { return "Line2D"; }
bool has_main_screen() const { return false; }
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 6b613c1bcc..bd4891ccb7 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -32,6 +32,7 @@
// Waiting for PropertyEditor rewrite (planned for 3.1) to be refactored.
#include "material_editor_plugin.h"
+#include "scene/3d/particles.h"
#if 0
@@ -449,6 +450,52 @@ Ref<Resource> SpatialMaterialConversionPlugin::convert(const Ref<Resource> &p_re
VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
+
+ // Texture parameter has to be treated specially since SpatialMaterial saved it
+ // as RID but ShaderMaterial needs Texture itself
+ Ref<Texture> texture = mat->get_texture_by_name(E->get().name);
+ if (texture.is_valid()) {
+ smat->set_shader_param(E->get().name, texture);
+ } else {
+ Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
+ smat->set_shader_param(E->get().name, value);
+ }
+ }
+
+ smat->set_render_priority(mat->get_render_priority());
+ return smat;
+}
+
+String ParticlesMaterialConversionPlugin::converts_to() const {
+
+ return "ShaderMaterial";
+}
+bool ParticlesMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
+
+ Ref<ParticlesMaterial> mat = p_resource;
+ return mat.is_valid();
+}
+Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) {
+
+ Ref<ParticlesMaterial> mat = p_resource;
+ ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
+
+ Ref<ShaderMaterial> smat;
+ smat.instance();
+
+ Ref<Shader> shader;
+ shader.instance();
+
+ String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid());
+
+ shader->set_code(code);
+
+ smat->set_shader(shader);
+
+ List<PropertyInfo> params;
+ VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+
+ for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
smat->set_shader_param(E->get().name, value);
}
diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h
index af9602f944..52c73cb7d8 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -111,4 +111,12 @@ public:
virtual Ref<Resource> convert(const Ref<Resource> &p_resource);
};
+class ParticlesMaterialConversionPlugin : public EditorResourceConversionPlugin {
+ GDCLASS(ParticlesMaterialConversionPlugin, EditorResourceConversionPlugin)
+public:
+ virtual String converts_to() const;
+ virtual bool handles(const Ref<Resource> &p_resource) const;
+ virtual Ref<Resource> convert(const Ref<Resource> &p_resource);
+};
+
#endif // MATERIAL_EDITOR_PLUGIN_H
diff --git a/editor/plugins/navigation_mesh_generator.cpp b/editor/plugins/navigation_mesh_generator.cpp
index 86dc5c3663..5d50e9c855 100644
--- a/editor/plugins/navigation_mesh_generator.cpp
+++ b/editor/plugins/navigation_mesh_generator.cpp
@@ -215,7 +215,7 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(Ref<NavigationMesh>
ep->step(TTR("Eroding walkable area..."), 6);
ERR_FAIL_COND(!rcErodeWalkableArea(&ctx, cfg.walkableRadius, *chf));
- ep->step(TTR("Partioning..."), 7);
+ ep->step(TTR("Partitioning..."), 7);
if (p_nav_mesh->get_sample_partition_type() == NavigationMesh::SAMPLE_PARTITION_WATERSHED) {
ERR_FAIL_COND(!rcBuildDistanceField(&ctx, *chf));
ERR_FAIL_COND(!rcBuildRegions(&ctx, *chf, 0, cfg.minRegionArea, cfg.mergeRegionArea));
diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp
index 6560a8dac7..6560a8dac7 100755..100644
--- a/editor/plugins/navigation_polygon_editor_plugin.cpp
+++ b/editor/plugins/navigation_polygon_editor_plugin.cpp
diff --git a/editor/plugins/navigation_polygon_editor_plugin.h b/editor/plugins/navigation_polygon_editor_plugin.h
index 54cc347a8c..54cc347a8c 100755..100644
--- a/editor/plugins/navigation_polygon_editor_plugin.h
+++ b/editor/plugins/navigation_polygon_editor_plugin.h
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index df10ac8929..2174f08e23 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -76,10 +76,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
Vector2 gpoint = mb->get_position();
- Vector2 cpoint =
- !mb->get_alt() ?
- canvas_item_editor->snap_point(xform.affine_inverse().xform(gpoint)) :
- node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)));
+ Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position())));
real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
@@ -239,10 +236,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
// Handle point/control movement.
Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
Vector2 gpoint = mm->get_position();
- Vector2 cpoint =
- !mm->get_alt() ?
- canvas_item_editor->snap_point(xform.affine_inverse().xform(gpoint)) :
- node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)));
+ Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mm->get_position())));
Ref<Curve2D> curve = node->get_curve();
@@ -274,7 +268,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
-void Path2DEditor::_canvas_draw() {
+
+void Path2DEditor::forward_draw_over_canvas(Control *p_canvas) {
if (!node)
return;
@@ -329,16 +324,11 @@ void Path2DEditor::edit(Node *p_path2d) {
if (p_path2d) {
node = Object::cast_to<Path2D>(p_path2d);
- if (!canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->get_viewport_control()->connect("draw", this, "_canvas_draw");
if (!node->is_connected("visibility_changed", this, "_node_visibility_changed"))
node->connect("visibility_changed", this, "_node_visibility_changed");
} else {
- if (canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->get_viewport_control()->disconnect("draw", this, "_canvas_draw");
-
// node may have been deleted at this point
if (node && node->is_connected("visibility_changed", this, "_node_visibility_changed"))
node->disconnect("visibility_changed", this, "_node_visibility_changed");
@@ -349,7 +339,6 @@ void Path2DEditor::edit(Node *p_path2d) {
void Path2DEditor::_bind_methods() {
//ClassDB::bind_method(D_METHOD("_menu_option"),&Path2DEditor::_menu_option);
- ClassDB::bind_method(D_METHOD("_canvas_draw"), &Path2DEditor::_canvas_draw);
ClassDB::bind_method(D_METHOD("_node_visibility_changed"), &Path2DEditor::_node_visibility_changed);
ClassDB::bind_method(D_METHOD("_mode_selected"), &Path2DEditor::_mode_selected);
}
diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h
index f0f5d4d637..516e48c471 100644
--- a/editor/plugins/path_2d_editor_plugin.h
+++ b/editor/plugins/path_2d_editor_plugin.h
@@ -84,7 +84,6 @@ class Path2DEditor : public HBoxContainer {
void _mode_selected(int p_mode);
- void _canvas_draw();
void _node_visibility_changed();
friend class Path2DEditorPlugin;
@@ -95,6 +94,7 @@ protected:
public:
bool forward_gui_input(const Ref<InputEvent> &p_event);
+ void forward_draw_over_canvas(Control *p_canvas);
void edit(Node *p_path2d);
Path2DEditor(EditorNode *p_editor);
};
@@ -107,7 +107,8 @@ class Path2DEditorPlugin : public EditorPlugin {
EditorNode *editor;
public:
- virtual bool forward_canvas_gui_input(const Transform2D &p_canvas_xform, const Ref<InputEvent> &p_event) { return path2d_editor->forward_gui_input(p_event); }
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return path2d_editor->forward_gui_input(p_event); }
+ virtual void forward_draw_over_canvas(Control *p_canvas) { return path2d_editor->forward_draw_over_canvas(p_canvas); }
virtual String get_name() const { return "Path2D"; }
bool has_main_screen() const { return false; }
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 0e8c13b067..a525983c75 100755..100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -437,14 +437,10 @@ void Polygon2DEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_snap_step_y"), &Polygon2DEditor::_set_snap_step_y);
}
-inline float _snap_scalar(float p_offset, float p_step, float p_target) {
- return p_step != 0 ? Math::stepify(p_target - p_offset, p_step) + p_offset : p_target;
-}
-
Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const {
if (use_snap) {
- p_target.x = _snap_scalar(snap_offset.x * uv_draw_zoom - uv_draw_ofs.x, snap_step.x * uv_draw_zoom, p_target.x);
- p_target.y = _snap_scalar(snap_offset.y * uv_draw_zoom - uv_draw_ofs.y, snap_step.y * uv_draw_zoom, p_target.y);
+ p_target.x = Math::snap_scalar(snap_offset.x * uv_draw_zoom - uv_draw_ofs.x, snap_step.x * uv_draw_zoom, p_target.x);
+ p_target.y = Math::snap_scalar(snap_offset.y * uv_draw_zoom - uv_draw_ofs.y, snap_step.y * uv_draw_zoom, p_target.y);
}
return p_target;
diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h
index 90da3e61c1..90da3e61c1 100755..100644
--- a/editor/plugins/polygon_2d_editor_plugin.h
+++ b/editor/plugins/polygon_2d_editor_plugin.h
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 84808cb876..a1183307fb 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -1169,6 +1169,8 @@ void ScriptEditor::_notification(int p_what) {
script_forward->set_icon(get_icon("Forward", "EditorIcons"));
script_back->set_icon(get_icon("Back", "EditorIcons"));
+
+ recent_scripts->set_as_minsize();
} break;
default:
@@ -2358,7 +2360,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/step_into", TTR("Step Into"), KEY_F11), DEBUG_STEP);
debug_menu->get_popup()->add_separator();
debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/break", TTR("Break")), DEBUG_BREAK);
- debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/continue", TTR("Continue")), DEBUG_CONTINUE);
+ debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/continue", TTR("Continue"), KEY_F12), DEBUG_CONTINUE);
debug_menu->get_popup()->add_separator();
//debug_menu->get_popup()->add_check_item("Show Debugger",DEBUG_SHOW);
debug_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("debugger/keep_debugger_open", TTR("Keep Debugger Open")), DEBUG_SHOW_KEEP_OPEN);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index b0ee1a32ca..f7dcc4b52d 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -348,6 +348,7 @@ void ShaderEditor::_editor_settings_changed() {
shader_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_line_numbers"));
shader_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/highlighting/syntax_highlighting"));
shader_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_all_occurrences"));
+ shader_editor->get_text_edit()->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_current_line"));
shader_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink"));
shader_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed"));
shader_editor->get_text_edit()->add_constant_override("line_spacing", EditorSettings::get_singleton()->get("text_editor/theme/line_spacing"));
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 703c9e96b6..25ca2d731e 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -267,12 +267,12 @@ Vector3 SpatialEditorViewport::_get_camera_position() const {
Point2 SpatialEditorViewport::_point_to_screen(const Vector3 &p_point) {
- return camera->unproject_position(p_point);
+ return camera->unproject_position(p_point) * viewport_container->get_stretch_shrink();
}
Vector3 SpatialEditorViewport::_get_ray_pos(const Vector2 &p_pos) const {
- return camera->project_ray_origin(p_pos);
+ return camera->project_ray_origin(p_pos / viewport_container->get_stretch_shrink());
}
Vector3 SpatialEditorViewport::_get_camera_normal() const {
@@ -282,7 +282,7 @@ Vector3 SpatialEditorViewport::_get_camera_normal() const {
Vector3 SpatialEditorViewport::_get_ray(const Vector2 &p_pos) const {
- return camera->project_ray_normal(p_pos);
+ return camera->project_ray_normal(p_pos / viewport_container->get_stretch_shrink());
}
/*
void SpatialEditorViewport::_clear_id(Spatial *p_node) {
@@ -847,6 +847,7 @@ void SpatialEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
selection_menu->set_invalidate_click_until_motion();
}
}
+
void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (previewing)
@@ -1576,7 +1577,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
- } else if (m->get_button_mask() & BUTTON_MASK_RIGHT) {
+ } else if ((m->get_button_mask() & BUTTON_MASK_RIGHT) || freelook_active) {
if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) {
nav_mode = NAVIGATION_ZOOM;
@@ -1791,6 +1792,13 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
set_message(TTR("Animation Key Inserted."));
}
+ if (ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) {
+ set_freelook_active(!is_freelook_active());
+
+ } else if (k->get_scancode() == KEY_ESCAPE) {
+ set_freelook_active(false);
+ }
+
if (k->get_scancode() == KEY_SPACE) {
if (!k->is_pressed()) emit_signal("toggle_maximize_view", this);
}
@@ -1815,9 +1823,15 @@ void SpatialEditorViewport::set_freelook_active(bool active_now) {
freelook_speed = base_speed * cursor.distance;
}
+ // Hide mouse like in an FPS (warping doesn't work)
+ OS::get_singleton()->set_mouse_mode(OS::MOUSE_MODE_CAPTURED);
+
} else if (freelook_active && !active_now) {
// Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential
cursor = camera_cursor;
+
+ // Restore mouse
+ OS::get_singleton()->set_mouse_mode(OS::MOUSE_MODE_VISIBLE);
}
freelook_active = active_now;
@@ -2036,6 +2050,12 @@ void SpatialEditorViewport::_notification(int p_what) {
viewport->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
viewport->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));
+ bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION));
+
+ if (shrink != viewport_container->get_stretch_shrink() > 1) {
+ viewport_container->set_stretch_shrink(shrink ? 2 : 1);
+ }
+
//update msaa if changed
int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/filters/msaa");
@@ -2387,6 +2407,13 @@ void SpatialEditorViewport::_menu_option(int p_option) {
view_menu->get_popup()->set_item_checked(idx, current);
} break;
+ case VIEW_HALF_RESOLUTION: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION);
+ bool current = view_menu->get_popup()->is_item_checked(idx);
+ current = !current;
+ view_menu->get_popup()->set_item_checked(idx, current);
+ } break;
case VIEW_INFORMATION: {
int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION);
@@ -2616,6 +2643,12 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) {
camera->set_doppler_tracking(doppler ? Camera::DOPPLER_TRACKING_IDLE_STEP : Camera::DOPPLER_TRACKING_DISABLED);
view_menu->get_popup()->set_item_checked(idx, doppler);
}
+ if (p_state.has("half_res")) {
+ bool half_res = p_state["half_res"];
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION);
+ view_menu->get_popup()->set_item_checked(idx, half_res);
+ }
if (p_state.has("previewing")) {
Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]);
@@ -2641,6 +2674,7 @@ Dictionary SpatialEditorViewport::get_state() const {
d["use_environment"] = camera->get_environment().is_valid();
d["use_orthogonal"] = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL;
d["listener"] = viewport->is_audio_listener();
+ d["half_res"] = viewport_container->get_stretch_shrink() > 1;
if (previewing) {
d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing);
}
@@ -2765,8 +2799,14 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const
normal = hit_normal;
}
}
- Vector3 center = preview_bounds->get_size() * 0.5;
- return point + (center * normal);
+ Vector3 offset = Vector3();
+ for (int i = 0; i < 3; i++) {
+ if (normal[i] > 0.0)
+ offset[i] = (preview_bounds->get_size()[i] - (preview_bounds->get_size()[i] + preview_bounds->get_position()[i]));
+ else if (normal[i] < 0.0)
+ offset[i] = -(preview_bounds->get_size()[i] + preview_bounds->get_position()[i]);
+ }
+ return point + offset;
}
Rect3 SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, const Rect3 p_bounds) {
@@ -2888,7 +2928,7 @@ bool SpatialEditorViewport::_create_instance(Node *parent, String &path, const P
if (parent_spatial)
global_transform = parent_spatial->get_global_transform();
- global_transform.origin = _get_instance_position(p_point);
+ global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
editor_data->get_undo_redo().add_do_method(instanced_scene, "set_global_transform", global_transform);
@@ -3052,6 +3092,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
spatial_editor = p_spatial_editor;
ViewportContainer *c = memnew(ViewportContainer);
+ viewport_container = c;
c->set_stretch(true);
add_child(c);
c->set_anchors_and_margins_preset(Control::PRESET_WIDE);
@@ -3098,6 +3139,8 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT), true);
view_menu->get_popup()->add_separator();
+ view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION);
+ view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_listener", TTR("Audio Listener")), VIEW_AUDIO_LISTENER);
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_doppler", TTR("Doppler Enable")), VIEW_AUDIO_DOPPLER);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS), true);
@@ -4589,6 +4632,8 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
ED_SHORTCUT("spatial_editor/display_wireframe", TTR("Display Wireframe"), KEY_Z);
+ ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F);
+
PopupMenu *p;
transform_menu = memnew(MenuButton);
@@ -4828,6 +4873,15 @@ void SpatialEditor::snap_cursor_to_plane(const Plane &p_plane) {
//cursor.pos=p_plane.project(cursor.pos);
}
+Vector3 SpatialEditor::snap_point(Vector3 p_target, Vector3 p_start) const {
+ if (is_snap_enabled()) {
+ p_target.x = Math::snap_scalar(0.0, get_translate_snap(), p_target.x);
+ p_target.y = Math::snap_scalar(0.0, get_translate_snap(), p_target.y);
+ p_target.z = Math::snap_scalar(0.0, get_translate_snap(), p_target.z);
+ }
+ return p_target;
+}
+
void SpatialEditorPlugin::_bind_methods() {
ClassDB::bind_method("snap_cursor_to_plane", &SpatialEditorPlugin::snap_cursor_to_plane);
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index a9dd1f1327..c2b698068f 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -83,6 +83,7 @@ class SpatialEditorViewport : public Control {
VIEW_PERSPECTIVE,
VIEW_ENVIRONMENT,
VIEW_ORTHOGONAL,
+ VIEW_HALF_RESOLUTION,
VIEW_AUDIO_LISTENER,
VIEW_AUDIO_DOPPLER,
VIEW_GIZMOS,
@@ -120,6 +121,7 @@ private:
UndoRedo *undo_redo;
Button *preview_camera;
+ ViewportContainer *viewport_container;
MenuButton *view_menu;
@@ -548,6 +550,8 @@ public:
static SpatialEditor *get_singleton() { return singleton; }
void snap_cursor_to_plane(const Plane &p_plane);
+ Vector3 snap_point(Vector3 p_target, Vector3 p_start = Vector3(0, 0, 0)) const;
+
float get_znear() const { return settings_znear->get_value(); }
float get_zfar() const { return settings_zfar->get_value(); }
float get_fov() const { return settings_fov->get_value(); }
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index dc7acd9fdc..b3bb103577 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -142,6 +142,19 @@ void SpriteFramesEditor::_paste_pressed() {
undo_redo->commit_action();
}
+void SpriteFramesEditor::_copy_pressed() {
+ ERR_FAIL_COND(!frames->has_animation(edited_anim));
+
+ if (tree->get_current() < 0)
+ return;
+ Ref<Texture> r = frames->get_frame(edited_anim, tree->get_current());
+ if (!r.is_valid()) {
+ return;
+ }
+
+ EditorSettings::get_singleton()->set_resource_clipboard(r);
+}
+
void SpriteFramesEditor::_empty_pressed() {
ERR_FAIL_COND(!frames->has_animation(edited_anim));
@@ -352,13 +365,11 @@ void SpriteFramesEditor::_animation_name_edited() {
}
void SpriteFramesEditor::_animation_add() {
- String new_name = "New Anim";
-
- String name = new_name;
+ String name = "New Anim";
int counter = 0;
while (frames->has_animation(name)) {
counter++;
- name = new_name + " " + itos(counter);
+ name = "New Anim " + itos(counter);
}
List<Node *> nodes;
@@ -380,7 +391,7 @@ void SpriteFramesEditor::_animation_add() {
undo_redo->add_undo_method(E->get(), "set_animation", current);
}
- edited_anim = new_name;
+ edited_anim = name;
undo_redo->commit_action();
}
@@ -642,6 +653,7 @@ void SpriteFramesEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_empty_pressed"), &SpriteFramesEditor::_empty_pressed);
ClassDB::bind_method(D_METHOD("_empty2_pressed"), &SpriteFramesEditor::_empty2_pressed);
ClassDB::bind_method(D_METHOD("_delete_pressed"), &SpriteFramesEditor::_delete_pressed);
+ ClassDB::bind_method(D_METHOD("_copy_pressed"), &SpriteFramesEditor::_copy_pressed);
ClassDB::bind_method(D_METHOD("_paste_pressed"), &SpriteFramesEditor::_paste_pressed);
ClassDB::bind_method(D_METHOD("_file_load_request", "files", "at_position"), &SpriteFramesEditor::_file_load_request, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("_update_library", "skipsel"), &SpriteFramesEditor::_update_library, DEFVAL(false));
@@ -725,6 +737,10 @@ SpriteFramesEditor::SpriteFramesEditor() {
load->set_tooltip(TTR("Load Resource"));
hbc->add_child(load);
+ copy = memnew(Button);
+ copy->set_text(TTR("Copy"));
+ hbc->add_child(copy);
+
paste = memnew(Button);
paste->set_text(TTR("Paste"));
hbc->add_child(paste);
@@ -772,6 +788,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
load->connect("pressed", this, "_load_pressed");
_delete->connect("pressed", this, "_delete_pressed");
+ copy->connect("pressed", this, "_copy_pressed");
paste->connect("pressed", this, "_paste_pressed");
empty->connect("pressed", this, "_empty_pressed");
empty2->connect("pressed", this, "_empty2_pressed");
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index 0d1ab9fd8c..9fdab37f0e 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -44,6 +44,7 @@ class SpriteFramesEditor : public PanelContainer {
Button *load;
Button *_delete;
+ Button *copy;
Button *paste;
Button *empty;
Button *empty2;
@@ -72,6 +73,7 @@ class SpriteFramesEditor : public PanelContainer {
void _load_pressed();
void _load_scene_pressed();
void _file_load_request(const PoolVector<String> &p_path, int p_at_pos = -1);
+ void _copy_pressed();
void _paste_pressed();
void _empty_pressed();
void _empty2_pressed();
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 0a7f3ff8f9..8870166dba 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -48,8 +48,8 @@ void TextureRegionEditor::_region_draw() {
Ref<Texture> base_tex = NULL;
if (node_sprite)
base_tex = node_sprite->get_texture();
- else if (node_patch9)
- base_tex = node_patch9->get_texture();
+ else if (node_ninepatch)
+ base_tex = node_ninepatch->get_texture();
else if (obj_styleBox.is_valid())
base_tex = obj_styleBox->get_texture();
else if (atlas_tex.is_valid())
@@ -177,12 +177,12 @@ void TextureRegionEditor::_region_draw() {
updating_scroll = false;
float margins[4];
- if (node_patch9 || obj_styleBox.is_valid()) {
- if (node_patch9) {
- margins[0] = node_patch9->get_patch_margin(MARGIN_TOP);
- margins[1] = node_patch9->get_patch_margin(MARGIN_BOTTOM);
- margins[2] = node_patch9->get_patch_margin(MARGIN_LEFT);
- margins[3] = node_patch9->get_patch_margin(MARGIN_RIGHT);
+ if (node_ninepatch || obj_styleBox.is_valid()) {
+ if (node_ninepatch) {
+ margins[0] = node_ninepatch->get_patch_margin(MARGIN_TOP);
+ margins[1] = node_ninepatch->get_patch_margin(MARGIN_BOTTOM);
+ margins[2] = node_ninepatch->get_patch_margin(MARGIN_LEFT);
+ margins[3] = node_ninepatch->get_patch_margin(MARGIN_RIGHT);
} else if (obj_styleBox.is_valid()) {
margins[0] = obj_styleBox->get_margin_size(MARGIN_TOP);
margins[1] = obj_styleBox->get_margin_size(MARGIN_BOTTOM);
@@ -225,14 +225,14 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
if (mb->get_button_index() == BUTTON_LEFT) {
if (mb->is_pressed()) {
- if (node_patch9 || obj_styleBox.is_valid()) {
+ if (node_ninepatch || obj_styleBox.is_valid()) {
edited_margin = -1;
float margins[4];
- if (node_patch9) {
- margins[0] = node_patch9->get_patch_margin(MARGIN_TOP);
- margins[1] = node_patch9->get_patch_margin(MARGIN_BOTTOM);
- margins[2] = node_patch9->get_patch_margin(MARGIN_LEFT);
- margins[3] = node_patch9->get_patch_margin(MARGIN_RIGHT);
+ if (node_ninepatch) {
+ margins[0] = node_ninepatch->get_patch_margin(MARGIN_TOP);
+ margins[1] = node_ninepatch->get_patch_margin(MARGIN_BOTTOM);
+ margins[2] = node_ninepatch->get_patch_margin(MARGIN_LEFT);
+ margins[3] = node_ninepatch->get_patch_margin(MARGIN_RIGHT);
} else if (obj_styleBox.is_valid()) {
margins[0] = obj_styleBox->get_margin_size(MARGIN_TOP);
margins[1] = obj_styleBox->get_margin_size(MARGIN_BOTTOM);
@@ -272,8 +272,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
Rect2 r;
if (node_sprite)
r = node_sprite->get_region_rect();
- else if (node_patch9)
- r = node_patch9->get_region_rect();
+ else if (node_ninepatch)
+ r = node_ninepatch->get_region_rect();
else if (obj_styleBox.is_valid())
r = obj_styleBox->get_region_rect();
else if (atlas_tex.is_valid())
@@ -285,9 +285,9 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
if (node_sprite) {
undo_redo->add_do_method(node_sprite, "set_region_rect", rect);
undo_redo->add_undo_method(node_sprite, "set_region_rect", node_sprite->get_region_rect());
- } else if (node_patch9) {
- undo_redo->add_do_method(node_patch9, "set_region_rect", rect);
- undo_redo->add_undo_method(node_patch9, "set_region_rect", node_patch9->get_region_rect());
+ } else if (node_ninepatch) {
+ undo_redo->add_do_method(node_ninepatch, "set_region_rect", rect);
+ undo_redo->add_undo_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect());
} else if (obj_styleBox.is_valid()) {
undo_redo->add_do_method(obj_styleBox.ptr(), "set_region_rect", rect);
undo_redo->add_undo_method(obj_styleBox.ptr(), "set_region_rect", obj_styleBox->get_region_rect());
@@ -310,8 +310,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
drag = true;
if (node_sprite)
rect_prev = node_sprite->get_region_rect();
- else if (node_patch9)
- rect_prev = node_patch9->get_region_rect();
+ else if (node_ninepatch)
+ rect_prev = node_ninepatch->get_region_rect();
else if (obj_styleBox.is_valid())
rect_prev = obj_styleBox->get_region_rect();
else if (atlas_tex.is_valid())
@@ -334,9 +334,9 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
if (edited_margin >= 0) {
undo_redo->create_action("Set Margin");
static Margin m[4] = { MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT };
- if (node_patch9) {
- undo_redo->add_do_method(node_patch9, "set_patch_margin", m[edited_margin], node_patch9->get_patch_margin(m[edited_margin]));
- undo_redo->add_undo_method(node_patch9, "set_patch_margin", m[edited_margin], prev_margin);
+ if (node_ninepatch) {
+ undo_redo->add_do_method(node_ninepatch, "set_patch_margin", m[edited_margin], node_ninepatch->get_patch_margin(m[edited_margin]));
+ undo_redo->add_undo_method(node_ninepatch, "set_patch_margin", m[edited_margin], prev_margin);
} else if (obj_styleBox.is_valid()) {
undo_redo->add_do_method(obj_styleBox.ptr(), "set_margin_size", m[edited_margin], obj_styleBox->get_margin_size(m[edited_margin]));
undo_redo->add_undo_method(obj_styleBox.ptr(), "set_margin_size", m[edited_margin], prev_margin);
@@ -351,11 +351,11 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
} else if (atlas_tex.is_valid()) {
undo_redo->add_do_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region());
undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", rect_prev);
- } else if (node_patch9) {
+ } else if (node_ninepatch) {
// FIXME: Is this intentional?
- } else if (node_patch9) {
- undo_redo->add_do_method(node_patch9, "set_region_rect", node_patch9->get_region_rect());
- undo_redo->add_undo_method(node_patch9, "set_region_rect", rect_prev);
+ } else if (node_ninepatch) {
+ undo_redo->add_do_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect());
+ undo_redo->add_undo_method(node_ninepatch, "set_region_rect", rect_prev);
} else if (obj_styleBox.is_valid()) {
undo_redo->add_do_method(obj_styleBox.ptr(), "set_region_rect", obj_styleBox->get_region_rect());
undo_redo->add_undo_method(obj_styleBox.ptr(), "set_region_rect", rect_prev);
@@ -375,8 +375,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
drag = false;
if (edited_margin >= 0) {
static Margin m[4] = { MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT };
- if (node_patch9)
- node_patch9->set_patch_margin(m[edited_margin], prev_margin);
+ if (node_ninepatch)
+ node_ninepatch->set_patch_margin(m[edited_margin], prev_margin);
if (obj_styleBox.is_valid())
obj_styleBox->set_margin_size(m[edited_margin], prev_margin);
edited_margin = -1;
@@ -422,8 +422,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
if (new_margin < 0)
new_margin = 0;
static Margin m[4] = { MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT };
- if (node_patch9)
- node_patch9->set_patch_margin(m[edited_margin], new_margin);
+ if (node_ninepatch)
+ node_ninepatch->set_patch_margin(m[edited_margin], new_margin);
if (obj_styleBox.is_valid())
obj_styleBox->set_margin_size(m[edited_margin], new_margin);
} else {
@@ -573,8 +573,8 @@ void TextureRegionEditor::_zoom_out() {
void TextureRegionEditor::apply_rect(const Rect2 &rect) {
if (node_sprite)
node_sprite->set_region_rect(rect);
- else if (node_patch9)
- node_patch9->set_region_rect(rect);
+ else if (node_ninepatch)
+ node_ninepatch->set_region_rect(rect);
else if (obj_styleBox.is_valid())
obj_styleBox->set_region_rect(rect);
else if (atlas_tex.is_valid())
@@ -593,8 +593,8 @@ void TextureRegionEditor::_notification(int p_what) {
}
void TextureRegionEditor::_node_removed(Object *p_obj) {
- if (p_obj == node_sprite || p_obj == node_patch9 || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr()) {
- node_patch9 = NULL;
+ if (p_obj == node_sprite || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr()) {
+ node_ninepatch = NULL;
node_sprite = NULL;
obj_styleBox = Ref<StyleBox>(NULL);
atlas_tex = Ref<AtlasTexture>(NULL);
@@ -623,15 +623,15 @@ void TextureRegionEditor::_bind_methods() {
void TextureRegionEditor::edit(Object *p_obj) {
if (node_sprite)
node_sprite->remove_change_receptor(this);
- if (node_patch9)
- node_patch9->remove_change_receptor(this);
+ if (node_ninepatch)
+ node_ninepatch->remove_change_receptor(this);
if (obj_styleBox.is_valid())
obj_styleBox->remove_change_receptor(this);
if (atlas_tex.is_valid())
atlas_tex->remove_change_receptor(this);
if (p_obj) {
node_sprite = Object::cast_to<Sprite>(p_obj);
- node_patch9 = Object::cast_to<NinePatchRect>(p_obj);
+ node_ninepatch = Object::cast_to<NinePatchRect>(p_obj);
if (Object::cast_to<StyleBoxTexture>(p_obj))
obj_styleBox = Ref<StyleBoxTexture>(Object::cast_to<StyleBoxTexture>(p_obj));
if (Object::cast_to<AtlasTexture>(p_obj))
@@ -640,7 +640,7 @@ void TextureRegionEditor::edit(Object *p_obj) {
_edit_region();
} else {
node_sprite = NULL;
- node_patch9 = NULL;
+ node_ninepatch = NULL;
obj_styleBox = Ref<StyleBoxTexture>(NULL);
atlas_tex = Ref<AtlasTexture>(NULL);
}
@@ -659,8 +659,8 @@ void TextureRegionEditor::_edit_region() {
Ref<Texture> texture = NULL;
if (node_sprite)
texture = node_sprite->get_texture();
- else if (node_patch9)
- texture = node_patch9->get_texture();
+ else if (node_ninepatch)
+ texture = node_ninepatch->get_texture();
else if (obj_styleBox.is_valid())
texture = obj_styleBox->get_texture();
else if (atlas_tex.is_valid())
@@ -726,8 +726,8 @@ void TextureRegionEditor::_edit_region() {
if (node_sprite)
rect = node_sprite->get_region_rect();
- else if (node_patch9)
- rect = node_patch9->get_region_rect();
+ else if (node_ninepatch)
+ rect = node_ninepatch->get_region_rect();
else if (obj_styleBox.is_valid())
rect = obj_styleBox->get_region_rect();
else if (atlas_tex.is_valid())
@@ -736,23 +736,10 @@ void TextureRegionEditor::_edit_region() {
edit_draw->update();
}
-inline float _snap_scalar(float p_offset, float p_step, float separation, float p_target) {
- if (p_step != 0) {
- float a = Math::stepify(p_target - p_offset, p_step + separation) + p_offset;
- float b = a;
- if (p_target >= 0)
- b -= separation;
- else
- b += p_step;
- return (Math::abs(p_target - a) < Math::abs(p_target - b)) ? a : b;
- }
- return p_target;
-}
-
Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const {
if (snap_mode == SNAP_GRID) {
- p_target.x = _snap_scalar(snap_offset.x, snap_step.x, snap_separation.x, p_target.x);
- p_target.y = _snap_scalar(snap_offset.y, snap_step.y, snap_separation.y, p_target.y);
+ p_target.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p_target.x, snap_separation.x);
+ p_target.y = Math::snap_scalar_seperation(snap_offset.y, snap_step.y, p_target.y, snap_separation.y);
}
return p_target;
@@ -760,7 +747,7 @@ Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const {
TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
node_sprite = NULL;
- node_patch9 = NULL;
+ node_ninepatch = NULL;
obj_styleBox = Ref<StyleBoxTexture>(NULL);
atlas_tex = Ref<AtlasTexture>(NULL);
editor = p_editor;
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index 0789dde1c1..2058dad791 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -37,7 +37,7 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/2d/sprite.h"
-#include "scene/gui/patch_9_rect.h"
+#include "scene/gui/nine_patch_rect.h"
#include "scene/resources/style_box.h"
#include "scene/resources/texture.h"
@@ -82,7 +82,7 @@ class TextureRegionEditor : public Control {
Vector2 snap_step;
Vector2 snap_separation;
- NinePatchRect *node_patch9;
+ NinePatchRect *node_ninepatch;
Sprite *node_sprite;
Ref<StyleBoxTexture> obj_styleBox;
Ref<AtlasTexture> atlas_tex;
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index e500dec0ef..02ead3aee8 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -588,6 +588,8 @@ void ThemeEditor::_notification(int p_what) {
time_left = 1.5;
_refresh_interval();
}
+ } else if (p_what == NOTIFICATION_THEME_CHANGED) {
+ theme_menu->set_icon(get_icon("Theme", "EditorIcons"));
}
}
@@ -627,7 +629,9 @@ ThemeEditor::ThemeEditor() {
main_vb->add_child(hb_menu);
theme_menu = memnew(MenuButton);
- theme_menu->set_text(TTR("Theme"));
+ theme_menu->set_text(TTR("Edit theme.."));
+ theme_menu->set_flat(false);
+ theme_menu->set_tooltip(TTR("Theme editing menu."));
theme_menu->get_popup()->add_item(TTR("Add Item"), POPUP_ADD);
theme_menu->get_popup()->add_item(TTR("Add Class Items"), POPUP_CLASS_ADD);
theme_menu->get_popup()->add_item(TTR("Remove Item"), POPUP_REMOVE);
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 2f2ed7bdf0..9235dafaa6 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -229,7 +229,7 @@ struct _PaletteEntry {
return name < p_rhs.name;
}
};
-}
+} // namespace
void TileMapEditor::_update_palette() {
@@ -945,6 +945,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid()) {
Point2i new_over_tile = node->world_to_map(xform_inv.xform(mm->get_position()));
+ Point2i old_over_tile = over_tile;
if (new_over_tile != over_tile) {
@@ -963,17 +964,43 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (tool == TOOL_PAINTING) {
+ // Paint using bresenham line to prevent holes in painting if the user moves fast
+
+ Vector<Point2i> points = line(old_over_tile.x, over_tile.x, old_over_tile.y, over_tile.y);
int id = get_selected_tile();
- if (id != TileMap::INVALID_CELL) {
+
+ for (int i = 0; i < points.size(); ++i) {
+
+ Point2i pos = points[i];
if (!paint_undo.has(over_tile)) {
- paint_undo[over_tile] = _get_op_from_cell(over_tile);
+ paint_undo[pos] = _get_op_from_cell(pos);
}
- _set_cell(over_tile, id, flip_h, flip_v, transpose);
+ _set_cell(pos, id, flip_h, flip_v, transpose);
+ }
- return true;
+ return true;
+ }
+
+ if (tool == TOOL_ERASING) {
+
+ // erase using bresenham line to prevent holes in painting if the user moves fast
+
+ Vector<Point2i> points = line(old_over_tile.x, over_tile.x, old_over_tile.y, over_tile.y);
+
+ for (int i = 0; i < points.size(); ++i) {
+
+ Point2i pos = points[i];
+
+ if (!paint_undo.has(over_tile)) {
+ paint_undo[pos] = _get_op_from_cell(pos);
+ }
+
+ _set_cell(pos, TileMap::INVALID_CELL);
}
+
+ return true;
}
if (tool == TOOL_SELECTING) {
@@ -1044,16 +1071,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return true;
}
- if (tool == TOOL_ERASING) {
-
- if (!paint_undo.has(over_tile)) {
- paint_undo[over_tile] = _get_op_from_cell(over_tile);
- }
-
- _set_cell(over_tile, TileMap::INVALID_CELL);
-
- return true;
- }
if (tool == TOOL_PICKING && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
_pick_tile(over_tile);
@@ -1152,7 +1169,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
-void TileMapEditor::_canvas_draw() {
+void TileMapEditor::forward_draw_over_canvas(Control *p_canvas) {
if (!node)
return;
@@ -1379,8 +1396,6 @@ void TileMapEditor::edit(Node *p_tile_map) {
if (p_tile_map) {
node = Object::cast_to<TileMap>(p_tile_map);
- if (!canvas_item_editor->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->connect("draw", this, "_canvas_draw");
if (!canvas_item_editor->is_connected("mouse_entered", this, "_canvas_mouse_enter"))
canvas_item_editor->connect("mouse_entered", this, "_canvas_mouse_enter");
if (!canvas_item_editor->is_connected("mouse_exited", this, "_canvas_mouse_exit"))
@@ -1391,8 +1406,6 @@ void TileMapEditor::edit(Node *p_tile_map) {
} else {
node = NULL;
- if (canvas_item_editor->is_connected("draw", this, "_canvas_draw"))
- canvas_item_editor->disconnect("draw", this, "_canvas_draw");
if (canvas_item_editor->is_connected("mouse_entered", this, "_canvas_mouse_enter"))
canvas_item_editor->disconnect("mouse_entered", this, "_canvas_mouse_enter");
if (canvas_item_editor->is_connected("mouse_exited", this, "_canvas_mouse_exit"))
@@ -1428,7 +1441,6 @@ void TileMapEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_text_changed"), &TileMapEditor::_text_changed);
ClassDB::bind_method(D_METHOD("_sbox_input"), &TileMapEditor::_sbox_input);
ClassDB::bind_method(D_METHOD("_menu_option"), &TileMapEditor::_menu_option);
- ClassDB::bind_method(D_METHOD("_canvas_draw"), &TileMapEditor::_canvas_draw);
ClassDB::bind_method(D_METHOD("_canvas_mouse_enter"), &TileMapEditor::_canvas_mouse_enter);
ClassDB::bind_method(D_METHOD("_canvas_mouse_exit"), &TileMapEditor::_canvas_mouse_exit);
ClassDB::bind_method(D_METHOD("_tileset_settings_changed"), &TileMapEditor::_tileset_settings_changed);
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
index c8f29dfb7b..73474a3f3d 100644
--- a/editor/plugins/tile_map_editor_plugin.h
+++ b/editor/plugins/tile_map_editor_plugin.h
@@ -163,7 +163,6 @@ class TileMapEditor : public VBoxContainer {
void _text_changed(const String &p_text);
void _sbox_input(const Ref<InputEvent> &p_ie);
void _update_palette();
- void _canvas_draw();
void _menu_option(int p_option);
void _set_cell(const Point2i &p_pos, int p_value, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false, bool p_with_undo = false);
@@ -183,6 +182,8 @@ public:
HBoxContainer *get_toolbar() const { return toolbar; }
bool forward_gui_input(const Ref<InputEvent> &p_event);
+ void forward_draw_over_canvas(Control *p_canvas);
+
void edit(Node *p_tile_map);
TileMapEditor(EditorNode *p_editor);
@@ -196,7 +197,8 @@ class TileMapEditorPlugin : public EditorPlugin {
TileMapEditor *tile_map_editor;
public:
- virtual bool forward_canvas_gui_input(const Transform2D &p_canvas_xform, const Ref<InputEvent> &p_event) { return tile_map_editor->forward_gui_input(p_event); }
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return tile_map_editor->forward_gui_input(p_event); }
+ virtual void forward_draw_over_canvas(Control *p_canvas) { tile_map_editor->forward_draw_over_canvas(p_canvas); }
virtual String get_name() const { return "TileMap"; }
bool has_main_screen() const { return false; }