diff options
Diffstat (limited to 'editor/plugins')
21 files changed, 499 insertions, 126 deletions
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 28c5b89741..c3e1f60ccc 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -254,6 +254,10 @@ void AnimationPlayerEditor::_play_bw_from_pressed() { } void AnimationPlayerEditor::_stop_pressed() { + if (!player) { + return; + } + player->stop(false); play->set_pressed(false); stop->set_pressed(true); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 7c6b233bd4..7ce884a455 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -199,6 +199,25 @@ void CanvasItemEditor::_edit_set_pivot(const Vector2 &mouse_pos) { undo_redo->add_undo_method(n2dc, "set_global_position", n2dc->get_global_position()); } } + + Control *cnt = E->get()->cast_to<Control>(); + if (cnt) { + + Vector2 old_pivot = cnt->get_pivot_offset(); + Vector2 new_pivot = cnt->get_global_transform_with_canvas().affine_inverse().xform(mouse_pos); + Vector2 old_pos = cnt->get_position(); + + Vector2 top_pos = cnt->get_transform().get_origin(); //remember where top pos was + cnt->set_pivot_offset(new_pivot); + Vector2 new_top_pos = cnt->get_transform().get_origin(); //check where it is now + + Vector2 new_pos = old_pos - (new_top_pos - top_pos); //offset it back + + undo_redo->add_do_method(cnt, "set_pivot_offset", new_pivot); + undo_redo->add_do_method(cnt, "set_position", new_pos); + undo_redo->add_undo_method(cnt, "set_pivot_offset", old_pivot); + undo_redo->add_undo_method(cnt, "set_position", old_pos); + } } undo_redo->commit_action(); @@ -842,6 +861,8 @@ void CanvasItemEditor::_prepare_drag(const Point2 &p_click_pos) { se->undo_state = canvas_item->edit_get_state(); if (canvas_item->cast_to<Node2D>()) se->undo_pivot = canvas_item->cast_to<Node2D>()->edit_get_pivot(); + if (canvas_item->cast_to<Control>()) + se->undo_pivot = canvas_item->cast_to<Control>()->get_pivot_offset(); } if (selection.size() == 1 && selection[0]->cast_to<Node2D>()) { @@ -1149,6 +1170,8 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { canvas_item->edit_set_state(se->undo_state); if (canvas_item->cast_to<Node2D>()) canvas_item->cast_to<Node2D>()->edit_set_pivot(se->undo_pivot); + if (canvas_item->cast_to<Control>()) + canvas_item->cast_to<Control>()->set_pivot_offset(se->undo_pivot); } } @@ -1238,12 +1261,18 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { Variant state = canvas_item->edit_get_state(); undo_redo->add_do_method(canvas_item, "edit_set_state", state); undo_redo->add_undo_method(canvas_item, "edit_set_state", se->undo_state); - if (canvas_item->cast_to<Node2D>()) { + { Node2D *pvt = canvas_item->cast_to<Node2D>(); - if (pvt->edit_has_pivot()) { + if (pvt && pvt->edit_has_pivot()) { undo_redo->add_do_method(canvas_item, "edit_set_pivot", pvt->edit_get_pivot()); undo_redo->add_undo_method(canvas_item, "edit_set_pivot", se->undo_pivot); } + + Control *cnt = canvas_item->cast_to<Control>(); + if (cnt) { + undo_redo->add_do_method(canvas_item, "set_pivot_offset", cnt->get_pivot_offset()); + undo_redo->add_undo_method(canvas_item, "set_pivot_offset", se->undo_pivot); + } } } undo_redo->commit_action(); @@ -1380,7 +1409,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { if (canvas_item->cast_to<Node2D>()) se->undo_pivot = canvas_item->cast_to<Node2D>()->edit_get_pivot(); if (canvas_item->cast_to<Control>()) - se->undo_pivot = Vector2(); + se->undo_pivot = canvas_item->cast_to<Control>()->get_pivot_offset(); return; } @@ -1405,6 +1434,8 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { se->undo_state = canvas_item->edit_get_state(); if (canvas_item->cast_to<Node2D>()) se->undo_pivot = canvas_item->cast_to<Node2D>()->edit_get_pivot(); + if (canvas_item->cast_to<Control>()) + se->undo_pivot = canvas_item->cast_to<Control>()->get_pivot_offset(); return; } @@ -1522,6 +1553,8 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { canvas_item->edit_set_state(se->undo_state); //reset state and reapply if (canvas_item->cast_to<Node2D>()) canvas_item->cast_to<Node2D>()->edit_set_pivot(se->undo_pivot); + if (canvas_item->cast_to<Control>()) + canvas_item->cast_to<Control>()->set_pivot_offset(se->undo_pivot); } Vector2 dfrom = drag_from; @@ -1659,6 +1692,9 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { Node2D *n2d = canvas_item->cast_to<Node2D>(); n2d->edit_set_pivot(se->undo_pivot + drag_vector); } + if (canvas_item->cast_to<Control>()) { + canvas_item->cast_to<Control>()->set_pivot_offset(se->undo_pivot + drag_vector); + } continue; } break; case DRAG_NODE_2D: { @@ -1920,6 +1956,14 @@ void CanvasItemEditor::_viewport_draw() { pivot_found = true; } } + if (canvas_item->cast_to<Control>()) { + Vector2 pivot_ofs = canvas_item->cast_to<Control>()->get_pivot_offset(); + if (pivot_ofs != Vector2()) { + viewport->draw_texture(pivot, xform.xform(pivot_ofs) + (-pivot->get_size() / 2).floor()); + } + can_move_pivot = true; + pivot_found = true; + } if (tool == TOOL_SELECT) { @@ -2108,10 +2152,16 @@ void CanvasItemEditor::_notification(int p_what) { Transform2D xform = canvas_item->get_transform(); - if (r != se->prev_rect || xform != se->prev_xform) { + Vector2 pivot; + if (canvas_item->cast_to<Control>()) { + pivot = canvas_item->cast_to<Control>()->get_pivot_offset(); + } + + if (r != se->prev_rect || xform != se->prev_xform || pivot != se->prev_pivot) { viewport->update(); se->prev_rect = r; se->prev_xform = xform; + se->prev_pivot = pivot; } } diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 22fa5b5db8..702deb51f9 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -56,6 +56,7 @@ public: Transform2D prev_xform; float prev_rot; Rect2 prev_rect; + Vector2 prev_pivot; CanvasItemEditorSelectedItem() { prev_rot = 0; } }; diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/editor/plugins/collision_polygon_2d_editor_plugin.cpp index 43abea0131..abee3ead71 100644 --- a/editor/plugins/collision_polygon_2d_editor_plugin.cpp +++ b/editor/plugins/collision_polygon_2d_editor_plugin.cpp @@ -112,7 +112,7 @@ bool CollisionPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) Vector<Vector2> poly = node->get_polygon(); //first check if a point is to be added (segment split) - real_t grab_treshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); + real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); switch (mode) { @@ -131,7 +131,7 @@ bool CollisionPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) return true; } else { - if (wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_treshold) { + if (wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) { //wip closed _wip_close(); @@ -185,7 +185,7 @@ bool CollisionPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) continue; //not valid to reuse point real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_pos = cp; closest_idx = i; @@ -214,7 +214,7 @@ bool CollisionPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) Vector2 cp = xform.xform(poly[i]); real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_pos = cp; closest_idx = i; @@ -259,7 +259,7 @@ bool CollisionPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) Vector2 cp = xform.xform(poly[i]); real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_pos = cp; closest_idx = i; diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 50a625ddc1..2d05c8eba1 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -43,7 +43,6 @@ CurveEditor::CurveEditor() { _tangents_length = 40; _dragging = false; _has_undo_data = false; - _world_rect = Rect2(0, 0, 1, 1); set_focus_mode(FOCUS_ALL); set_clip_contents(true); @@ -70,11 +69,15 @@ void CurveEditor::set_curve(Ref<Curve> curve) { return; if (_curve_ref.is_valid()) { - _curve_ref->disconnect("changed", this, "_curve_changed"); + _curve_ref->disconnect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); + _curve_ref->disconnect(Curve::SIGNAL_RANGE_CHANGED, this, "_curve_changed"); } + _curve_ref = curve; + if (_curve_ref.is_valid()) { - _curve_ref->connect("changed", this, "_curve_changed"); + _curve_ref->connect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); + _curve_ref->connect(Curve::SIGNAL_RANGE_CHANGED, this, "_curve_changed"); } _selected_point = -1; @@ -130,7 +133,16 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { if (!mb.is_pressed() && _dragging && mb.get_button_index() == BUTTON_LEFT) { _dragging = false; if (_has_undo_data) { - push_undo(_undo_data); + + UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); + + ur.create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent")); + ur.add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data()); + ur.add_undo_method(*_curve_ref, "_set_data", _undo_data); + // Note: this will trigger one more "changed" signal even if nothing changes, + // but it's ok since it would have fired every frame during the drag anyways + ur.commit_action(); + _has_undo_data = false; } } @@ -144,11 +156,14 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { Vector2 mpos = mm.get_position(); if (_dragging && _curve_ref.is_valid()) { + Curve &curve = **_curve_ref; + if (_selected_point != -1) { if (!_has_undo_data) { - // Save curve state before dragging points - _undo_data = _curve_ref->get_data(); + // Save full curve state before dragging points, + // because this operation can modify their order + _undo_data = curve.get_data(); _has_undo_data = true; } @@ -157,26 +172,23 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { Vector2 point_pos = get_world_pos(mpos); - int i = _curve_ref->set_point_offset(_selected_point, point_pos.x); + int i = curve.set_point_offset(_selected_point, point_pos.x); // The index may change if the point is dragged across another one set_hover_point_index(i); set_selected_point(i); - // TODO Get rid of this clamp if zoom is implemented in this editor. // This is to prevent the user from loosing a point out of view. - if (point_pos.y < 0.0) - point_pos.y = 0.0; - else if (point_pos.y > 1.0) - point_pos.y = 1.0; + if (point_pos.y < curve.get_min_value()) + point_pos.y = curve.get_min_value(); + else if (point_pos.y > curve.get_max_value()) + point_pos.y = curve.get_max_value(); - _curve_ref->set_point_value(_selected_point, point_pos.y); - - //auto_calculate_tangents(i); + curve.set_point_value(_selected_point, point_pos.y); } else { // Drag tangent - Vector2 point_pos = _curve_ref->get_point_pos(_selected_point); + Vector2 point_pos = curve.get_point_pos(_selected_point); Vector2 control_pos = get_world_pos(mpos); Vector2 dir = (control_pos - point_pos).normalized(); @@ -190,13 +202,17 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { bool link = !Input::get_singleton()->is_key_pressed(KEY_SHIFT); if (_selected_tangent == TANGENT_LEFT) { - _curve_ref->set_point_left_tangent(_selected_point, tangent); - if (link && _selected_point != _curve_ref->get_point_count() - 1) - _curve_ref->set_point_right_tangent(_selected_point, tangent); + curve.set_point_left_tangent(_selected_point, tangent); + + // Note: if a tangent is set to linear, it shouldn't be linked to the other + if (link && _selected_point != curve.get_point_count() - 1 && !curve.get_point_right_mode(_selected_point) != Curve::TANGENT_FREE) + curve.set_point_right_tangent(_selected_point, tangent); + } else { - _curve_ref->set_point_right_tangent(_selected_point, tangent); - if (link && _selected_point != 0) - _curve_ref->set_point_left_tangent(_selected_point, tangent); + curve.set_point_right_tangent(_selected_point, tangent); + + if (link && _selected_point != 0 && !curve.get_point_left_mode(_selected_point) != Curve::TANGENT_FREE) + curve.set_point_left_tangent(_selected_point, tangent); } } } @@ -230,25 +246,31 @@ void CurveEditor::on_preset_item_selected(int preset_id) { case PRESET_FLAT0: curve.add_point(Vector2(0, 0)); curve.add_point(Vector2(1, 0)); + curve.set_point_right_mode(0, Curve::TANGENT_LINEAR); + curve.set_point_left_mode(1, Curve::TANGENT_LINEAR); break; case PRESET_FLAT1: curve.add_point(Vector2(0, 1)); curve.add_point(Vector2(1, 1)); + curve.set_point_right_mode(0, Curve::TANGENT_LINEAR); + curve.set_point_left_mode(1, Curve::TANGENT_LINEAR); break; case PRESET_LINEAR: - curve.add_point(Vector2(0, 0), 0, 1); - curve.add_point(Vector2(1, 1), 1, 0); + curve.add_point(Vector2(0, 0)); + curve.add_point(Vector2(1, 1)); + curve.set_point_right_mode(0, Curve::TANGENT_LINEAR); + curve.set_point_left_mode(1, Curve::TANGENT_LINEAR); break; case PRESET_EASE_IN: curve.add_point(Vector2(0, 0)); - curve.add_point(Vector2(1, 1), 1.4, 0); + curve.add_point(Vector2(1, 1), (curve.get_max_value() - curve.get_min_value()) * 1.4, 0); break; case PRESET_EASE_OUT: - curve.add_point(Vector2(0, 0), 0, 1.4); + curve.add_point(Vector2(0, 0), 0, (curve.get_max_value() - curve.get_min_value()) * 1.4); curve.add_point(Vector2(1, 1)); break; @@ -261,7 +283,13 @@ void CurveEditor::on_preset_item_selected(int preset_id) { break; } - push_undo(previous_data); + UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); + ur.create_action(TTR("Load Curve Preset")); + + ur.add_do_method(&curve, "_set_data", curve.get_data()); + ur.add_undo_method(&curve, "_set_data", previous_data); + + ur.commit_action(); } void CurveEditor::_curve_changed() { @@ -281,6 +309,18 @@ void CurveEditor::on_context_menu_item_selected(int action_id) { case CONTEXT_REMOVE_POINT: remove_point(_selected_point); break; + + case CONTEXT_LINEAR: + toggle_linear(); + break; + + case CONTEXT_LEFT_LINEAR: + toggle_linear(TANGENT_LEFT); + break; + + case CONTEXT_RIGHT_LINEAR: + toggle_linear(TANGENT_RIGHT); + break; } } @@ -291,9 +331,37 @@ void CurveEditor::open_context_menu(Vector2 pos) { if (_curve_ref.is_valid()) { _context_menu->add_item(TTR("Add point"), CONTEXT_ADD_POINT); + if (_selected_point >= 0) { _context_menu->add_item(TTR("Remove point"), CONTEXT_REMOVE_POINT); + + if (_selected_tangent != TANGENT_NONE) { + _context_menu->add_separator(); + + _context_menu->add_check_item(TTR("Linear"), CONTEXT_LINEAR); + + bool is_linear = _selected_tangent == TANGENT_LEFT ? + _curve_ref->get_point_left_mode(_selected_point) == Curve::TANGENT_LINEAR : + _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR; + + _context_menu->set_item_checked(CONTEXT_LINEAR, is_linear); + + } else { + _context_menu->add_separator(); + + if (_selected_point > 0) { + _context_menu->add_check_item(TTR("Left linear"), CONTEXT_LEFT_LINEAR); + _context_menu->set_item_checked(CONTEXT_LEFT_LINEAR, + _curve_ref->get_point_left_mode(_selected_point) == Curve::TANGENT_LINEAR); + } + if (_selected_point + 1 < _curve_ref->get_point_count()) { + _context_menu->add_check_item(TTR("Right linear"), CONTEXT_RIGHT_LINEAR); + _context_menu->set_item_checked(CONTEXT_RIGHT_LINEAR, + _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR); + } + } } + _context_menu->add_separator(); } @@ -319,7 +387,7 @@ int CurveEditor::get_point_at(Vector2 pos) const { return -1; } -int CurveEditor::get_tangent_at(Vector2 pos) const { +CurveEditor::TangentIndex CurveEditor::get_tangent_at(Vector2 pos) const { if (_curve_ref.is_null() || _selected_point < 0) return TANGENT_NONE; @@ -343,7 +411,8 @@ int CurveEditor::get_tangent_at(Vector2 pos) const { void CurveEditor::add_point(Vector2 pos) { ERR_FAIL_COND(_curve_ref.is_null()); - Array prev_data = _curve_ref->get_data(); + UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); + ur.create_action(TTR("Remove Curve Point")); Vector2 point_pos = get_world_pos(pos); if (point_pos.y < 0.0) @@ -351,22 +420,64 @@ void CurveEditor::add_point(Vector2 pos) { else if (point_pos.y > 1.0) point_pos.y = 1.0; - _curve_ref->add_point(point_pos); + // Small trick to get the point index to feed the undo method + int i = _curve_ref->add_point(point_pos); + _curve_ref->remove_point(i); + + ur.add_do_method(*_curve_ref, "add_point", point_pos); + ur.add_undo_method(*_curve_ref, "remove_point", i); - push_undo(prev_data); + ur.commit_action(); } void CurveEditor::remove_point(int index) { ERR_FAIL_COND(_curve_ref.is_null()); - Array prev_data = _curve_ref->get_data(); + UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); + ur.create_action(TTR("Remove Curve Point")); - _curve_ref->remove_point(index); + Curve::Point p = _curve_ref->get_point(index); + + ur.add_do_method(*_curve_ref, "remove_point", index); + ur.add_undo_method(*_curve_ref, "add_point", p.pos, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode); if (index == _selected_point) set_selected_point(-1); - push_undo(prev_data); + ur.commit_action(); +} + +void CurveEditor::toggle_linear(TangentIndex tangent) { + ERR_FAIL_COND(_curve_ref.is_null()); + + UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); + ur.create_action(TTR("Toggle Curve Linear Tangent")); + + if (tangent == TANGENT_NONE) + tangent = _selected_tangent; + + if (tangent == TANGENT_LEFT) { + + bool is_linear = _curve_ref->get_point_left_mode(_selected_point) == Curve::TANGENT_LINEAR; + + Curve::TangentMode prev_mode = _curve_ref->get_point_left_mode(_selected_point); + Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR; + + ur.add_do_method(*_curve_ref, "set_point_left_mode", _selected_point, mode); + ur.add_undo_method(*_curve_ref, "set_point_left_mode", _selected_point, prev_mode); + + } else { + + bool is_linear = _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR; + + Curve::TangentMode prev_mode = _curve_ref->get_point_right_mode(_selected_point); + Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR; + + ur.add_do_method(*_curve_ref, "set_point_right_mode", _selected_point, mode); + ur.add_undo_method(*_curve_ref, "set_point_right_mode", _selected_point, prev_mode); + } + + ur.commit_action(); } void CurveEditor::set_selected_point(int index) { @@ -383,32 +494,27 @@ void CurveEditor::set_hover_point_index(int index) { } } -void CurveEditor::push_undo(Array previous_curve_data) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - - ur->create_action(TTR("Modify Curve")); - ur->add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data()); - ur->add_undo_method(*_curve_ref, "_set_data", previous_curve_data); - - // This boolean is to prevent commit_action from executing the do method, - // because at this point it's already done, there is no point in doing it twice - _curve_ref->_disable_set_data = true; - ur->commit_action(); - _curve_ref->_disable_set_data = false; -} - void CurveEditor::update_view_transform() { Vector2 control_size = get_size(); const real_t margin = 24; - _world_rect = Rect2(Curve::MIN_X, 0, Curve::MAX_X, 1); + float min_y = 0; + float max_y = 1; + + if (_curve_ref.is_valid()) { + min_y = _curve_ref->get_min_value(); + max_y = _curve_ref->get_max_value(); + } + + Rect2 world_rect = Rect2(Curve::MIN_X, min_y, Curve::MAX_X, max_y - min_y); Vector2 wm = Vector2(margin, margin) / control_size; - _world_rect.position -= wm; - _world_rect.size += 2.0 * wm; + wm.y *= (max_y - min_y); + world_rect.position -= wm; + world_rect.size += 2.0 * wm; _world_to_view = Transform2D(); - _world_to_view.translate(-_world_rect.position - Vector2(0, _world_rect.size.y)); - _world_to_view.scale(Vector2(control_size.x, -control_size.y) / _world_rect.size); + _world_to_view.translate(-world_rect.position - Vector2(0, world_rect.size.y)); + _world_to_view.scale(Vector2(control_size.x, -control_size.y) / world_rect.size); } Vector2 CurveEditor::get_tangent_view_pos(int i, TangentIndex tangent) const { @@ -509,17 +615,18 @@ void CurveEditor::_draw() { const Color grid_color0(0, 0, 0, 0.5); const Color grid_color1(0, 0, 0, 0.15); - draw_line(Vector2(min_edge.x, 0), Vector2(max_edge.x, 0), grid_color0); + draw_line(Vector2(min_edge.x, curve.get_min_value()), Vector2(max_edge.x, curve.get_min_value()), grid_color0); + draw_line(Vector2(max_edge.x, curve.get_max_value()), Vector2(min_edge.x, curve.get_max_value()), grid_color0); draw_line(Vector2(0, min_edge.y), Vector2(0, max_edge.y), grid_color0); draw_line(Vector2(1, max_edge.y), Vector2(1, min_edge.y), grid_color0); - draw_line(Vector2(max_edge.x, 1), Vector2(min_edge.x, 1), grid_color0); - const Vector2 grid_step(0.25, 0.5); + float curve_height = (curve.get_max_value() - curve.get_min_value()); + const Vector2 grid_step(0.25, 0.5 * curve_height); for (real_t x = 0; x < 1.0; x += grid_step.x) { draw_line(Vector2(x, min_edge.y), Vector2(x, max_edge.y), grid_color1); } - for (real_t y = 0; y < 1.0; y += grid_step.y) { + for (real_t y = curve.get_min_value(); y < curve.get_max_value(); y += grid_step.y) { draw_line(Vector2(min_edge.x, y), Vector2(max_edge.x, y), grid_color1); } @@ -528,17 +635,30 @@ void CurveEditor::_draw() { draw_set_transform_matrix(Transform2D()); Ref<Font> font = get_font("font", "Label"); + float font_height = font->get_height(); const Color text_color(1, 1, 1, 0.3); - draw_string(font, get_view_pos(Vector2(0, 0)), "0.0", text_color); - - draw_string(font, get_view_pos(Vector2(0.25, 0)), "0.25", text_color); - draw_string(font, get_view_pos(Vector2(0.5, 0)), "0.5", text_color); - draw_string(font, get_view_pos(Vector2(0.75, 0)), "0.75", text_color); - draw_string(font, get_view_pos(Vector2(1, 0)), "1.0", text_color); + { + // X axis + float y = curve.get_min_value(); + Vector2 off(0, font_height - 1); + draw_string(font, get_view_pos(Vector2(0, y)) + off, "0.0", text_color); + draw_string(font, get_view_pos(Vector2(0.25, y)) + off, "0.25", text_color); + draw_string(font, get_view_pos(Vector2(0.5, y)) + off, "0.5", text_color); + draw_string(font, get_view_pos(Vector2(0.75, y)) + off, "0.75", text_color); + draw_string(font, get_view_pos(Vector2(1, y)) + off, "1.0", text_color); + } - draw_string(font, get_view_pos(Vector2(0, 0.5)), "0.5", text_color); - draw_string(font, get_view_pos(Vector2(0, 1)), "1.0", text_color); + { + // Y axis + float m0 = curve.get_min_value(); + float m1 = 0.5 * (curve.get_min_value() + curve.get_max_value()); + float m2 = curve.get_max_value(); + Vector2 off(1, -1); + draw_string(font, get_view_pos(Vector2(0, m0)) + off, String::num(m0, 2), text_color); + draw_string(font, get_view_pos(Vector2(0, m1)) + off, String::num(m1, 2), text_color); + draw_string(font, get_view_pos(Vector2(0, m2)) + off, String::num(m2, 3), text_color); + } // Draw tangents for current point @@ -611,6 +731,12 @@ void CurveEditor::_draw() { Vector2 pos = curve.get_point_pos(_hover_point); stroke_rect(Rect2(get_view_pos(pos), Vector2(1, 1)).grow(_hover_radius), hover_color); } + + // Help text + + if (_selected_point > 0 && _selected_point + 1 < curve.get_point_count()) { + draw_string(font, Vector2(50, font_height), TTR("Hold Shift to edit tangents individually"), text_color); + } } // TODO That should be part of the drawing API... @@ -648,6 +774,8 @@ CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) { _toggle_button = _editor_node->add_bottom_panel_item(get_name(), _view); _toggle_button->hide(); + + get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator)); } CurveEditorPlugin::~CurveEditorPlugin() { @@ -719,3 +847,74 @@ void CurveEditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("_curve_texture_changed"), &CurveEditorPlugin::_curve_texture_changed); } + +//----------------------------------- +// Preview generator + +bool CurvePreviewGenerator::handles(const String &p_type) const { + return p_type == "Curve"; +} + +Ref<Texture> CurvePreviewGenerator::generate(const Ref<Resource> &p_from) { + + Ref<Curve> curve_ref = p_from; + ERR_FAIL_COND_V(curve_ref.is_null(), Ref<Texture>()); + Curve &curve = **curve_ref; + + int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); + thumbnail_size *= EDSCALE; + Ref<Image> img_ref; + img_ref.instance(); + Image &im = **img_ref; + + im.create(thumbnail_size, thumbnail_size, 0, Image::FORMAT_RGBA8); + + im.lock(); + + Color bg_color(0.1, 0.1, 0.1, 1.0); + for (int i = 0; i < thumbnail_size; i++) { + for (int j = 0; j < thumbnail_size; j++) { + im.set_pixel(i, j, bg_color); + } + } + + Color line_color(0.8, 0.8, 0.8, 1.0); + float range_y = curve.get_max_value() - curve.get_min_value(); + + int prev_y = 0; + for (int x = 0; x < im.get_width(); ++x) { + + float t = static_cast<float>(x) / im.get_width(); + float v = (curve.interpolate_baked(t) - curve.get_min_value()) / range_y; + int y = CLAMP(im.get_height() - v * im.get_height(), 0, im.get_height()); + + // Plot point + if (y >= 0 && y < im.get_height()) { + im.set_pixel(x, y, line_color); + } + + // Plot vertical line to fix discontinuity (not 100% correct but enough for a preview) + if (x != 0 && Math::abs(y - prev_y) > 1) { + int y0, y1; + if (y < prev_y) { + y0 = y; + y1 = prev_y; + } else { + y0 = prev_y; + y1 = y; + } + for (int ly = y0; ly < y1; ++ly) { + im.set_pixel(x, ly, line_color); + } + } + + prev_y = y; + } + + im.unlock(); + + Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); + + ptex->create_from_image(img_ref, 0); + return ptex; +} diff --git a/editor/plugins/curve_editor_plugin.h b/editor/plugins/curve_editor_plugin.h index 0ed4ee3517..040c298a92 100644 --- a/editor/plugins/curve_editor_plugin.h +++ b/editor/plugins/curve_editor_plugin.h @@ -57,7 +57,10 @@ public: enum ContextAction { CONTEXT_ADD_POINT = 0, - CONTEXT_REMOVE_POINT + CONTEXT_REMOVE_POINT, + CONTEXT_LINEAR, + CONTEXT_LEFT_LINEAR, + CONTEXT_RIGHT_LINEAR }; enum TangentIndex { @@ -79,12 +82,12 @@ private: void open_context_menu(Vector2 pos); int get_point_at(Vector2 pos) const; - int get_tangent_at(Vector2 pos) const; + TangentIndex get_tangent_at(Vector2 pos) const; void add_point(Vector2 pos); void remove_point(int index); + void toggle_linear(TangentIndex tangent = TANGENT_NONE); void set_selected_point(int index); void set_hover_point_index(int index); - void push_undo(Array previous_curve_data); void update_view_transform(); Vector2 get_tangent_view_pos(int i, TangentIndex tangent) const; @@ -96,7 +99,6 @@ private: void stroke_rect(Rect2 rect, Color color); private: - Rect2 _world_rect; Transform2D _world_to_view; Ref<Curve> _curve_ref; @@ -105,12 +107,11 @@ private: Array _undo_data; bool _has_undo_data; - bool _undo_no_commit; Vector2 _context_click_pos; int _selected_point; int _hover_point; - int _selected_tangent; + TangentIndex _selected_tangent; bool _dragging; // Constant @@ -142,4 +143,11 @@ private: ToolButton *_toggle_button; }; +class CurvePreviewGenerator : public EditorResourcePreviewGenerator { + GDCLASS(CurvePreviewGenerator, EditorResourcePreviewGenerator) +public: + bool handles(const String &p_type) const; + Ref<Texture> generate(const Ref<Resource> &p_from); +}; + #endif // CURVE_EDITOR_PLUGIN_H diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 11d804422a..7f8581535c 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -431,7 +431,7 @@ Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from) { for (int i = 0; i < thumbnail_size; i++) { for (int j = 0; j < thumbnail_size; j++) { - img->put_pixel(i, j, bg_color); + img->set_pixel(i, j, bg_color); } } @@ -469,8 +469,8 @@ Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from) { Color ul = color; ul.a *= 0.5; - img->put_pixel(col, line * 2, bg_color.blend(ul)); - img->put_pixel(col, line * 2 + 1, color); + img->set_pixel(col, line * 2, bg_color.blend(ul)); + img->set_pixel(col, line * 2 + 1, color); prev_is_text = _is_text_char(c); } diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp index 7f56286f08..f567abc5b1 100644 --- a/editor/plugins/item_list_editor_plugin.cpp +++ b/editor/plugins/item_list_editor_plugin.cpp @@ -193,6 +193,45 @@ ItemListPopupMenuPlugin::ItemListPopupMenuPlugin() { } /////////////////////////////////////////////////////////////// + +void ItemListItemListPlugin::set_object(Object *p_object) { + + pp = p_object->cast_to<ItemList>(); +} + +bool ItemListItemListPlugin::handles(Object *p_object) const { + + return p_object->is_class("ItemList"); +} + +int ItemListItemListPlugin::get_flags() const { + + return FLAG_ICON | FLAG_ENABLE; +} + +void ItemListItemListPlugin::add_item() { + + pp->add_item(vformat(TTR("Item %d"), pp->get_item_count())); + _change_notify(); +} + +int ItemListItemListPlugin::get_item_count() const { + + return pp->get_item_count(); +} + +void ItemListItemListPlugin::erase(int p_idx) { + + pp->remove_item(p_idx); + _change_notify(); +} + +ItemListItemListPlugin::ItemListItemListPlugin() { + + pp = NULL; +} + +/////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// @@ -373,6 +412,7 @@ ItemListEditorPlugin::ItemListEditorPlugin(EditorNode *p_node) { item_list_editor->hide(); item_list_editor->add_plugin(memnew(ItemListOptionButtonPlugin)); item_list_editor->add_plugin(memnew(ItemListPopupMenuPlugin)); + item_list_editor->add_plugin(memnew(ItemListItemListPlugin)); } ItemListEditorPlugin::~ItemListEditorPlugin() { diff --git a/editor/plugins/item_list_editor_plugin.h b/editor/plugins/item_list_editor_plugin.h index 042e88839f..4fed8e49f5 100644 --- a/editor/plugins/item_list_editor_plugin.h +++ b/editor/plugins/item_list_editor_plugin.h @@ -167,6 +167,35 @@ public: /////////////////////////////////////////////////////////////// +class ItemListItemListPlugin : public ItemListPlugin { + + GDCLASS(ItemListItemListPlugin, ItemListPlugin); + + ItemList *pp; + +public: + virtual void set_object(Object *p_object); + virtual bool handles(Object *p_object) const; + virtual int get_flags() const; + + virtual void set_item_text(int p_idx, const String &p_text) { pp->set_item_text(p_idx, p_text); } + virtual String get_item_text(int p_idx) const { return pp->get_item_text(p_idx); } + + virtual void set_item_icon(int p_idx, const Ref<Texture> &p_tex) { pp->set_item_icon(p_idx, p_tex); } + virtual Ref<Texture> get_item_icon(int p_idx) const { return pp->get_item_icon(p_idx); } + + virtual void set_item_enabled(int p_idx, int p_enabled) { pp->set_item_disabled(p_idx, !p_enabled); } + virtual bool is_item_enabled(int p_idx) const { return !pp->is_item_disabled(p_idx); } + + virtual void add_item(); + virtual int get_item_count() const; + virtual void erase(int p_idx); + + ItemListItemListPlugin(); +}; + +/////////////////////////////////////////////////////////////// + class ItemListEditor : public HBoxContainer { GDCLASS(ItemListEditor, HBoxContainer); diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp index 09021446dc..a7a20e71fe 100644 --- a/editor/plugins/light_occluder_2d_editor_plugin.cpp +++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp @@ -126,7 +126,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Vector<Vector2> poly = Variant(node->get_occluder_polygon()->get_polygon()); //first check if a point is to be added (segment split) - real_t grab_treshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); + real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); switch (mode) { @@ -145,12 +145,12 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { return true; } else { - if (wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_treshold) { + if (wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) { //wip closed _wip_close(true); return true; - } else if (wip.size() > 1 && xform.xform(wip[wip.size() - 1]).distance_to(gpoint) < grab_treshold) { + } else if (wip.size() > 1 && xform.xform(wip[wip.size() - 1]).distance_to(gpoint) < grab_threshold) { //wip closed _wip_close(false); return true; @@ -204,7 +204,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { continue; //not valid to reuse point real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_pos = cp; closest_idx = i; @@ -233,7 +233,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Vector2 cp = xform.xform(poly[i]); real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_pos = cp; closest_idx = i; @@ -278,7 +278,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Vector2 cp = xform.xform(poly[i]); real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_pos = cp; closest_idx = i; diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp index 76906a5b93..4a7ad74fbe 100644 --- a/editor/plugins/line_2d_editor_plugin.cpp +++ b/editor/plugins/line_2d_editor_plugin.cpp @@ -62,12 +62,12 @@ Vector2 Line2DEditor::mouse_to_local_pos(Vector2 gpoint, bool alt) { int Line2DEditor::get_point_index_at(Vector2 gpos) { ERR_FAIL_COND_V(node == 0, -1); - real_t grab_treshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); + 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_pos(i)); - if (gpos.distance_to(p) < grab_treshold) { + if (gpos.distance_to(p) < grab_threshold) { return i; } } diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp index 1457b28ed1..725e57fe0b 100644 --- a/editor/plugins/navigation_polygon_editor_plugin.cpp +++ b/editor/plugins/navigation_polygon_editor_plugin.cpp @@ -140,7 +140,7 @@ bool NavigationPolygonEditor::forward_gui_input(const Ref<InputEvent> &p_event) 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("editors/poly_editor/point_grab_radius", 8); + real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); switch (mode) { @@ -160,7 +160,7 @@ bool NavigationPolygonEditor::forward_gui_input(const Ref<InputEvent> &p_event) return true; } else { - if (wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_treshold) { + if (wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) { //wip closed _wip_close(); @@ -211,7 +211,7 @@ bool NavigationPolygonEditor::forward_gui_input(const Ref<InputEvent> &p_event) continue; //not valid to reuse point real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_outline = j; closest_pos = cp; @@ -252,7 +252,7 @@ bool NavigationPolygonEditor::forward_gui_input(const Ref<InputEvent> &p_event) Vector2 cp = xform.xform(poly[i]); real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_pos = cp; closest_outline = j; @@ -312,7 +312,7 @@ bool NavigationPolygonEditor::forward_gui_input(const Ref<InputEvent> &p_event) Vector2 cp = xform.xform(poly[i]); real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_pos = cp; closest_outline = j; diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp index 877707d77b..3524c34d62 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_editor_plugin.cpp @@ -104,7 +104,7 @@ void PathSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_p if (SpatialEditor::get_singleton()->is_snap_enabled()) { float snap = SpatialEditor::get_singleton()->get_translate_snap(); - inters.snap(snap); + inters.snap(Vector3(snap, snap, snap)); } Vector3 local = gi.xform(inters); diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index dd13ca0e63..24ccdcd445 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -220,7 +220,7 @@ bool Polygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Vector<Vector2> poly = Variant(node->get_polygon()); //first check if a point is to be added (segment split) - real_t grab_treshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); + real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); switch (mode) { @@ -239,7 +239,7 @@ bool Polygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { return true; } else { - if (wip.size() > 1 && xform.xform(wip[0] + node->get_offset()).distance_to(gpoint) < grab_treshold) { + if (wip.size() > 1 && xform.xform(wip[0] + node->get_offset()).distance_to(gpoint) < grab_threshold) { //wip closed _wip_close(); @@ -293,7 +293,7 @@ bool Polygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { continue; //not valid to reuse point real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_pos = cp; closest_idx = i; @@ -322,7 +322,7 @@ bool Polygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Vector2 cp = xform.xform(poly[i] + node->get_offset()); real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_pos = cp; closest_idx = i; @@ -367,7 +367,7 @@ bool Polygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Vector2 cp = xform.xform(poly[i] + node->get_offset()); real_t d = cp.distance_to(gpoint); - if (d < closest_dist && d < grab_treshold) { + if (d < closest_dist && d < grab_threshold) { closest_dist = d; closest_pos = cp; closest_idx = i; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index f3941d6a16..dc2eddda39 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -313,6 +313,13 @@ void ScriptEditor::_goto_script_line(REF p_script, int p_line) { editor->push_item(p_script.ptr()); + if (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) { + + Ref<Script> script = p_script->cast_to<Script>(); + if (!script.is_null() && script->get_path().is_resource_file()) + edit(p_script, p_line, 0); + } + int selected = tab_container->get_current_tab(); if (selected < 0 || selected >= tab_container->get_child_count()) return; @@ -502,9 +509,8 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save) { if (p_save) { apply_scripts(); } - if (current->get_edit_menu()) { - memdelete(current->get_edit_menu()); - } + current->clear_edit_menu(); + } else { EditorHelp *help = tab_container->get_child(selected)->cast_to<EditorHelp>(); _add_recent_script(help->get_class()); @@ -866,6 +872,14 @@ void ScriptEditor::_menu_option(int p_option) { debugger->set_hide_on_stop(visible); debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(DEBUG_SHOW_KEEP_OPEN), !visible); } break; + case DEBUG_WITH_EXTERNAL_EDITOR: { + bool debug_with_external_editor = !debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(DEBUG_WITH_EXTERNAL_EDITOR)); + debugger->set_debug_with_external_editor(debug_with_external_editor); + debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(DEBUG_WITH_EXTERNAL_EDITOR), debug_with_external_editor); + } break; + case TOGGLE_SCRIPTS_PANEL: { + list_split->set_visible(!list_split->is_visible()); + } } int selected = tab_container->get_current_tab(); @@ -1545,13 +1559,10 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change"); - Error err = p_script->get_language()->open_in_external_editor(p_script, p_line >= 0 ? p_line : 0, p_col); - if (err == OK) - return false; - if (err != ERR_UNAVAILABLE) - WARN_PRINT("Couldn't open in custom external text editor"); - - if (p_script->get_path().is_resource_file() && bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) { + if ((debugger->get_dump_stack_script() != p_script || debugger->get_debug_with_external_editor()) && + p_script->get_language()->open_in_external_editor(p_script, p_line >= 0 ? p_line : 0, p_col) == OK && + p_script->get_path().is_resource_file() && + bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) { String path = EditorSettings::get_singleton()->get("text_editor/external/exec_path"); String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags"); @@ -1876,6 +1887,9 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { for (int i = 0; i < helps.size(); i++) { String path = helps[i]; + if (path == "") { // invalid, skip + continue; + } _help_class_open(path); } @@ -2171,13 +2185,15 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { script_list = memnew(ItemList); list_split->add_child(script_list); - script_list->set_custom_minimum_size(Size2(0, 0)); + script_list->set_custom_minimum_size(Size2(150 * EDSCALE, 100)); //need to give a bit of limit to avoid it from disappearing + script_list->set_v_size_flags(SIZE_EXPAND_FILL); script_split->set_split_offset(140); - list_split->set_split_offset(500); + //list_split->set_split_offset(500); members_overview = memnew(ItemList); list_split->add_child(members_overview); - members_overview->set_custom_minimum_size(Size2(0, 0)); + members_overview->set_custom_minimum_size(Size2(0, 100)); //need to give a bit of limit to avoid it from disappearing + members_overview->set_v_size_flags(SIZE_EXPAND_FILL); tab_container = memnew(TabContainer); tab_container->add_style_override("panel", p_editor->get_gui_base()->get_stylebox("ScriptPanel", "EditorStyles")); @@ -2222,6 +2238,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_docs", TTR("Close Docs")), CLOSE_DOCS); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_file", TTR("Close"), KEY_MASK_CMD | KEY_W), FILE_CLOSE); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_all", TTR("Close All")), CLOSE_ALL); + file_menu->get_popup()->add_separator(); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/toggle_scripts_panel", TTR("Toggle Scripts Panel"), KEY_MASK_CMD | KEY_BACKSLASH), TOGGLE_SCRIPTS_PANEL); file_menu->get_popup()->connect("id_pressed", this, "_menu_option"); script_search_menu = memnew(MenuButton); @@ -2244,6 +2262,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { 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); + debug_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("debugger/debug_with_exteral_editor", TTR("Debug with external editor")), DEBUG_WITH_EXTERNAL_EDITOR); debug_menu->get_popup()->connect("id_pressed", this, "_menu_option"); debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_NEXT), true); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index e036d1ed9c..7f17365931 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -106,6 +106,7 @@ public: virtual void set_tooltip_request_func(String p_method, Object *p_obj) = 0; virtual Control *get_edit_menu() = 0; + virtual void clear_edit_menu() = 0; ScriptEditorBase() {} }; @@ -133,6 +134,7 @@ class ScriptEditor : public VBoxContainer { FILE_CLOSE, CLOSE_DOCS, CLOSE_ALL, + TOGGLE_SCRIPTS_PANEL, FILE_TOOL_RELOAD, FILE_TOOL_RELOAD_SOFT, DEBUG_NEXT, @@ -141,6 +143,7 @@ class ScriptEditor : public VBoxContainer { DEBUG_CONTINUE, DEBUG_SHOW, DEBUG_SHOW_KEEP_OPEN, + DEBUG_WITH_EXTERNAL_EDITOR, SEARCH_HELP, SEARCH_CLASSES, SEARCH_WEBSITE, @@ -362,6 +365,8 @@ public: bool can_take_away_focus() const; + VSplitContainer *get_left_list_split() { return list_split; } + ScriptEditorDebugger *get_debugger() { return debugger; } void set_live_auto_reload_running_scripts(bool p_enabled); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 9f76119374..83741c7fb8 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -557,6 +557,8 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo if (!bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) return; + ERR_FAIL_COND(!get_tree()); + Set<Ref<Script> > scripts; Node *base = get_tree()->get_edited_scene_root(); @@ -1091,6 +1093,10 @@ Control *ScriptTextEditor::get_edit_menu() { return edit_hb; } +void ScriptTextEditor::clear_edit_menu() { + memdelete(edit_hb); +} + void ScriptTextEditor::reload(bool p_soft) { TextEdit *te = code_editor->get_text_edit(); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index ba40645161..e55847832f 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -156,7 +156,7 @@ public: virtual void set_debugger_active(bool p_active); Control *get_edit_menu(); - + virtual void clear_edit_menu(); static void register_editor(); ScriptTextEditor(); diff --git a/editor/plugins/shader_graph_editor_plugin.cpp b/editor/plugins/shader_graph_editor_plugin.cpp index 9c65ef667a..5506c035ec 100644 --- a/editor/plugins/shader_graph_editor_plugin.cpp +++ b/editor/plugins/shader_graph_editor_plugin.cpp @@ -1382,7 +1382,7 @@ ToolButton *ShaderGraphView::make_editor(String text,GraphNode* gn,int p_id,int Color c = graph->default_get_value(type,p_id,param); for (int x=1;x<14;x++) for (int y=1;y<14;y++) - icon_color.put_pixel(x,y,c); + icon_color.set_pixel(x,y,c); Ref<ImageTexture> t; t.instance(); t->create_from_image(icon_color); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index c55bef1b03..995d13f6a8 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -1180,7 +1180,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (_edit.snap || spatial_editor->is_snap_enabled()) { snap = spatial_editor->get_translate_snap(); - motion.snap(snap); + motion.snap(Vector3(snap, snap, snap)); } //set_message("Translating: "+motion); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 14b25681b7..3563f70d0b 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -53,6 +53,7 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { Sprite *mi = child->cast_to<Sprite>(); Ref<Texture> texture = mi->get_texture(); + Ref<Texture> normal_map = mi->get_normal_map(); Ref<ShaderMaterial> material = mi->get_material(); if (texture.is_null()) @@ -67,6 +68,7 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { } p_library->tile_set_texture(id, texture); + p_library->tile_set_normal_map(id, normal_map); p_library->tile_set_material(id, material); p_library->tile_set_modulate(id, mi->get_modulate()); @@ -88,9 +90,10 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { phys_offset += -s / 2; } - Vector<Ref<Shape2D> > collisions; + Vector<TileSet::ShapeData> collisions; Ref<NavigationPolygon> nav_poly; Ref<OccluderPolygon2D> occluder; + bool found_collisions = false; for (int j = 0; j < mi->get_child_count(); j++) { @@ -104,27 +107,36 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { if (!child2->cast_to<StaticBody2D>()) continue; + + found_collisions = true; + StaticBody2D *sb = child2->cast_to<StaticBody2D>(); List<uint32_t> shapes; sb->get_shape_owners(&shapes); for (List<uint32_t>::Element *E = shapes.front(); E; E = E->next()) { + if (sb->is_shape_owner_disabled(E->get())) continue; + + Transform2D shape_transform = sb->shape_owner_get_transform(E->get()); + bool one_way = sb->is_shape_owner_one_way_collision_enabled(E->get()); + + shape_transform.set_origin(shape_transform.get_origin() - phys_offset); for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) { - Ref<Shape> shape = sb->shape_owner_get_shape(E->get(), k); - collisions.push_back(shape); //uh what about transform? + Ref<Shape2D> shape = sb->shape_owner_get_shape(E->get(), k); + TileSet::ShapeData shape_data; + shape_data.shape = shape; + shape_data.shape_transform = shape_transform; + shape_data.one_way_collision = one_way; + collisions.push_back(shape_data); } } } - if (collisions.size()) { - + if (found_collisions) { p_library->tile_set_shapes(id, collisions); - p_library->tile_set_shape_offset(id, -phys_offset); - } else { - p_library->tile_set_shape_offset(id, Vector2()); } p_library->tile_set_texture_offset(id, mi->get_offset()); |