summaryrefslogtreecommitdiff
path: root/tools/editor
diff options
context:
space:
mode:
Diffstat (limited to 'tools/editor')
-rw-r--r--tools/editor/editor_import_export.cpp26
-rw-r--r--tools/editor/editor_import_export.h1
-rw-r--r--tools/editor/editor_node.cpp72
-rw-r--r--tools/editor/editor_node.h10
-rw-r--r--tools/editor/icons/icon_light_2d.pngbin0 -> 342 bytes
-rw-r--r--tools/editor/icons/icon_navigation_2d.pngbin0 -> 541 bytes
-rw-r--r--tools/editor/icons/icon_navigation_polygon_instance.pngbin0 -> 391 bytes
-rw-r--r--tools/editor/plugins/collision_polygon_editor_plugin.cpp14
-rw-r--r--tools/editor/plugins/navigation_polygon_editor_plugin.cpp547
-rw-r--r--tools/editor/plugins/navigation_polygon_editor_plugin.h91
-rw-r--r--tools/editor/plugins/script_editor_plugin.cpp6
-rw-r--r--tools/editor/scene_tree_dock.cpp33
-rw-r--r--tools/editor/scene_tree_dock.h1
13 files changed, 782 insertions, 19 deletions
diff --git a/tools/editor/editor_import_export.cpp b/tools/editor/editor_import_export.cpp
index 58f9afaa5d..6399d0f909 100644
--- a/tools/editor/editor_import_export.cpp
+++ b/tools/editor/editor_import_export.cpp
@@ -1141,10 +1141,36 @@ EditorImportExport* EditorImportExport::singleton=NULL;
void EditorImportExport::add_import_plugin(const Ref<EditorImportPlugin>& p_plugin) {
+ // Need to make sure the name is unique if we are going to lookup by it
+ ERR_FAIL_COND(by_idx.has(p_plugin->get_name()));
+
by_idx[ p_plugin->get_name() ]=plugins.size();
plugins.push_back(p_plugin);
}
+void EditorImportExport::remove_import_plugin(const Ref<EditorImportPlugin>& p_plugin) {
+
+ String plugin_name = p_plugin->get_name();
+
+ // Keep the indices the same
+ // Find the index of the target plugin
+ ERR_FAIL_COND(!by_idx.has(plugin_name));
+ int idx = by_idx[plugin_name];
+ int last_idx = plugins.size() - 1;
+
+ // Swap the last plugin and the target one
+ SWAP(plugins[idx], plugins[last_idx]);
+
+ // Update the index of the old last one
+ by_idx[plugins[idx]->get_name()] = idx;
+
+ // Remove the target plugin's by_idx entry
+ by_idx.erase(plugin_name);
+
+ // Erase the plugin
+ plugins.remove(last_idx);
+}
+
int EditorImportExport::get_import_plugin_count() const{
return plugins.size();
diff --git a/tools/editor/editor_import_export.h b/tools/editor/editor_import_export.h
index 8305e3c88c..cd24fa076b 100644
--- a/tools/editor/editor_import_export.h
+++ b/tools/editor/editor_import_export.h
@@ -270,6 +270,7 @@ public:
static EditorImportExport* get_singleton() { return singleton; }
void add_import_plugin(const Ref<EditorImportPlugin>& p_plugin);
+ void remove_import_plugin(const Ref<EditorImportPlugin>& p_plugin);
int get_import_plugin_count() const;
Ref<EditorImportPlugin> get_import_plugin(int p_idx) const;
Ref<EditorImportPlugin> get_import_plugin_by_name(const String& p_string) const;
diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp
index 6ff16e661c..cc1a05f7d3 100644
--- a/tools/editor/editor_node.cpp
+++ b/tools/editor/editor_node.cpp
@@ -89,6 +89,7 @@
#include "plugins/animation_player_editor_plugin.h"
#include "plugins/baked_light_editor_plugin.h"
#include "plugins/polygon_2d_editor_plugin.h"
+#include "plugins/navigation_polygon_editor_plugin.h"
// end
#include "tools/editor/io_plugins/editor_texture_import_plugin.h"
#include "tools/editor/io_plugins/editor_scene_import_plugin.h"
@@ -336,6 +337,19 @@ void EditorNode::_vp_resized() {
}
+void EditorNode::_rebuild_import_menu()
+{
+ PopupMenu* p = import_menu->get_popup();
+ p->clear();
+ p->add_item("Sub-Scene", FILE_IMPORT_SUBSCENE);
+ p->add_separator();
+ for (int i = 0; i < editor_import_export->get_import_plugin_count(); i++) {
+ p->add_item(editor_import_export->get_import_plugin(i)->get_visible_name(), IMPORT_PLUGIN_BASE + i);
+ }
+ p->add_separator();
+ p->add_item("Re-Import..", SETTINGS_IMPORT);
+}
+
void EditorNode::_node_renamed() {
if (property_editor)
@@ -1967,6 +1981,25 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
log->add_message("REDO: "+action);
} break;
+
+ case EDIT_REVERT: {
+
+ Node *scene = get_edited_scene();
+
+ if (!scene)
+ break;
+
+ if (unsaved_cache && !p_confirmed) {
+ confirmation->get_ok()->set_text("Revert");
+ confirmation->set_text("This action cannot be undone. Revert anyway?");
+ confirmation->popup_centered(Size2(300,70));
+ break;
+ }
+
+ Error err = load_scene(scene->get_filename());
+
+ } break;
+
#if 0
case NODE_EXTERNAL_INSTANCE: {
@@ -2388,6 +2421,19 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor) {
}
+void EditorNode::add_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import) {
+
+ editor_import_export->add_import_plugin(p_editor_import);
+ _rebuild_import_menu();
+}
+
+void EditorNode::remove_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import) {
+
+ editor_import_export->remove_import_plugin(p_editor_import);
+ _rebuild_import_menu();
+}
+
+
void EditorNode::set_edited_scene(Node *p_scene) {
if (edited_scene) {
@@ -3152,6 +3198,9 @@ void EditorNode::_bind_methods() {
ObjectTypeDB::bind_method("_sources_changed",&EditorNode::_sources_changed);
ObjectTypeDB::bind_method("_fs_changed",&EditorNode::_fs_changed);
+ ObjectTypeDB::bind_method(_MD("add_editor_import_plugin", "plugin"), &EditorNode::add_editor_import_plugin);
+ ObjectTypeDB::bind_method(_MD("remove_editor_import_plugin", "plugin"), &EditorNode::remove_editor_import_plugin);
+ ObjectTypeDB::bind_method(_MD("get_gui_base"), &EditorNode::get_gui_base);
ADD_SIGNAL( MethodInfo("play_pressed") );
ADD_SIGNAL( MethodInfo("pause_pressed") );
@@ -3212,6 +3261,11 @@ Error EditorNode::export_platform(const String& p_platform, const String& p_path
return OK;
}
+void EditorNode::show_warning(const String& p_text) {
+
+ warning->set_text(p_text);
+ warning->popup_centered_minsize();
+}
EditorNode::EditorNode() {
@@ -3469,6 +3523,8 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_item("Project Settings",RUN_SETTINGS);
p->add_separator();
+ p->add_item("Revert Scene",EDIT_REVERT);
+ p->add_separator();
p->add_item("Quit to Project List",RUN_PROJECT_MANAGER,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_Q);
p->add_item("Quit",FILE_QUIT,KEY_MASK_CMD+KEY_Q);
@@ -3513,8 +3569,6 @@ EditorNode::EditorNode() {
left_menu_hb->add_child( import_menu );
p=import_menu->get_popup();
- p->add_item("Sub-Scene",FILE_IMPORT_SUBSCENE);
- p->add_separator();
p->connect("item_pressed",this,"_menu_option");
export_button = memnew( ToolButton );
@@ -3552,7 +3606,7 @@ EditorNode::EditorNode() {
play_button->set_icon(gui_base->get_icon("MainPlay","EditorIcons"));
play_button->set_focus_mode(Control::FOCUS_NONE);
play_button->connect("pressed", this,"_menu_option",make_binds(RUN_PLAY));
- play_button->set_tooltip("Start the scene (F5).");
+ play_button->set_tooltip("Play the project (F5).");
@@ -3922,6 +3976,8 @@ EditorNode::EditorNode() {
logo->set_pos(Point2(20,20));
logo->set_texture(gui_base->get_icon("Logo","EditorIcons") );
+ warning = memnew( AcceptDialog );
+ add_child(warning);
@@ -4023,11 +4079,6 @@ EditorNode::EditorNode() {
editor_import_export->add_import_plugin( Ref<EditorSampleImportPlugin>( memnew(EditorSampleImportPlugin(this))));
editor_import_export->add_import_plugin( Ref<EditorTranslationImportPlugin>( memnew(EditorTranslationImportPlugin(this))));
-
- for(int i=0;i<editor_import_export->get_import_plugin_count();i++) {
- import_menu->get_popup()->add_item(editor_import_export->get_import_plugin(i)->get_visible_name(),IMPORT_PLUGIN_BASE+i);
- }
-
editor_import_export->add_export_plugin( Ref<EditorTextureExportPlugin>( memnew(EditorTextureExportPlugin)));
add_editor_plugin( memnew( CanvasItemEditorPlugin(this) ) );
@@ -4064,6 +4115,7 @@ EditorNode::EditorNode() {
add_editor_plugin( memnew( PathEditorPlugin(this) ) );
add_editor_plugin( memnew( BakedLightEditorPlugin(this) ) );
add_editor_plugin( memnew( Polygon2DEditorPlugin(this) ) );
+ add_editor_plugin( memnew( NavigationPolygonEditorPlugin(this) ) );
for(int i=0;i<EditorPlugins::get_plugin_count();i++)
add_editor_plugin( EditorPlugins::create(i,this) );
@@ -4072,9 +4124,7 @@ EditorNode::EditorNode() {
circle_step_frame=OS::get_singleton()->get_frames_drawn();;
circle_step=0;
-
- import_menu->get_popup()->add_separator();
- import_menu->get_popup()->add_item("Re-Import..",SETTINGS_IMPORT);
+ _rebuild_import_menu();
editor_plugin_screen=NULL;
editor_plugin_over=NULL;
diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h
index 7560c2b149..531eccb546 100644
--- a/tools/editor/editor_node.h
+++ b/tools/editor/editor_node.h
@@ -127,6 +127,7 @@ class EditorNode : public Node {
FILE_EXTERNAL_OPEN_SCENE,
EDIT_UNDO,
EDIT_REDO,
+ EDIT_REVERT,
RESOURCE_NEW,
RESOURCE_LOAD,
RESOURCE_SAVE,
@@ -231,6 +232,7 @@ class EditorNode : public Node {
ConfirmationDialog *open_recent_confirmation;
AcceptDialog *accept;
AcceptDialog *about;
+ AcceptDialog *warning;
//OptimizedPresetsDialog *optimized_presets;
EditorSettingsDialog *settings_config_dialog;
@@ -339,6 +341,8 @@ class EditorNode : public Node {
void _show_messages();
void _vp_resized();
+ void _rebuild_import_menu();
+
void _save_scene(String p_file);
@@ -420,6 +424,9 @@ public:
static void add_editor_plugin(EditorPlugin *p_editor);
static void remove_editor_plugin(EditorPlugin *p_editor);
+ void add_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import);
+ void remove_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import);
+
void edit_node(Node *p_node);
void edit_resource(const Ref<Resource>& p_resource);
@@ -478,6 +485,9 @@ public:
Ref<Theme> get_editor_theme() const { return theme; }
+ void show_warning(const String& p_text);
+
+
Error export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after=false);
static void register_editor_types();
diff --git a/tools/editor/icons/icon_light_2d.png b/tools/editor/icons/icon_light_2d.png
new file mode 100644
index 0000000000..9162b33090
--- /dev/null
+++ b/tools/editor/icons/icon_light_2d.png
Binary files differ
diff --git a/tools/editor/icons/icon_navigation_2d.png b/tools/editor/icons/icon_navigation_2d.png
new file mode 100644
index 0000000000..8170ecf68c
--- /dev/null
+++ b/tools/editor/icons/icon_navigation_2d.png
Binary files differ
diff --git a/tools/editor/icons/icon_navigation_polygon_instance.png b/tools/editor/icons/icon_navigation_polygon_instance.png
new file mode 100644
index 0000000000..9f9c318906
--- /dev/null
+++ b/tools/editor/icons/icon_navigation_polygon_instance.png
Binary files differ
diff --git a/tools/editor/plugins/collision_polygon_editor_plugin.cpp b/tools/editor/plugins/collision_polygon_editor_plugin.cpp
index b92acb60f9..a6f2085a19 100644
--- a/tools/editor/plugins/collision_polygon_editor_plugin.cpp
+++ b/tools/editor/plugins/collision_polygon_editor_plugin.cpp
@@ -31,6 +31,8 @@
#include "os/file_access.h"
#include "tools/editor/editor_settings.h"
#include "scene/3d/camera.h"
+#include "canvas_item_editor_plugin.h"
+
void CollisionPolygonEditor::_notification(int p_what) {
switch(p_what) {
@@ -71,14 +73,14 @@ void CollisionPolygonEditor::_node_removed(Node *p_node) {
Vector2 CollisionPolygonEditor::snap_point(const Vector2& p_point) const {
return p_point;
- /*
- if (canvas_item_editor->is_snap_active()) {
+
+ if (CanvasItemEditor::get_singleton()->is_snap_active()) {
- return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap());
+ return p_point.snapped(Vector2(1,1)*CanvasItemEditor::get_singleton()->get_snap());
} else {
return p_point;
- } ??? */
+ }
}
void CollisionPolygonEditor::_menu_option(int p_option) {
@@ -148,7 +150,7 @@ bool CollisionPolygonEditor::forward_spatial_input_event(Camera* p_camera,const
Vector2 cpoint(spoint.x,spoint.y);
- //cpoint=snap_point(cpoint); snap?
+ cpoint=snap_point(cpoint);
Vector<Vector2> poly = node->get_polygon();
@@ -362,7 +364,7 @@ bool CollisionPolygonEditor::forward_spatial_input_event(Camera* p_camera,const
Vector2 cpoint(spoint.x,spoint.y);
- //cpoint=snap_point(cpoint);
+ cpoint=snap_point(cpoint);
edited_point_pos = cpoint;
_polygon_draw();
diff --git a/tools/editor/plugins/navigation_polygon_editor_plugin.cpp b/tools/editor/plugins/navigation_polygon_editor_plugin.cpp
new file mode 100644
index 0000000000..599d18c8bb
--- /dev/null
+++ b/tools/editor/plugins/navigation_polygon_editor_plugin.cpp
@@ -0,0 +1,547 @@
+#include "navigation_polygon_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "os/file_access.h"
+#include "tools/editor/editor_settings.h"
+
+void NavigationPolygonEditor::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_READY: {
+
+ button_create->set_icon( get_icon("Edit","EditorIcons"));
+ button_edit->set_icon( get_icon("MovePoint","EditorIcons"));
+ button_edit->set_pressed(true);
+ get_tree()->connect("node_removed",this,"_node_removed");
+ create_nav->connect("confirmed",this,"_create_nav");
+
+ } break;
+ case NOTIFICATION_FIXED_PROCESS: {
+
+
+ } break;
+ }
+
+}
+void NavigationPolygonEditor::_node_removed(Node *p_node) {
+
+ if(p_node==node) {
+ node=NULL;
+ hide();
+ canvas_item_editor->get_viewport_control()->update();
+ }
+
+}
+
+void NavigationPolygonEditor::_create_nav() {
+
+ undo_redo->create_action("Create Navigation Polygon");
+ undo_redo->add_do_method(node,"set_navigation_polygon",Ref<NavigationPolygon>(memnew( NavigationPolygon)));
+ undo_redo->add_undo_method(node,"set_navigation_polygon",Variant(REF()));
+ undo_redo->commit_action();
+}
+
+Vector2 NavigationPolygonEditor::snap_point(const Vector2& p_point) const {
+
+ if (canvas_item_editor->is_snap_active()) {
+
+ return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap());
+
+ } else {
+ return p_point;
+ }
+}
+
+void NavigationPolygonEditor::_menu_option(int p_option) {
+
+ switch(p_option) {
+
+ case MODE_CREATE: {
+
+ mode=MODE_CREATE;
+ button_create->set_pressed(true);
+ button_edit->set_pressed(false);
+ } break;
+ case MODE_EDIT: {
+
+ mode=MODE_EDIT;
+ button_create->set_pressed(false);
+ button_edit->set_pressed(true);
+ } break;
+
+ }
+}
+
+void NavigationPolygonEditor::_wip_close() {
+
+
+ if (wip.size()>=3) {
+
+ undo_redo->create_action("Create Poly");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"remove_outline",node->get_navigation_polygon()->get_outline_count());
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"add_outline",wip);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+ mode=MODE_EDIT;
+ button_edit->set_pressed(true);
+ button_create->set_pressed(false);
+ }
+
+ wip.clear();
+ wip_active=false;
+ edited_point=-1;
+}
+
+bool NavigationPolygonEditor::forward_input_event(const InputEvent& p_event) {
+
+
+ if (!node)
+ return false;
+
+ if (node->get_navigation_polygon().is_null()) {
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) {
+ create_nav->set_text("No NavigationPolygon resource on this node.\nCreate and assign one?");
+ create_nav->popup_centered_minsize();
+ }
+ return false;
+ }
+
+
+ switch(p_event.type) {
+
+ case InputEvent::MOUSE_BUTTON: {
+
+ const InputEventMouseButton &mb=p_event.mouse_button;
+
+ Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+
+
+ Vector2 gpoint = Point2(mb.x,mb.y);
+ Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
+ cpoint=snap_point(cpoint);
+ cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
+
+
+
+ //first check if a point is to be added (segment split)
+ real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8);
+
+ switch(mode) {
+
+
+ case MODE_CREATE: {
+
+ if (mb.button_index==BUTTON_LEFT && mb.pressed) {
+
+
+ if (!wip_active) {
+
+ wip.clear();
+ wip.push_back( cpoint );
+ wip_active=true;
+ edited_point_pos=cpoint;
+ edited_outline=-1;
+ canvas_item_editor->get_viewport_control()->update();
+ edited_point=1;
+ return true;
+ } else {
+
+
+ if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) {
+ //wip closed
+ _wip_close();
+
+ return true;
+ } else {
+
+ wip.push_back( cpoint );
+ edited_point=wip.size();
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+
+ //add wip point
+ }
+ }
+ } else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) {
+ _wip_close();
+ }
+
+
+
+ } break;
+
+ case MODE_EDIT: {
+
+ if (mb.button_index==BUTTON_LEFT) {
+ if (mb.pressed) {
+
+ if (mb.mod.control) {
+
+
+ //search edges
+ int closest_outline=-1;
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+
+ for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) {
+
+
+ DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j);
+
+ int pc=points.size();
+ DVector<Vector2>::Read poly=points.read();
+
+ for(int i=0;i<pc;i++) {
+
+ Vector2 points[2] ={ xform.xform(poly[i]),
+ xform.xform(poly[(i+1)%pc]) };
+
+ Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points);
+ 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_treshold) {
+ closest_dist=d;
+ closest_outline=j;
+ closest_pos=cp;
+ closest_idx=i;
+ }
+
+
+ }
+ }
+
+ if (closest_idx>=0) {
+
+ pre_move_edit=node->get_navigation_polygon()->get_outline(closest_outline);
+ DVector<Point2> poly = pre_move_edit;
+ poly.insert(closest_idx+1,xform.affine_inverse().xform(closest_pos));
+ edited_point=closest_idx+1;
+ edited_outline=closest_outline;
+ edited_point_pos=xform.affine_inverse().xform(closest_pos);
+ node->get_navigation_polygon()->set_outline(closest_outline,poly);
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+ }
+ } else {
+
+ //look for points to move
+ int closest_outline=-1;
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+
+ for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) {
+
+
+ DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j);
+
+ int pc=points.size();
+ DVector<Vector2>::Read poly=points.read();
+
+ for(int i=0;i<pc;i++) {
+
+
+ Vector2 cp =xform.xform(poly[i]);
+
+ real_t d = cp.distance_to(gpoint);
+ if (d<closest_dist && d<grab_treshold) {
+ closest_dist=d;
+ closest_pos=cp;
+ closest_outline=j;
+ closest_idx=i;
+ }
+ }
+ }
+
+ if (closest_idx>=0) {
+
+ pre_move_edit=node->get_navigation_polygon()->get_outline(closest_outline);
+ edited_point=closest_idx;
+ edited_outline=closest_outline;
+ edited_point_pos=xform.affine_inverse().xform(closest_pos);
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+ }
+ }
+ } else {
+
+ if (edited_point!=-1) {
+
+ //apply
+
+ DVector<Vector2> poly = node->get_navigation_polygon()->get_outline(edited_outline);
+ ERR_FAIL_INDEX_V(edited_point,poly.size(),false);
+ poly.set(edited_point,edited_point_pos);
+ undo_redo->create_action("Edit Poly");
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"set_outline",edited_outline,poly);
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"set_outline",edited_outline,pre_move_edit);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+
+ edited_point=-1;
+ return true;
+ }
+ }
+ } if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) {
+
+ int closest_outline=-1;
+ int closest_idx=-1;
+ Vector2 closest_pos;
+ real_t closest_dist=1e10;
+
+ for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) {
+
+
+ DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j);
+
+ int pc=points.size();
+ DVector<Vector2>::Read poly=points.read();
+
+ for(int i=0;i<pc;i++) {
+
+
+ Vector2 cp =xform.xform(poly[i]);
+
+ real_t d = cp.distance_to(gpoint);
+ if (d<closest_dist && d<grab_treshold) {
+ closest_dist=d;
+ closest_pos=cp;
+ closest_outline=j;
+ closest_idx=i;
+ }
+ }
+ }
+
+ if (closest_idx>=0) {
+
+
+ DVector<Vector2> poly = node->get_navigation_polygon()->get_outline(closest_outline);
+
+ if (poly.size()>3) {
+ undo_redo->create_action("Edit Poly (Remove Point)");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"set_outline",closest_outline,poly);
+ poly.remove(closest_idx);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"set_outline",closest_outline,poly);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+ } else {
+
+ undo_redo->create_action("Remove Poly And Point");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"add_outline_at_index",poly,closest_outline);
+ poly.remove(closest_idx);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"remove_outline",closest_outline);
+ undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
+ undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+ undo_redo->commit_action();
+
+ }
+ return true;
+ }
+ }
+
+
+
+ } break;
+ }
+
+
+
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+
+ const InputEventMouseMotion &mm=p_event.mouse_motion;
+
+ if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) {
+
+ Vector2 gpoint = Point2(mm.x,mm.y);
+ Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
+ cpoint=snap_point(cpoint);
+ edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);
+
+ canvas_item_editor->get_viewport_control()->update();
+
+ }
+
+ } break;
+ }
+
+ return false;
+}
+void NavigationPolygonEditor::_canvas_draw() {
+
+ if (!node)
+ return;
+
+ Control *vpc = canvas_item_editor->get_viewport_control();
+ if (node->get_navigation_polygon().is_null())
+ return;
+
+ Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+ Ref<Texture> handle= get_icon("EditorHandle","EditorIcons");
+
+
+
+ for(int j=-1;j<node->get_navigation_polygon()->get_outline_count();j++) {
+ Vector<Vector2> poly;
+
+ if (wip_active && j==edited_outline) {
+ poly=wip;
+ } else {
+ if (j==-1)
+ continue;
+ poly = Variant(node->get_navigation_polygon()->get_outline(j));
+ }
+
+ int len = poly.size();
+
+ for(int i=0;i<poly.size();i++) {
+
+
+ Vector2 p,p2;
+ p = (j==edited_outline && i==edited_point) ? edited_point_pos : poly[i];
+ if (j==edited_outline && ((wip_active && i==poly.size()-1) || (((i+1)%poly.size())==edited_point)))
+ p2=edited_point_pos;
+ else
+ p2 = poly[(i+1)%poly.size()];
+
+ Vector2 point = xform.xform(p);
+ Vector2 next_point = xform.xform(p2);
+
+ Color col=Color(1,0.3,0.1,0.8);
+ vpc->draw_line(point,next_point,col,2);
+ vpc->draw_texture(handle,point-handle->get_size()*0.5);
+ }
+ }
+}
+
+
+
+void NavigationPolygonEditor::edit(Node *p_collision_polygon) {
+
+ if (!canvas_item_editor) {
+ canvas_item_editor=CanvasItemEditor::get_singleton();
+ }
+
+ if (p_collision_polygon) {
+
+ node=p_collision_polygon->cast_to<NavigationPolygonInstance>();
+ 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;
+
+ } 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");
+
+ }
+
+}
+
+void NavigationPolygonEditor::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_menu_option"),&NavigationPolygonEditor::_menu_option);
+ ObjectTypeDB::bind_method(_MD("_canvas_draw"),&NavigationPolygonEditor::_canvas_draw);
+ ObjectTypeDB::bind_method(_MD("_node_removed"),&NavigationPolygonEditor::_node_removed);
+ ObjectTypeDB::bind_method(_MD("_create_nav"),&NavigationPolygonEditor::_create_nav);
+
+}
+
+NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) {
+
+ canvas_item_editor=NULL;
+ editor=p_editor;
+ undo_redo = editor->get_undo_redo();
+
+ add_child( memnew( VSeparator ));
+ button_create = memnew( ToolButton );
+ add_child(button_create);
+ button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE));
+ button_create->set_toggle_mode(true);
+ button_create->set_tooltip("Create a new polygon from scratch");
+
+ button_edit = memnew( ToolButton );
+ add_child(button_edit);
+ button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT));
+ button_edit->set_toggle_mode(true);
+ button_edit->set_tooltip("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point.");
+ create_nav = memnew( ConfirmationDialog );
+ add_child(create_nav);
+ create_nav->get_ok()->set_text("Create");
+
+
+ //add_constant_override("separation",0);
+
+#if 0
+ options = memnew( MenuButton );
+ add_child(options);
+ options->set_area_as_parent_rect();
+ options->set_text("Polygon");
+ //options->get_popup()->add_item("Parse BBCODE",PARSE_BBCODE);
+ options->get_popup()->connect("item_pressed", this,"_menu_option");
+#endif
+
+ mode = MODE_EDIT;
+ wip_active=false;
+ edited_outline=-1;
+
+}
+
+
+void NavigationPolygonEditorPlugin::edit(Object *p_object) {
+
+ collision_polygon_editor->edit(p_object->cast_to<Node>());
+}
+
+bool NavigationPolygonEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_type("NavigationPolygonInstance");
+}
+
+void NavigationPolygonEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ collision_polygon_editor->show();
+ } else {
+
+ collision_polygon_editor->hide();
+ collision_polygon_editor->edit(NULL);
+ }
+
+}
+
+NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) {
+
+ editor=p_node;
+ collision_polygon_editor = memnew( NavigationPolygonEditor(p_node) );
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
+
+ collision_polygon_editor->hide();
+
+
+
+}
+
+
+NavigationPolygonEditorPlugin::~NavigationPolygonEditorPlugin()
+{
+}
+
diff --git a/tools/editor/plugins/navigation_polygon_editor_plugin.h b/tools/editor/plugins/navigation_polygon_editor_plugin.h
new file mode 100644
index 0000000000..a86d28c8a8
--- /dev/null
+++ b/tools/editor/plugins/navigation_polygon_editor_plugin.h
@@ -0,0 +1,91 @@
+#ifndef NAVIGATIONPOLYGONEDITORPLUGIN_H
+#define NAVIGATIONPOLYGONEDITORPLUGIN_H
+
+
+
+#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_node.h"
+#include "scene/2d/navigation_polygon.h"
+#include "scene/gui/tool_button.h"
+#include "scene/gui/button_group.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class CanvasItemEditor;
+
+class NavigationPolygonEditor : public HBoxContainer {
+
+ OBJ_TYPE(NavigationPolygonEditor, HBoxContainer );
+
+ UndoRedo *undo_redo;
+ enum Mode {
+
+ MODE_CREATE,
+ MODE_EDIT,
+
+ };
+
+ Mode mode;
+
+ ToolButton *button_create;
+ ToolButton *button_edit;
+
+ ConfirmationDialog *create_nav;
+
+ CanvasItemEditor *canvas_item_editor;
+ EditorNode *editor;
+ Panel *panel;
+ NavigationPolygonInstance *node;
+ MenuButton *options;
+
+ int edited_outline;
+ int edited_point;
+ Vector2 edited_point_pos;
+ DVector<Vector2> pre_move_edit;
+ Vector<Vector2> wip;
+ bool wip_active;
+
+
+ void _wip_close();
+ void _canvas_draw();
+ void _create_nav();
+
+ void _menu_option(int p_option);
+
+protected:
+ void _notification(int p_what);
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+public:
+
+ Vector2 snap_point(const Vector2& p_point) const;
+ bool forward_input_event(const InputEvent& p_event);
+ void edit(Node *p_collision_polygon);
+ NavigationPolygonEditor(EditorNode *p_editor);
+};
+
+class NavigationPolygonEditorPlugin : public EditorPlugin {
+
+ OBJ_TYPE( NavigationPolygonEditorPlugin, EditorPlugin );
+
+ NavigationPolygonEditor *collision_polygon_editor;
+ EditorNode *editor;
+
+public:
+
+ virtual bool forward_input_event(const InputEvent& p_event) { return collision_polygon_editor->forward_input_event(p_event); }
+
+ virtual String get_name() const { return "NavigationPolygonInstance"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_node);
+ virtual bool handles(Object *p_node) const;
+ virtual void make_visible(bool p_visible);
+
+ NavigationPolygonEditorPlugin(EditorNode *p_node);
+ ~NavigationPolygonEditorPlugin();
+
+};
+
+
+#endif // NAVIGATIONPOLYGONEDITORPLUGIN_H
diff --git a/tools/editor/plugins/script_editor_plugin.cpp b/tools/editor/plugins/script_editor_plugin.cpp
index 4b7d1cf0e0..1349d5ccab 100644
--- a/tools/editor/plugins/script_editor_plugin.cpp
+++ b/tools/editor/plugins/script_editor_plugin.cpp
@@ -631,7 +631,10 @@ bool ScriptEditor::_test_script_times_on_disk() {
if (!all_ok)
- disk_changed->call_deferred("popup_centered_ratio",0.5);
+ if (bool(EDITOR_DEF("text_editor/auto_reload_changed_scripts",false)))
+ script_editor->_reload_scripts();
+ else
+ disk_changed->call_deferred("popup_centered_ratio",0.5);
return all_ok;
}
@@ -1806,6 +1809,7 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {
script_editor->hide();
+ EDITOR_DEF("text_editor/auto_reload_changed_scripts",false);
EDITOR_DEF("external_editor/use_external_editor",false);
EDITOR_DEF("external_editor/exec_path","");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"external_editor/exec_path",PROPERTY_HINT_GLOBAL_FILE));
diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp
index cff3913579..6f33d4b3d1 100644
--- a/tools/editor/scene_tree_dock.cpp
+++ b/tools/editor/scene_tree_dock.cpp
@@ -79,10 +79,22 @@ Node* SceneTreeDock::instance(const String& p_file) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("Ugh");
accept->set_text(String("Error loading scene from ")+p_file);
- accept->popup_centered(Size2(300,70));;
+ accept->popup_centered(Size2(300,70));
return NULL;
}
+ // If the scene hasn't been saved yet a cyclical dependency cannot exist.
+ if (edited_scene->get_filename()!="") {
+
+ if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) {
+
+ accept->get_ok()->set_text("Ok");
+ accept->set_text(String("Cannot instance the scene '")+p_file+String("' because the current scene exists within one of its' nodes."));
+ accept->popup_centered(Size2(300,90));
+ return NULL;
+ }
+ }
+
instanced_scene->generate_instance_state();
instanced_scene->set_filename( Globals::get_singleton()->localize_path(p_file) );
@@ -100,6 +112,25 @@ Node* SceneTreeDock::instance(const String& p_file) {
}
+bool SceneTreeDock::_cyclical_dependency_exists(const String& p_target_scene_path, Node* p_desired_node) {
+ int childCount = p_desired_node->get_child_count();
+
+ if (p_desired_node->get_filename()==p_target_scene_path) {
+ return true;
+ }
+
+ for (int i=0;i<childCount;i++) {
+ Node* child=p_desired_node->get_child(i);
+
+ if(_cyclical_dependency_exists(p_target_scene_path,child)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
static String _get_name_num_separator() {
switch(EditorSettings::get_singleton()->get("scenetree_editor/duplicate_node_name_num_separator").operator int()) {
case 0: return "";
diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h
index ac5391f3b9..92ebfc5bee 100644
--- a/tools/editor/scene_tree_dock.h
+++ b/tools/editor/scene_tree_dock.h
@@ -102,6 +102,7 @@ class SceneTreeDock : public VBoxContainer {
void _load_request(const String& p_path);
void _script_open_request(const Ref<Script>& p_script);
+ bool _cyclical_dependency_exists(const String& p_target_scene_path, Node* p_desired_node);
void _node_selected();
void _node_renamed();