diff options
Diffstat (limited to 'editor/plugins')
24 files changed, 946 insertions, 521 deletions
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index c94014944c..69206daea8 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -89,7 +89,7 @@ Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const { void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) { AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_tree(); updating = true; - undo_redo->create_action(TTR("Parameter Changed") + ": " + String(p_property), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS); undo_redo->add_do_property(tree, p_property, p_value); undo_redo->add_undo_property(tree, p_property, tree->get(p_property)); undo_redo->add_do_method(this, "_update_graph"); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 4ba9147955..681c3e7195 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -408,7 +408,8 @@ void AnimationPlayerEditor::_animation_save_as(const Ref<Resource> &p_resource) if (p_resource->get_name() != "") { path = p_resource->get_name() + "." + extensions.front()->get().to_lower(); } else { - path = "new_" + p_resource->get_class().to_lower() + "." + extensions.front()->get().to_lower(); + String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore(); + path = "new_" + resource_name_snake_case + "." + extensions.front()->get().to_lower(); } } } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 02b6dd654e..16e224b105 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -81,8 +81,8 @@ public: SnapDialog() { const int SPIN_BOX_GRID_RANGE = 16384; const int SPIN_BOX_ROTATION_RANGE = 360; - const float SPIN_BOX_SCALE_MIN = 0.01f; - const float SPIN_BOX_SCALE_MAX = 100; + const real_t SPIN_BOX_SCALE_MIN = 0.01; + const real_t SPIN_BOX_SCALE_MAX = 100; Label *label; VBoxContainer *container; @@ -210,7 +210,7 @@ public: child_container->add_child(scale_step); } - void set_fields(const Point2 p_grid_offset, const Point2 p_grid_step, const int p_primary_grid_steps, const float p_rotation_offset, const float p_rotation_step, const float p_scale_step) { + void set_fields(const Point2 p_grid_offset, const Point2 p_grid_step, const int p_primary_grid_steps, const real_t p_rotation_offset, const real_t p_rotation_step, const real_t p_scale_step) { grid_offset_x->set_value(p_grid_offset.x); grid_offset_y->set_value(p_grid_offset.y); grid_step_x->set_value(p_grid_step.x); @@ -221,7 +221,7 @@ public: scale_step->set_value(p_scale_step); } - void get_fields(Point2 &p_grid_offset, Point2 &p_grid_step, int &p_primary_grid_steps, float &p_rotation_offset, float &p_rotation_step, float &p_scale_step) { + void get_fields(Point2 &p_grid_offset, Point2 &p_grid_step, int &p_primary_grid_steps, real_t &p_rotation_offset, real_t &p_rotation_step, real_t &p_scale_step) { p_grid_offset = Point2(grid_offset_x->get_value(), grid_offset_y->get_value()); p_grid_step = Point2(grid_step_x->get_value(), grid_step_y->get_value()); p_primary_grid_steps = int(primary_grid_steps->get_value()); @@ -249,12 +249,12 @@ bool CanvasItemEditor::_is_node_movable(const Node *p_node, bool p_popup_warning } void CanvasItemEditor::_snap_if_closer_float( - float p_value, - float &r_current_snap, SnapTarget &r_current_snap_target, - float p_target_value, SnapTarget p_snap_target, - float p_radius) { - float radius = p_radius / zoom; - float dist = Math::abs(p_value - p_target_value); + const real_t p_value, + real_t &r_current_snap, SnapTarget &r_current_snap_target, + const real_t p_target_value, const SnapTarget p_snap_target, + const real_t p_radius) { + const real_t radius = p_radius / zoom; + const real_t dist = Math::abs(p_value - p_target_value); if ((p_radius < 0 || dist < radius) && (r_current_snap_target == SNAP_TARGET_NONE || dist < Math::abs(r_current_snap - p_value))) { r_current_snap = p_target_value; r_current_snap_target = p_snap_target; @@ -264,9 +264,9 @@ void CanvasItemEditor::_snap_if_closer_float( void CanvasItemEditor::_snap_if_closer_point( Point2 p_value, Point2 &r_current_snap, SnapTarget (&r_current_snap_target)[2], - Point2 p_target_value, SnapTarget p_snap_target, - real_t rotation, - float p_radius) { + Point2 p_target_value, const SnapTarget p_snap_target, + const real_t rotation, + const real_t p_radius) { Transform2D rot_trans = Transform2D(rotation, Point2()); p_value = rot_trans.inverse().xform(p_value); p_target_value = rot_trans.inverse().xform(p_target_value); @@ -459,7 +459,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig return output; } -float CanvasItemEditor::snap_angle(float p_target, float p_start) const { +real_t CanvasItemEditor::snap_angle(real_t p_target, real_t p_start) const { if (((smart_snap_active || snap_rotation) ^ Input::get_singleton()->is_key_pressed(KEY_CTRL)) && snap_rotation_step != 0) { if (snap_relative) { return Math::snapped(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset + (p_start - (int)(p_start / snap_rotation_step) * snap_rotation_step); @@ -923,7 +923,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve } // Hover over guides - float minimum = 1e20; + real_t minimum = 1e20; is_hovering_h_guide = false; is_hovering_v_guide = false; @@ -1264,7 +1264,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo if (pan_gesture.is_valid() && !p_already_accepted) { // If ctrl key pressed, then zoom instead of pan. if (pan_gesture->is_ctrl_pressed()) { - const float factor = pan_gesture->get_delta().y; + const real_t factor = pan_gesture->get_delta().y; zoom_widget->set_zoom_by_increments(1); if (factor != 1.f) { @@ -1490,9 +1490,9 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) { anchor_pos[i] = (transform * control->get_global_transform_with_canvas()).xform(_anchor_to_position(control, anchor_pos[i])); anchor_rects[i] = Rect2(anchor_pos[i], anchor_handle->get_size()); if (control->is_layout_rtl()) { - anchor_rects[i].position -= anchor_handle->get_size() * Vector2(float(i == 1 || i == 2), float(i <= 1)); + anchor_rects[i].position -= anchor_handle->get_size() * Vector2(real_t(i == 1 || i == 2), real_t(i <= 1)); } else { - anchor_rects[i].position -= anchor_handle->get_size() * Vector2(float(i == 0 || i == 3), float(i <= 1)); + anchor_rects[i].position -= anchor_handle->get_size() * Vector2(real_t(i == 0 || i == 3), real_t(i <= 1)); } } @@ -1646,7 +1646,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) { }; DragType resize_drag = DRAG_NONE; - float radius = (select_handle->get_size().width / 2) * 1.5; + real_t radius = (select_handle->get_size().width / 2) * 1.5; for (int i = 0; i < 4; i++) { int prev = (i + 3) % 4; @@ -1692,7 +1692,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) { bool symmetric = m->is_alt_pressed(); Rect2 local_rect = canvas_item->_edit_get_rect(); - float aspect = local_rect.get_size().y / local_rect.get_size().x; + real_t aspect = local_rect.get_size().y / local_rect.get_size().x; Point2 current_begin = local_rect.get_position(); Point2 current_end = local_rect.get_position() + local_rect.get_size(); Point2 max_begin = (symmetric) ? (current_begin + current_end - canvas_item->_edit_get_minimum_size()) / 2.0 : current_end - canvas_item->_edit_get_minimum_size(); @@ -1883,7 +1883,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { Size2 scale = canvas_item->call("get_scale"); Size2 original_scale = scale; - float ratio = scale.y / scale.x; + real_t ratio = scale.y / scale.x; if (drag_type == DRAG_SCALE_BOTH) { Size2 scale_factor = drag_to_local / drag_from_local; if (uniform) { @@ -2012,11 +2012,13 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { drag_to = transform.affine_inverse().xform(m->get_position()); Point2 previous_pos; - if (drag_selection.size() == 1) { - Transform2D xform = drag_selection[0]->get_global_transform_with_canvas() * drag_selection[0]->get_transform().affine_inverse(); - previous_pos = xform.xform(drag_selection[0]->_edit_get_position()); - } else { - previous_pos = _get_encompassing_rect_from_list(drag_selection).position; + if (!drag_selection.is_empty()) { + if (drag_selection.size() == 1) { + Transform2D xform = drag_selection[0]->get_global_transform_with_canvas() * drag_selection[0]->get_transform().affine_inverse(); + previous_pos = xform.xform(drag_selection[0]->_edit_get_position()); + } else { + previous_pos = _get_encompassing_rect_from_list(drag_selection).position; + } } Point2 new_pos = snap_point(previous_pos + (drag_to - drag_from), SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL | SNAP_NODE_PARENT | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES, 0, nullptr, drag_selection); @@ -2539,7 +2541,7 @@ void CanvasItemEditor::_update_cursor() { List<CanvasItem *> selection = _get_edited_canvas_items(); if (selection.size() == 1) { - float angle = Math::fposmod((double)selection[0]->get_global_transform_with_canvas().get_rotation(), Math_PI); + const double angle = Math::fposmod((double)selection[0]->get_global_transform_with_canvas().get_rotation(), Math_PI); if (angle > Math_PI * 7.0 / 8.0) { rotation_array_index = 0; } else if (angle > Math_PI * 5.0 / 8.0) { @@ -2645,7 +2647,7 @@ void CanvasItemEditor::_draw_margin_at_position(int p_value, Point2 p_position, } } -void CanvasItemEditor::_draw_percentage_at_position(float p_value, Point2 p_position, Side p_side) { +void CanvasItemEditor::_draw_percentage_at_position(real_t p_value, Point2 p_position, Side p_side) { String str = TS->format_number(vformat("%.1f ", p_value * 100.0)) + TS->percent_sign(); if (p_value != 0) { _draw_text_at_position(p_position, str, p_side); @@ -2655,7 +2657,7 @@ void CanvasItemEditor::_draw_percentage_at_position(float p_value, Point2 p_posi void CanvasItemEditor::_draw_focus() { // Draw the focus around the base viewport if (viewport->has_focus()) { - get_theme_stylebox(SNAME("Focus"), SNAME("EditorStyles"))->draw(viewport->get_canvas_item(), Rect2(Point2(), viewport->get_size())); + get_theme_stylebox(SNAME("FocusViewport"), SNAME("EditorStyles"))->draw(viewport->get_canvas_item(), Rect2(Point2(), viewport->get_size())); } } @@ -2670,7 +2672,7 @@ void CanvasItemEditor::_draw_guides() { if (drag_type == DRAG_V_GUIDE && i == dragged_guide_index) { continue; } - float x = xform.xform(Point2(vguides[i], 0)).x; + real_t x = xform.xform(Point2(vguides[i], 0)).x; viewport->draw_line(Point2(x, 0), Point2(x, viewport->get_size().y), guide_color, Math::round(EDSCALE)); } } @@ -2681,7 +2683,7 @@ void CanvasItemEditor::_draw_guides() { if (drag_type == DRAG_H_GUIDE && i == dragged_guide_index) { continue; } - float y = xform.xform(Point2(0, hguides[i])).y; + real_t y = xform.xform(Point2(0, hguides[i])).y; viewport->draw_line(Point2(0, y), Point2(viewport->get_size().x, y), guide_color, Math::round(EDSCALE)); } } @@ -2745,7 +2747,7 @@ void CanvasItemEditor::_draw_rulers() { ruler_transform.scale_basis(Point2(2, 2)); } } else { - float basic_rule = 100; + real_t basic_rule = 100; for (int i = 0; basic_rule * zoom > 100; i++) { basic_rule /= (i % 2) ? 5.0 : 2.0; } @@ -2774,7 +2776,7 @@ void CanvasItemEditor::_draw_rulers() { Point2 position = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)).round(); if (i % (major_subdivision * minor_subdivision) == 0) { viewport->draw_line(Point2(position.x, 0), Point2(position.x, RULER_WIDTH), graduation_color, Math::round(EDSCALE)); - float val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)).x; + real_t val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)).x; viewport->draw_string(font, Point2(position.x + 2, font->get_height(font_size)), TS->format_number(vformat(((int)val == val) ? "%d" : "%.1f", val)), HALIGN_LEFT, -1, font_size, font_color); } else { if (i % minor_subdivision == 0) { @@ -2791,7 +2793,7 @@ void CanvasItemEditor::_draw_rulers() { Point2 position = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i)).round(); if (i % (major_subdivision * minor_subdivision) == 0) { viewport->draw_line(Point2(0, position.y), Point2(RULER_WIDTH, position.y), graduation_color, Math::round(EDSCALE)); - float val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i)).y; + real_t val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i)).y; Transform2D text_xform = Transform2D(-Math_PI / 2.0, Point2(font->get_height(font_size), position.y - 2)); viewport->draw_set_transform_matrix(viewport->get_transform() * text_xform); @@ -2924,8 +2926,8 @@ void CanvasItemEditor::_draw_ruler_tool() { viewport->draw_string(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HALIGN_LEFT, -1, font_size, font_color, outline_size, outline_color); if (draw_secondary_lines) { - const float horizontal_angle_rad = atan2(length_vector.y, length_vector.x); - const float vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad; + const real_t horizontal_angle_rad = atan2(length_vector.y, length_vector.x); + const real_t vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad; const int horizontal_angle = round(180 * horizontal_angle_rad / Math_PI); const int vertical_angle = round(180 * vertical_angle_rad / Math_PI); @@ -2961,28 +2963,28 @@ void CanvasItemEditor::_draw_ruler_tool() { // Angle arcs int arc_point_count = 8; - float arc_radius_max_length_percent = 0.1; - float ruler_length = length_vector.length() * zoom; - float arc_max_radius = 50.0; - float arc_line_width = 2.0; + real_t arc_radius_max_length_percent = 0.1; + real_t ruler_length = length_vector.length() * zoom; + real_t arc_max_radius = 50.0; + real_t arc_line_width = 2.0; const Vector2 end_to_begin = (end - begin); - float arc_1_start_angle = + real_t arc_1_start_angle = end_to_begin.x < 0 ? (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0) : (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad); - float arc_1_end_angle = arc_1_start_angle + vertical_angle_rad; + real_t arc_1_end_angle = arc_1_start_angle + vertical_angle_rad; // Constrain arc to triangle height & max size - float arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius); + real_t arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius); - float arc_2_start_angle = + real_t arc_2_start_angle = end_to_begin.x < 0 ? (end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad) : (end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI); - float arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad; + real_t arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad; // Constrain arc to triangle width & max size - float arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius); + real_t arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius); viewport->draw_arc(begin, arc_1_radius, arc_1_start_angle, arc_1_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width)); viewport->draw_arc(end, arc_2_radius, arc_2_start_angle, arc_2_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width)); @@ -3020,7 +3022,7 @@ void CanvasItemEditor::_draw_control_anchors(Control *control) { RID ci = viewport->get_canvas_item(); if (tool == TOOL_SELECT && !Object::cast_to<Container>(control->get_parent())) { // Compute the anchors - float anchors_values[4]; + real_t anchors_values[4]; anchors_values[0] = control->get_anchor(SIDE_LEFT); anchors_values[1] = control->get_anchor(SIDE_TOP); anchors_values[2] = control->get_anchor(SIDE_RIGHT); @@ -3059,7 +3061,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { Color color_base = Color(0.8, 0.8, 0.8, 0.5); // Compute the anchors - float anchors_values[4]; + real_t anchors_values[4]; anchors_values[0] = control->get_anchor(SIDE_LEFT); anchors_values[1] = control->get_anchor(SIDE_TOP); anchors_values[2] = control->get_anchor(SIDE_RIGHT); @@ -3105,7 +3107,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { Vector2 line_starts[4]; Vector2 line_ends[4]; for (int i = 0; i < 4; i++) { - float anchor_val = (i >= 2) ? ANCHOR_END - anchors_values[i] : anchors_values[i]; + real_t anchor_val = (i >= 2) ? ANCHOR_END - anchors_values[i] : anchors_values[i]; line_starts[i] = corners_pos[i].lerp(corners_pos[(i + 1) % 4], anchor_val); line_ends[i] = corners_pos[(i + 3) % 4].lerp(corners_pos[(i + 2) % 4], anchor_val); anchor_snapped = anchors_values[i] == 0.0 || anchors_values[i] == 0.5 || anchors_values[i] == 1.0; @@ -3113,7 +3115,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { } // Display the percentages next to the lines - float percent_val; + real_t percent_val; percent_val = anchors_values[(dragged_anchor + 2) % 4] - anchors_values[dragged_anchor]; percent_val = (dragged_anchor >= 2) ? -percent_val : percent_val; _draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 1) % 4]) / 2, (Side)((dragged_anchor + 1) % 4)); @@ -3132,9 +3134,9 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { } // Draw the margin values and the node width/height when dragging control side - float ratio = 0.33; + const real_t ratio = 0.33; Transform2D parent_transform = xform * control->get_transform().affine_inverse(); - float node_pos_in_parent[4]; + real_t node_pos_in_parent[4]; Rect2 parent_rect = control->get_parent_anchorable_rect(); @@ -3451,10 +3453,10 @@ void CanvasItemEditor::_draw_straight_line(Point2 p_from, Point2 p_to, Color p_c points.push_back(Point2(0, to.y)); points.push_back(Point2(viewport_size.x, to.y)); } else { - float y_for_zero_x = (to.y * from.x - from.y * to.x) / (from.x - to.x); - float x_for_zero_y = (to.x * from.y - from.x * to.y) / (from.y - to.y); - float y_for_viewport_x = ((to.y - from.y) * (viewport_size.x - from.x)) / (to.x - from.x) + from.y; - float x_for_viewport_y = ((to.x - from.x) * (viewport_size.y - from.y)) / (to.y - from.y) + from.x; // faux + real_t y_for_zero_x = (to.y * from.x - from.y * to.x) / (from.x - to.x); + real_t x_for_zero_y = (to.x * from.y - from.x * to.y) / (from.y - to.y); + real_t y_for_viewport_x = ((to.y - from.y) * (viewport_size.x - from.x)) / (to.x - from.x) + from.y; + real_t x_for_viewport_y = ((to.x - from.x) * (viewport_size.y - from.y)) / (to.y - from.y) + from.x; // faux //bool start_set = false; if (y_for_zero_x >= 0 && y_for_zero_x <= viewport_size.y) { @@ -3600,7 +3602,7 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p RID viewport_canvas_item = viewport->get_canvas_item(); if (canvas_item) { - float offset = 0; + real_t offset = 0; Ref<Texture2D> lock = get_theme_icon(SNAME("LockViewport"), SNAME("EditorIcons")); if (p_node->has_meta("_edit_lock_") && show_edit_locks) { @@ -3724,7 +3726,7 @@ void CanvasItemEditor::_notification(int p_what) { Control *control = Object::cast_to<Control>(canvas_item); if (control) { - float anchors[4]; + real_t anchors[4]; Vector2 pivot; pivot = control->get_pivot_offset(); @@ -3853,7 +3855,10 @@ void CanvasItemEditor::_notification(int p_what) { key_auto_insert_button->add_theme_color_override("icon_pressed_color", key_auto_color.lerp(Color(1, 0, 0), 0.55)); animation_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); + _update_context_menu_stylebox(); + presets_menu->set_icon(get_theme_icon(SNAME("ControlLayout"), SNAME("EditorIcons"))); + PopupMenu *p = presets_menu->get_popup(); p->clear(); @@ -3954,6 +3959,18 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) { } } +void CanvasItemEditor::_update_context_menu_stylebox() { + // This must be called when the theme changes to follow the new accent color. + Ref<StyleBoxFlat> context_menu_stylebox = memnew(StyleBoxFlat); + const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color("accent_color", "Editor"); + context_menu_stylebox->set_bg_color(accent_color * Color(1, 1, 1, 0.1)); + // Add an underline to the StyleBox, but prevent its minimum vertical size from changing. + context_menu_stylebox->set_border_color(accent_color); + context_menu_stylebox->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE)); + context_menu_stylebox->set_default_margin(SIDE_BOTTOM, 0); + context_menu_container->add_theme_style_override("panel", context_menu_stylebox); +} + void CanvasItemEditor::_update_scrollbars() { updating_scroll = true; @@ -3986,7 +4003,7 @@ void CanvasItemEditor::_update_scrollbars() { bool constrain_editor_view = bool(EditorSettings::get_singleton()->get("editors/2d/constrain_editor_view")); if (canvas_item_rect.size.height <= (local_rect.size.y / zoom)) { - float centered = -(size.y / 2) / zoom + screen_rect.y / 2; + real_t centered = -(size.y / 2) / zoom + screen_rect.y / 2; if (constrain_editor_view && ABS(centered - previous_update_view_offset.y) < ABS(centered - view_offset.y)) { view_offset.y = previous_update_view_offset.y; } @@ -4007,7 +4024,7 @@ void CanvasItemEditor::_update_scrollbars() { } if (canvas_item_rect.size.width <= (local_rect.size.x / zoom)) { - float centered = -(size.x / 2) / zoom + screen_rect.x / 2; + real_t centered = -(size.x / 2) / zoom + screen_rect.x / 2; if (constrain_editor_view && ABS(centered - previous_update_view_offset.x) < ABS(centered - view_offset.x)) { view_offset.x = previous_update_view_offset.x; } @@ -4074,7 +4091,7 @@ void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const floa info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); } -void CanvasItemEditor::_update_scroll(float) { +void CanvasItemEditor::_update_scroll(real_t) { if (updating_scroll) { return; } @@ -4168,14 +4185,14 @@ void CanvasItemEditor::_set_anchors_preset(Control::LayoutPreset p_preset) { undo_redo->commit_action(); } -void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) { +void CanvasItemEditor::_zoom_on_position(real_t p_zoom, Point2 p_position) { p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM); if (p_zoom == zoom) { return; } - float prev_zoom = zoom; + real_t prev_zoom = zoom; zoom = p_zoom; view_offset += p_position / prev_zoom - p_position / zoom; @@ -4184,7 +4201,7 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) { // in small details (texts, lines). // This correction adds a jitter movement when zooming, so we correct only when the // zoom factor is an integer. (in the other cases, all pixels won't be aligned anyway) - float closest_zoom_factor = Math::round(zoom); + const real_t closest_zoom_factor = Math::round(zoom); if (Math::is_zero_approx(zoom - closest_zoom_factor)) { // make sure scene pixel at view_offset is aligned on a screen pixel Vector2 view_offset_int = view_offset.floor(); @@ -4196,7 +4213,7 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) { update_viewport(); } -void CanvasItemEditor::_update_zoom(float p_zoom) { +void CanvasItemEditor::_update_zoom(real_t p_zoom) { _zoom_on_position(p_zoom, viewport_scrollable->get_size() / 2.0); } @@ -4881,8 +4898,8 @@ void CanvasItemEditor::_focus_selection(int p_op) { } else { // VIEW_FRAME_TO_SELECTION if (rect.size.x > CMP_EPSILON && rect.size.y > CMP_EPSILON) { - float scale_x = viewport->get_size().x / rect.size.x; - float scale_y = viewport->get_size().y / rect.size.y; + real_t scale_x = viewport->get_size().x / rect.size.x; + real_t scale_y = viewport->get_size().y / rect.size.y; zoom = scale_x < scale_y ? scale_x : scale_y; zoom *= 0.90; viewport->update(); @@ -4947,7 +4964,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { if (state.has("zoom")) { // Compensate the editor scale, so that the editor scale can be changed // and the zoom level will still be the same (relative to the editor scale). - zoom = float(p_state["zoom"]) * MAX(1, EDSCALE); + zoom = real_t(p_state["zoom"]) * MAX(1, EDSCALE); zoom_widget->set_zoom(zoom); } @@ -5127,11 +5144,11 @@ void CanvasItemEditor::remove_control_from_info_overlay(Control *p_control) { void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) { ERR_FAIL_COND(!p_control); - hb->add_child(p_control); + hbc_context_menu->add_child(p_control); } void CanvasItemEditor::remove_control_from_menu_panel(Control *p_control) { - hb->remove_child(p_control); + hbc_context_menu->remove_child(p_control); } HSplitContainer *CanvasItemEditor::get_palette_split() { @@ -5516,10 +5533,21 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->add_separator(); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_P), PREVIEW_CANVAS_SCALE); + hb->add_child(memnew(VSeparator)); + + context_menu_container = memnew(PanelContainer); + hbc_context_menu = memnew(HBoxContainer); + context_menu_container->add_child(hbc_context_menu); + // Use a custom stylebox to make contextual menu items stand out from the rest. + // This helps with editor usability as contextual menu items change when selecting nodes, + // even though it may not be immediately obvious at first. + hb->add_child(context_menu_container); + _update_context_menu_stylebox(); + presets_menu = memnew(MenuButton); presets_menu->set_shortcut_context(this); presets_menu->set_text(TTR("Layout")); - hb->add_child(presets_menu); + hbc_context_menu->add_child(presets_menu); presets_menu->hide(); presets_menu->set_switch_on_hover(true); @@ -5533,17 +5561,18 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { anchor_mode_button = memnew(Button); anchor_mode_button->set_flat(true); - hb->add_child(anchor_mode_button); + hbc_context_menu->add_child(anchor_mode_button); anchor_mode_button->set_toggle_mode(true); anchor_mode_button->hide(); anchor_mode_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_anchor_mode)); animation_hb = memnew(HBoxContainer); - hb->add_child(animation_hb); + hbc_context_menu->add_child(animation_hb); animation_hb->add_child(memnew(VSeparator)); animation_hb->hide(); key_loc_button = memnew(Button); + key_loc_button->set_flat(true); key_loc_button->set_toggle_mode(true); key_loc_button->set_pressed(true); key_loc_button->set_focus_mode(FOCUS_NONE); @@ -5552,6 +5581,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { animation_hb->add_child(key_loc_button); key_rot_button = memnew(Button); + key_rot_button->set_flat(true); key_rot_button->set_toggle_mode(true); key_rot_button->set_pressed(true); key_rot_button->set_focus_mode(FOCUS_NONE); @@ -5560,6 +5590,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { animation_hb->add_child(key_rot_button); key_scale_button = memnew(Button); + key_scale_button->set_flat(true); key_scale_button->set_toggle_mode(true); key_scale_button->set_focus_mode(FOCUS_NONE); key_scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_SCALE)); @@ -5567,6 +5598,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { animation_hb->add_child(key_scale_button); key_insert_button = memnew(Button); + key_insert_button->set_flat(true); key_insert_button->set_focus_mode(FOCUS_NONE); key_insert_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_KEY)); key_insert_button->set_tooltip(TTR("Insert keys (based on mask).")); @@ -5733,11 +5765,14 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons preview_node->add_child(sprite); label->show(); label_desc->show(); + label_desc->set_text(TTR("Drag and drop to add as child of current scene's root node.\nHold Ctrl when dropping to add as child of selected node.\nHold Shift when dropping to add as sibling of selected node.\nHold Alt when dropping to add as a different node type.")); } else { if (scene.is_valid()) { Node *instance = scene->instantiate(); if (instance) { preview_node->add_child(instance); + label_desc->show(); + label_desc->set_text(TTR("Drag and drop to add as child of current scene's root node.\nHold Ctrl when dropping to add as child of selected node.\nHold Shift when dropping to add as sibling of selected node.")); } } } @@ -6051,6 +6086,7 @@ bool CanvasItemEditorViewport::_only_packed_scenes_selected() const { void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) { bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT); + bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL); bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT); selected_files.clear(); @@ -6062,24 +6098,25 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p return; } - List<Node *> list = editor->get_editor_selection()->get_selected_node_list(); - if (list.size() == 0) { - Node *root_node = editor->get_edited_scene(); + List<Node *> selected_nodes = editor->get_editor_selection()->get_selected_node_list(); + Node *root_node = editor->get_edited_scene(); + if (selected_nodes.size() > 0) { + Node *selected_node = selected_nodes[0]; + target_node = root_node; + if (is_ctrl) { + target_node = selected_node; + } else if (is_shift && selected_node != root_node) { + target_node = selected_node->get_parent(); + } + } else { if (root_node) { - list.push_back(root_node); + target_node = root_node; } else { drop_pos = p_point; target_node = nullptr; } } - if (list.size() > 0) { - target_node = list[0]; - if (is_shift && target_node != editor->get_edited_scene()) { - target_node = target_node->get_parent(); - } - } - drop_pos = p_point; if (is_alt && !_only_packed_scenes_selected()) { @@ -6160,7 +6197,6 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte canvas_item_editor->get_controls_container()->add_child(label); label_desc = memnew(Label); - label_desc->set_text(TTR("Drag & drop + Shift : Add node as sibling\nDrag & drop + Alt : Change node type")); label_desc->add_theme_color_override("font_color", Color(0.6f, 0.6f, 0.6f, 1)); label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1)); label_desc->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 7b64d0cb5d..1f59dfbc49 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -48,10 +48,10 @@ class CanvasItemEditorSelectedItem : public Object { public: Transform2D prev_xform; - float prev_rot = 0; + real_t prev_rot = 0; Rect2 prev_rect; Vector2 prev_pivot; - float prev_anchors[4] = { 0.0f }; + real_t prev_anchors[4] = { (real_t)0.0 }; Transform2D pre_drag_xform; Rect2 pre_drag_rect; @@ -230,6 +230,10 @@ private: HScrollBar *h_scroll; VScrollBar *v_scroll; HBoxContainer *hb; + // Used for secondary menu items which are displayed depending on the currently selected node + // (such as MeshInstance's "Mesh" menu). + PanelContainer *context_menu_container; + HBoxContainer *hbc_context_menu; Map<Control *, Timer *> popup_temporarily_timers; @@ -246,7 +250,7 @@ private: bool show_edit_locks; bool show_transformation_gizmos; - float zoom; + real_t zoom; Point2 view_offset; Point2 previous_update_view_offset; @@ -258,9 +262,9 @@ private: int primary_grid_steps; int grid_step_multiplier; - float snap_rotation_step; - float snap_rotation_offset; - float snap_scale_step; + real_t snap_rotation_step; + real_t snap_rotation_offset; + real_t snap_scale_step; bool smart_snap_active; bool grid_snap_active; @@ -288,7 +292,7 @@ private: struct _SelectResult { CanvasItem *item = nullptr; - float z_index = 0; + real_t z_index = 0; bool has_z = true; _FORCE_INLINE_ bool operator<(const _SelectResult &p_rr) const { return has_z && p_rr.has_z ? p_rr.z_index < z_index : p_rr.has_z; @@ -305,7 +309,7 @@ private: struct BoneList { Transform2D xform; - float length = 0.f; + real_t length = 0; uint64_t last_pass = 0; }; @@ -328,7 +332,7 @@ private: struct PoseClipboard { Vector2 pos; Vector2 scale; - float rot = 0; + real_t rot = 0; ObjectID id; }; List<PoseClipboard> pose_clipboard; @@ -428,7 +432,7 @@ private: void _popup_callback(int p_op); bool updating_scroll; - void _update_scroll(float); + void _update_scroll(real_t); void _update_scrollbars(); void _append_canvas_item(CanvasItem *p_item); void _snap_changed(); @@ -455,7 +459,7 @@ private: void _draw_text_at_position(Point2 p_position, String p_string, Side p_side); void _draw_margin_at_position(int p_value, Point2 p_position, Side p_side); - void _draw_percentage_at_position(float p_value, Point2 p_position, Side p_side); + void _draw_percentage_at_position(real_t p_value, Point2 p_position, Side p_side); void _draw_straight_line(Point2 p_from, Point2 p_to, Color p_color); void _draw_smart_snapping(); @@ -497,16 +501,16 @@ private: SnapTarget snap_target[2]; Transform2D snap_transform; void _snap_if_closer_float( - float p_value, - float &r_current_snap, SnapTarget &r_current_snap_target, - float p_target_value, SnapTarget p_snap_target, - float p_radius = 10.0); + const real_t p_value, + real_t &r_current_snap, SnapTarget &r_current_snap_target, + const real_t p_target_value, const SnapTarget p_snap_target, + const real_t p_radius = 10.0); void _snap_if_closer_point( Point2 p_value, Point2 &r_current_snap, SnapTarget (&r_current_snap_target)[2], - Point2 p_target_value, SnapTarget p_snap_target, - real_t rotation = 0.0, - float p_radius = 10.0); + Point2 p_target_value, const SnapTarget p_snap_target, + const real_t rotation = 0.0, + const real_t p_radius = 10.0); void _snap_other_nodes( const Point2 p_value, const Transform2D p_transform_to_snap, @@ -523,8 +527,8 @@ private: VBoxContainer *controls_vb; EditorZoomWidget *zoom_widget; - void _update_zoom(float p_zoom); - void _zoom_on_position(float p_zoom, Point2 p_position = Point2()); + void _update_zoom(real_t p_zoom); + void _zoom_on_position(real_t p_zoom, Point2 p_position = Point2()); void _button_toggle_smart_snap(bool p_status); void _button_toggle_grid_snap(bool p_status); void _button_override_camera(bool p_pressed); @@ -535,6 +539,7 @@ private: HSplitContainer *palette_split; VSplitContainer *bottom_split; + void _update_context_menu_stylebox(); void _popup_warning_temporarily(Control *p_control, const float p_duration); void _popup_warning_depop(Control *p_control); @@ -552,28 +557,6 @@ protected: HBoxContainer *get_panel_hb() { return hb; } - struct compare_items_x { - bool operator()(const CanvasItem *a, const CanvasItem *b) const { - return a->get_global_transform().elements[2].x < b->get_global_transform().elements[2].x; - } - }; - - struct compare_items_y { - bool operator()(const CanvasItem *a, const CanvasItem *b) const { - return a->get_global_transform().elements[2].y < b->get_global_transform().elements[2].y; - } - }; - - struct proj_vector2_x { - float get(const Vector2 &v) { return v.x; } - void set(Vector2 &v, float f) { v.x = f; } - }; - - struct proj_vector2_y { - float get(const Vector2 &v) { return v.y; } - void set(Vector2 &v, float f) { v.y = f; } - }; - template <class P, class C> void space_selected_items(); @@ -594,7 +577,7 @@ public: }; Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = nullptr, List<CanvasItem *> p_other_nodes_exceptions = List<CanvasItem *>()); - float snap_angle(float p_target, float p_start = 0) const; + real_t snap_angle(real_t p_target, real_t p_start = 0) const; Transform2D get_canvas_transform() const { return transform; } diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 81c340e9a4..d7618b973e 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -724,7 +724,7 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI * 0.125); xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI * 0.125) * xform.basis; AABB rot_aabb = xform.xform(aabb); - float m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5; + real_t m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5; if (m == 0) { return Ref<Texture2D>(); } diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 2138f943da..46e15d97bf 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -320,7 +320,7 @@ void EditorNode3DGizmo::add_vertices(const Vector<Vector3> &p_vertices, const Re instances.push_back(ins); } -void EditorNode3DGizmo::add_unscaled_billboard(const Ref<Material> &p_material, float p_scale, const Color &p_modulate) { +void EditorNode3DGizmo::add_unscaled_billboard(const Ref<Material> &p_material, real_t p_scale, const Color &p_modulate) { ERR_FAIL_COND(!spatial_node); Instance ins; diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h index 61ee3a95a9..f303a61607 100644 --- a/editor/plugins/node_3d_editor_gizmos.h +++ b/editor/plugins/node_3d_editor_gizmos.h @@ -84,7 +84,7 @@ public: void add_mesh(const Ref<ArrayMesh> &p_mesh, const Ref<Material> &p_material = Ref<Material>(), const Transform3D &p_xform = Transform3D(), const Ref<SkinReference> &p_skin_reference = Ref<SkinReference>()); void add_collision_segments(const Vector<Vector3> &p_lines); void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh); - void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1, const Color &p_modulate = Color(1, 1, 1)); + void add_unscaled_billboard(const Ref<Material> &p_material, real_t p_scale = 1, const Color &p_modulate = Color(1, 1, 1)); void add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, const Vector<int> &p_ids = Vector<int>(), bool p_billboard = false, bool p_secondary = false); void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3(), const Transform3D &p_xform = Transform3D()); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index ebd6615ac1..5f12294e22 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -107,8 +107,8 @@ void ViewportRotationControl::_notification(int p_what) { } void ViewportRotationControl::_draw() { - Vector2i center = get_size() / 2.0; - float radius = get_size().x / 2.0; + const Vector2i center = get_size() / 2.0; + const real_t radius = get_size().x / 2.0; if (focused_axis > -2 || orbiting) { draw_circle(center, radius, Color(0.5, 0.5, 0.5, 0.25)); @@ -149,15 +149,13 @@ void ViewportRotationControl::_draw_axis(const Axis2D &p_axis) { } void ViewportRotationControl::_get_sorted_axis(Vector<Axis2D> &r_axis) { - Vector2i center = get_size() / 2.0; - float radius = get_size().x / 2.0; - - float axis_radius = radius - AXIS_CIRCLE_RADIUS - 2.0 * EDSCALE; - Basis camera_basis = viewport->to_camera_transform(viewport->cursor).get_basis().inverse(); + const Vector2i center = get_size() / 2.0; + const real_t radius = get_size().x / 2.0 - AXIS_CIRCLE_RADIUS - 2.0 * EDSCALE; + const Basis camera_basis = viewport->to_camera_transform(viewport->cursor).get_basis().inverse(); for (int i = 0; i < 3; ++i) { Vector3 axis_3d = camera_basis.get_axis(i); - Vector2i axis_vector = Vector2(axis_3d.x, -axis_3d.y) * axis_radius; + Vector2i axis_vector = Vector2(axis_3d.x, -axis_3d.y) * radius; if (Math::abs(axis_3d.z) < 1.0) { Axis2D pos_axis; @@ -259,7 +257,7 @@ void ViewportRotationControl::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &ViewportRotationControl::_gui_input); } -void Node3DEditorViewport::_update_camera(float p_interp_delta) { +void Node3DEditorViewport::_update_camera(real_t p_interp_delta) { bool is_orthogonal = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL; Cursor old_camera_cursor = camera_cursor; @@ -279,7 +277,7 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) { // We interpolate a different point here, because in freelook mode the focus point (cursor.pos) orbits around eye_pos camera_cursor.eye_pos = old_camera_cursor.eye_pos.lerp(cursor.eye_pos, CLAMP(factor, 0, 1)); - float orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia"); + real_t orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia"); orbit_inertia = MAX(0.0001, orbit_inertia); camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia))); camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia))); @@ -297,13 +295,13 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) { } else { //when not being manipulated, move softly - float free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia"); - float free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia"); + real_t free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia"); + real_t free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia"); //when being manipulated, move more quickly - float manip_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_orbit_inertia"); - float manip_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_translation_inertia"); + real_t manip_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_orbit_inertia"); + real_t manip_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_translation_inertia"); - float zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia"); + real_t zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia"); //determine if being manipulated bool manipulated = Input::get_singleton()->get_mouse_button_mask() & (2 | 4); @@ -311,8 +309,8 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) { manipulated |= Input::get_singleton()->is_key_pressed(KEY_ALT); manipulated |= Input::get_singleton()->is_key_pressed(KEY_CTRL); - float orbit_inertia = MAX(0.00001, manipulated ? manip_orbit_inertia : free_orbit_inertia); - float translation_inertia = MAX(0.0001, manipulated ? manip_translation_inertia : free_translation_inertia); + real_t orbit_inertia = MAX(0.00001, manipulated ? manip_orbit_inertia : free_orbit_inertia); + real_t translation_inertia = MAX(0.0001, manipulated ? manip_translation_inertia : free_translation_inertia); zoom_inertia = MAX(0.0001, zoom_inertia); camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia))); @@ -327,7 +325,7 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) { } camera_cursor.pos = old_camera_cursor.pos.lerp(cursor.pos, MIN(1.f, p_interp_delta * (1 / translation_inertia))); - camera_cursor.distance = Math::lerp(old_camera_cursor.distance, cursor.distance, MIN(1.f, p_interp_delta * (1 / zoom_inertia))); + camera_cursor.distance = Math::lerp(old_camera_cursor.distance, cursor.distance, MIN((real_t)1.0, p_interp_delta * (1 / zoom_inertia))); } } @@ -537,7 +535,7 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) { continue; } - float dist = pos.distance_to(point); + const real_t dist = pos.distance_to(point); if (dist < 0) { continue; @@ -601,7 +599,7 @@ void Node3DEditorViewport::_find_items_at_pos(const Point2 &p_pos, Vector<_RayRe continue; } - float dist = pos.distance_to(point); + const real_t dist = pos.distance_to(point); if (dist < 0) { continue; @@ -646,7 +644,7 @@ void Node3DEditorViewport::_select_region() { return; //nothing really } - float z_offset = MAX(0.0, 5.0 - get_znear()); + const real_t z_offset = MAX(0.0, 5.0 - get_znear()); Vector3 box[4] = { Vector3( @@ -912,20 +910,19 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b Vector3 ray = _get_ray(Vector2(p_screenpos.x, p_screenpos.y)); Transform3D gt = spatial_editor->get_gizmo_transform(); - float gs = gizmo_scale; if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { int col_axis = -1; - float col_d = 1e20; + real_t col_d = 1e20; for (int i = 0; i < 3; i++) { - Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5)); - float grabber_radius = gs * GIZMO_ARROW_SIZE; + const Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gizmo_scale * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5)); + const real_t grabber_radius = gizmo_scale * GIZMO_ARROW_SIZE; Vector3 r; if (Geometry3D::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) { - float d = r.distance_to(ray_pos); + const real_t d = r.distance_to(ray_pos); if (d < col_d) { col_d = d; col_axis = i; @@ -944,17 +941,17 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b // Allow some tolerance to make the plane easier to click, // even if the click is actually slightly outside the plane. - const Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST * 0.6667); + const Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gizmo_scale * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST * 0.6667); Vector3 r; Plane plane(gt.origin, gt.basis.get_axis(i).normalized()); if (plane.intersects_ray(ray_pos, ray, &r)) { - float dist = r.distance_to(grabber_pos); + const real_t dist = r.distance_to(grabber_pos); // Allow some tolerance to make the plane easier to click, // even if the click is actually slightly outside the plane. - if (dist < (gs * GIZMO_PLANE_SIZE * 1.5)) { - float d = ray_pos.distance_to(r); + if (dist < (gizmo_scale * GIZMO_PLANE_SIZE * 1.5)) { + const real_t d = ray_pos.distance_to(r); if (d < col_d) { col_d = d; col_axis = i; @@ -991,12 +988,12 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b continue; } - float dist = r.distance_to(gt.origin); - Vector3 r_dir = (r - gt.origin).normalized(); + const real_t dist = r.distance_to(gt.origin); + const Vector3 r_dir = (r - gt.origin).normalized(); if (_get_camera_normal().dot(r_dir) <= 0.005) { - if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) { - float d = ray_pos.distance_to(r); + if (dist > gizmo_scale * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gizmo_scale * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) { + const real_t d = ray_pos.distance_to(r); if (d < col_d) { col_d = d; col_axis = i; @@ -1023,13 +1020,13 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b float col_d = 1e20; for (int i = 0; i < 3; i++) { - Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * GIZMO_SCALE_OFFSET; - float grabber_radius = gs * GIZMO_ARROW_SIZE; + const Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gizmo_scale * GIZMO_SCALE_OFFSET; + const real_t grabber_radius = gizmo_scale * GIZMO_ARROW_SIZE; Vector3 r; if (Geometry3D::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) { - float d = r.distance_to(ray_pos); + const real_t d = r.distance_to(ray_pos); if (d < col_d) { col_d = d; col_axis = i; @@ -1043,22 +1040,22 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b col_d = 1e20; for (int i = 0; i < 3; i++) { - Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized(); - Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized(); + const Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized(); + const Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized(); // Allow some tolerance to make the plane easier to click, // even if the click is actually slightly outside the plane. - Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST * 0.6667); + const Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gizmo_scale * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST * 0.6667); Vector3 r; Plane plane(gt.origin, gt.basis.get_axis(i).normalized()); if (plane.intersects_ray(ray_pos, ray, &r)) { - float dist = r.distance_to(grabber_pos); + const real_t dist = r.distance_to(grabber_pos); // Allow some tolerance to make the plane easier to click, // even if the click is actually slightly outside the plane. - if (dist < (gs * GIZMO_PLANE_SIZE * 1.5)) { - float d = ray_pos.distance_to(r); + if (dist < (gizmo_scale * GIZMO_PLANE_SIZE * 1.5)) { + const real_t d = ray_pos.distance_to(r); if (d < col_d) { col_d = d; col_axis = i; @@ -1293,7 +1290,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (b.is_valid()) { emit_signal(SNAME("clicked"), this); - float zoom_factor = 1 + (ZOOM_FREELOOK_MULTIPLIER - 1) * b->get_factor(); + const real_t zoom_factor = 1 + (ZOOM_FREELOOK_MULTIPLIER - 1) * b->get_factor(); switch (b->get_button_index()) { case MOUSE_BUTTON_WHEEL_UP: { if (is_freelook_active()) { @@ -1596,8 +1593,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { se->gizmo->commit_subgizmos(ids, restore, false); spatial_editor->update_transform_gizmo(); } else { - static const char *_transform_name[4] = { "None", "Rotate", "Translate", "Scale" }; - undo_redo->create_action(_transform_name[_edit.mode]); + static const char *_transform_name[4] = { + TTRC("None"), + TTRC("Rotate"), + // TRANSLATORS: This refers to the movement that changes the position of an object. + TTRC("Translate"), + TTRC("Scale"), + }; + undo_redo->create_action(TTRGET(_transform_name[_edit.mode])); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -1774,13 +1777,13 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } else { - float center_click_dist = click.distance_to(_edit.center); - float center_inters_dist = intersection.distance_to(_edit.center); + const real_t center_click_dist = click.distance_to(_edit.center); + const real_t center_inters_dist = intersection.distance_to(_edit.center); if (center_click_dist == 0) { break; } - float scale = center_inters_dist - center_click_dist; + const real_t scale = center_inters_dist - center_click_dist; motion = Vector3(scale, scale, scale); } @@ -2871,7 +2874,7 @@ void Node3DEditorViewport::_draw() { if (surface->has_focus()) { Size2 size = surface->get_size(); Rect2 r = Rect2(Point2(), size); - get_theme_stylebox(SNAME("Focus"), SNAME("EditorStyles"))->draw(surface->get_canvas_item(), r); + get_theme_stylebox(SNAME("FocusViewport"), SNAME("EditorStyles"))->draw(surface->get_canvas_item(), r); } if (cursor.region_select) { @@ -3521,18 +3524,15 @@ void Node3DEditorViewport::update_transform_gizmo_view() { return; } - Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized(); - Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized(); - Plane p(camera_xform.origin, camz); - float gizmo_d = MAX(Math::abs(p.distance_to(xform.origin)), CMP_EPSILON); - float d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y; - float d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y; - float dd = Math::abs(d0 - d1); - if (dd == 0) { - dd = 0.0001; - } + const Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized(); + const Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized(); + const Plane p(camera_xform.origin, camz); + const real_t gizmo_d = MAX(Math::abs(p.distance_to(xform.origin)), CMP_EPSILON); + const real_t d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y; + const real_t d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y; + const real_t dd = MAX(Math::abs(d0 - d1), CMP_EPSILON); - float gizmo_size = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size"); + const real_t gizmo_size = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size"); // At low viewport heights, multiply the gizmo scale based on the viewport height. // This prevents the gizmo from growing very large and going outside the viewport. const int viewport_base_height = 400 * MAX(1, EDSCALE); @@ -3788,7 +3788,7 @@ void Node3DEditorViewport::focus_selection() { } if (count != 0) { - center /= float(count); + center /= count; } cursor.pos = center; @@ -4066,6 +4066,7 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_ } bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT); + bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL); selected_files.clear(); Dictionary d = p_data; @@ -4073,29 +4074,32 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_ selected_files = d["files"]; } - List<Node *> list = editor->get_editor_selection()->get_selected_node_list(); - if (list.size() == 0) { - Node *root_node = editor->get_edited_scene(); + List<Node *> selected_nodes = editor->get_editor_selection()->get_selected_node_list(); + Node *root_node = editor->get_edited_scene(); + if (selected_nodes.size() == 1) { + Node *selected_node = selected_nodes[0]; + target_node = root_node; + if (is_ctrl) { + target_node = selected_node; + } else if (is_shift && selected_node != root_node) { + target_node = selected_node->get_parent(); + } + } else if (selected_nodes.size() == 0) { if (root_node) { - list.push_back(root_node); + target_node = root_node; } else { - accept->set_text(TTR("No parent to instance a child at.")); + accept->set_text(TTR("Cannot drag and drop into scene with no root node.")); accept->popup_centered(); _remove_preview(); return; } - } - if (list.size() != 1) { - accept->set_text(TTR("This operation requires a single selected node.")); + } else { + accept->set_text(TTR("Cannot drag and drop into multiple selected nodes.")); accept->popup_centered(); _remove_preview(); return; } - target_node = list[0]; - if (is_shift && target_node != editor->get_edited_scene()) { - target_node = target_node->get_parent(); - } drop_pos = p_point; _perform_drop_data(); @@ -4448,14 +4452,14 @@ void Node3DEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) { } if (dragging_h) { - float new_ratio = drag_begin_ratio.x + (mm->get_position().x - drag_begin_pos.x) / get_size().width; + real_t new_ratio = drag_begin_ratio.x + (mm->get_position().x - drag_begin_pos.x) / get_size().width; new_ratio = CLAMP(new_ratio, 40 / get_size().width, (get_size().width - 40) / get_size().width); ratio_h = new_ratio; queue_sort(); update(); } if (dragging_v) { - float new_ratio = drag_begin_ratio.y + (mm->get_position().y - drag_begin_pos.y) / get_size().height; + real_t new_ratio = drag_begin_ratio.y + (mm->get_position().y - drag_begin_pos.y) / get_size().height; new_ratio = CLAMP(new_ratio, 40 / get_size().height, (get_size().height - 40) / get_size().height); ratio_v = new_ratio; queue_sort(); @@ -5006,13 +5010,13 @@ void Node3DEditor::set_state(const Dictionary &p_state) { } if (d.has("zfar")) { - settings_zfar->set_value(float(d["zfar"])); + settings_zfar->set_value(double(d["zfar"])); } if (d.has("znear")) { - settings_znear->set_value(float(d["znear"])); + settings_znear->set_value(double(d["znear"])); } if (d.has("fov")) { - settings_fov->set_value(float(d["fov"])); + settings_fov->set_value(double(d["fov"])); } if (d.has("show_grid")) { bool use = d["show_grid"]; @@ -5968,6 +5972,18 @@ void fragment() { _generate_selection_boxes(); } +void Node3DEditor::_update_context_menu_stylebox() { + // This must be called when the theme changes to follow the new accent color. + Ref<StyleBoxFlat> context_menu_stylebox = memnew(StyleBoxFlat); + const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color("accent_color", "Editor"); + context_menu_stylebox->set_bg_color(accent_color * Color(1, 1, 1, 0.1)); + // Add an underline to the StyleBox, but prevent its minimum vertical size from changing. + context_menu_stylebox->set_border_color(accent_color); + context_menu_stylebox->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE)); + context_menu_stylebox->set_default_margin(SIDE_BOTTOM, 0); + context_menu_container->add_theme_style_override("panel", context_menu_stylebox); +} + void Node3DEditor::_update_gizmos_menu() { gizmos_menu->clear(); @@ -6535,6 +6551,7 @@ void Node3DEditor::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { _update_theme(); _update_gizmos_menu_theme(); + _update_context_menu_stylebox(); sun_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window"))); environ_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window"))); } break; @@ -6583,11 +6600,11 @@ Vector<int> Node3DEditor::get_subgizmo_selection() { } void Node3DEditor::add_control_to_menu_panel(Control *p_control) { - hbc_menu->add_child(p_control); + hbc_context_menu->add_child(p_control); } void Node3DEditor::remove_control_from_menu_panel(Control *p_control) { - hbc_menu->remove_child(p_control); + hbc_context_menu->remove_child(p_control); } void Node3DEditor::set_can_preview(Camera3D *p_preview) { @@ -7170,7 +7187,20 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) { view_menu->set_shortcut_context(this); hbc_menu->add_child(view_menu); + hbc_menu->add_child(memnew(VSeparator)); + + context_menu_container = memnew(PanelContainer); + hbc_context_menu = memnew(HBoxContainer); + context_menu_container->add_child(hbc_context_menu); + // Use a custom stylebox to make contextual menu items stand out from the rest. + // This helps with editor usability as contextual menu items change when selecting nodes, + // even though it may not be immediately obvious at first. + hbc_menu->add_child(context_menu_container); + _update_context_menu_stylebox(); + + // Get the view menu popup and have it stay open when a checkable item is selected p = view_menu->get_popup(); + p->set_hide_on_checkable_item_selection(false); accept = memnew(AcceptDialog); editor->get_gui_base()->add_child(accept); @@ -7589,8 +7619,8 @@ Vector3 Node3DEditor::snap_point(Vector3 p_target, Vector3 p_start) const { return p_target; } -float Node3DEditor::get_translate_snap() const { - float snap_value; +double Node3DEditor::get_translate_snap() const { + double snap_value; if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { snap_value = snap_translate->get_text().to_float() / 10.0; } else { @@ -7600,8 +7630,8 @@ float Node3DEditor::get_translate_snap() const { return snap_value; } -float Node3DEditor::get_rotate_snap() const { - float snap_value; +double Node3DEditor::get_rotate_snap() const { + double snap_value; if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { snap_value = snap_rotate->get_text().to_float() / 3.0; } else { @@ -7611,8 +7641,8 @@ float Node3DEditor::get_rotate_snap() const { return snap_value; } -float Node3DEditor::get_scale_snap() const { - float snap_value; +double Node3DEditor::get_scale_snap() const { + double snap_value; if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { snap_value = snap_scale->get_text().to_float() / 2.0; } else { diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 0c7a0d14a2..cb2edbcbc1 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -201,7 +201,7 @@ private: bool orthogonal; bool auto_orthogonal; bool lock_rotation; - float gizmo_scale; + real_t gizmo_scale; bool freelook_active; real_t freelook_speed; @@ -221,7 +221,7 @@ private: struct _RayResult { Node3D *item = nullptr; - float depth = 0; + real_t depth = 0; _FORCE_INLINE_ bool operator<(const _RayResult &p_rr) const { return depth < p_rr.depth; } }; @@ -306,7 +306,7 @@ private: struct Cursor { Vector3 pos; - float x_rot, y_rot, distance; + real_t x_rot, y_rot, distance; Vector3 eye_pos; // Used in freelook mode bool region_select; Point2 region_begin, region_end; @@ -340,8 +340,7 @@ private: void set_message(String p_message, float p_time = 5); - // - void _update_camera(float p_interp_delta); + void _update_camera(real_t p_interp_delta); Transform3D to_camera_transform(const Cursor &p_cursor) const; void _draw(); @@ -450,8 +449,8 @@ public: private: View view; bool mouseover; - float ratio_h; - float ratio_v; + real_t ratio_h; + real_t ratio_v; bool hovering_v; bool hovering_h; @@ -534,9 +533,9 @@ private: Ref<Node3DGizmo> current_hover_gizmo; int current_hover_gizmo_handle; - float snap_translate_value; - float snap_rotate_value; - float snap_scale_value; + real_t snap_translate_value; + real_t snap_rotate_value; + real_t snap_scale_value; Ref<ArrayMesh> selection_box_xray; Ref<ArrayMesh> selection_box; @@ -554,7 +553,7 @@ private: struct Gizmo { bool visible = false; - float scale = 0; + real_t scale = 0; Transform3D transform; } gizmo; @@ -625,6 +624,10 @@ private: void _update_camera_override_viewport(Object *p_viewport); HBoxContainer *hbc_menu; + // Used for secondary menu items which are displayed depending on the currently selected node + // (such as MeshInstance's "Mesh" menu). + PanelContainer *context_menu_container; + HBoxContainer *hbc_context_menu; void _generate_selection_boxes(); UndoRedo *undo_redo; @@ -632,6 +635,7 @@ private: int camera_override_viewport_id; void _init_indicators(); + void _update_context_menu_stylebox(); void _update_gizmos_menu(); void _update_gizmos_menu_theme(); void _init_grid(); @@ -747,9 +751,9 @@ public: ToolMode get_tool_mode() const { return tool_mode; } bool are_local_coords_enabled() const { return tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); } bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; } - float get_translate_snap() const; - float get_rotate_snap() const; - float get_scale_snap() const; + double get_translate_snap() const; + double get_rotate_snap() const; + double get_scale_snap() const; Ref<ArrayMesh> get_move_gizmo(int idx) const { return move_gizmo[idx]; } Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; } diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index b420372eff..9377395418 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -400,25 +400,25 @@ void Polygon2DEditor::_set_show_grid(bool p_show) { uv_edit_draw->update(); } -void Polygon2DEditor::_set_snap_off_x(float p_val) { +void Polygon2DEditor::_set_snap_off_x(real_t p_val) { snap_offset.x = p_val; EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_offset", snap_offset); uv_edit_draw->update(); } -void Polygon2DEditor::_set_snap_off_y(float p_val) { +void Polygon2DEditor::_set_snap_off_y(real_t p_val) { snap_offset.y = p_val; EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_offset", snap_offset); uv_edit_draw->update(); } -void Polygon2DEditor::_set_snap_step_x(float p_val) { +void Polygon2DEditor::_set_snap_step_x(real_t p_val) { snap_step.x = p_val; EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_step", snap_step); uv_edit_draw->update(); } -void Polygon2DEditor::_set_snap_step_y(float p_val) { +void Polygon2DEditor::_set_snap_step_y(real_t p_val) { snap_step.y = p_val; EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_step", snap_step); uv_edit_draw->update(); @@ -569,11 +569,11 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } int closest = -1; - float closest_dist = 1e20; + real_t closest_dist = 1e20; for (int i = points_prev.size() - internal_vertices; i < points_prev.size(); i++) { Vector2 tuv = mtx.xform(uv_create_poly_prev[i]); - float dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)); + real_t dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)); if (dist < 8 && dist < closest_dist) { closest = i; closest_dist = dist; @@ -639,11 +639,11 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { if (uv_move_current == UV_MODE_ADD_POLYGON) { int closest = -1; - float closest_dist = 1e20; + real_t closest_dist = 1e20; for (int i = 0; i < points_prev.size(); i++) { Vector2 tuv = mtx.xform(points_prev[i]); - float dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)); + real_t dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)); if (dist < 8 && dist < closest_dist) { closest = i; closest_dist = dist; @@ -825,7 +825,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } center /= uv_new.size(); - float angle = (uv_drag_from - mtx.xform(center)).normalized().angle_to((uv_drag_to - mtx.xform(center)).normalized()); + real_t angle = (uv_drag_from - mtx.xform(center)).normalized().angle_to((uv_drag_to - mtx.xform(center)).normalized()); for (int i = 0; i < uv_new.size(); i++) { Vector2 rel = points_prev[i] - center; @@ -848,13 +848,13 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } center /= uv_new.size(); - float from_dist = uv_drag_from.distance_to(mtx.xform(center)); - float to_dist = uv_drag_to.distance_to(mtx.xform(center)); + real_t from_dist = uv_drag_from.distance_to(mtx.xform(center)); + real_t to_dist = uv_drag_to.distance_to(mtx.xform(center)); if (from_dist < 2) { break; } - float scale = to_dist / from_dist; + real_t scale = to_dist / from_dist; for (int i = 0; i < uv_new.size(); i++) { Vector2 rel = points_prev[i] - center; @@ -881,8 +881,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { { int pc = painted_weights.size(); - float amount = bone_paint_strength->get_value(); - float radius = bone_paint_radius->get_value() * EDSCALE; + real_t amount = bone_paint_strength->get_value(); + real_t radius = bone_paint_radius->get_value() * EDSCALE; if (uv_mode == UV_MODE_CLEAR_WEIGHT) { amount = -amount; @@ -925,7 +925,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } } -void Polygon2DEditor::_uv_scroll_changed(float) { +void Polygon2DEditor::_uv_scroll_changed(real_t) { if (updating_uv_scroll) { return; } diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h index af3b2f5aef..cbe7ecf360 100644 --- a/editor/plugins/polygon_2d_editor_plugin.h +++ b/editor/plugins/polygon_2d_editor_plugin.h @@ -95,7 +95,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { void _update_bone_list(); Vector2 uv_draw_ofs; - float uv_draw_zoom; + real_t uv_draw_zoom; Vector<Vector2> points_prev; Vector<Vector2> uv_create_uv_prev; Vector<Vector2> uv_create_poly_prev; @@ -127,17 +127,17 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { void _cancel_editing(); void _update_polygon_editing_state(); - void _uv_scroll_changed(float); + void _uv_scroll_changed(real_t); void _uv_input(const Ref<InputEvent> &p_input); void _uv_draw(); void _uv_mode(int p_mode); void _set_use_snap(bool p_use); void _set_show_grid(bool p_show); - void _set_snap_off_x(float p_val); - void _set_snap_off_y(float p_val); - void _set_snap_step_x(float p_val); - void _set_snap_step_y(float p_val); + void _set_snap_off_x(real_t p_val); + void _set_snap_off_y(real_t p_val); + void _set_snap_step_x(real_t p_val); + void _set_snap_step_y(real_t p_val); void _uv_edit_mode_select(int p_mode); void _uv_edit_popup_hide(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 65459d159d..5bbe56a800 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -204,7 +204,13 @@ void ScriptTextEditor::_set_theme_for_script() { for (const String &string : strings) { String beg = string.get_slice(" ", 0); String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String(); - text_edit->add_string_delimiter(beg, end, end == ""); + if (!text_edit->has_string_delimiter(beg)) { + text_edit->add_string_delimiter(beg, end, end == ""); + } + + if (!end.is_empty() && !text_edit->has_auto_brace_completion_open_key(beg)) { + text_edit->add_auto_brace_completion_pair(beg, end); + } } List<String> comments; @@ -214,6 +220,10 @@ void ScriptTextEditor::_set_theme_for_script() { String beg = comment.get_slice(" ", 0); String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String(); text_edit->add_comment_delimiter(beg, end, end == ""); + + if (!end.is_empty() && !text_edit->has_auto_brace_completion_open_key(beg)) { + text_edit->add_auto_brace_completion_pair(beg, end); + } } } @@ -742,7 +752,7 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c EditorNode::get_singleton()->load_resource(p_symbol); } - } else if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK) { + } else if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_symbol_lookup(), p_symbol, script->get_path(), base, result) == OK) { _goto_line(p_row); result.class_name = result.class_name.trim_prefix("_"); @@ -845,18 +855,17 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) { } ScriptLanguage::LookupResult result; - if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK || (ProjectSettings::get_singleton()->has_autoload(p_symbol) && ProjectSettings::get_singleton()->get_autoload(p_symbol).is_singleton)) { - text_edit->set_highlighted_word(p_symbol); + if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_symbol_lookup(), p_symbol, script->get_path(), base, result) == OK || (ProjectSettings::get_singleton()->has_autoload(p_symbol) && ProjectSettings::get_singleton()->get_autoload(p_symbol).is_singleton)) { + text_edit->set_symbol_lookup_word_as_valid(true); } else if (p_symbol.is_rel_path()) { String path = _get_absolute_path(p_symbol); if (FileAccess::exists(path)) { - text_edit->set_highlighted_word(p_symbol); + text_edit->set_symbol_lookup_word_as_valid(true); } else { - text_edit->set_highlighted_word(String()); + text_edit->set_symbol_lookup_word_as_valid(false); } - } else { - text_edit->set_highlighted_word(String()); + text_edit->set_symbol_lookup_word_as_valid(false); } } @@ -1544,7 +1553,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { base = _find_node_for_script(base, base, script); } ScriptLanguage::LookupResult result; - if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_lookup_completion(), word_at_pos, script->get_path(), base, result) == OK) { + if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_symbol_lookup(), word_at_pos, script->get_path(), base, result) == OK) { open_docs = true; } } @@ -1829,7 +1838,7 @@ ScriptTextEditor::ScriptTextEditor() { code_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line")); - code_editor->get_text_editor()->set_select_identifiers_on_hover(true); + code_editor->get_text_editor()->set_symbol_lookup_on_click_enabled(true); code_editor->get_text_editor()->set_context_menu_enabled(false); context_menu = memnew(PopupMenu); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 2c45b96106..95973f9dfd 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -158,6 +158,10 @@ void ShaderTextEditor::_load_theme_settings() { text_editor->add_comment_delimiter("/*", "*/", false); text_editor->add_comment_delimiter("//", "", true); + if (!text_editor->has_auto_brace_completion_open_key("/*")) { + text_editor->add_auto_brace_completion_pair("/*", "*/"); + } + if (warnings_panel) { // Warnings panel warnings_panel->add_theme_font_override("normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("main"), SNAME("EditorFonts"))); @@ -659,7 +663,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { shader_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line")); - shader_editor->get_text_editor()->set_select_identifiers_on_hover(true); + shader_editor->get_text_editor()->set_symbol_lookup_on_click_enabled(true); shader_editor->get_text_editor()->set_context_menu_enabled(false); shader_editor->get_text_editor()->connect("gui_input", callable_mp(this, &ShaderEditor::_text_edit_gui_input)); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 6bcc65e30c..0929a629f8 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -3112,7 +3112,7 @@ void ThemeEditor::edit(const Ref<Theme> &p_theme) { preview_tab->set_preview_theme(p_theme); } - theme_name->set_text(TTR("Theme") + ": " + theme->get_path().get_file()); + theme_name->set_text(TTR("Theme:") + " " + theme->get_path().get_file()); } Ref<Theme> ThemeEditor::get_edited_theme() { @@ -3230,7 +3230,7 @@ ThemeEditor::ThemeEditor() { add_child(top_menu); theme_name = memnew(Label); - theme_name->set_text(TTR("Theme") + ": "); + theme_name->set_text(TTR("Theme:")); theme_name->set_theme_type_variation("HeaderSmall"); top_menu->add_child(theme_name); diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp index bbafc7802b..d54906c98c 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.cpp +++ b/editor/plugins/tiles/atlas_merging_dialog.cpp @@ -154,7 +154,7 @@ void AtlasMergingDialog::_merge_confirmed(String p_path) { Ref<Texture2D> new_texture_resource = ResourceLoader::load(p_path, "Texture2D"); merged->set_texture(new_texture_resource); - undo_redo->create_action("Merge TileSetAtlasSource"); + undo_redo->create_action(TTR("Merge TileSetAtlasSource")); int next_id = tile_set->get_next_source_id(); undo_redo->add_do_method(*tile_set, "add_source", merged, next_id); undo_redo->add_undo_method(*tile_set, "remove_source", next_id); diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 84e40e2ffa..13f04cb804 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -32,6 +32,7 @@ #include "core/input/input.h" #include "core/os/keyboard.h" +#include "scene/2d/tile_map.h" #include "scene/gui/box_container.h" #include "scene/gui/label.h" #include "scene/gui/panel.h" @@ -259,7 +260,7 @@ void TileAtlasView::_draw_base_tiles() { Vector2i offset_pos = (margins + (atlas_coords * texture_region_size) + tile_set_atlas_source->get_tile_texture_region(atlas_coords).size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0)); // Draw the tile. - TileSetPluginAtlasRendering::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0); + TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0); } } } @@ -375,7 +376,7 @@ void TileAtlasView::_draw_alternatives() { } // Draw the tile. - TileSetPluginAtlasRendering::draw_tile(alternatives_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, alternative_id); + TileMap::draw_tile(alternatives_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, alternative_id); // Increment the x position. current_pos.x += transposed ? texture_region.size.y : texture_region.size.x; diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index 781f26cc02..99998dc779 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -36,10 +36,10 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" +#include "scene/2d/tile_map.h" #include "scene/gui/box_container.h" #include "scene/gui/control.h" #include "scene/gui/label.h" -#include "scene/resources/tile_set.h" class TileDataEditor : public VBoxContainer { GDCLASS(TileDataEditor, VBoxContainer); diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 4a4e81dae3..77084f551a 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -377,6 +377,11 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p return false; } + if (tile_map_layer < 0) { + return false; + } + ERR_FAIL_INDEX_V(tile_map_layer, tile_map->get_layers_count(), false); + Ref<TileSet> tile_set = tile_map->get_tileset(); if (!tile_set.is_valid()) { return false; @@ -391,7 +396,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) { coords_array.push_back(E->get()); } - tile_map_clipboard = tile_map->get_pattern(coords_array); + tile_map_clipboard = tile_map->get_pattern(tile_map_layer, coords_array); } if (ED_IS_SHORTCUT("tiles_editor/cut", p_event)) { @@ -399,8 +404,8 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p if (!tile_map_selection.is_empty()) { undo_redo->create_action(TTR("Delete tiles")); for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) { - undo_redo->add_do_method(tile_map, "set_cell", E->get(), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); - undo_redo->add_undo_method(tile_map, "set_cell", E->get(), tile_map->get_cell_source_id(E->get()), tile_map->get_cell_atlas_coords(E->get()), tile_map->get_cell_alternative_tile(E->get())); + undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->get(), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); + undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->get(), tile_map->get_cell_source_id(tile_map_layer, E->get()), tile_map->get_cell_atlas_coords(tile_map_layer, E->get()), tile_map->get_cell_alternative_tile(tile_map_layer, E->get())); } undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection()); tile_map_selection.clear(); @@ -430,8 +435,8 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p if (!tile_map_selection.is_empty()) { undo_redo->create_action(TTR("Delete tiles")); for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) { - undo_redo->add_do_method(tile_map, "set_cell", E->get(), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); - undo_redo->add_undo_method(tile_map, "set_cell", E->get(), tile_map->get_cell_source_id(E->get()), tile_map->get_cell_atlas_coords(E->get()), tile_map->get_cell_alternative_tile(E->get())); + undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->get(), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); + undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->get(), tile_map->get_cell_source_id(tile_map_layer, E->get()), tile_map->get_cell_atlas_coords(tile_map_layer, E->get()), tile_map->get_cell_alternative_tile(tile_map_layer, E->get())); } undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection()); tile_map_selection.clear(); @@ -456,9 +461,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p } Vector2i coords = E->key(); if (!drag_modified.has(coords)) { - drag_modified.insert(coords, tile_map->get_cell(coords)); + drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords)); } - tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + tile_map->set_cell(tile_map_layer, coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); } } break; case DRAG_TYPE_BUCKET: { @@ -472,9 +477,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p } Vector2i coords = E->key(); if (!drag_modified.has(coords)) { - drag_modified.insert(coords, tile_map->get_cell(coords)); + drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords)); } - tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + tile_map->set_cell(tile_map_layer, coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); } } } @@ -497,7 +502,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (mb->is_pressed()) { // Pressed - if (tool_buttons_group->get_pressed_button() == select_tool_button) { + if (drag_type == DRAG_TYPE_CLIPBOARD_PASTE) { + // Do nothing. + } else if (tool_buttons_group->get_pressed_button() == select_tool_button) { drag_start_mouse_pos = mpos; if (tile_map_selection.has(tile_map->world_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed()) { // Move the selection @@ -505,8 +512,8 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p drag_modified.clear(); for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) { Vector2i coords = E->get(); - drag_modified.insert(coords, tile_map->get_cell(coords)); - tile_map->set_cell(coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); + drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords)); + tile_map->set_cell(tile_map_layer, coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); } } else { // Select tiles @@ -530,9 +537,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p } Vector2i coords = E->key(); if (!drag_modified.has(coords)) { - drag_modified.insert(coords, tile_map->get_cell(coords)); + drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords)); } - tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + tile_map->set_cell(tile_map_layer, coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); } } else if (tool_buttons_group->get_pressed_button() == line_tool_button) { drag_type = DRAG_TYPE_LINE; @@ -556,9 +563,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p } Vector2i coords = E->key(); if (!drag_modified.has(coords)) { - drag_modified.insert(coords, tile_map->get_cell(coords)); + drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords)); } - tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + tile_map->set_cell(tile_map_layer, coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); } } } @@ -587,6 +594,11 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over return; } + if (tile_map_layer < 0) { + return; + } + ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count()); + Ref<TileSet> tile_set = tile_map->get_tileset(); if (!tile_set.is_valid()) { return; @@ -623,7 +635,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over for (int x = rect.position.x; x < rect.get_end().x; x++) { for (int y = rect.position.y; y < rect.get_end().y; y++) { Vector2i coords = Vector2i(x, y); - if (tile_map->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) { + if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) { Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - tile_shape_size / 2, tile_shape_size)); tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 1.0, 1.0), false); } @@ -637,7 +649,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over for (int x = rect.position.x; x < rect.get_end().x; x++) { for (int y = rect.position.y; y < rect.get_end().y; y++) { Vector2i coords = Vector2i(x, y); - if (tile_map->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) { + if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) { to_draw.insert(coords); } } @@ -914,6 +926,8 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start TileMapPattern erase_pattern; erase_pattern.set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); TileMapPattern *pattern = erase_button->is_pressed() ? &erase_pattern : selection_pattern; + Map<Vector2i, TileMapCell> err_output; + ERR_FAIL_COND_V(pattern->is_empty(), err_output); // Compute the offset to align things to the bottom or right. bool aligned_right = p_end_cell.x < p_start_cell.x; @@ -956,6 +970,12 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i return Map<Vector2i, TileMapCell>(); } + if (tile_map_layer < 0) { + return Map<Vector2i, TileMapCell>(); + } + Map<Vector2i, TileMapCell> output; + ERR_FAIL_INDEX_V(tile_map_layer, tile_map->get_layers_count(), output); + Ref<TileSet> tile_set = tile_map->get_tileset(); if (!tile_set.is_valid()) { return Map<Vector2i, TileMapCell>(); @@ -966,9 +986,8 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i erase_pattern.set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); TileMapPattern *pattern = erase_button->is_pressed() ? &erase_pattern : selection_pattern; - Map<Vector2i, TileMapCell> output; if (!pattern->is_empty()) { - TileMapCell source = tile_map->get_cell(p_coords); + TileMapCell source = tile_map->get_cell(tile_map_layer, p_coords); // If we are filling empty tiles, compute the tilemap boundaries. Rect2i boundaries; @@ -985,9 +1004,9 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i Vector2i coords = to_check.back()->get(); to_check.pop_back(); if (!already_checked.has(coords)) { - if (source.source_id == tile_map->get_cell_source_id(coords) && - source.get_atlas_coords() == tile_map->get_cell_atlas_coords(coords) && - source.alternative_tile == tile_map->get_cell_alternative_tile(coords) && + if (source.source_id == tile_map->get_cell_source_id(tile_map_layer, coords) && + source.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) && + source.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) && (source.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) { if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) { // Paint a random tile. @@ -1027,13 +1046,13 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i } } } else { - to_check = tile_map->get_used_cells(); + to_check = tile_map->get_used_cells(tile_map_layer); } for (int i = 0; i < to_check.size(); i++) { Vector2i coords = to_check[i]; - if (source.source_id == tile_map->get_cell_source_id(coords) && - source.get_atlas_coords() == tile_map->get_cell_atlas_coords(coords) && - source.alternative_tile == tile_map->get_cell_alternative_tile(coords) && + if (source.source_id == tile_map->get_cell_source_id(tile_map_layer, coords) && + source.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) && + source.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) && (source.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) { if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) { // Paint a random tile. @@ -1066,6 +1085,11 @@ void TileMapEditorTilesPlugin::_stop_dragging() { return; } + if (tile_map_layer < 0) { + return; + } + ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count()); + Ref<TileSet> tile_set = tile_map->get_tileset(); if (!tile_set.is_valid()) { return; @@ -1091,7 +1115,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() { tile_map_selection.erase(coords); } } else { - if (tile_map->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) { + if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) { tile_map_selection.insert(coords); } } @@ -1123,7 +1147,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() { coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern); cells_undo[coords] = TileMapCell(drag_modified[coords].source_id, drag_modified[coords].get_atlas_coords(), drag_modified[coords].alternative_tile); coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern); - cells_undo[coords] = TileMapCell(tile_map->get_cell_source_id(coords), tile_map->get_cell_atlas_coords(coords), tile_map->get_cell_alternative_tile(coords)); + cells_undo[coords] = TileMapCell(tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords)); } Map<Vector2i, TileMapCell> cells_do; @@ -1138,10 +1162,10 @@ void TileMapEditorTilesPlugin::_stop_dragging() { undo_redo->create_action(TTR("Move tiles")); // Move the tiles. for (Map<Vector2i, TileMapCell>::Element *E = cells_do.front(); E; E = E->next()) { - undo_redo->add_do_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); } for (Map<Vector2i, TileMapCell>::Element *E = cells_undo.front(); E; E = E->next()) { - undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); } // Update the selection. @@ -1162,12 +1186,12 @@ void TileMapEditorTilesPlugin::_stop_dragging() { for (int x = rect.position.x; x < rect.get_end().x; x++) { for (int y = rect.position.y; y < rect.get_end().y; y++) { Vector2i coords = Vector2i(x, y); - if (tile_map->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) { + if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) { coords_array.push_back(coords); } } } - selection_pattern = tile_map->get_pattern(coords_array); + selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array); if (!selection_pattern->is_empty()) { _update_tileset_selection_from_selection_pattern(); } else { @@ -1178,8 +1202,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() { case DRAG_TYPE_PAINT: { undo_redo->create_action(TTR("Paint tiles")); for (Map<Vector2i, TileMapCell>::Element *E = drag_modified.front(); E; E = E->next()) { - undo_redo->add_do_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key())); - undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), tile_map->get_cell_source_id(tile_map_layer, E->key()), tile_map->get_cell_atlas_coords(tile_map_layer, E->key()), tile_map->get_cell_alternative_tile(tile_map_layer, E->key())); + undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); } undo_redo->commit_action(false); } break; @@ -1190,8 +1214,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() { if (!erase_button->is_pressed() && E->get().source_id == TileSet::INVALID_SOURCE) { continue; } - undo_redo->add_do_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); - undo_redo->add_undo_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key())); + undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), tile_map->get_cell_source_id(tile_map_layer, E->key()), tile_map->get_cell_atlas_coords(tile_map_layer, E->key()), tile_map->get_cell_alternative_tile(tile_map_layer, E->key())); } undo_redo->commit_action(); } break; @@ -1202,16 +1226,16 @@ void TileMapEditorTilesPlugin::_stop_dragging() { if (!erase_button->is_pressed() && E->get().source_id == TileSet::INVALID_SOURCE) { continue; } - undo_redo->add_do_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); - undo_redo->add_undo_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key())); + undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), tile_map->get_cell_source_id(tile_map_layer, E->key()), tile_map->get_cell_atlas_coords(tile_map_layer, E->key()), tile_map->get_cell_alternative_tile(tile_map_layer, E->key())); } undo_redo->commit_action(); } break; case DRAG_TYPE_BUCKET: { undo_redo->create_action(TTR("Paint tiles")); for (Map<Vector2i, TileMapCell>::Element *E = drag_modified.front(); E; E = E->next()) { - undo_redo->add_do_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key())); - undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), tile_map->get_cell_source_id(tile_map_layer, E->key()), tile_map->get_cell_atlas_coords(tile_map_layer, E->key()), tile_map->get_cell_alternative_tile(tile_map_layer, E->key())); + undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); } undo_redo->commit_action(false); } break; @@ -1221,8 +1245,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() { TypedArray<Vector2i> used_cells = tile_map_clipboard->get_used_cells(); for (int i = 0; i < used_cells.size(); i++) { Vector2i coords = tile_map->map_pattern(tile_map->world_to_map(mpos - mouse_offset), used_cells[i], tile_map_clipboard); - undo_redo->add_do_method(tile_map, "set_cell", coords, tile_map_clipboard->get_cell_source_id(used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(used_cells[i])); - undo_redo->add_undo_method(tile_map, "set_cell", coords, tile_map->get_cell_source_id(coords), tile_map->get_cell_atlas_coords(coords), tile_map->get_cell_alternative_tile(coords)); + undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, coords, tile_map_clipboard->get_cell_source_id(used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(used_cells[i])); + undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, coords, tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords)); } undo_redo->commit_action(); } break; @@ -1301,13 +1325,15 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection( return; } + ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count()); + memdelete(selection_pattern); TypedArray<Vector2i> coords_array; for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) { coords_array.push_back(E->get()); } - selection_pattern = tile_map->get_pattern(coords_array); + selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array); } void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection() { @@ -1344,8 +1370,7 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection( TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); if (atlas_source) { // Organize using coordinates. - for (List<const TileMapCell *>::Element *E_cell = E_source->get().front(); E_cell; E_cell = E_cell->next()) { - const TileMapCell *current = E_cell->get(); + for (const TileMapCell *current : E_source->get()) { if (current->alternative_tile == 0) { organized_pattern[current->get_atlas_coords()] = current; } else { @@ -1364,8 +1389,8 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection( } } else { // Add everything unorganized. - for (List<const TileMapCell *>::Element *E_cell = E_source->get().front(); E_cell; E_cell = E_cell->next()) { - unorganized.push_back(E_cell->get()); + for (const TileMapCell *cell : E_source->get()) { + unorganized.push_back(cell); } } @@ -1375,8 +1400,8 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection( } Vector2i organized_size = selection_pattern->get_size(); int unorganized_index = 0; - for (List<const TileMapCell *>::Element *E_cell = unorganized.front(); E_cell; E_cell = E_cell->next()) { - selection_pattern->set_cell(Vector2(organized_size.x + unorganized_index, vertical_offset), E_cell->get()->source_id, E_cell->get()->get_atlas_coords(), E_cell->get()->alternative_tile); + for (const TileMapCell *cell : unorganized) { + selection_pattern->set_cell(Vector2(organized_size.x + unorganized_index, vertical_offset), cell->source_id, cell->get_atlas_coords(), cell->alternative_tile); unorganized_index++; } vertical_offset += MAX(organized_size.y, 1); @@ -1711,13 +1736,19 @@ TypedArray<Vector2i> TileMapEditorTilesPlugin::_get_tile_map_selection() const { return output; } -void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id) { - tile_map_id = p_tile_map_id; +void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) { + _stop_dragging(); // Avoids staying in a wrong drag state. - // Clear the selection. - tile_set_selection.clear(); - tile_map_selection.clear(); - selection_pattern->clear(); + if (tile_map_id != p_tile_map_id) { + tile_map_id = p_tile_map_id; + + // Clear the selection. + tile_set_selection.clear(); + tile_map_selection.clear(); + selection_pattern->clear(); + } + + tile_map_layer = p_tile_map_layer; } void TileMapEditorTilesPlugin::_bind_methods() { @@ -1756,7 +1787,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { paint_tool_button->set_flat(true); paint_tool_button->set_toggle_mode(true); paint_tool_button->set_button_group(tool_buttons_group); - paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", KEY_E)); + paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", KEY_D)); paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(paint_tool_button); @@ -2299,6 +2330,7 @@ Set<TileMapEditorTerrainsPlugin::Constraint> TileMapEditorTerrainsPlugin::_get_c } ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), Set<Constraint>()); + ERR_FAIL_INDEX_V(tile_map_layer, tile_map->get_layers_count(), Set<Constraint>()); // Build a set of dummy constraints get the constrained points. Set<Constraint> dummy_constraints; @@ -2322,7 +2354,7 @@ Set<TileMapEditorTerrainsPlugin::Constraint> TileMapEditorTerrainsPlugin::_get_c Map<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = c.get_overlapping_coords_and_peering_bits(); for (Map<Vector2i, TileSet::CellNeighbor>::Element *E_overlapping = overlapping_terrain_bits.front(); E_overlapping; E_overlapping = E_overlapping->next()) { if (!p_to_replace.has(E_overlapping->key())) { - TileMapCell neighbor_cell = tile_map->get_cell(E_overlapping->key()); + TileMapCell neighbor_cell = tile_map->get_cell(tile_map_layer, E_overlapping->key()); TileData *neighbor_tile_data = nullptr; if (terrain_tiles.has(neighbor_cell) && terrain_tiles[neighbor_cell]->get_terrain_set() == p_terrain_set) { neighbor_tile_data = terrain_tiles[neighbor_cell]; @@ -2629,6 +2661,90 @@ Map<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrains(const Map return output; } +void TileMapEditorTerrainsPlugin::_stop_dragging() { + TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); + if (!tile_map) { + return; + } + + Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform(); + Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position()); + + switch (drag_type) { + case DRAG_TYPE_PICK: { + Vector2i coords = tile_map->world_to_map(mpos); + TileMapCell tile = tile_map->get_cell(tile_map_layer, coords); + + if (terrain_tiles.has(tile)) { + Array terrains_tile_pattern = _build_terrains_tile_pattern(terrain_tiles[tile]); + + // Find the tree item for the right terrain set. + bool need_tree_item_switch = true; + TreeItem *tree_item = terrains_tree->get_selected(); + if (tree_item) { + Dictionary metadata_dict = tree_item->get_metadata(0); + if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) { + int terrain_set = metadata_dict["terrain_set"]; + int terrain_id = metadata_dict["terrain_id"]; + if (per_terrain_terrains_tile_patterns[terrain_set][terrain_id].has(terrains_tile_pattern)) { + need_tree_item_switch = false; + } + } + } + + if (need_tree_item_switch) { + for (tree_item = terrains_tree->get_root()->get_first_child(); tree_item; tree_item = tree_item->get_next_visible()) { + Dictionary metadata_dict = tree_item->get_metadata(0); + if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) { + int terrain_set = metadata_dict["terrain_set"]; + int terrain_id = metadata_dict["terrain_id"]; + if (per_terrain_terrains_tile_patterns[terrain_set][terrain_id].has(terrains_tile_pattern)) { + // Found + tree_item->select(0); + _update_tiles_list(); + break; + } + } + } + } + + // Find the list item for the given tile. + if (tree_item) { + for (int i = 0; i < terrains_tile_list->get_item_count(); i++) { + Dictionary metadata_dict = terrains_tile_list->get_item_metadata(i); + TerrainsTilePattern in_meta_terrains_tile_pattern = metadata_dict["terrains_tile_pattern"]; + bool equals = true; + for (int j = 0; j < terrains_tile_pattern.size(); j++) { + if (terrains_tile_pattern[j] != in_meta_terrains_tile_pattern[j]) { + equals = false; + break; + } + } + if (equals) { + terrains_tile_list->select(i); + break; + } + } + } else { + ERR_PRINT("Terrain tile not found."); + } + } + picker_button->set_pressed(false); + } break; + case DRAG_TYPE_PAINT: { + undo_redo->create_action(TTR("Paint terrain")); + for (Map<Vector2i, TileMapCell>::Element *E = drag_modified.front(); E; E = E->next()) { + undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), tile_map->get_cell_source_id(tile_map_layer, E->key()), tile_map->get_cell_atlas_coords(tile_map_layer, E->key()), tile_map->get_cell_alternative_tile(tile_map_layer, E->key())); + undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + } + undo_redo->commit_action(false); + } break; + default: + break; + } + drag_type = DRAG_TYPE_NONE; +} + bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { if (!is_visible_in_tree()) { // If the bottom editor is not visible, we ignore inputs. @@ -2649,6 +2765,11 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> return false; } + if (tile_map_layer < 0) { + return false; + } + ERR_FAIL_COND_V(tile_map_layer >= tile_map->get_layers_count(), false); + // Get the selected terrain. TerrainsTilePattern selected_terrains_tile_pattern; int selected_terrain_set = -1; @@ -2690,9 +2811,9 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> Map<Vector2i, TileMapCell> modified = _draw_terrains(to_draw, selected_terrain_set); for (Map<Vector2i, TileMapCell>::Element *E = modified.front(); E; E = E->next()) { if (!drag_modified.has(E->key())) { - drag_modified[E->key()] = tile_map->get_cell(E->key()); + drag_modified[E->key()] = tile_map->get_cell(tile_map_layer, E->key()); } - tile_map->set_cell(E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + tile_map->set_cell(tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); } } } break; @@ -2728,86 +2849,14 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> Map<Vector2i, TileMapCell> to_draw = _draw_terrains(terrains_to_draw, selected_terrain_set); for (Map<Vector2i, TileMapCell>::Element *E = to_draw.front(); E; E = E->next()) { - drag_modified[E->key()] = tile_map->get_cell(E->key()); - tile_map->set_cell(E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); + drag_modified[E->key()] = tile_map->get_cell(tile_map_layer, E->key()); + tile_map->set_cell(tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); } } } } else { // Released - switch (drag_type) { - case DRAG_TYPE_PICK: { - Vector2i coords = tile_map->world_to_map(mpos); - TileMapCell tile = tile_map->get_cell(coords); - - if (terrain_tiles.has(tile)) { - Array terrains_tile_pattern = _build_terrains_tile_pattern(terrain_tiles[tile]); - - // Find the tree item for the right terrain set. - bool need_tree_item_switch = true; - TreeItem *tree_item = terrains_tree->get_selected(); - if (tree_item) { - Dictionary metadata_dict = tree_item->get_metadata(0); - if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) { - int terrain_set = metadata_dict["terrain_set"]; - int terrain_id = metadata_dict["terrain_id"]; - if (per_terrain_terrains_tile_patterns[terrain_set][terrain_id].has(terrains_tile_pattern)) { - need_tree_item_switch = false; - } - } - } - - if (need_tree_item_switch) { - for (tree_item = terrains_tree->get_root()->get_first_child(); tree_item; tree_item = tree_item->get_next_visible()) { - Dictionary metadata_dict = tree_item->get_metadata(0); - if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) { - int terrain_set = metadata_dict["terrain_set"]; - int terrain_id = metadata_dict["terrain_id"]; - if (per_terrain_terrains_tile_patterns[terrain_set][terrain_id].has(terrains_tile_pattern)) { - // Found - tree_item->select(0); - _update_tiles_list(); - break; - } - } - } - } - - // Find the list item for the given tile. - if (tree_item) { - for (int i = 0; i < terrains_tile_list->get_item_count(); i++) { - Dictionary metadata_dict = terrains_tile_list->get_item_metadata(i); - TerrainsTilePattern in_meta_terrains_tile_pattern = metadata_dict["terrains_tile_pattern"]; - bool equals = true; - for (int j = 0; j < terrains_tile_pattern.size(); j++) { - if (terrains_tile_pattern[j] != in_meta_terrains_tile_pattern[j]) { - equals = false; - break; - } - } - if (equals) { - terrains_tile_list->select(i); - break; - } - } - } else { - ERR_PRINT("Terrain tile not found."); - } - } - picker_button->set_pressed(false); - } break; - case DRAG_TYPE_PAINT: { - undo_redo->create_action(TTR("Paint terrain")); - for (Map<Vector2i, TileMapCell>::Element *E = drag_modified.front(); E; E = E->next()) { - undo_redo->add_do_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key())); - undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile); - } - undo_redo->commit_action(false); - } break; - default: - break; - } - drag_type = DRAG_TYPE_NONE; + _stop_dragging(); } CanvasItemEditor::get_singleton()->update_viewport(); @@ -3080,8 +3129,12 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() { } } -void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id) { +void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) { + _stop_dragging(); // Avoids staying in a wrong drag state. + tile_map_id = p_tile_map_id; + tile_map_layer = p_tile_map_layer; + _update_terrains_cache(); _update_terrains_tree(); _update_tiles_list(); @@ -3166,10 +3219,12 @@ void TileMapEditor::_notification(int p_what) { advanced_menu_button->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons"))); toggle_grid_button->set_icon(get_theme_icon(SNAME("Grid"), SNAME("EditorIcons"))); toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid")); + toogle_highlight_selected_layer_button->set_icon(get_theme_icon(SNAME("TileMapHighlightSelected"), SNAME("EditorIcons"))); break; case NOTIFICATION_INTERNAL_PROCESS: if (is_visible_in_tree() && tileset_changed_needs_update) { _update_bottom_panel(); + _update_layers_selection(); tile_map_editor_plugins[tabs->get_current_tab()]->tile_set_changed(); CanvasItemEditor::get_singleton()->update_viewport(); tileset_changed_needs_update = false; @@ -3178,6 +3233,16 @@ void TileMapEditor::_notification(int p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid")); break; + case NOTIFICATION_VISIBILITY_CHANGED: + TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); + if (tile_map) { + if (is_visible_in_tree()) { + tile_map->set_selected_layer(tile_map_layer); + } else { + tile_map->set_selected_layer(-1); + } + } + break; } } @@ -3185,6 +3250,63 @@ void TileMapEditor::_on_grid_toggled(bool p_pressed) { EditorSettings::get_singleton()->set("editors/tiles_editor/display_grid", p_pressed); } +void TileMapEditor::_layers_selection_button_draw() { + if (!has_theme_icon(SNAME("arrow"), SNAME("OptionButton"))) { + return; + } + + RID ci = layers_selection_button->get_canvas_item(); + Ref<Texture2D> arrow = Control::get_theme_icon(SNAME("arrow"), SNAME("OptionButton")); + + Color clr = Color(1, 1, 1); + if (get_theme_constant(SNAME("modulate_arrow"))) { + switch (layers_selection_button->get_draw_mode()) { + case BaseButton::DRAW_PRESSED: + clr = get_theme_color(SNAME("font_pressed_color")); + break; + case BaseButton::DRAW_HOVER: + clr = get_theme_color(SNAME("font_hover_color")); + break; + case BaseButton::DRAW_DISABLED: + clr = get_theme_color(SNAME("font_disabled_color")); + break; + default: + clr = get_theme_color(SNAME("font_color")); + } + } + + Size2 size = layers_selection_button->get_size(); + + Point2 ofs; + if (is_layout_rtl()) { + ofs = Point2(get_theme_constant(SNAME("arrow_margin"), SNAME("OptionButton")), int(Math::abs((size.height - arrow->get_height()) / 2))); + } else { + ofs = Point2(size.width - arrow->get_width() - get_theme_constant(SNAME("arrow_margin"), SNAME("OptionButton")), int(Math::abs((size.height - arrow->get_height()) / 2))); + } + Rect2 dst_rect = Rect2(ofs, arrow->get_size()); + if (!layers_selection_button->is_pressed()) { + dst_rect.size = -dst_rect.size; + } + arrow->draw_rect(ci, dst_rect, false, clr); +} + +void TileMapEditor::_layers_selection_button_pressed() { + if (!layers_selection_popup->is_visible()) { + Size2 size = layers_selection_popup->get_contents_minimum_size(); + size.x = MAX(size.x, layers_selection_button->get_size().x); + layers_selection_popup->set_position(layers_selection_button->get_screen_position() - Size2(0, size.y * get_global_transform().get_scale().y)); + layers_selection_popup->set_size(size); + layers_selection_popup->popup(); + } else { + layers_selection_popup->hide(); + } +} + +void TileMapEditor::_layers_selection_id_pressed(int p_id) { + tile_map_layer = p_id; + _update_layers_selection(); +} + void TileMapEditor::_advanced_menu_button_id_pressed(int p_id) { TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); if (!tile_map) { @@ -3198,18 +3320,20 @@ void TileMapEditor::_advanced_menu_button_id_pressed(int p_id) { if (p_id == 0) { // Replace Tile Proxies undo_redo->create_action(TTR("Replace Tiles with Proxies")); - TypedArray<Vector2i> used_cells = tile_map->get_used_cells(); - for (int i = 0; i < used_cells.size(); i++) { - Vector2i cell_coords = used_cells[i]; - TileMapCell from = tile_map->get_cell(cell_coords); - Array to_array = tile_set->map_tile_proxy(from.source_id, from.get_atlas_coords(), from.alternative_tile); - TileMapCell to; - to.source_id = to_array[0]; - to.set_atlas_coords(to_array[1]); - to.alternative_tile = to_array[2]; - if (from != to) { - undo_redo->add_do_method(tile_map, "set_cell", cell_coords, to.source_id, to.get_atlas_coords(), to.alternative_tile); - undo_redo->add_undo_method(tile_map, "set_cell", cell_coords, from.source_id, from.get_atlas_coords(), from.alternative_tile); + for (int layer_index = 0; layer_index < tile_map->get_layers_count(); layer_index++) { + TypedArray<Vector2i> used_cells = tile_map->get_used_cells(layer_index); + for (int i = 0; i < used_cells.size(); i++) { + Vector2i cell_coords = used_cells[i]; + TileMapCell from = tile_map->get_cell(layer_index, cell_coords); + Array to_array = tile_set->map_tile_proxy(from.source_id, from.get_atlas_coords(), from.alternative_tile); + TileMapCell to; + to.source_id = to_array[0]; + to.set_atlas_coords(to_array[1]); + to.alternative_tile = to_array[2]; + if (from != to) { + undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, cell_coords, to.source_id, to.get_atlas_coords(), to.alternative_tile); + undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, cell_coords, from.source_id, from.get_atlas_coords(), from.alternative_tile); + } } } undo_redo->commit_action(); @@ -3315,7 +3439,7 @@ void TileMapEditor::_tile_map_changed() { void TileMapEditor::_tab_changed(int p_tab_id) { // Make the plugin edit the correct tilemap. - tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id); + tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer); // Update toolbar. for (int i = 0; i < tile_map_editor_plugins.size(); i++) { @@ -3339,7 +3463,129 @@ void TileMapEditor::_tab_changed(int p_tab_id) { CanvasItemEditor::get_singleton()->update_viewport(); } +void TileMapEditor::_layers_select_next_or_previous(bool p_next) { + TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); + if (!tile_map) { + return; + } + + if (tile_map->get_layers_count() < 1) { + return; + } + + if (tile_map_layer < 0) { + tile_map_layer = 0; + } + + int inc = p_next ? 1 : -1; + int origin_layer = tile_map_layer; + tile_map_layer = Math::posmod((tile_map_layer + inc), tile_map->get_layers_count()); + while (tile_map_layer != origin_layer) { + if (tile_map->is_layer_enabled(tile_map_layer)) { + break; + } + tile_map_layer = Math::posmod((tile_map_layer + inc), tile_map->get_layers_count()); + } + + _update_layers_selection(); +} + +void TileMapEditor::_update_layers_selection() { + layers_selection_popup->clear(); + + TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); + if (!tile_map) { + return; + } + + // Update the selected layer. + if (is_visible_in_tree() && tile_map->get_layers_count() >= 1) { + tile_map_layer = CLAMP(tile_map_layer, 0, tile_map->get_layers_count() - 1); + + // Search for an enabled layer if the current one is not. + int origin_layer = tile_map_layer; + while (tile_map_layer >= 0 && !tile_map->is_layer_enabled(tile_map_layer)) { + tile_map_layer--; + } + if (tile_map_layer < 0) { + tile_map_layer = origin_layer; + while (tile_map_layer < tile_map->get_layers_count() && !tile_map->is_layer_enabled(tile_map_layer)) { + tile_map_layer++; + } + } + if (tile_map_layer >= tile_map->get_layers_count()) { + tile_map_layer = -1; + } + } else { + tile_map_layer = -1; + } + tile_map->set_selected_layer(toogle_highlight_selected_layer_button->is_pressed() ? tile_map_layer : -1); + + // Build the list of layers. + for (int i = 0; i < tile_map->get_layers_count(); i++) { + String name = tile_map->get_layer_name(i); + layers_selection_popup->add_item(name.is_empty() ? vformat(TTR("Layer #%d"), i) : name, i); + layers_selection_popup->set_item_as_radio_checkable(i, true); + layers_selection_popup->set_item_disabled(i, !tile_map->is_layer_enabled(i)); + layers_selection_popup->set_item_checked(i, i == tile_map_layer); + } + + // Update the button label. + if (tile_map_layer >= 0) { + layers_selection_button->set_text(layers_selection_popup->get_item_text(tile_map_layer)); + } else { + layers_selection_button->set_text(TTR("Select a layer")); + } + + // Set button minimum width. + Size2 min_button_size = Size2(layers_selection_popup->get_contents_minimum_size().x, 0); + if (has_theme_icon(SNAME("arrow"), SNAME("OptionButton"))) { + Ref<Texture2D> arrow = Control::get_theme_icon(SNAME("arrow"), SNAME("OptionButton")); + min_button_size.x += arrow->get_size().x; + } + layers_selection_button->set_custom_minimum_size(min_button_size); + layers_selection_button->update(); + + tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer); +} + +void TileMapEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) { + UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); + ERR_FAIL_COND(!undo_redo); + + TileMap *tile_map = Object::cast_to<TileMap>(p_edited); + if (tile_map) { + if (p_property == "layers_count") { + int new_layers_count = (int)p_new_value; + if (new_layers_count < tile_map->get_layers_count()) { + List<PropertyInfo> property_list; + tile_map->get_property_list(&property_list); + + for (PropertyInfo property_info : property_list) { + Vector<String> components = String(property_info.name).split("/", true, 2); + if (components.size() == 2 && components[0].begins_with("layer_") && components[0].trim_prefix("layer_").is_valid_int()) { + int index = components[0].trim_prefix("layer_").to_int(); + if (index >= new_layers_count) { + undo_redo->add_undo_property(tile_map, property_info.name, tile_map->get(property_info.name)); + } + } + } + } + } + } +} + bool TileMapEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { + if (ED_IS_SHORTCUT("tiles_editor/select_next_layer", p_event) && p_event->is_pressed()) { + _layers_select_next_or_previous(true); + return true; + } + + if (ED_IS_SHORTCUT("tiles_editor/select_previous_layer", p_event) && p_event->is_pressed()) { + _layers_select_next_or_previous(false); + return true; + } + return tile_map_editor_plugins[tabs->get_current_tab()]->forward_canvas_gui_input(p_event); } @@ -3363,49 +3609,52 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { Vector2i tile_shape_size = tile_set->get_tile_size(); // Draw tiles with invalid IDs in the grid. - TypedArray<Vector2i> used_cells = tile_map->get_used_cells(); - for (int i = 0; i < used_cells.size(); i++) { - Vector2i coords = used_cells[i]; - int tile_source_id = tile_map->get_cell_source_id(coords); - if (tile_source_id >= 0) { - Vector2i tile_atlas_coords = tile_map->get_cell_atlas_coords(coords); - int tile_alternative_tile = tile_map->get_cell_alternative_tile(coords); - - TileSetSource *source = nullptr; - if (tile_set->has_source(tile_source_id)) { - source = *tile_set->get_source(tile_source_id); - } - - if (!source || !source->has_tile(tile_atlas_coords) || !source->has_alternative_tile(tile_atlas_coords, tile_alternative_tile)) { - // Generate a random color from the hashed values of the tiles. - Array a = tile_set->map_tile_proxy(tile_source_id, tile_atlas_coords, tile_alternative_tile); - if (int(a[0]) == tile_source_id && Vector2i(a[1]) == tile_atlas_coords && int(a[2]) == tile_alternative_tile) { - // Only display the pattern if we have no proxy tile. - Array to_hash; - to_hash.push_back(tile_source_id); - to_hash.push_back(tile_atlas_coords); - to_hash.push_back(tile_alternative_tile); - uint32_t hash = RandomPCG(to_hash.hash()).rand(); - - Color color; - color = color.from_hsv( - (float)((hash >> 24) & 0xFF) / 256.0, - Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), - Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), - 0.8); - - // Draw the scaled tile. - Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - Vector2(tile_shape_size) / 2, Vector2(tile_shape_size))); - tile_set->draw_tile_shape(p_overlay, cell_region, color, true, warning_pattern_texture); + if (tile_map_layer >= 0) { + ERR_FAIL_COND(tile_map_layer >= tile_map->get_layers_count()); + TypedArray<Vector2i> used_cells = tile_map->get_used_cells(tile_map_layer); + for (int i = 0; i < used_cells.size(); i++) { + Vector2i coords = used_cells[i]; + int tile_source_id = tile_map->get_cell_source_id(tile_map_layer, coords); + if (tile_source_id >= 0) { + Vector2i tile_atlas_coords = tile_map->get_cell_atlas_coords(tile_map_layer, coords); + int tile_alternative_tile = tile_map->get_cell_alternative_tile(tile_map_layer, coords); + + TileSetSource *source = nullptr; + if (tile_set->has_source(tile_source_id)) { + source = *tile_set->get_source(tile_source_id); } - // Draw the warning icon. - int min_axis = missing_tile_texture->get_size().min_axis(); - Vector2 icon_size; - icon_size[min_axis] = tile_set->get_tile_size()[min_axis] / 3; - icon_size[(min_axis + 1) % 2] = (icon_size[min_axis] * missing_tile_texture->get_size()[(min_axis + 1) % 2] / missing_tile_texture->get_size()[min_axis]); - Rect2 rect = Rect2(xform.xform(tile_map->map_to_world(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale()); - p_overlay->draw_texture_rect(missing_tile_texture, rect); + if (!source || !source->has_tile(tile_atlas_coords) || !source->has_alternative_tile(tile_atlas_coords, tile_alternative_tile)) { + // Generate a random color from the hashed values of the tiles. + Array a = tile_set->map_tile_proxy(tile_source_id, tile_atlas_coords, tile_alternative_tile); + if (int(a[0]) == tile_source_id && Vector2i(a[1]) == tile_atlas_coords && int(a[2]) == tile_alternative_tile) { + // Only display the pattern if we have no proxy tile. + Array to_hash; + to_hash.push_back(tile_source_id); + to_hash.push_back(tile_atlas_coords); + to_hash.push_back(tile_alternative_tile); + uint32_t hash = RandomPCG(to_hash.hash()).rand(); + + Color color; + color = color.from_hsv( + (float)((hash >> 24) & 0xFF) / 256.0, + Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), + Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), + 0.8); + + // Draw the scaled tile. + Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - Vector2(tile_shape_size) / 2, Vector2(tile_shape_size))); + tile_set->draw_tile_shape(p_overlay, cell_region, color, true, warning_pattern_texture); + } + + // Draw the warning icon. + int min_axis = missing_tile_texture->get_size().min_axis(); + Vector2 icon_size; + icon_size[min_axis] = tile_set->get_tile_size()[min_axis] / 3; + icon_size[(min_axis + 1) % 2] = (icon_size[min_axis] * missing_tile_texture->get_size()[(min_axis + 1) % 2] / missing_tile_texture->get_size()[min_axis]); + Rect2 rect = Rect2(xform.xform(tile_map->map_to_world(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale()); + p_overlay->draw_texture_rect(missing_tile_texture, rect); + } } } } @@ -3476,14 +3725,19 @@ void TileMapEditor::edit(TileMap *p_tile_map) { return; } - // Disconnect to changes. TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); if (tile_map) { + // Unselect layer if we are changing tile_map. + if (tile_map != p_tile_map) { + tile_map->set_selected_layer(-1); + } + + // Disconnect to changes. tile_map->disconnect("changed", callable_mp(this, &TileMapEditor::_tile_map_changed)); } - // Change the edited object. if (p_tile_map) { + // Change the edited object. tile_map_id = p_tile_map->get_instance_id(); tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); // Connect to changes. @@ -3494,8 +3748,10 @@ void TileMapEditor::edit(TileMap *p_tile_map) { tile_map_id = ObjectID(); } + _update_layers_selection(); + // Call the plugins. - tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id); + tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer); _tile_map_changed(); } @@ -3503,6 +3759,10 @@ void TileMapEditor::edit(TileMap *p_tile_map) { TileMapEditor::TileMapEditor() { set_process_internal(true); + // Shortcuts. + ED_SHORTCUT("tiles_editor/select_next_layer", TTR("Select Next Tile Map Layer"), KEY_PAGEUP); + ED_SHORTCUT("tiles_editor/select_previous_layer", TTR("Select Previous Tile Map Layer"), KEY_PAGEDOWN); + // TileMap editor plugins tile_map_editor_plugins.push_back(memnew(TileMapEditorTilesPlugin)); tile_map_editor_plugins.push_back(memnew(TileMapEditorTerrainsPlugin)); @@ -3516,18 +3776,46 @@ TileMapEditor::TileMapEditor() { tabs->connect("tab_changed", callable_mp(this, &TileMapEditor::_tab_changed)); // --- TileMap toolbar --- - tilemap_toolbar = memnew(HBoxContainer); - tilemap_toolbar->set_h_size_flags(SIZE_EXPAND_FILL); - tilemap_toolbar->add_child(tabs); + tile_map_toolbar = memnew(HBoxContainer); + tile_map_toolbar->set_h_size_flags(SIZE_EXPAND_FILL); + + // Tabs. + tile_map_toolbar->add_child(tabs); + + // Tabs toolbars. for (int i = 0; i < tile_map_editor_plugins.size(); i++) { tile_map_editor_plugins[i]->get_toolbar()->hide(); - tilemap_toolbar->add_child(tile_map_editor_plugins[i]->get_toolbar()); + tile_map_toolbar->add_child(tile_map_editor_plugins[i]->get_toolbar()); } // Wide empty separation control. Control *h_empty_space = memnew(Control); h_empty_space->set_h_size_flags(SIZE_EXPAND_FILL); - tilemap_toolbar->add_child(h_empty_space); + tile_map_toolbar->add_child(h_empty_space); + + // Layer selector. + layers_selection_popup = memnew(PopupMenu); + layers_selection_popup->connect("id_pressed", callable_mp(this, &TileMapEditor::_layers_selection_id_pressed)); + layers_selection_popup->set_close_on_parent_focus(false); + + layers_selection_button = memnew(Button); + layers_selection_button->set_toggle_mode(true); + layers_selection_button->connect("draw", callable_mp(this, &TileMapEditor::_layers_selection_button_draw)); + layers_selection_button->connect("pressed", callable_mp(this, &TileMapEditor::_layers_selection_button_pressed)); + layers_selection_button->connect("hidden", callable_mp((Window *)layers_selection_popup, &Popup::hide)); + layers_selection_button->set_tooltip(TTR("Tile Map Layer")); + layers_selection_button->add_child(layers_selection_popup); + tile_map_toolbar->add_child(layers_selection_button); + + toogle_highlight_selected_layer_button = memnew(Button); + toogle_highlight_selected_layer_button->set_flat(true); + toogle_highlight_selected_layer_button->set_toggle_mode(true); + toogle_highlight_selected_layer_button->set_pressed(true); + toogle_highlight_selected_layer_button->connect("pressed", callable_mp(this, &TileMapEditor::_update_layers_selection)); + toogle_highlight_selected_layer_button->set_tooltip(TTR("Highlight Selected TileMap Layer")); + tile_map_toolbar->add_child(toogle_highlight_selected_layer_button); + + tile_map_toolbar->add_child(memnew(VSeparator)); // Grid toggle. toggle_grid_button = memnew(Button); @@ -3535,14 +3823,14 @@ TileMapEditor::TileMapEditor() { toggle_grid_button->set_toggle_mode(true); toggle_grid_button->set_tooltip(TTR("Toggle grid visibility.")); toggle_grid_button->connect("toggled", callable_mp(this, &TileMapEditor::_on_grid_toggled)); - tilemap_toolbar->add_child(toggle_grid_button); + tile_map_toolbar->add_child(toggle_grid_button); // Advanced settings menu button. advanced_menu_button = memnew(MenuButton); advanced_menu_button->set_flat(true); advanced_menu_button->get_popup()->add_item(TTR("Automatically Replace Tiles with Proxies")); advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileMapEditor::_advanced_menu_button_id_pressed)); - tilemap_toolbar->add_child(advanced_menu_button); + tile_map_toolbar->add_child(advanced_menu_button); missing_tileset_label = memnew(Label); missing_tileset_label->set_text(TTR("The edited TileMap node has no TileSet resource.")); @@ -3561,6 +3849,9 @@ TileMapEditor::TileMapEditor() { } _tab_changed(0); + + // Registers UndoRedo inspector callback. + EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileMapEditor::_undo_redo_inspector_callback)); } TileMapEditor::~TileMapEditor() { diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h index 236774a06b..6e2f2ce2ba 100644 --- a/editor/plugins/tiles/tile_map_editor.h +++ b/editor/plugins/tiles/tile_map_editor.h @@ -47,7 +47,7 @@ public: virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; }; virtual void forward_canvas_draw_over_viewport(Control *p_overlay){}; virtual void tile_set_changed(){}; - virtual void edit(ObjectID p_tile_map_id){}; + virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer){}; }; class TileMapEditorTilesPlugin : public TileMapEditorPlugin { @@ -56,7 +56,8 @@ class TileMapEditorTilesPlugin : public TileMapEditorPlugin { private: UndoRedo *undo_redo = EditorNode::get_undo_redo(); ObjectID tile_map_id; - virtual void edit(ObjectID p_tile_map_id) override; + int tile_map_layer = -1; + virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override; ///// Toolbar ///// HBoxContainer *toolbar; @@ -185,7 +186,8 @@ class TileMapEditorTerrainsPlugin : public TileMapEditorPlugin { private: UndoRedo *undo_redo = EditorNode::get_undo_redo(); ObjectID tile_map_id; - virtual void edit(ObjectID p_tile_map_id) override; + int tile_map_layer = -1; + virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override; // Toolbar. HBoxContainer *toolbar; @@ -258,9 +260,9 @@ private: Map<Vector2i, TerrainsTilePattern> _wave_function_collapse(const Set<Vector2i> &p_to_replace, int p_terrain_set, const Set<TileMapEditorTerrainsPlugin::Constraint> p_constraints) const; TileMapCell _get_random_tile_from_pattern(int p_terrain_set, TerrainsTilePattern p_terrain_tile_pattern) const; Map<Vector2i, TileMapCell> _draw_terrains(const Map<Vector2i, TerrainsTilePattern> &p_to_paint, int p_terrain_set) const; + void _stop_dragging(); // Cached data. - TerrainsTilePattern _build_terrains_tile_pattern(TileData *p_tile_data); LocalVector<Map<TerrainsTilePattern, Set<TileMapCell>>> per_terrain_terrains_tile_patterns_tiles; LocalVector<LocalVector<Set<TerrainsTilePattern>>> per_terrain_terrains_tile_patterns; @@ -300,12 +302,20 @@ private: UndoRedo *undo_redo = EditorNode::get_undo_redo(); bool tileset_changed_needs_update = false; ObjectID tile_map_id; + int tile_map_layer = -1; // Vector to keep plugins. Vector<TileMapEditorPlugin *> tile_map_editor_plugins; // Toolbar. - HBoxContainer *tilemap_toolbar; + HBoxContainer *tile_map_toolbar; + + PopupMenu *layers_selection_popup; + Button *layers_selection_button; + Button *toogle_highlight_selected_layer_button; + void _layers_selection_button_draw(); + void _layers_selection_button_pressed(); + void _layers_selection_id_pressed(int p_id); Button *toggle_grid_button; void _on_grid_toggled(bool p_pressed); @@ -313,19 +323,26 @@ private: MenuButton *advanced_menu_button; void _advanced_menu_button_id_pressed(int p_id); - // Bottom panel + // Bottom panel. Label *missing_tileset_label; Tabs *tabs; void _update_bottom_panel(); - // TileMap + // TileMap. Ref<Texture2D> missing_tile_texture; Ref<Texture2D> warning_pattern_texture; - // CallBack + // CallBack. void _tile_map_changed(); void _tab_changed(int p_tab_changed); + // Updates. + void _layers_select_next_or_previous(bool p_next); + void _update_layers_selection(); + + // Inspector undo/redo callback. + void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value); + protected: void _notification(int p_what); void _draw_shape(Control *p_control, Rect2 p_region, TileSet::TileShape p_shape, TileSet::TileOffsetAxis p_offset_axis, Color p_color); @@ -335,7 +352,7 @@ public: void forward_canvas_draw_over_viewport(Control *p_overlay); void edit(TileMap *p_tile_map); - Control *get_toolbar() { return tilemap_toolbar; }; + Control *get_toolbar() { return tile_map_toolbar; }; TileMapEditor(); ~TileMapEditor(); diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp index e5e7efa531..9e47a44b34 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp @@ -47,7 +47,7 @@ void TileProxiesManagerDialog::_menu_id_pressed(int p_id) { } void TileProxiesManagerDialog::_delete_selected_bindings() { - undo_redo->create_action("Remove Tile Proxies"); + undo_redo->create_action(TTR("Remove Tile Proxies")); Vector<int> source_level_selected = source_level_list->get_selected_items(); for (int i = 0; i < source_level_selected.size(); i++) { @@ -151,7 +151,7 @@ void TileProxiesManagerDialog::_add_button_pressed() { Vector2i to_coords = to.get_atlas_coords(); if (from_coords.x >= 0 && from_coords.y >= 0 && to_coords.x >= 0 && to_coords.y >= 0) { if (from.alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE && to.alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE) { - undo_redo->create_action("Create Alternative-level Tile Proxy"); + undo_redo->create_action(TTR("Create Alternative-level Tile Proxy")); undo_redo->add_do_method(*tile_set, "set_alternative_level_tile_proxy", from.source_id, from.get_atlas_coords(), from.alternative_tile, to.source_id, to.get_atlas_coords(), to.alternative_tile); if (tile_set->has_alternative_level_tile_proxy(from.source_id, from.get_atlas_coords(), from.alternative_tile)) { Array a = tile_set->get_alternative_level_tile_proxy(from.source_id, from.get_atlas_coords(), from.alternative_tile); @@ -160,7 +160,7 @@ void TileProxiesManagerDialog::_add_button_pressed() { undo_redo->add_undo_method(*tile_set, "remove_alternative_level_tile_proxy", from.source_id, from.get_atlas_coords(), from.alternative_tile); } } else { - undo_redo->create_action("Create Coords-level Tile Proxy"); + undo_redo->create_action(TTR("Create Coords-level Tile Proxy")); undo_redo->add_do_method(*tile_set, "set_coords_level_tile_proxy", from.source_id, from.get_atlas_coords(), to.source_id, to.get_atlas_coords()); if (tile_set->has_coords_level_tile_proxy(from.source_id, from.get_atlas_coords())) { Array a = tile_set->get_coords_level_tile_proxy(from.source_id, from.get_atlas_coords()); @@ -170,7 +170,7 @@ void TileProxiesManagerDialog::_add_button_pressed() { } } } else { - undo_redo->create_action("Create source-level Tile Proxy"); + undo_redo->create_action(TTR("Create source-level Tile Proxy")); undo_redo->add_do_method(*tile_set, "set_source_level_tile_proxy", from.source_id, to.source_id); if (tile_set->has_source_level_tile_proxy(from.source_id)) { undo_redo->add_undo_method(*tile_set, "set_source_level_tile_proxy", to.source_id, tile_set->get_source_level_tile_proxy(from.source_id)); @@ -186,7 +186,7 @@ void TileProxiesManagerDialog::_add_button_pressed() { } void TileProxiesManagerDialog::_clear_invalid_button_pressed() { - undo_redo->create_action("Delete All Invalid Tile Proxies"); + undo_redo->create_action(TTR("Delete All Invalid Tile Proxies")); undo_redo->add_do_method(*tile_set, "cleanup_invalid_tile_proxies"); @@ -213,7 +213,7 @@ void TileProxiesManagerDialog::_clear_invalid_button_pressed() { } void TileProxiesManagerDialog::_clear_all_button_pressed() { - undo_redo->create_action("Delete All Tile Proxies"); + undo_redo->create_action(TTR("Delete All Tile Proxies")); undo_redo->add_do_method(*tile_set, "clear_tile_proxies"); diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.h b/editor/plugins/tiles/tile_proxies_manager_dialog.h index f6898e960b..6849be2cd6 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.h +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.h @@ -34,9 +34,9 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" +#include "scene/2d/tile_map.h" #include "scene/gui/dialogs.h" #include "scene/gui/item_list.h" -#include "scene/resources/tile_set.h" class TileProxiesManagerDialog : public ConfirmationDialog { GDCLASS(TileProxiesManagerDialog, ConfirmationDialog); diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index 5804f54649..a9a36427db 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -31,6 +31,7 @@ #include "version_control_editor_plugin.h" #include "core/object/script_language.h" +#include "core/os/keyboard.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" @@ -292,6 +293,29 @@ void VersionControlEditorPlugin::_update_commit_button() { commit_button->set_disabled(commit_message->get_text().strip_edges() == ""); } +void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent> &p_event) { + if (!commit_message->has_focus()) { + return; + } + if (commit_message->get_text().strip_edges().is_empty()) { + // Do not allow empty commit messages. + return; + } + const Ref<InputEventKey> k = p_event; + + if (k.is_valid() && k->is_pressed()) { + if (ED_IS_SHORTCUT("version_control/commit", p_event)) { + if (staged_files_count == 0) { + // Stage all files only when no files were previously staged. + _stage_all(); + } + _send_commit_msg(); + commit_message->accept_event(); + return; + } + } +} + void VersionControlEditorPlugin::register_editor() { if (!EditorVCSInterface::get_singleton()) { EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock); @@ -462,7 +486,9 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { commit_message->set_custom_minimum_size(Size2(200, 100)); commit_message->set_wrap_enabled(true); commit_message->connect("text_changed", callable_mp(this, &VersionControlEditorPlugin::_update_commit_button)); + commit_message->connect("gui_input", callable_mp(this, &VersionControlEditorPlugin::_commit_message_gui_input)); commit_box_vbc->add_child(commit_message); + ED_SHORTCUT("version_control/commit", TTR("Commit"), KEY_MASK_CMD | KEY_ENTER); commit_button = memnew(Button); commit_button->set_text(TTR("Commit Changes")); diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h index 7d7c66a7ee..d2ba63c86c 100644 --- a/editor/plugins/version_control_editor_plugin.h +++ b/editor/plugins/version_control_editor_plugin.h @@ -111,6 +111,7 @@ private: void _update_stage_status(); void _update_commit_status(); void _update_commit_button(); + void _commit_message_gui_input(const Ref<InputEvent> &p_event); friend class EditorVCSInterface; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 46818afe45..452ad126b3 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -35,7 +35,6 @@ #include "core/io/resource_loader.h" #include "core/math/math_defs.h" #include "core/os/keyboard.h" -#include "core/version.h" #include "editor/editor_log.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" @@ -921,6 +920,10 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { expression_box->add_comment_delimiter("/*", "*/", false); expression_box->add_comment_delimiter("//", "", true); + if (!expression_box->has_auto_brace_completion_open_key("/*")) { + expression_box->add_auto_brace_completion_pair("/*", "*/"); + } + expression_box->set_text(expression); expression_box->set_context_menu_enabled(false); expression_box->set_draw_line_numbers(true); @@ -995,9 +998,23 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { visual_shader->connect("changed", callable_mp(this, &VisualShaderEditor::_update_preview)); } #ifndef DISABLE_DEPRECATED - String version = VERSION_BRANCH; - if (visual_shader->get_version() != version) { - visual_shader->update_version(version); + Dictionary engine_version = Engine::get_singleton()->get_version_info(); + static Array components; + if (components.is_empty()) { + components.push_back("major"); + components.push_back("minor"); + } + const Dictionary vs_version = visual_shader->get_engine_version(); + if (!vs_version.has_all(components)) { + visual_shader->update_engine_version(engine_version); + } else { + for (int i = 0; i < components.size(); i++) { + if (vs_version[components[i]] != engine_version[components[i]]) { + visual_shader->update_engine_version(engine_version); + print_line(vformat(TTR("The shader (\"%s\") has been updated to correspond Godot %s.%s version."), visual_shader->get_path(), engine_version["major"], engine_version["minor"])); + break; + } + } } #endif visual_shader->set_graph_offset(graph->get_scroll_ofs() / EDSCALE); @@ -4143,6 +4160,8 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("OutputIsSRGB", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "output_is_srgb"), "output_is_srgb", VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Projection", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "projection"), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("UV", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("UV2", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ViewportSize", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "viewport_size"), "viewport_size", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("World", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); @@ -4175,8 +4194,6 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Input", "Input", "Common", "VisualShaderNodeInput", TTR("Input parameter."))); - // SPATIAL INPUTS - const String input_param_for_vertex_and_fragment_shader_modes = TTR("'%s' input parameter for vertex and fragment shader modes."); const String input_param_for_fragment_and_light_shader_modes = TTR("'%s' input parameter for fragment and light shader modes."); const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode."); @@ -4190,6 +4207,19 @@ VisualShaderEditor::VisualShaderEditor() { const String input_param_for_process_and_collide_shader_mode = TTR("'%s' input parameter for process and collide shader modes."); const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader modes."); + // NODE3D INPUTS + + add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("InstanceId", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_id"), "instance_id", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("InstanceCustom", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom"), "instance_custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("InstanceCustomAlpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom_alpha"), "instance_custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview"), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); @@ -4199,15 +4229,13 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "side"), "side", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("UV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("UV2", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("View", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo"), "albedo", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation"), "attenuation", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Backlight", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "backlight"), "backlight", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "diffuse"), "diffuse", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light"), "light", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); @@ -4215,21 +4243,19 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Metallic", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "metallic"), "metallic", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness"), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular"), "specular", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Backlight", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "backlight"), "backlight", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("View", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview"), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("UV", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("UV2", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - // CANVASITEM INPUTS + add_options.push_back(AddOption("AtLightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass"), "at_light_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Canvas", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "canvas"), "canvas", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("InstanceCustom", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom"), "instance_custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("InstanceCustomAlpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom_alpha"), "instance_custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Screen", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "screen"), "screen", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("AtLightPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass"), "at_light_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("NormalTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture"), "normal_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); @@ -4241,6 +4267,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("SpecularShininessAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess_alpha"), "specular_shininess_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("SpecularShininessTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "specular_shininess_texture"), "specular_shininess_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("Texture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light"), "light", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); @@ -4248,23 +4275,16 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("LightColorAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color_alpha"), "light_color_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("LightPosition", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_position"), "light_position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("LightVertex", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_vertex"), "light_vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightVertex", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "light_vertex"), "light_vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("Normal", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "normal"), "normal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("PointCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("ScreenUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Shadow", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow"), "shadow", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("ShadowAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_alpha"), "shadow_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("ShadowColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_color"), "shadow_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("SpecularShininess", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess"), "specular_shininess", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("SpecularShininessAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess_alpha"), "specular_shininess_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("Texture", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("AtLightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass"), "at_light_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("Canvas", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "canvas"), "canvas", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("Screen", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "screen"), "screen", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); - // SKY INPUTS add_options.push_back(AddOption("AtCubeMapPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY)); @@ -4297,12 +4317,14 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("SkyCoords", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("Time", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY)); - // PARTICLES + // PARTICLES INPUTS add_options.push_back(AddOption("CollisionDepth", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_depth"), "collision_depth", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES)); add_options.push_back(AddOption("CollisionNormal", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_normal"), "collision_normal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("EmitParticle", "Particles", "", "VisualShaderNodeParticleEmit", "", -1, -1, -1, Shader::MODE_PARTICLES)); + // PARTICLES + + add_options.push_back(AddOption("EmitParticle", "Particles", "", "VisualShaderNodeParticleEmit", "", -1, -1, TYPE_FLAGS_PROCESS | TYPE_FLAGS_PROCESS_CUSTOM | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES)); add_options.push_back(AddOption("ParticleAccelerator", "Particles", "", "VisualShaderNodeParticleAccelerator", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); add_options.push_back(AddOption("ParticleRandomness", "Particles", "", "VisualShaderNodeParticleRandomness", "", -1, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES)); add_options.push_back(AddOption("MultiplyByAxisAngle", "Particles", "Transform", "VisualShaderNodeParticleMultiplyByAxisAngle", "A node for help to multiply a position input vector by rotation using specific axis. Intended to work with emitters.", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES)); @@ -4320,7 +4342,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("FloatOp", "Scalar", "Common", "VisualShaderNodeFloatOp", TTR("Float operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("IntOp", "Scalar", "Common", "VisualShaderNodeIntOp", TTR("Integer operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR_INT)); - //CONSTANTS + // CONSTANTS for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) { add_options.push_back(AddOption(float_constant_defs[i].name, "Scalar", "Constants", "VisualShaderNodeFloatConstant", float_constant_defs[i].desc, -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, float_constant_defs[i].value)); @@ -4697,7 +4719,7 @@ public: UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); updating = true; - undo_redo->create_action(TTR("Edit Visual Property") + ": " + p_property, UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Edit Visual Property:") + " " + p_property, UndoRedo::MERGE_ENDS); undo_redo->add_do_property(node.ptr(), p_property, p_value); undo_redo->add_undo_property(node.ptr(), p_property, node->get(p_property)); |