1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-15 13:51:40 +00:00

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).
This commit is contained in:
Marc Gilleron
2016-12-09 02:52:40 +01:00
parent dab73c701a
commit e2fba10b95
12 changed files with 1489 additions and 0 deletions

View File

@@ -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();
}