diff options
author | Marc Gilleron <marc.gilleron@gmail.com> | 2016-12-09 02:52:40 +0100 |
---|---|---|
committer | Marc Gilleron <marc.gilleron@gmail.com> | 2017-01-15 00:44:46 +0100 |
commit | e2fba10b952f694f604e20b9e5f220023a5f8fd2 (patch) | |
tree | 39b17083e2e7b8b830bce929c45109a4928064d5 /tools | |
parent | dab73c701a9785be443977a613e57600d1e136c8 (diff) |
Added Line2D node that draws a polygon-based line
It supports unlimited width, color gradient, texture and some geometry
options for joints and caps. Also transparency without artifacts
(provided that line joints aren't too sharp).
Diffstat (limited to 'tools')
-rw-r--r-- | tools/editor/editor_node.cpp | 2 | ||||
-rw-r--r-- | tools/editor/icons/2x/icon_line_2d.png | bin | 0 -> 795 bytes | |||
-rw-r--r-- | tools/editor/icons/icon_line_2d.png | bin | 0 -> 474 bytes | |||
-rw-r--r-- | tools/editor/icons/source/icon_line_2d.svg | 82 | ||||
-rw-r--r-- | tools/editor/plugins/line_2d_editor_plugin.cpp | 283 | ||||
-rw-r--r-- | tools/editor/plugins/line_2d_editor_plugin.h | 85 |
6 files changed, 452 insertions, 0 deletions
diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index bb33f19a2b..979f54dabb 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -88,6 +88,7 @@ #include "plugins/script_editor_plugin.h" #include "plugins/script_text_editor.h" #include "plugins/path_2d_editor_plugin.h" +#include "plugins/line_2d_editor_plugin.h" #include "plugins/particles_editor_plugin.h" #include "plugins/particles_2d_editor_plugin.h" #include "plugins/animation_tree_editor_plugin.h" @@ -6599,6 +6600,7 @@ EditorNode::EditorNode() { add_editor_plugin( memnew( Path2DEditorPlugin(this) ) ); //add_editor_plugin( memnew( PathEditorPlugin(this) ) ); //add_editor_plugin( memnew( BakedLightEditorPlugin(this) ) ); + add_editor_plugin( memnew( Line2DEditorPlugin(this) ) ); add_editor_plugin( memnew( Polygon2DEditorPlugin(this) ) ); add_editor_plugin( memnew( LightOccluder2DEditorPlugin(this) ) ); add_editor_plugin( memnew( NavigationPolygonEditorPlugin(this) ) ); diff --git a/tools/editor/icons/2x/icon_line_2d.png b/tools/editor/icons/2x/icon_line_2d.png Binary files differnew file mode 100644 index 0000000000..27299a2b69 --- /dev/null +++ b/tools/editor/icons/2x/icon_line_2d.png diff --git a/tools/editor/icons/icon_line_2d.png b/tools/editor/icons/icon_line_2d.png Binary files differnew file mode 100644 index 0000000000..4ebf46af04 --- /dev/null +++ b/tools/editor/icons/icon_line_2d.png diff --git a/tools/editor/icons/source/icon_line_2d.svg b/tools/editor/icons/source/icon_line_2d.svg new file mode 100644 index 0000000000..7f833f4a9c --- /dev/null +++ b/tools/editor/icons/source/icon_line_2d.svg @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + viewBox="0 0 16 16" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + inkscape:export-filename="D:\PROJETS\INFO\GODOT\ENGINE\godot_fork\tools\editor\icons\2x\icon_line_2d.png" + inkscape:export-xdpi="180" + inkscape:export-ydpi="180" + sodipodi:docname="icon_line_2d.svg"> + <defs + id="defs4" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="31.999999" + inkscape:cx="7.5587317" + inkscape:cy="9.1781644" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + units="px" + inkscape:snap-bbox="true" + inkscape:bbox-paths="true" + inkscape:bbox-nodes="true" + inkscape:snap-bbox-edge-midpoints="true" + inkscape:snap-bbox-midpoints="true" + inkscape:snap-object-midpoints="true" + inkscape:snap-center="true" + inkscape:window-width="1920" + inkscape:window-height="1017" + inkscape:window-x="-8" + inkscape:window-y="32" + inkscape:window-maximized="1" + inkscape:snap-grids="true" + inkscape:object-nodes="true" + showguides="false"> + <inkscape:grid + type="xygrid" + id="grid3336" + empspacing="4" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-1036.3622)"> + <path + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#a5b7f3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529" + d="m 2,1045.3622 3,4 3,-10 3,6 3,-2" + id="path4135" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccc" /> + </g> +</svg> diff --git a/tools/editor/plugins/line_2d_editor_plugin.cpp b/tools/editor/plugins/line_2d_editor_plugin.cpp new file mode 100644 index 0000000000..054a2c62e0 --- /dev/null +++ b/tools/editor/plugins/line_2d_editor_plugin.cpp @@ -0,0 +1,283 @@ +#include "line_2d_editor_plugin.h" + +#include "canvas_item_editor_plugin.h" +#include "os/file_access.h" +#include "tools/editor/editor_settings.h" +#include "os/keyboard.h" + + +//---------------------------------------------------------------------------- +// Line2DEditor +//---------------------------------------------------------------------------- + +void Line2DEditor::_node_removed(Node *p_node) { + if(p_node == node) { + node=NULL; + hide(); + } +} + +void Line2DEditor::_notification(int p_what) { + switch(p_what) { + case NOTIFICATION_VISIBILITY_CHANGED: + // This widget is not a child but should have the same visibility state + base_hb->set_visible(is_visible()); + break; + } +} + +Vector2 Line2DEditor::mouse_to_local_pos(Vector2 gpoint, 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(gpoint)) + : node->get_global_transform().affine_inverse().xform( + canvas_item_editor->snap_point( + canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)) ); +} + +int Line2DEditor::get_point_index_at(Vector2 gpos) { + ERR_FAIL_COND_V(node == 0, -1); + + real_t grab_treshold = EDITOR_DEF("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_pos(i) ); + if(gpos.distance_to(p) < grab_treshold) { + return i; + } + } + + return -1; +} + +bool Line2DEditor::forward_input_event(const InputEvent& p_event) { + + if (!node) + return false; + + if (!node->is_visible()) + return false; + + switch(p_event.type) { + + case InputEvent::MOUSE_BUTTON: { + + const InputEventMouseButton &mb = p_event.mouse_button; + + Vector2 gpoint = Point2(mb.x,mb.y); + Vector2 cpoint = mouse_to_local_pos(gpoint, mb.mod.alt); + + if(mb.pressed && _dragging == false) { + int i = get_point_index_at(gpoint); + if(i != -1) { + if (mb.button_index == BUTTON_LEFT && !mb.mod.shift && mode == MODE_EDIT) { + _dragging = true; + action_point = i; + moving_from = node->get_point_pos(i); + moving_screen_from = gpoint; + } + else if((mb.button_index == BUTTON_RIGHT && mode == MODE_EDIT) || (mb.button_index == BUTTON_LEFT && mode == MODE_DELETE)) { + undo_redo->create_action(TTR("Remove Point from Line2D")); + undo_redo->add_do_method(node, "remove_point", i); + undo_redo->add_undo_method(node, "add_point", node->get_point_pos(i), i); + 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; + } + + if(mb.pressed && mb.button_index == BUTTON_LEFT && ((mb.mod.command && mode == MODE_EDIT) || mode == MODE_CREATE)) { + + undo_redo->create_action(TTR("Add Point to Line2D")); + undo_redo->add_do_method(node, "add_point", cpoint); + undo_redo->add_undo_method(node, "remove_point", node->get_point_count()); + 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(); + + _dragging = true; + action_point = node->get_point_count()-1; + moving_from = node->get_point_pos(action_point); + moving_screen_from = gpoint; + + canvas_item_editor->get_viewport_control()->update(); + + return true; + } + + if(!mb.pressed && mb.button_index == BUTTON_LEFT && _dragging) { + undo_redo->create_action(TTR("Move Point in Line2D")); + undo_redo->add_do_method(node, "set_point_pos", action_point, cpoint); + undo_redo->add_undo_method(node, "set_point_pos", action_point, moving_from); + 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(); + _dragging = false; + return true; + } + } + break; + + case InputEvent::MOUSE_MOTION: { + if (_dragging) { + const InputEventMouseMotion &mm = p_event.mouse_motion; + Vector2 cpoint = mouse_to_local_pos(Vector2(mm.x, mm.y), mm.mod.alt); + node->set_point_pos(action_point,cpoint); + canvas_item_editor->get_viewport_control()->update(); + return true; + } + } + break; + } + + return false; +} + +void Line2DEditor::_canvas_draw() { + + if (!node) + return; + + if (!node->is_visible()) + return; + + Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); + Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); + Size2 handle_size = handle->get_size(); + + int len = node->get_point_count(); + Control *vpc = canvas_item_editor->get_viewport_control(); + + for(int i=0; i < len; ++i) { + Vector2 point = xform.xform(node->get_point_pos(i)); + vpc->draw_texture_rect(handle, Rect2(point - handle_size * 0.5, handle_size), false); + } +} + +void Line2DEditor::_node_visibility_changed() { + if (!node) + return; + canvas_item_editor->get_viewport_control()->update(); +} + +void Line2DEditor::edit(Node *p_line2d) { + + if (!canvas_item_editor) + canvas_item_editor = CanvasItemEditor::get_singleton(); + + if (p_line2d) { + node = p_line2d->cast_to<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"); + node = NULL; + } +} + +void Line2DEditor::_bind_methods() { + ClassDB::bind_method(_MD("_canvas_draw"), &Line2DEditor::_canvas_draw); + ClassDB::bind_method(_MD("_node_visibility_changed"), &Line2DEditor::_node_visibility_changed); + ClassDB::bind_method(_MD("_mode_selected"), &Line2DEditor::_mode_selected); +} + +void Line2DEditor::_mode_selected(int p_mode) { + for(unsigned int i = 0; i < _MODE_COUNT; ++i) { + toolbar_buttons[i]->set_pressed(i == p_mode); + } + mode = Mode(p_mode); +} + +Line2DEditor::Line2DEditor(EditorNode *p_editor) { + + canvas_item_editor = NULL; + editor = p_editor; + undo_redo = editor->get_undo_redo(); + + _dragging = false; + + base_hb = memnew( HBoxContainer ); + CanvasItemEditor::get_singleton()->add_control_to_menu_panel(base_hb); + + sep = memnew( VSeparator); + base_hb->add_child(sep); + + { + ToolButton * b = memnew(ToolButton); + b->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveEdit", "EditorIcons")); + b->set_toggle_mode(true); + b->set_focus_mode(Control::FOCUS_NONE); + b->set_tooltip( + TTR("Select Points")+"\n" + + TTR("Shift+Drag: Select Control Points")+"\n" + + keycode_get_string(KEY_MASK_CMD) + + TTR("Click: Add Point")+"\n" + + TTR("Right Click: Delete Point")); + b->connect("pressed", this, "_mode_selected", varray(MODE_EDIT)); + toolbar_buttons[MODE_EDIT] = b; + base_hb->add_child(b); + } + + { + ToolButton * b = memnew(ToolButton); + b->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCreate", "EditorIcons")); + b->set_toggle_mode(true); + b->set_focus_mode(Control::FOCUS_NONE); + b->set_tooltip(TTR("Add Point (in empty space)")+"\n"+TTR("Split Segment (in line)")); + b->connect("pressed", this, "_mode_selected", varray(MODE_CREATE)); + toolbar_buttons[MODE_CREATE] = b; + base_hb->add_child(b); + } + + { + ToolButton * b = memnew( ToolButton ); + b->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveDelete", "EditorIcons")); + b->set_toggle_mode(true); + b->set_focus_mode(Control::FOCUS_NONE); + b->set_tooltip(TTR("Delete Point")); + b->connect("pressed", this, "_mode_selected", varray(MODE_DELETE)); + toolbar_buttons[MODE_DELETE] = b; + base_hb->add_child(b); + } + + base_hb->hide(); + hide(); + + _mode_selected(MODE_CREATE); +} + +//---------------------------------------------------------------------------- +// Line2DEditorPlugin +//---------------------------------------------------------------------------- + +void Line2DEditorPlugin::edit(Object *p_object) { + line2d_editor->edit(p_object->cast_to<Node>()); +} + +bool Line2DEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("Line2D"); +} + +void Line2DEditorPlugin::make_visible(bool p_visible) { + line2d_editor->set_visible(p_visible); + if(p_visible == false) + line2d_editor->edit(NULL); +} + +Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node) { + editor=p_node; + line2d_editor = memnew( Line2DEditor(p_node) ); + CanvasItemEditor::get_singleton()->add_control_to_menu_panel(line2d_editor); + line2d_editor->hide(); +} + + diff --git a/tools/editor/plugins/line_2d_editor_plugin.h b/tools/editor/plugins/line_2d_editor_plugin.h new file mode 100644 index 0000000000..0df64208a8 --- /dev/null +++ b/tools/editor/plugins/line_2d_editor_plugin.h @@ -0,0 +1,85 @@ +#ifndef LINE_2D_EDITOR_PLUGIN_H +#define LINE_2D_EDITOR_PLUGIN_H + +#include "tools/editor/editor_plugin.h" +#include "tools/editor/editor_node.h" +#include "scene/2d/path_2d.h" +#include "scene/gui/tool_button.h" +#include "scene/gui/button_group.h" +#include "scene/2d/line_2d.h" + + +class CanvasItemEditor; + +class Line2DEditor : public HBoxContainer { + GDCLASS(Line2DEditor, HBoxContainer) + +public: + bool forward_input_event(const 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); + + UndoRedo *undo_redo; + + CanvasItemEditor *canvas_item_editor; + EditorNode *editor; + Panel *panel; + Line2D *node; + + HBoxContainer *base_hb; + Separator *sep; + + enum Mode { + MODE_CREATE = 0, + MODE_EDIT, + MODE_DELETE, + _MODE_COUNT + }; + + Mode mode; + ToolButton* toolbar_buttons[_MODE_COUNT]; + + bool _dragging; + int action_point; + Point2 moving_from; + Point2 moving_screen_from; +}; + +class Line2DEditorPlugin : public EditorPlugin { + GDCLASS( Line2DEditorPlugin, EditorPlugin ) + +public: + virtual bool forward_canvas_input_event(const Transform2D& p_canvas_xform,const InputEvent& p_event) { return line2d_editor->forward_input_event(p_event); } + + virtual String get_name() const { return "Line2D"; } + 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); + + Line2DEditorPlugin(EditorNode *p_node); + +private: + Line2DEditor *line2d_editor; + EditorNode *editor; + +}; + +#endif // LINE_2D_EDITOR_PLUGIN_H + |