diff options
Diffstat (limited to 'editor/plugins')
42 files changed, 1879 insertions, 533 deletions
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index 4a4e7f25b8..1afd7df049 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -481,6 +481,17 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) if (edited_point.valid() && (wip_active || (mm->get_button_mask() & BUTTON_MASK_LEFT))) { Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint))); + + //Move the point in a single axis. Should only work when editing a polygon and while holding shift. + if (mode == MODE_EDIT && mm->get_shift()) { + Vector2 old_point = pre_move_edit.get(selected_point.vertex); + if (ABS(cpoint.x - old_point.x) > ABS(cpoint.y - old_point.y)) { + cpoint.y = old_point.y; + } else { + cpoint.x = old_point.x; + } + } + edited_point = PosVertex(edited_point, cpoint); if (!wip_active) { diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 918f3a2149..5e8fb8e059 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -195,7 +195,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven //add triangle! if (blend_space->has_triangle(making_triangle[0], making_triangle[1], making_triangle[2])) { making_triangle.clear(); - EditorNode::get_singleton()->show_warning(TTR("Triangle already exists")); + EditorNode::get_singleton()->show_warning(TTR("Triangle already exists.")); return; } diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index f13c2170ea..bfee76492b 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -949,7 +949,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { filter_dialog->add_child(filter_vbox); filter_enabled = memnew(CheckBox); - filter_enabled->set_text(TTR("Enable filtering")); + filter_enabled->set_text(TTR("Enable Filtering")); filter_enabled->connect("pressed", this, "_filter_toggled"); filter_vbox->add_child(filter_enabled); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index bbaf41e3cc..0a9436952b 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -129,8 +129,10 @@ void AnimationPlayerEditor::_notification(int p_what) { autoplay_icon = get_icon("AutoPlay", "EditorIcons"); stop->set_icon(get_icon("Stop", "EditorIcons")); + onion_toggle->set_icon(get_icon("Onion", "EditorIcons")); + onion_skinning->set_icon(get_icon("GuiMiniTabMenu", "EditorIcons")); + pin->set_icon(get_icon("Pin", "EditorIcons")); - onion_skinning->set_icon(get_icon("Onion", "EditorIcons")); tool_anim->add_style_override("normal", get_stylebox("normal", "Button")); track_editor->get_edit_menu()->add_style_override("normal", get_stylebox("normal", "Button")); @@ -670,6 +672,7 @@ Dictionary AnimationPlayerEditor::get_state() const { if (EditorNode::get_singleton()->get_edited_scene() && is_visible_in_tree() && player) { d["player"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(player); d["animation"] = player->get_assigned_animation(); + d["track_editor_state"] = track_editor->get_state(); } return d; @@ -696,6 +699,10 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) { _animation_edit(); } } + + if (p_state.has("track_editor_state")) { + track_editor->set_state(p_state["track_editor_state"]); + } } } @@ -841,6 +848,12 @@ void AnimationPlayerEditor::_update_player() { onion_skinning->set_disabled(player == NULL); pin->set_disabled(player == NULL); + if (!player) { + AnimationPlayerEditor::singleton->get_track_editor()->update_keying(); + EditorNode::get_singleton()->update_keying(); + return; + } + int active_idx = -1; for (List<StringName>::Element *E = animlist.front(); E; E = E->next()) { @@ -853,12 +866,6 @@ void AnimationPlayerEditor::_update_player() { active_idx = animation->get_item_count() - 1; } - if (!player) { - AnimationPlayerEditor::singleton->get_track_editor()->update_keying(); - EditorNode::get_singleton()->update_keying(); - return; - } - updating = false; if (active_idx != -1) { animation->select(active_idx); @@ -1224,7 +1231,6 @@ void AnimationPlayerEditor::_onion_skinning_menu(int p_option) { case ONION_SKINNING_ENABLE: { onion.enabled = !onion.enabled; - menu->set_item_checked(idx, onion.enabled); if (onion.enabled) _start_onion_skinning(); @@ -1703,19 +1709,21 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay hb->add_child(track_editor->get_edit_menu()); + hb->add_child(memnew(VSeparator)); + + onion_toggle = memnew(ToolButton); + onion_toggle->set_toggle_mode(true); + onion_toggle->set_tooltip(TTR("Enable Onion Skinning")); + onion_toggle->connect("pressed", this, "_onion_skinning_menu", varray(ONION_SKINNING_ENABLE)); + hb->add_child(onion_toggle); + onion_skinning = memnew(MenuButton); - //onion_skinning->set_flat(false); - onion_skinning->set_tooltip(TTR("Onion Skinning")); - onion_skinning->get_popup()->add_check_shortcut(ED_SHORTCUT("animation_player_editor/onion_skinning", TTR("Enable Onion Skinning")), ONION_SKINNING_ENABLE); - onion_skinning->get_popup()->add_separator(); - onion_skinning->get_popup()->add_item(TTR("Directions"), -1); - onion_skinning->get_popup()->set_item_disabled(onion_skinning->get_popup()->get_item_count() - 1, true); + onion_skinning->set_tooltip(TTR("Onion Skinning Options")); + onion_skinning->get_popup()->add_separator(TTR("Directions")); onion_skinning->get_popup()->add_check_item(TTR("Past"), ONION_SKINNING_PAST); onion_skinning->get_popup()->set_item_checked(onion_skinning->get_popup()->get_item_count() - 1, true); onion_skinning->get_popup()->add_check_item(TTR("Future"), ONION_SKINNING_FUTURE); - onion_skinning->get_popup()->add_separator(); - onion_skinning->get_popup()->add_item(TTR("Depth"), -1); - onion_skinning->get_popup()->set_item_disabled(onion_skinning->get_popup()->get_item_count() - 1, true); + onion_skinning->get_popup()->add_separator(TTR("Depth")); onion_skinning->get_popup()->add_radio_check_item(TTR("1 step"), ONION_SKINNING_1_STEP); onion_skinning->get_popup()->set_item_checked(onion_skinning->get_popup()->get_item_count() - 1, true); onion_skinning->get_popup()->add_radio_check_item(TTR("2 steps"), ONION_SKINNING_2_STEPS); @@ -1726,6 +1734,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay onion_skinning->get_popup()->add_check_item(TTR("Include Gizmos (3D)"), ONION_SKINNING_INCLUDE_GIZMOS); hb->add_child(onion_skinning); + hb->add_child(memnew(VSeparator)); + pin = memnew(ToolButton); pin->set_toggle_mode(true); pin->set_tooltip(TTR("Pin AnimationPlayer")); diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 9085c70410..c6ab6c5e30 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -102,6 +102,7 @@ class AnimationPlayerEditor : public VBoxContainer { Button *autoplay; MenuButton *tool_anim; + ToolButton *onion_toggle; MenuButton *onion_skinning; ToolButton *pin; SpinBox *frame; diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index cb3e5a8129..f06b4b2828 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -874,9 +874,9 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { } to.y = from.y; - float len = MAX(0.0001, playback->get_current_length()); + float len = MAX(0.0001, current_length); - float pos = CLAMP(playback->get_current_play_pos(), 0, len); + float pos = CLAMP(play_pos, 0, len); float c = pos / len; Color fg = get_color("font_color", "Label"); Color bg = fg; @@ -1011,7 +1011,8 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { bool is_playing = false; StringName current_node; StringName blend_from_node; - float play_pos = 0; + play_pos = 0; + current_length = 0; if (playback.is_valid()) { tp = playback->get_travel_path(); @@ -1019,6 +1020,7 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { current_node = playback->get_current_node(); blend_from_node = playback->get_blend_from_node(); play_pos = playback->get_current_play_pos(); + current_length = playback->get_current_length(); } { @@ -1046,6 +1048,27 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { state_machine_play_pos->update(); } + { + if (current_node != StringName() && state_machine->has_node(current_node)) { + + String next = current_node; + Ref<AnimationNodeStateMachine> anodesm = state_machine->get_node(next); + Ref<AnimationNodeStateMachinePlayback> current_node_playback; + + while (anodesm.is_valid()) { + current_node_playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + next + "/playback"); + next += "/" + current_node_playback->get_current_node(); + anodesm = anodesm->get_node(current_node_playback->get_current_node()); + } + + // when current_node is a state machine, use playback of current_node to set play_pos + if (current_node_playback.is_valid()) { + play_pos = current_node_playback->get_current_play_pos(); + current_length = current_node_playback->get_current_length(); + } + } + } + if (last_play_pos != play_pos) { last_play_pos = play_pos; diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index 1c4c06090a..8b0a5a0b00 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -160,6 +160,8 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { StringName last_current_node; Vector<StringName> last_travel_path; float last_play_pos; + float play_pos; + float current_length; float error_time; String error_text; diff --git a/editor/plugins/animation_tree_player_editor_plugin.cpp b/editor/plugins/animation_tree_player_editor_plugin.cpp index e21ae4834d..f5d21ffb26 100644 --- a/editor/plugins/animation_tree_player_editor_plugin.cpp +++ b/editor/plugins/animation_tree_player_editor_plugin.cpp @@ -840,7 +840,7 @@ void AnimationTreePlayerEditor::_gui_input(Ref<InputEvent> p_event) { click_motion = Point2(mm->get_position().x, mm->get_position().y); update(); } - if ((mm->get_button_mask() & 4 || Input::get_singleton()->is_key_pressed(KEY_SPACE))) { + if (mm->get_button_mask() & 4 || Input::get_singleton()->is_key_pressed(KEY_SPACE)) { h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x); v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 386bc1738e..0dfb53b34a 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -175,7 +175,7 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const Ref<Image> overlay = get_icon("PlayOverlay", "EditorIcons")->get_data(); Ref<Image> thumbnail = p_image->get_data(); thumbnail = thumbnail->duplicate(); - Point2 overlay_pos = Point2((thumbnail->get_width() - overlay->get_width()) / 2, (thumbnail->get_height() - overlay->get_height()) / 2); + Point2 overlay_pos = Point2((thumbnail->get_width() - overlay->get_width() / 2) / 2, (thumbnail->get_height() - overlay->get_height() / 2) / 2); // Overlay and thumbnail need the same format for `blend_rect` to work. thumbnail->convert(Image::FORMAT_RGBA8); @@ -310,15 +310,20 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() { description = memnew(RichTextLabel); description->connect("meta_clicked", this, "_link_click"); + description->set_custom_minimum_size(Size2(440 * EDSCALE, 300 * EDSCALE)); desc_bg->add_child(description); + VBoxContainer *previews_vbox = memnew(VBoxContainer); + hbox->add_child(previews_vbox); + previews_vbox->add_constant_override("separation", 15 * EDSCALE); + preview = memnew(TextureRect); preview->set_custom_minimum_size(Size2(640 * EDSCALE, 345 * EDSCALE)); - hbox->add_child(preview); + previews_vbox->add_child(preview); previews_bg = memnew(PanelContainer); - vbox->add_child(previews_bg); - previews_bg->set_custom_minimum_size(Size2(0, 101 * EDSCALE)); + previews_vbox->add_child(previews_bg); + previews_bg->set_custom_minimum_size(Size2(640 * EDSCALE, 101 * EDSCALE)); previews = memnew(ScrollContainer); previews_bg->add_child(previews); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index c3cac582ad..126cd20c53 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -84,7 +84,6 @@ public: container = memnew(VBoxContainer); add_child(container); - //set_child_rect(container); child_container = memnew(GridContainer); child_container->set_columns(3); @@ -99,12 +98,14 @@ public: grid_offset_x->set_min(-SPIN_BOX_GRID_RANGE); grid_offset_x->set_max(SPIN_BOX_GRID_RANGE); grid_offset_x->set_suffix("px"); + grid_offset_x->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(grid_offset_x); grid_offset_y = memnew(SpinBox); grid_offset_y->set_min(-SPIN_BOX_GRID_RANGE); grid_offset_y->set_max(SPIN_BOX_GRID_RANGE); grid_offset_y->set_suffix("px"); + grid_offset_y->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(grid_offset_y); label = memnew(Label); @@ -116,12 +117,14 @@ public: grid_step_x->set_min(0.01); grid_step_x->set_max(SPIN_BOX_GRID_RANGE); grid_step_x->set_suffix("px"); + grid_step_x->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(grid_step_x); grid_step_y = memnew(SpinBox); grid_step_y->set_min(0.01); grid_step_y->set_max(SPIN_BOX_GRID_RANGE); grid_step_y->set_suffix("px"); + grid_step_y->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(grid_step_y); container->add_child(memnew(HSeparator)); @@ -139,6 +142,7 @@ public: rotation_offset->set_min(-SPIN_BOX_ROTATION_RANGE); rotation_offset->set_max(SPIN_BOX_ROTATION_RANGE); rotation_offset->set_suffix("deg"); + rotation_offset->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(rotation_offset); label = memnew(Label); @@ -150,6 +154,7 @@ public: rotation_step->set_min(-SPIN_BOX_ROTATION_RANGE); rotation_step->set_max(SPIN_BOX_ROTATION_RANGE); rotation_step->set_suffix("deg"); + rotation_step->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(rotation_step); } @@ -1340,6 +1345,10 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) { // Confirms the node rotation if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) { _commit_canvas_item_state(drag_selection, TTR("Rotate CanvasItem")); + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(false, true, false, true); + } + drag_type = DRAG_NONE; return true; } @@ -1378,7 +1387,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) { // Starts anchor dragging if needed if (drag_type == DRAG_NONE) { - if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT && show_helpers) { + if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) { List<CanvasItem *> selection = _get_edited_canvas_items(); if (selection.size() == 1) { Control *control = Object::cast_to<Control>(selection[0]); @@ -1462,10 +1471,14 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) { if (!use_single_axis || use_y) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false); break; case DRAG_ANCHOR_ALL: - if (!use_single_axis || !use_y) control->set_anchor(MARGIN_LEFT, new_anchor.x, false, true); - if (!use_single_axis || !use_y) control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, true); - if (!use_single_axis || use_y) control->set_anchor(MARGIN_TOP, new_anchor.y, false, true); - if (!use_single_axis || use_y) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, true); + if (!use_single_axis || !use_y) { + control->set_anchor(MARGIN_LEFT, new_anchor.x, false, true); + control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, true); + } + if (!use_single_axis || use_y) { + control->set_anchor(MARGIN_TOP, new_anchor.y, false, true); + control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, true); + } break; default: break; @@ -1641,6 +1654,9 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) { // Confirm resize if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) { _commit_canvas_item_state(drag_selection, TTR("Resize CanvasItem")); + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(false, false, true, true); + } drag_type = DRAG_NONE; viewport->update(); return true; @@ -1747,6 +1763,10 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { // Confirm resize if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) { _commit_canvas_item_state(drag_selection, TTR("Scale CanvasItem")); + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(false, false, true, true); + } + drag_type = DRAG_NONE; viewport->update(); return true; @@ -1847,11 +1867,14 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { } // Confirm the move (only if it was moved) - if (b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT && (drag_type == DRAG_MOVE)) { + if (b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT) { if (transform.affine_inverse().xform(b->get_position()) != drag_from) { _commit_canvas_item_state(drag_selection, TTR("Move CanvasItem"), true); } + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(true, false, false, true); + } drag_type = DRAG_NONE; viewport->update(); return true; @@ -2190,6 +2213,7 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) { void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { bool accepted = false; + if (EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning") || !Input::get_singleton()->is_key_pressed(KEY_SPACE)) { if ((accepted = _gui_input_rulers_and_guides(p_event))) { //printf("Rulers and guides\n"); @@ -2489,20 +2513,50 @@ void CanvasItemEditor::_draw_grid() { } } -void CanvasItemEditor::_draw_control_helpers(Control *control) { +void CanvasItemEditor::_draw_control_anchors(Control *control) { Transform2D xform = transform * control->get_global_transform_with_canvas(); RID ci = viewport->get_canvas_item(); + if (tool == TOOL_SELECT && !Object::cast_to<Container>(control->get_parent())) { + + // Compute the anchors + float anchors_values[4]; + anchors_values[0] = control->get_anchor(MARGIN_LEFT); + anchors_values[1] = control->get_anchor(MARGIN_TOP); + anchors_values[2] = control->get_anchor(MARGIN_RIGHT); + anchors_values[3] = control->get_anchor(MARGIN_BOTTOM); + + Vector2 anchors_pos[4]; + for (int i = 0; i < 4; i++) { + Vector2 value = Vector2((i % 2 == 0) ? anchors_values[i] : anchors_values[(i + 1) % 4], (i % 2 == 1) ? anchors_values[i] : anchors_values[(i + 1) % 4]); + anchors_pos[i] = xform.xform(_anchor_to_position(control, value)); + } + + // Draw the anchors handles + Rect2 anchor_rects[4]; + anchor_rects[0] = Rect2(anchors_pos[0] - anchor_handle->get_size(), anchor_handle->get_size()); + anchor_rects[1] = Rect2(anchors_pos[1] - Vector2(0.0, anchor_handle->get_size().y), Point2(-anchor_handle->get_size().x, anchor_handle->get_size().y)); + anchor_rects[2] = Rect2(anchors_pos[2], -anchor_handle->get_size()); + anchor_rects[3] = Rect2(anchors_pos[3] - Vector2(anchor_handle->get_size().x, 0.0), Point2(anchor_handle->get_size().x, -anchor_handle->get_size().y)); + + for (int i = 0; i < 4; i++) { + anchor_handle->draw_rect(ci, anchor_rects[i]); + } + } +} + +void CanvasItemEditor::_draw_control_helpers(Control *control) { + Transform2D xform = transform * control->get_global_transform_with_canvas(); if (tool == TOOL_SELECT && show_helpers && !Object::cast_to<Container>(control->get_parent())) { // Draw the helpers Color color_base = Color(0.8, 0.8, 0.8, 0.5); + // Compute the anchors float anchors_values[4]; anchors_values[0] = control->get_anchor(MARGIN_LEFT); anchors_values[1] = control->get_anchor(MARGIN_TOP); anchors_values[2] = control->get_anchor(MARGIN_RIGHT); anchors_values[3] = control->get_anchor(MARGIN_BOTTOM); - // Draw the anchors Vector2 anchors[4]; Vector2 anchors_pos[4]; for (int i = 0; i < 4; i++) { @@ -2569,16 +2623,6 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { _draw_percentage_at_position(percent_val, (line_ends[(dragged_anchor + 1) % 4] + anchors_pos[dragged_anchor]) / 2, (Margin)((dragged_anchor + 1) % 4)); } - Rect2 anchor_rects[4]; - anchor_rects[0] = Rect2(anchors_pos[0] - anchor_handle->get_size(), anchor_handle->get_size()); - anchor_rects[1] = Rect2(anchors_pos[1] - Vector2(0.0, anchor_handle->get_size().y), Point2(-anchor_handle->get_size().x, anchor_handle->get_size().y)); - anchor_rects[2] = Rect2(anchors_pos[2], -anchor_handle->get_size()); - anchor_rects[3] = Rect2(anchors_pos[3] - Vector2(anchor_handle->get_size().x, 0.0), Point2(anchor_handle->get_size().x, -anchor_handle->get_size().y)); - - for (int i = 0; i < 4; i++) { - anchor_handle->draw_rect(ci, anchor_rects[i]); - } - // Draw the margin values and the node width/height when dragging control side float ratio = 0.33; Transform2D parent_transform = xform * control->get_transform().affine_inverse(); @@ -2756,6 +2800,7 @@ void CanvasItemEditor::_draw_selection() { // Draw control-related helpers Control *control = Object::cast_to<Control>(canvas_item); if (control && _is_node_movable(control)) { + _draw_control_anchors(control); _draw_control_helpers(control); } @@ -3288,24 +3333,32 @@ void CanvasItemEditor::_notification(int p_what) { // Activate / Deactivate the pivot tool pivot_button->set_disabled(nb_having_pivot == 0); - // Show / Hide the layout button + // Show / Hide the layout and anchors mode buttons if (nb_control > 0 && nb_control == selection.size()) { presets_menu->set_visible(true); presets_menu->set_tooltip(TTR("Presets for the anchors and margins values of a Control node.")); + anchor_mode_button->set_visible(true); + anchor_mode_button->set_tooltip(TTR("When active, moving Control nodes changes their anchors instead of their margins.")); + + // Set the pressed state of the node + anchor_mode_button->set_pressed(anchors_mode); // Disable if the selected node is child of a container presets_menu->set_disabled(false); + anchor_mode_button->set_disabled(false); for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) { Control *control = Object::cast_to<Control>(E->get()); if (!control || Object::cast_to<Container>(control->get_parent())) { presets_menu->set_disabled(true); presets_menu->set_tooltip(TTR("Children of containers have their anchors and margins values overridden by their parent.")); + anchor_mode_button->set_disabled(true); + anchor_mode_button->set_tooltip(TTR("Children of containers have their anchors and margins values overridden by their parent.")); break; } } - } else { presets_menu->set_visible(false); + anchor_mode_button->set_visible(false); } // Update the viewport if bones changes @@ -3384,6 +3437,7 @@ void CanvasItemEditor::_notification(int p_what) { key_rot_button->set_icon(get_icon("KeyRotation", "EditorIcons")); key_scale_button->set_icon(get_icon("KeyScale", "EditorIcons")); key_insert_button->set_icon(get_icon("Key", "EditorIcons")); + key_auto_insert_button->set_icon(get_icon("AutoKey", "EditorIcons")); zoom_minus->set_icon(get_icon("ZoomLess", "EditorIcons")); zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons")); @@ -3412,9 +3466,10 @@ void CanvasItemEditor::_notification(int p_what) { p->add_icon_item(get_icon("ControlHcenterWide", "EditorIcons"), "HCenter Wide ", ANCHORS_AND_MARGINS_PRESET_HCENTER_WIDE); p->add_separator(); p->add_icon_item(get_icon("ControlAlignWide", "EditorIcons"), "Full Rect", ANCHORS_AND_MARGINS_PRESET_WIDE); + p->add_icon_item(get_icon("Anchor", "EditorIcons"), "Keep Ratio", ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO); p->add_separator(); p->add_submenu_item(TTR("Anchors only"), "Anchors"); - p->set_item_icon(20, get_icon("Anchor", "EditorIcons")); + p->set_item_icon(21, get_icon("Anchor", "EditorIcons")); anchors_popup->clear(); anchors_popup->add_icon_item(get_icon("ControlAlignTopLeft", "EditorIcons"), "Top Left", ANCHORS_PRESET_TOP_LEFT); @@ -3436,7 +3491,29 @@ void CanvasItemEditor::_notification(int p_what) { anchors_popup->add_icon_item(get_icon("ControlHcenterWide", "EditorIcons"), "HCenter Wide ", ANCHORS_PRESET_HCENTER_WIDE); anchors_popup->add_separator(); anchors_popup->add_icon_item(get_icon("ControlAlignWide", "EditorIcons"), "Full Rect", ANCHORS_PRESET_WIDE); + + anchor_mode_button->set_icon(get_icon("Anchor", "EditorIcons")); + } +} + +void CanvasItemEditor::_selection_changed() { + // Update the anchors_mode + int nbValidControls = 0; + int nbAnchorsMode = 0; + List<Node *> selection = editor_selection->get_selected_node_list(); + for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { + Control *control = Object::cast_to<Control>(E->get()); + if (!control) + continue; + if (Object::cast_to<Container>(control->get_parent())) + continue; + + nbValidControls++; + if (control->has_meta("_edit_use_anchors_") && control->get_meta("_edit_use_anchors_")) { + nbAnchorsMode++; + } } + anchors_mode = (nbValidControls == nbAnchorsMode); } void CanvasItemEditor::edit(CanvasItem *p_canvas_item) { @@ -3656,6 +3733,36 @@ void CanvasItemEditor::_set_anchors_and_margins_preset(Control::LayoutPreset p_p } undo_redo->commit_action(); + + anchors_mode = false; +} + +void CanvasItemEditor::_set_anchors_and_margins_to_keep_ratio() { + List<Node *> selection = editor_selection->get_selected_node_list(); + + undo_redo->create_action(TTR("Change Anchors and Margins")); + + for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { + + Control *control = Object::cast_to<Control>(E->get()); + if (control) { + Point2 top_left_anchor = _position_to_anchor(control, Point2()); + Point2 bottom_right_anchor = _position_to_anchor(control, control->get_size()); + undo_redo->add_do_method(control, "set_anchor", MARGIN_LEFT, top_left_anchor.x, false, true); + undo_redo->add_do_method(control, "set_anchor", MARGIN_RIGHT, bottom_right_anchor.x, false, true); + undo_redo->add_do_method(control, "set_anchor", MARGIN_TOP, top_left_anchor.y, false, true); + undo_redo->add_do_method(control, "set_anchor", MARGIN_BOTTOM, bottom_right_anchor.y, false, true); + undo_redo->add_do_method(control, "set_meta", "_edit_use_anchors_", true); + + bool use_anchors = control->has_meta("_edit_use_anchors_") && control->get_meta("_edit_use_anchors_"); + undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state()); + undo_redo->add_undo_method(control, "set_meta", "_edit_use_anchors_", use_anchors); + + anchors_mode = true; + } + } + + undo_redo->commit_action(); } void CanvasItemEditor::_set_anchors_preset(Control::LayoutPreset p_preset) { @@ -3716,6 +3823,92 @@ void CanvasItemEditor::_button_tool_select(int p_index) { tool = (Tool)p_index; } +void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing) { + + Map<Node *, Object *> &selection = editor_selection->get_selection(); + + for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { + + CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key()); + if (!canvas_item || !canvas_item->is_visible_in_tree()) + continue; + + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + continue; + + if (Object::cast_to<Node2D>(canvas_item)) { + Node2D *n2d = Object::cast_to<Node2D>(canvas_item); + + if (key_pos && p_location) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), p_on_existing); + if (key_rot && p_rotation) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "rotation_degrees", Math::rad2deg(n2d->get_rotation()), p_on_existing); + if (key_scale && p_scale) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), p_on_existing); + + if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) { + //look for an IK chain + List<Node2D *> ik_chain; + + Node2D *n = Object::cast_to<Node2D>(n2d->get_parent_item()); + bool has_chain = false; + + while (n) { + + ik_chain.push_back(n); + if (n->has_meta("_edit_ik_")) { + has_chain = true; + break; + } + + if (!n->get_parent_item()) + break; + n = Object::cast_to<Node2D>(n->get_parent_item()); + } + + if (has_chain && ik_chain.size()) { + + for (List<Node2D *>::Element *F = ik_chain.front(); F; F = F->next()) { + + if (key_pos) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "position", F->get()->get_position(), p_on_existing); + if (key_rot) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "rotation_degrees", Math::rad2deg(F->get()->get_rotation()), p_on_existing); + if (key_scale) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "scale", F->get()->get_scale(), p_on_existing); + } + } + } + + } else if (Object::cast_to<Control>(canvas_item)) { + + Control *ctrl = Object::cast_to<Control>(canvas_item); + + if (key_pos) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing); + if (key_rot) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation_degrees(), p_on_existing); + if (key_scale) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing); + } + } +} + +void CanvasItemEditor::_button_toggle_anchor_mode(bool p_status) { + List<CanvasItem *> selection = _get_edited_canvas_items(false, false); + for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) { + Control *control = Object::cast_to<Control>(E->get()); + if (!control || Object::cast_to<Container>(control->get_parent())) + continue; + + control->set_meta("_edit_use_anchors_", p_status); + } + + anchors_mode = p_status; + + viewport->update(); +} + void CanvasItemEditor::_popup_callback(int p_op) { last_option = MenuOption(p_op); @@ -3825,6 +4018,8 @@ void CanvasItemEditor::_popup_callback(int p_op) { viewport->update(); } break; case LOCK_SELECTED: { + undo_redo->create_action(TTR("Lock Selected")); + List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); @@ -3833,12 +4028,18 @@ void CanvasItemEditor::_popup_callback(int p_op) { if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - canvas_item->set_meta("_edit_lock_", true); - emit_signal("item_lock_status_changed"); + undo_redo->add_do_method(canvas_item, "set_meta", "_edit_lock_", true); + undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_lock_"); + undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); } - viewport->update(); + undo_redo->add_do_method(viewport, "update", Variant()); + undo_redo->add_undo_method(viewport, "update", Variant()); + undo_redo->commit_action(); } break; case UNLOCK_SELECTED: { + undo_redo->create_action(TTR("Unlock Selected")); + List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); @@ -3847,12 +4048,18 @@ void CanvasItemEditor::_popup_callback(int p_op) { if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - canvas_item->set_meta("_edit_lock_", Variant()); - emit_signal("item_lock_status_changed"); + undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_lock_"); + undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_lock_", true); + undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); } - viewport->update(); + undo_redo->add_do_method(viewport, "update", Variant()); + undo_redo->add_undo_method(viewport, "update", Variant()); + undo_redo->commit_action(); } break; case GROUP_SELECTED: { + undo_redo->create_action(TTR("Group Selected")); + List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); @@ -3861,12 +4068,18 @@ void CanvasItemEditor::_popup_callback(int p_op) { if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - canvas_item->set_meta("_edit_group_", true); - emit_signal("item_group_status_changed"); + undo_redo->add_do_method(canvas_item, "set_meta", "_edit_group_", true); + undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_group_"); + undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); } - viewport->update(); + undo_redo->add_do_method(viewport, "update", Variant()); + undo_redo->add_undo_method(viewport, "update", Variant()); + undo_redo->commit_action(); } break; case UNGROUP_SELECTED: { + undo_redo->create_action(TTR("Ungroup Selected")); + List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); @@ -3875,10 +4088,14 @@ void CanvasItemEditor::_popup_callback(int p_op) { if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - canvas_item->set_meta("_edit_group_", Variant()); - emit_signal("item_group_status_changed"); + undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_group_"); + undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_group_", true); + undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); } - viewport->update(); + undo_redo->add_do_method(viewport, "update", Variant()); + undo_redo->add_undo_method(viewport, "update", Variant()); + undo_redo->commit_action(); } break; case ANCHORS_AND_MARGINS_PRESET_TOP_LEFT: { _set_anchors_and_margins_preset(PRESET_TOP_LEFT); @@ -3928,6 +4145,9 @@ void CanvasItemEditor::_popup_callback(int p_op) { case ANCHORS_AND_MARGINS_PRESET_WIDE: { _set_anchors_and_margins_preset(Control::PRESET_WIDE); } break; + case ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO: { + _set_anchors_and_margins_to_keep_ratio(); + } break; case ANCHORS_PRESET_TOP_LEFT: { _set_anchors_preset(PRESET_TOP_LEFT); @@ -3983,73 +4203,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { bool existing = p_op == ANIM_INSERT_KEY_EXISTING; - Map<Node *, Object *> &selection = editor_selection->get_selection(); - - for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - - CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key()); - if (!canvas_item || !canvas_item->is_visible_in_tree()) - continue; - - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) - continue; - - if (Object::cast_to<Node2D>(canvas_item)) { - Node2D *n2d = Object::cast_to<Node2D>(canvas_item); - - if (key_pos) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), existing); - if (key_rot) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "rotation_degrees", Math::rad2deg(n2d->get_rotation()), existing); - if (key_scale) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), existing); - - if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) { - //look for an IK chain - List<Node2D *> ik_chain; - - Node2D *n = Object::cast_to<Node2D>(n2d->get_parent_item()); - bool has_chain = false; - - while (n) { - - ik_chain.push_back(n); - if (n->has_meta("_edit_ik_")) { - has_chain = true; - break; - } - - if (!n->get_parent_item()) - break; - n = Object::cast_to<Node2D>(n->get_parent_item()); - } - - if (has_chain && ik_chain.size()) { - - for (List<Node2D *>::Element *F = ik_chain.front(); F; F = F->next()) { - - if (key_pos) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "position", F->get()->get_position(), existing); - if (key_rot) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "rotation_degrees", Math::rad2deg(F->get()->get_rotation()), existing); - if (key_scale) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "scale", F->get()->get_scale(), existing); - } - } - } - - } else if (Object::cast_to<Control>(canvas_item)) { - - Control *ctrl = Object::cast_to<Control>(canvas_item); - - if (key_pos) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), existing); - if (key_rot) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation_degrees(), existing); - if (key_scale) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), existing); - } - } + _insert_animation_keys(true, true, true, existing); } break; case ANIM_INSERT_POS: { @@ -4313,6 +4467,7 @@ void CanvasItemEditor::_bind_methods() { ClassDB::bind_method("_button_zoom_reset", &CanvasItemEditor::_button_zoom_reset); ClassDB::bind_method("_button_zoom_plus", &CanvasItemEditor::_button_zoom_plus); ClassDB::bind_method("_button_toggle_snap", &CanvasItemEditor::_button_toggle_snap); + ClassDB::bind_method("_button_toggle_anchor_mode", &CanvasItemEditor::_button_toggle_anchor_mode); ClassDB::bind_method("_update_scroll", &CanvasItemEditor::_update_scroll); ClassDB::bind_method("_update_scrollbars", &CanvasItemEditor::_update_scrollbars); ClassDB::bind_method("_popup_callback", &CanvasItemEditor::_popup_callback); @@ -4325,6 +4480,7 @@ void CanvasItemEditor::_bind_methods() { ClassDB::bind_method("_snap_changed", &CanvasItemEditor::_snap_changed); ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list); ClassDB::bind_method("_tree_changed", &CanvasItemEditor::_tree_changed); + ClassDB::bind_method("_selection_changed", &CanvasItemEditor::_selection_changed); ClassDB::bind_method("_popup_warning_depop", &CanvasItemEditor::_popup_warning_depop); ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &CanvasItemEditor::_selection_result_pressed); ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &CanvasItemEditor::_selection_menu_hide); @@ -4583,6 +4739,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { snap_relative = false; snap_pixel = false; + anchors_mode = false; + skeleton_show_bones = true; drag_type = DRAG_NONE; @@ -4601,6 +4759,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { editor_selection = p_editor->get_editor_selection(); editor_selection->add_editor_plugin(this); editor_selection->connect("selection_changed", this, "update"); + editor_selection->connect("selection_changed", this, "_selection_changed"); hb = memnew(HBoxContainer); add_child(hb); @@ -4757,28 +4916,29 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { hb->add_child(snap_config_menu); snap_config_menu->set_h_size_flags(SIZE_SHRINK_END); snap_config_menu->set_tooltip(TTR("Snapping Options")); + snap_config_menu->set_switch_on_hover(true); PopupMenu *p = snap_config_menu->get_popup(); p->connect("id_pressed", this, "_popup_callback"); p->set_hide_on_checkable_item_selection(false); - p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_grid", TTR("Snap to grid")), SNAP_USE_GRID); + p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_grid", TTR("Snap to Grid")), SNAP_USE_GRID); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_rotation_snap", TTR("Use Rotation Snap")), SNAP_USE_ROTATION); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/configure_snap", TTR("Configure Snap...")), SNAP_CONFIGURE); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_relative", TTR("Snap Relative")), SNAP_RELATIVE); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_pixel_snap", TTR("Use Pixel Snap")), SNAP_USE_PIXEL); - p->add_submenu_item(TTR("Smart snapping"), "SmartSnapping"); + p->add_submenu_item(TTR("Smart Snapping"), "SmartSnapping"); smartsnap_config_popup = memnew(PopupMenu); p->add_child(smartsnap_config_popup); smartsnap_config_popup->set_name("SmartSnapping"); smartsnap_config_popup->connect("id_pressed", this, "_popup_callback"); smartsnap_config_popup->set_hide_on_checkable_item_selection(false); - smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_parent", TTR("Snap to parent")), SNAP_USE_NODE_PARENT); - smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_anchors", TTR("Snap to node anchor")), SNAP_USE_NODE_ANCHORS); - smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_sides", TTR("Snap to node sides")), SNAP_USE_NODE_SIDES); - smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_center", TTR("Snap to node center")), SNAP_USE_NODE_CENTER); - smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_other_nodes", TTR("Snap to other nodes")), SNAP_USE_OTHER_NODES); - smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_guides", TTR("Snap to guides")), SNAP_USE_GUIDES); + smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_parent", TTR("Snap to Parent")), SNAP_USE_NODE_PARENT); + smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_anchors", TTR("Snap to Node Anchor")), SNAP_USE_NODE_ANCHORS); + smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_sides", TTR("Snap to Node Sides")), SNAP_USE_NODE_SIDES); + smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_center", TTR("Snap to Node Center")), SNAP_USE_NODE_CENTER); + smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_other_nodes", TTR("Snap to Other Nodes")), SNAP_USE_OTHER_NODES); + smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_guides", TTR("Snap to Guides")), SNAP_USE_GUIDES); hb->add_child(memnew(VSeparator)); @@ -4808,6 +4968,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { skeleton_menu = memnew(MenuButton); hb->add_child(skeleton_menu); skeleton_menu->set_tooltip(TTR("Skeleton Options")); + skeleton_menu->set_switch_on_hover(true); p = skeleton_menu->get_popup(); p->set_hide_on_checkable_item_selection(false); @@ -4826,8 +4987,10 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { view_menu->set_text(TTR("View")); hb->add_child(view_menu); view_menu->get_popup()->connect("id_pressed", this, "_popup_callback"); + view_menu->set_switch_on_hover(true); p = view_menu->get_popup(); + p->set_hide_on_checkable_item_selection(false); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Show Grid"), KEY_G), SHOW_GRID); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show Helpers"), KEY_H), SHOW_HELPERS); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show Rulers"), KEY_R), SHOW_RULERS); @@ -4846,6 +5009,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { presets_menu->set_text(TTR("Layout")); hb->add_child(presets_menu); presets_menu->hide(); + presets_menu->set_switch_on_hover(true); p = presets_menu->get_popup(); p->connect("id_pressed", this, "_popup_callback"); @@ -4855,6 +5019,12 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { anchors_popup->set_name("Anchors"); anchors_popup->connect("id_pressed", this, "_popup_callback"); + anchor_mode_button = memnew(ToolButton); + hb->add_child(anchor_mode_button); + anchor_mode_button->set_toggle_mode(true); + anchor_mode_button->hide(); + anchor_mode_button->connect("toggled", this, "_button_toggle_anchor_mode"); + animation_hb = memnew(HBoxContainer); hb->add_child(animation_hb); animation_hb->add_child(memnew(VSeparator)); @@ -4866,6 +5036,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { key_loc_button->set_pressed(true); key_loc_button->set_focus_mode(FOCUS_NONE); key_loc_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_POS)); + key_loc_button->set_tooltip(TTR("Translation mask for inserting keys.")); animation_hb->add_child(key_loc_button); key_rot_button = memnew(Button); key_rot_button->set_toggle_mode(true); @@ -4873,26 +5044,36 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { key_rot_button->set_pressed(true); key_rot_button->set_focus_mode(FOCUS_NONE); key_rot_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_ROT)); + key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys.")); animation_hb->add_child(key_rot_button); key_scale_button = memnew(Button); key_scale_button->set_toggle_mode(true); key_scale_button->set_flat(true); key_scale_button->set_focus_mode(FOCUS_NONE); key_scale_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_SCALE)); + key_scale_button->set_tooltip(TTR("Scale mask for inserting keys.")); 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", this, "_popup_callback", varray(ANIM_INSERT_KEY)); - key_insert_button->set_tooltip(TTR("Insert keys.")); + key_insert_button->set_tooltip(TTR("Insert keys (based on mask).")); key_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key", TTR("Insert Key"), KEY_INSERT)); - animation_hb->add_child(key_insert_button); + key_auto_insert_button = memnew(Button); + key_auto_insert_button->set_flat(true); + key_auto_insert_button->set_toggle_mode(true); + key_auto_insert_button->set_focus_mode(FOCUS_NONE); + //key_auto_insert_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_KEY)); + key_auto_insert_button->set_tooltip(TTR("Auto insert keys when objects are translated, rotated on scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time.")); + key_auto_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_auto_insert_key", TTR("Auto Insert Key"))); + animation_hb->add_child(key_auto_insert_button); animation_menu = memnew(MenuButton); animation_menu->set_text(TTR("Animation")); animation_hb->add_child(animation_menu); animation_menu->get_popup()->connect("id_pressed", this, "_popup_callback"); + animation_menu->set_switch_on_hover(true); p = animation_menu->get_popup(); @@ -5401,7 +5582,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte selector = memnew(AcceptDialog); editor->get_gui_base()->add_child(selector); - selector->set_title(TTR("Change default type")); + selector->set_title(TTR("Change Default Type")); selector->connect("confirmed", this, "_on_change_type_confirmed"); selector->connect("popup_hide", this, "_on_change_type_closed"); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 9173c55ae0..e098d261c0 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -129,6 +129,7 @@ private: ANCHORS_AND_MARGINS_PRESET_VCENTER_WIDE, ANCHORS_AND_MARGINS_PRESET_HCENTER_WIDE, ANCHORS_AND_MARGINS_PRESET_WIDE, + ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO, ANCHORS_PRESET_TOP_LEFT, ANCHORS_PRESET_TOP_RIGHT, ANCHORS_PRESET_BOTTOM_LEFT, @@ -240,6 +241,8 @@ private: Point2 view_offset; Point2 previous_update_view_offset; + bool anchors_mode; + Point2 grid_offset; Point2 grid_step; int grid_step_multiplier; @@ -347,10 +350,13 @@ private: PopupMenu *anchors_and_margins_popup; PopupMenu *anchors_popup; + ToolButton *anchor_mode_button; + Button *key_loc_button; Button *key_rot_button; Button *key_scale_button; Button *key_insert_button; + Button *key_auto_insert_button; PopupMenu *selection_menu; @@ -422,6 +428,8 @@ private: Object *_get_editor_data(Object *p_what); + void _insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing); + void _keying_changed(); void _unhandled_key_input(const Ref<InputEvent> &p_ev); @@ -435,6 +443,7 @@ private: void _draw_guides(); void _draw_focus(); void _draw_grid(); + void _draw_control_anchors(Control *control); void _draw_control_helpers(Control *control); void _draw_selection(); void _draw_axis(); @@ -459,6 +468,8 @@ private: void _gui_input_viewport(const Ref<InputEvent> &p_event); + void _selection_changed(); + void _focus_selection(int p_op); void _solve_IK(Node2D *leaf_node, Point2 target_position); @@ -470,6 +481,9 @@ private: void _set_anchors_preset(Control::LayoutPreset p_preset); void _set_margins_preset(Control::LayoutPreset p_preset); void _set_anchors_and_margins_preset(Control::LayoutPreset p_preset); + void _set_anchors_and_margins_to_keep_ratio(); + + void _button_toggle_anchor_mode(bool p_status); HBoxContainer *zoom_hb; void _zoom_on_position(float p_zoom, Point2 p_position = Point2()); @@ -572,6 +586,8 @@ public: void focus_selection(); + bool is_anchors_mode_enabled() { return anchors_mode; }; + CanvasItemEditor(EditorNode *p_editor); }; diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 559558cdb8..1622ce17b2 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -267,6 +267,7 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) { menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK); // menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK); menu->set_text(TTR("Particles")); + menu->set_switch_on_hover(true); toolbar->add_child(menu); file = memnew(EditorFileDialog); diff --git a/editor/plugins/cpu_particles_editor_plugin.cpp b/editor/plugins/cpu_particles_editor_plugin.cpp index 7222525dd7..70be9b95bb 100644 --- a/editor/plugins/cpu_particles_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_editor_plugin.cpp @@ -101,6 +101,7 @@ CPUParticlesEditor::CPUParticlesEditor() { particles_editor_hb = memnew(HBoxContainer); SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb); options = memnew(MenuButton); + options->set_switch_on_hover(true); particles_editor_hb->add_child(options); particles_editor_hb->hide(); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 3d76b5da21..55feb40c2c 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -53,11 +53,11 @@ CurveEditor::CurveEditor() { _presets_menu = memnew(PopupMenu); _presets_menu->set_name("_presets_menu"); - _presets_menu->add_item(TTR("Flat0"), PRESET_FLAT0); - _presets_menu->add_item(TTR("Flat1"), PRESET_FLAT1); + _presets_menu->add_item(TTR("Flat 0"), PRESET_FLAT0); + _presets_menu->add_item(TTR("Flat 1"), PRESET_FLAT1); _presets_menu->add_item(TTR("Linear"), PRESET_LINEAR); - _presets_menu->add_item(TTR("Ease in"), PRESET_EASE_IN); - _presets_menu->add_item(TTR("Ease out"), PRESET_EASE_OUT); + _presets_menu->add_item(TTR("Ease In"), PRESET_EASE_IN); + _presets_menu->add_item(TTR("Ease Out"), PRESET_EASE_OUT); _presets_menu->add_item(TTR("Smoothstep"), PRESET_SMOOTHSTEP); _presets_menu->connect("id_pressed", this, "_on_preset_item_selected"); _context_menu->add_child(_presets_menu); @@ -194,7 +194,7 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { Vector2 dir = (control_pos - point_pos).normalized(); real_t tangent; - if (Math::abs(dir.x) > CMP_EPSILON) + if (!Math::is_zero_approx(dir.x)) tangent = dir.y / dir.x; else tangent = 9999 * (dir.y >= 0 ? 1 : -1); @@ -330,10 +330,10 @@ void CurveEditor::open_context_menu(Vector2 pos) { _context_menu->clear(); if (_curve_ref.is_valid()) { - _context_menu->add_item(TTR("Add point"), CONTEXT_ADD_POINT); + _context_menu->add_item(TTR("Add Point"), CONTEXT_ADD_POINT); if (_selected_point >= 0) { - _context_menu->add_item(TTR("Remove point"), CONTEXT_REMOVE_POINT); + _context_menu->add_item(TTR("Remove Point"), CONTEXT_REMOVE_POINT); if (_selected_tangent != TANGENT_NONE) { _context_menu->add_separator(); @@ -351,12 +351,12 @@ void CurveEditor::open_context_menu(Vector2 pos) { _context_menu->add_separator(); if (_selected_point > 0) { - _context_menu->add_check_item(TTR("Left linear"), CONTEXT_LEFT_LINEAR); + _context_menu->add_check_item(TTR("Left Linear"), CONTEXT_LEFT_LINEAR); _context_menu->set_item_checked(_context_menu->get_item_index(CONTEXT_LEFT_LINEAR), _curve_ref->get_point_left_mode(_selected_point) == Curve::TANGENT_LINEAR); } if (_selected_point + 1 < _curve_ref->get_point_count()) { - _context_menu->add_check_item(TTR("Right linear"), CONTEXT_RIGHT_LINEAR); + _context_menu->add_check_item(TTR("Right Linear"), CONTEXT_RIGHT_LINEAR); _context_menu->set_item_checked(_context_menu->get_item_index(CONTEXT_RIGHT_LINEAR), _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR); } @@ -366,7 +366,7 @@ void CurveEditor::open_context_menu(Vector2 pos) { _context_menu->add_separator(); } - _context_menu->add_submenu_item(TTR("Load preset"), _presets_menu->get_name()); + _context_menu->add_submenu_item(TTR("Load Preset"), _presets_menu->get_name()); _context_menu->set_size(Size2(0, 0)); _context_menu->popup(); diff --git a/editor/plugins/item_list_editor_plugin.h b/editor/plugins/item_list_editor_plugin.h index 679235e316..701632e576 100644 --- a/editor/plugins/item_list_editor_plugin.h +++ b/editor/plugins/item_list_editor_plugin.h @@ -157,7 +157,7 @@ public: virtual void set_item_enabled(int p_idx, int p_enabled) { pp->set_item_disabled(p_idx, !p_enabled); } virtual bool is_item_enabled(int p_idx) const { return !pp->is_item_disabled(p_idx); } - virtual void set_item_id(int p_idx, int p_id) { pp->set_item_id(p_idx, p_idx); } + virtual void set_item_id(int p_idx, int p_id) { pp->set_item_id(p_idx, p_id); } virtual int get_item_id(int p_idx) const { return pp->get_item_id(p_idx); } virtual void set_item_separator(int p_idx, bool p_separator) { pp->set_item_as_separator(p_idx, p_separator); } diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp index 3e10cdbbfa..635b934333 100644 --- a/editor/plugins/mesh_instance_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_editor_plugin.cpp @@ -95,10 +95,7 @@ void MeshInstanceEditor::_menu_option(int p_option) { return; } - if (trimesh_shape) - ur->create_action(TTR("Create Static Trimesh Body")); - else - ur->create_action(TTR("Create Static Convex Body")); + ur->create_action(TTR("Create Static Trimesh Body")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { @@ -132,8 +129,7 @@ void MeshInstanceEditor::_menu_option(int p_option) { } break; - case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE: - case MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE: { + case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE: { if (node == get_tree()->get_edited_scene_root()) { err_dialog->set_text(TTR("This doesn't work on scene root!")); @@ -141,9 +137,7 @@ void MeshInstanceEditor::_menu_option(int p_option) { return; } - bool trimesh_shape = (p_option == MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE); - - Ref<Shape> shape = trimesh_shape ? mesh->create_trimesh_shape() : mesh->create_convex_shape(); + Ref<Shape> shape = mesh->create_trimesh_shape(); if (shape.is_null()) return; @@ -154,10 +148,7 @@ void MeshInstanceEditor::_menu_option(int p_option) { UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - if (trimesh_shape) - ur->create_action(TTR("Create Trimesh Shape")); - else - ur->create_action(TTR("Create Convex Shape")); + ur->create_action(TTR("Create Trimesh Static Shape")); ur->add_do_method(node->get_parent(), "add_child", cshape); ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1); @@ -165,6 +156,40 @@ void MeshInstanceEditor::_menu_option(int p_option) { ur->add_do_reference(cshape); ur->add_undo_method(node->get_parent(), "remove_child", cshape); ur->commit_action(); + } break; + case MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE: { + + if (node == get_tree()->get_edited_scene_root()) { + err_dialog->set_text(TTR("This doesn't work on scene root!")); + err_dialog->popup_centered_minsize(); + return; + } + + Vector<Ref<Shape> > shapes = mesh->convex_decompose(); + + if (!shapes.size()) { + err_dialog->set_text(TTR("Failed creating shapes!")); + err_dialog->popup_centered_minsize(); + return; + } + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action(TTR("Create Convex Shape(s)")); + + for (int i = 0; i < shapes.size(); i++) { + + CollisionShape *cshape = memnew(CollisionShape); + cshape->set_shape(shapes[i]); + + Node *owner = node->get_owner(); + + ur->add_do_method(node->get_parent(), "add_child", cshape); + ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1); + ur->add_do_method(cshape, "set_owner", owner); + ur->add_do_reference(cshape); + ur->add_undo_method(node->get_parent(), "remove_child", cshape); + } + ur->commit_action(); } break; @@ -387,16 +412,16 @@ void MeshInstanceEditor::_bind_methods() { MeshInstanceEditor::MeshInstanceEditor() { options = memnew(MenuButton); + options->set_switch_on_hover(true); SpatialEditor::get_singleton()->add_control_to_menu_panel(options); options->set_text(TTR("Mesh")); options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshInstance", "EditorIcons")); options->get_popup()->add_item(TTR("Create Trimesh Static Body"), MENU_OPTION_CREATE_STATIC_TRIMESH_BODY); - options->get_popup()->add_item(TTR("Create Convex Static Body"), MENU_OPTION_CREATE_STATIC_CONVEX_BODY); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Trimesh Collision Sibling"), MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE); - options->get_popup()->add_item(TTR("Create Convex Collision Sibling"), MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE); + options->get_popup()->add_item(TTR("Create Convex Collision Sibling(s)"), MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH); options->get_popup()->add_separator(); diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp index 8ff6080443..fc0a425bfc 100644 --- a/editor/plugins/multimesh_editor_plugin.cpp +++ b/editor/plugins/multimesh_editor_plugin.cpp @@ -293,6 +293,7 @@ void MultiMeshEditor::_bind_methods() { MultiMeshEditor::MultiMeshEditor() { options = memnew(MenuButton); + options->set_switch_on_hover(true); SpatialEditor::get_singleton()->add_control_to_menu_panel(options); options->set_text("MultiMesh"); diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp index 70d4919e9f..50bdf4512b 100644 --- a/editor/plugins/particles_2d_editor_plugin.cpp +++ b/editor/plugins/particles_2d_editor_plugin.cpp @@ -375,6 +375,7 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) { menu->get_popup()->add_separator(); menu->get_popup()->add_item(TTR("Convert to CPUParticles"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES); menu->set_text(TTR("Particles")); + menu->set_switch_on_hover(true); toolbar->add_child(menu); file = memnew(EditorFileDialog); diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp index 0032850535..09180edf2a 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/particles_editor_plugin.cpp @@ -454,6 +454,7 @@ ParticlesEditor::ParticlesEditor() { particles_editor_hb = memnew(HBoxContainer); SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb); options = memnew(MenuButton); + options->set_switch_on_hover(true); particles_editor_hb->add_child(options); particles_editor_hb->hide(); diff --git a/editor/plugins/physical_bone_plugin.cpp b/editor/plugins/physical_bone_plugin.cpp index 9ea37aceb9..96681a105f 100644 --- a/editor/plugins/physical_bone_plugin.cpp +++ b/editor/plugins/physical_bone_plugin.cpp @@ -61,7 +61,7 @@ PhysicalBoneEditor::PhysicalBoneEditor(EditorNode *p_editor) : button_transform_joint = memnew(ToolButton); spatial_editor_hb->add_child(button_transform_joint); - button_transform_joint->set_text(TTR("Move joint")); + button_transform_joint->set_text(TTR("Move Joint")); button_transform_joint->set_icon(SpatialEditor::get_singleton()->get_icon("PhysicalBone", "EditorIcons")); button_transform_joint->set_toggle_mode(true); button_transform_joint->connect("toggled", this, "_on_toggle_button_transform_joint"); diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index af43f679fd..712b1a0ae4 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -1060,8 +1060,7 @@ void Polygon2DEditor::_uv_draw() { polygon_fill_color.push_back(pf); } Color prev_color = Color(0.5, 0.5, 0.5); - Rect2 rect(Point2(), mtx.basis_xform(base_tex->get_size())); - rect.expand_to(mtx.basis_xform(uv_edit_draw->get_size())); + Rect2 rect; int uv_draw_max = uvs.size(); @@ -1204,7 +1203,8 @@ void Polygon2DEditor::_uv_draw() { uv_edit_draw->draw_circle(bone_paint_pos, bone_paint_radius->get_value() * EDSCALE, Color(1, 1, 1, 0.1)); } - rect = rect.grow(200); + rect.position -= uv_edit_draw->get_size(); + rect.size += uv_edit_draw->get_size() * 2.0; updating_uv_scroll = true; uv_hscroll->set_min(rect.position.x); uv_hscroll->set_max(rect.position.x + rect.size.x); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index d7d4cec07d..828abef9a9 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -312,6 +312,38 @@ void ScriptEditor::_goto_script_line(REF p_script, int p_line) { } } +void ScriptEditor::_set_execution(REF p_script, int p_line) { + Ref<Script> script = Object::cast_to<Script>(*p_script); + if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) { + for (int i = 0; i < tab_container->get_child_count(); i++) { + + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); + if (!se) + continue; + + if ((script != NULL && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) { + se->set_executing_line(p_line); + } + } + } +} + +void ScriptEditor::_clear_execution(REF p_script) { + Ref<Script> script = Object::cast_to<Script>(*p_script); + if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) { + for (int i = 0; i < tab_container->get_child_count(); i++) { + + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); + if (!se) + continue; + + if ((script != NULL && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) { + se->clear_executing_line(); + } + } + } +} + ScriptEditorBase *ScriptEditor::_get_current_editor() const { int selected = tab_container->get_current_tab(); @@ -571,6 +603,8 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { idx = history[history_pos].control->get_index(); } tab_container->set_current_tab(idx); + } else { + _update_selected_editor_menu(); } _update_history_arrows(); @@ -970,6 +1004,9 @@ void ScriptEditor::_menu_option(int p_option) { save_all_scripts(); } break; + case SEARCH_IN_FILES: { + _on_find_in_files_requested(""); + } break; case SEARCH_HELP: { help_search_dialog->popup_dialog(); @@ -1801,6 +1838,16 @@ void ScriptEditor::_update_script_names() { _update_script_colors(); } +void ScriptEditor::_update_script_connections() { + for (int i = 0; i < tab_container->get_child_count(); i++) { + ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(tab_container->get_child(i)); + if (!ste) { + continue; + } + ste->_update_connected_methods(); + } +} + Ref<TextFile> ScriptEditor::_load_text_file(const String &p_path, Error *r_error) { if (r_error) { *r_error = ERR_FILE_CANT_OPEN; @@ -2203,6 +2250,7 @@ void ScriptEditor::_tree_changed() { waiting_update_names = true; call_deferred("_update_script_names"); + call_deferred("_update_script_connections"); } void ScriptEditor::_script_split_dragged(float) { @@ -2482,22 +2530,39 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { for (int i = 0; i < scripts.size(); i++) { String path = scripts[i]; + + Dictionary script_info = scripts[i]; + if (!script_info.empty()) { + path = script_info["path"]; + } + if (!FileAccess::exists(path)) continue; if (extensions.find(path.get_extension())) { Ref<Script> scr = ResourceLoader::load(path); - if (scr.is_valid()) { - edit(scr); + if (!scr.is_valid()) { + continue; + } + if (!edit(scr)) { + continue; + } + } else { + Error error; + Ref<TextFile> text_file = _load_text_file(path, &error); + if (error != OK || !text_file.is_valid()) { + continue; + } + if (!edit(text_file)) { continue; } } - Error error; - Ref<TextFile> text_file = _load_text_file(path, &error); - if (error == OK && text_file.is_valid()) { - edit(text_file); - continue; + if (!script_info.empty()) { + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(tab_container->get_tab_count() - 1)); + if (se) { + se->set_edit_state(script_info["state"]); + } } } @@ -2537,7 +2602,11 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) { if (!path.is_resource_file()) continue; - scripts.push_back(path); + Dictionary script_info; + script_info["path"] = path; + script_info["state"] = se->get_edit_state(); + + scripts.push_back(script_info); } EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i)); @@ -2630,10 +2699,22 @@ void ScriptEditor::_update_selected_editor_menu() { } EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_current_tab_control()); + script_search_menu->get_popup()->clear(); if (eh) { + + script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F), HELP_SEARCH_FIND); + script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), KEY_F3), HELP_SEARCH_FIND_NEXT); + script_search_menu->get_popup()->add_separator(); + script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F), SEARCH_IN_FILES); script_search_menu->show(); } else { - script_search_menu->hide(); + + if (tab_container->get_child_count() == 0) { + script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F), SEARCH_IN_FILES); + script_search_menu->show(); + } else { + script_search_menu->hide(); + } } } @@ -2846,6 +2927,8 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_res_saved_callback", &ScriptEditor::_res_saved_callback); ClassDB::bind_method("_goto_script_line", &ScriptEditor::_goto_script_line); ClassDB::bind_method("_goto_script_line2", &ScriptEditor::_goto_script_line2); + ClassDB::bind_method("_set_execution", &ScriptEditor::_set_execution); + ClassDB::bind_method("_clear_execution", &ScriptEditor::_clear_execution); ClassDB::bind_method("_help_search", &ScriptEditor::_help_search); ClassDB::bind_method("_save_history", &ScriptEditor::_save_history); ClassDB::bind_method("_copy_script_path", &ScriptEditor::_copy_script_path); @@ -2856,6 +2939,7 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_autosave_scripts", &ScriptEditor::_autosave_scripts); ClassDB::bind_method("_editor_settings_changed", &ScriptEditor::_editor_settings_changed); ClassDB::bind_method("_update_script_names", &ScriptEditor::_update_script_names); + ClassDB::bind_method("_update_script_connections", &ScriptEditor::_update_script_connections); ClassDB::bind_method("_tree_changed", &ScriptEditor::_tree_changed); ClassDB::bind_method("_members_overview_selected", &ScriptEditor::_members_overview_selected); ClassDB::bind_method("_help_overview_selected", &ScriptEditor::_help_overview_selected); @@ -2883,6 +2967,7 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("can_drop_data_fw", "point", "data", "from"), &ScriptEditor::can_drop_data_fw); ClassDB::bind_method(D_METHOD("drop_data_fw", "point", "data", "from"), &ScriptEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("goto_line", "line_number"), &ScriptEditor::_goto_script_line2); ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script); ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts); ClassDB::bind_method(D_METHOD("open_script_create_dialog", "base_name", "base_path"), &ScriptEditor::open_script_create_dialog); @@ -3041,10 +3126,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { script_search_menu->set_text(TTR("Search")); script_search_menu->set_switch_on_hover(true); script_search_menu->get_popup()->set_hide_on_window_lose_focus(true); - script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F), HELP_SEARCH_FIND); - script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), KEY_F3), HELP_SEARCH_FIND_NEXT); script_search_menu->get_popup()->connect("id_pressed", this, "_menu_option"); - script_search_menu->hide(); debug_menu = memnew(MenuButton); menu_hb->add_child(debug_menu); @@ -3135,6 +3217,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { debugger = memnew(ScriptEditorDebugger(editor)); debugger->connect("goto_script_line", this, "_goto_script_line"); + debugger->connect("set_execution", this, "_set_execution"); + debugger->connect("clear_execution", this, "_clear_execution"); debugger->connect("show_debugger", this, "_show_debugger"); disk_changed = memnew(ConfirmationDialog); @@ -3221,9 +3305,7 @@ void ScriptEditorPlugin::edit(Object *p_object) { } else { script_editor->edit(p_script); } - } - - if (Object::cast_to<TextFile>(p_object)) { + } else if (Object::cast_to<TextFile>(p_object)) { script_editor->edit(Object::cast_to<TextFile>(p_object)); } } diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 954b014935..683fa881f8 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -96,6 +96,8 @@ public: virtual Variant get_edit_state() = 0; virtual void set_edit_state(const Variant &p_state) = 0; virtual void goto_line(int p_line, bool p_with_error = false) = 0; + virtual void set_executing_line(int p_line) = 0; + virtual void clear_executing_line() = 0; virtual void trim_trailing_whitespace() = 0; virtual void convert_indent_to_spaces() = 0; virtual void convert_indent_to_tabs() = 0; @@ -155,6 +157,7 @@ class ScriptEditor : public PanelContainer { DEBUG_SHOW, DEBUG_SHOW_KEEP_OPEN, DEBUG_WITH_EXTERNAL_EDITOR, + SEARCH_IN_FILES, SEARCH_HELP, SEARCH_WEBSITE, REQUEST_DOCS, @@ -318,6 +321,8 @@ class ScriptEditor : public PanelContainer { void _goto_script_line2(int p_line); void _goto_script_line(REF p_script, int p_line); + void _set_execution(REF p_script, int p_line); + void _clear_execution(REF p_script); void _breaked(bool p_breaked, bool p_can_debug); void _show_debugger(bool p_show); void _update_window_menu(); @@ -333,6 +338,7 @@ class ScriptEditor : public PanelContainer { void _update_members_overview(); void _toggle_members_overview_alpha_sort(bool p_alphabetic_sort); void _update_script_names(); + void _update_script_connections(); bool _sort_list_on_update; void _members_overview_selected(int p_idx); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 9fc42e3862..315898e9ed 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -35,6 +35,76 @@ #include "editor/editor_settings.h" #include "editor/script_editor_debugger.h" +void ConnectionInfoDialog::ok_pressed() { +} + +void ConnectionInfoDialog::popup_connections(String p_method, Vector<Node *> p_nodes) { + method->set_text(p_method); + + tree->clear(); + TreeItem *root = tree->create_item(); + + for (int i = 0; i < p_nodes.size(); i++) { + List<Connection> all_connections; + p_nodes[i]->get_signals_connected_to_this(&all_connections); + + for (List<Connection>::Element *E = all_connections.front(); E; E = E->next()) { + Connection connection = E->get(); + + if (connection.method != p_method) { + continue; + } + + TreeItem *node_item = tree->create_item(root); + + node_item->set_text(0, Object::cast_to<Node>(connection.source)->get_name()); + node_item->set_icon(0, EditorNode::get_singleton()->get_object_icon(connection.source, "Node")); + node_item->set_selectable(0, false); + node_item->set_editable(0, false); + + node_item->set_text(1, connection.signal); + node_item->set_icon(1, get_parent_control()->get_icon("Slot", "EditorIcons")); + node_item->set_selectable(1, false); + node_item->set_editable(1, false); + + node_item->set_text(2, Object::cast_to<Node>(connection.target)->get_name()); + node_item->set_icon(2, EditorNode::get_singleton()->get_object_icon(connection.target, "Node")); + node_item->set_selectable(2, false); + node_item->set_editable(2, false); + } + } + + popup_centered(Size2(400, 300) * EDSCALE); +} + +ConnectionInfoDialog::ConnectionInfoDialog() { + set_title(TTR("Connections to method:")); + + VBoxContainer *vbc = memnew(VBoxContainer); + vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 8 * EDSCALE); + vbc->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 8 * EDSCALE); + vbc->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -8 * EDSCALE); + vbc->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -8 * EDSCALE); + add_child(vbc); + + method = memnew(Label); + method->set_align(Label::ALIGN_CENTER); + vbc->add_child(method); + + tree = memnew(Tree); + tree->set_columns(3); + tree->set_hide_root(true); + tree->set_column_titles_visible(true); + tree->set_column_title(0, TTR("Source")); + tree->set_column_title(1, TTR("Signal")); + tree->set_column_title(2, TTR("Target")); + vbc->add_child(tree); + tree->set_v_size_flags(SIZE_EXPAND_FILL); + tree->set_allow_rmb_select(true); +} + +//////////////////////////////////////////////////////////////////////////////// + Vector<String> ScriptTextEditor::get_functions() { String errortxt; @@ -81,6 +151,8 @@ void ScriptTextEditor::set_edited_resource(const RES &p_res) { emit_signal("name_changed"); code_editor->update_line_and_column(); + + _validate_script(); } void ScriptTextEditor::_update_member_keywords() { @@ -142,6 +214,7 @@ void ScriptTextEditor::_load_theme_settings() { Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color"); Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color"); + Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color"); Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color"); Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color"); Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); @@ -173,6 +246,7 @@ void ScriptTextEditor::_load_theme_settings() { text_edit->add_color_override("function_color", function_color); text_edit->add_color_override("member_variable_color", member_variable_color); text_edit->add_color_override("breakpoint_color", breakpoint_color); + text_edit->add_color_override("executing_line_color", executing_line_color); text_edit->add_color_override("mark_color", mark_color); text_edit->add_color_override("code_folding_color", code_folding_color); text_edit->add_color_override("search_result_color", search_result_color); @@ -286,7 +360,7 @@ void ScriptTextEditor::_warning_clicked(Variant p_line) { code_editor->get_text_edit()->cursor_set_line(p_line.operator int64_t()); } else if (p_line.get_type() == Variant::DICTIONARY) { Dictionary meta = p_line.operator Dictionary(); - code_editor->get_text_edit()->insert_at("#warning-ignore:" + meta["code"].operator String(), meta["line"].operator int64_t() - 1); + code_editor->get_text_edit()->insert_at("# warning-ignore:" + meta["code"].operator String(), meta["line"].operator int64_t() - 1); _validate_script(); } } @@ -302,7 +376,6 @@ void ScriptTextEditor::reload_text() { int v = te->get_v_scroll(); te->set_text(script->get_source_code()); - te->clear_undo_history(); te->cursor_set_line(row); te->cursor_set_column(column); te->set_h_scroll(h); @@ -318,7 +391,6 @@ void ScriptTextEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: _load_theme_settings(); - _change_syntax_highlighter(EditorSettings::get_singleton()->get_project_metadata("script_text_editor", "syntax_highlighter", 0)); break; } } @@ -363,6 +435,14 @@ Variant ScriptTextEditor::get_edit_state() { void ScriptTextEditor::set_edit_state(const Variant &p_state) { code_editor->set_edit_state(p_state); + + Dictionary state = p_state; + if (state.has("syntax_highlighter")) { + int idx = highlighter_menu->get_item_idx_from_text(state["syntax_highlighter"]); + if (idx >= 0) { + _change_syntax_highlighter(idx); + } + } } void ScriptTextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) { @@ -400,6 +480,14 @@ void ScriptTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { code_editor->goto_line_selection(p_line, p_begin, p_end); } +void ScriptTextEditor::set_executing_line(int p_line) { + code_editor->set_executing_line(p_line); +} + +void ScriptTextEditor::clear_executing_line() { + code_editor->clear_executing_line(); +} + void ScriptTextEditor::ensure_focus() { code_editor->get_text_edit()->grab_focus(); @@ -461,9 +549,32 @@ void ScriptTextEditor::_validate_script() { functions.push_back(E->get()); } } + _update_connected_methods(); - code_editor->set_warning_nb(warnings.size()); + code_editor->set_warning_nb(missing_connections.size() + warnings.size()); warnings_panel->clear(); + + // add missing connections + Node *base = get_tree()->get_edited_scene_root(); + if (base && missing_connections.size() > 0) { + warnings_panel->push_table(1); + for (List<Connection>::Element *E = missing_connections.front(); E; E = E->next()) { + Connection connection = E->get(); + + String base_path = base->get_name(); + String source_path = base == connection.source ? base_path : base_path + "/" + String(base->get_path_to(Object::cast_to<Node>(connection.source))); + String target_path = base == connection.target ? base_path : base_path + "/" + String(base->get_path_to(Object::cast_to<Node>(connection.target))); + + warnings_panel->push_cell(); + warnings_panel->push_color(warnings_panel->get_color("warning_color", "Editor")); + warnings_panel->add_text(vformat(TTR("Missing connected method '%s' for signal '%s' from node '%s' to node '%s'"), connection.method, connection.signal, source_path, target_path)); + warnings_panel->pop(); // Color + warnings_panel->pop(); // Cell + } + warnings_panel->pop(); // Table + } + + // add script warnings warnings_panel->push_table(3); for (List<ScriptLanguage::Warning>::Element *E = warnings.front(); E; E = E->next()) { ScriptLanguage::Warning w = E->get(); @@ -517,6 +628,27 @@ void ScriptTextEditor::_validate_script() { emit_signal("edited_script_changed"); } +static Vector<Node *> _find_all_node_for_script(Node *p_base, Node *p_current, const Ref<Script> &p_script) { + + Vector<Node *> nodes; + + if (p_current->get_owner() != p_base && p_base != p_current) { + return nodes; + } + + Ref<Script> c = p_current->get_script(); + if (c == p_script) { + nodes.push_back(p_current); + } + + for (int i = 0; i < p_current->get_child_count(); i++) { + Vector<Node *> found = _find_all_node_for_script(p_base, p_current->get_child(i), p_script); + nodes.append_array(found); + } + + return nodes; +} + static Node *_find_node_for_script(Node *p_base, Node *p_current, const Ref<Script> &p_script) { if (p_current->get_owner() != p_base && p_base != p_current) @@ -712,6 +844,47 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c } } +void ScriptTextEditor::_update_connected_methods() { + TextEdit *text_edit = code_editor->get_text_edit(); + text_edit->clear_info_icons(); + missing_connections.clear(); + + Node *base = get_tree()->get_edited_scene_root(); + if (!base) { + return; + } + + Vector<Node *> nodes = _find_all_node_for_script(base, base, script); + for (int i = 0; i < nodes.size(); i++) { + List<Connection> connections; + nodes[i]->get_signals_connected_to_this(&connections); + + for (List<Connection>::Element *E = connections.front(); E; E = E->next()) { + Connection connection = E->get(); + if (!(connection.flags & CONNECT_PERSIST)) { + continue; + } + + int line = script->get_language()->find_function(connection.method, text_edit->get_text()); + if (line < 0) { + missing_connections.push_back(connection); + continue; + } + text_edit->set_line_info_icon(line - 1, get_parent_control()->get_icon("Slot", "EditorIcons"), connection.method); + } + } +} + +void ScriptTextEditor::_lookup_connections(int p_row, String p_method) { + Node *base = get_tree()->get_edited_scene_root(); + if (!base) { + return; + } + + Vector<Node *> nodes = _find_all_node_for_script(base, base, script); + connection_info_dialog->popup_connections(p_method, nodes); +} + void ScriptTextEditor::_edit_option(int p_op) { TextEdit *tx = code_editor->get_text_edit(); @@ -1024,7 +1197,6 @@ void ScriptTextEditor::_change_syntax_highlighter(int p_idx) { } // highlighter_menu->set_item_checked(p_idx, true); set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]); - EditorSettings::get_singleton()->set_project_metadata("script_text_editor", "syntax_highlighter", p_idx); } void ScriptTextEditor::_bind_methods() { @@ -1032,6 +1204,8 @@ void ScriptTextEditor::_bind_methods() { ClassDB::bind_method("_validate_script", &ScriptTextEditor::_validate_script); ClassDB::bind_method("_load_theme_settings", &ScriptTextEditor::_load_theme_settings); ClassDB::bind_method("_breakpoint_toggled", &ScriptTextEditor::_breakpoint_toggled); + ClassDB::bind_method("_lookup_connections", &ScriptTextEditor::_lookup_connections); + ClassDB::bind_method("_update_connected_methods", &ScriptTextEditor::_update_connected_methods); ClassDB::bind_method("_change_syntax_highlighter", &ScriptTextEditor::_change_syntax_highlighter); ClassDB::bind_method("_edit_option", &ScriptTextEditor::_edit_option); ClassDB::bind_method("_goto_line", &ScriptTextEditor::_goto_line); @@ -1091,7 +1265,8 @@ bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_ Dictionary d = p_data; if (d.has("type") && (String(d["type"]) == "resource" || String(d["type"]) == "files" || - String(d["type"]) == "nodes")) { + String(d["type"]) == "nodes" || + String(d["type"]) == "files_and_dirs")) { return true; } @@ -1153,7 +1328,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data te->insert_text_at_cursor(res->get_path()); } - if (d.has("type") && String(d["type"]) == "files") { + if (d.has("type") && (String(d["type"]) == "files" || String(d["type"]) == "files_and_dirs")) { Array files = d["files"]; @@ -1364,6 +1539,7 @@ ScriptTextEditor::ScriptTextEditor() { code_editor->set_code_complete_func(_code_complete_scripts, this); code_editor->get_text_edit()->connect("breakpoint_toggled", this, "_breakpoint_toggled"); code_editor->get_text_edit()->connect("symbol_lookup", this, "_lookup_symbol"); + code_editor->get_text_edit()->connect("info_clicked", this, "_lookup_connections"); code_editor->set_v_size_flags(SIZE_EXPAND_FILL); warnings_panel = memnew(RichTextLabel); @@ -1484,6 +1660,9 @@ ScriptTextEditor::ScriptTextEditor() { goto_line_dialog = memnew(GotoLineDialog); add_child(goto_line_dialog); + connection_info_dialog = memnew(ConnectionInfoDialog); + add_child(connection_info_dialog); + code_editor->get_text_edit()->set_drag_forwarding(this); } diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index b081a31c18..0dbc884594 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -32,8 +32,25 @@ #define SCRIPT_TEXT_EDITOR_H #include "scene/gui/color_picker.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/tree.h" #include "script_editor_plugin.h" +class ConnectionInfoDialog : public AcceptDialog { + + GDCLASS(ConnectionInfoDialog, AcceptDialog); + + Label *method; + Tree *tree; + + virtual void ok_pressed(); + +public: + void popup_connections(String p_method, Vector<Node *> p_nodes); + + ConnectionInfoDialog(); +}; + class ScriptTextEditor : public ScriptEditorBase { GDCLASS(ScriptTextEditor, ScriptEditorBase); @@ -45,6 +62,8 @@ class ScriptTextEditor : public ScriptEditorBase { Vector<String> functions; + List<Connection> missing_connections; + Vector<String> member_keywords; HBoxContainer *edit_hb; @@ -56,6 +75,7 @@ class ScriptTextEditor : public ScriptEditorBase { GotoLineDialog *goto_line_dialog; ScriptEditorQuickOpen *quick_open; + ConnectionInfoDialog *connection_info_dialog; PopupPanel *color_panel; ColorPicker *color_picker; @@ -144,6 +164,8 @@ protected: void _goto_line(int p_line) { goto_line(p_line); } void _lookup_symbol(const String &p_symbol, int p_row, int p_column); + void _lookup_connections(int p_row, String p_method); + void _convert_case(CodeTextEditor::CaseStyle p_case); Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); @@ -151,6 +173,8 @@ protected: void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); public: + void _update_connected_methods(); + virtual void add_syntax_highlighter(SyntaxHighlighter *p_highlighter); virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter); @@ -172,6 +196,8 @@ public: virtual void goto_line(int p_line, bool p_with_error = false); void goto_line_selection(int p_line, int p_begin, int p_end); + virtual void set_executing_line(int p_line); + virtual void clear_executing_line(); virtual void reload(bool p_soft); virtual void get_breakpoints(List<int> *p_breakpoints); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index d39e521113..31660a9e19 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -85,6 +85,7 @@ void ShaderTextEditor::_load_theme_settings() { Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color"); Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color"); + Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color"); Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color"); Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color"); Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); @@ -113,6 +114,7 @@ void ShaderTextEditor::_load_theme_settings() { get_text_edit()->add_color_override("member_variable_color", member_variable_color); get_text_edit()->add_color_override("mark_color", mark_color); get_text_edit()->add_color_override("breakpoint_color", breakpoint_color); + get_text_edit()->add_color_override("executing_line_color", executing_line_color); get_text_edit()->add_color_override("code_folding_color", code_folding_color); get_text_edit()->add_color_override("search_result_color", search_result_color); get_text_edit()->add_color_override("search_result_border_color", search_result_border_color); diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index ef3e17279c..0ccb60e39e 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -108,6 +108,7 @@ Skeleton2DEditor::Skeleton2DEditor() { options->get_popup()->add_item(TTR("Make Rest Pose (From Bones)"), MENU_OPTION_MAKE_REST); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Set Bones to Rest Pose"), MENU_OPTION_SET_REST); + options->set_switch_on_hover(true); options->get_popup()->connect("id_pressed", this, "_menu_option"); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index ba297539d3..95a70f2ae5 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -269,11 +269,21 @@ void SpatialEditorViewport::_select_clicked(bool p_append, bool p_single) { if (!clicked) return; - Spatial *sp = Object::cast_to<Spatial>(ObjectDB::get_instance(clicked)); - if (!sp) + Node *node = Object::cast_to<Node>(ObjectDB::get_instance(clicked)); + Spatial *selected = Object::cast_to<Spatial>(node); + if (!selected) return; - _select(sp, clicked_wants_append, true); + // Replace the node by the group if grouped + while (node && node != editor->get_edited_scene()->get_parent()) { + Spatial *selected_tmp = Object::cast_to<Spatial>(node); + if (selected_tmp && node->has_meta("_edit_group_")) { + selected = selected_tmp; + } + node = node->get_parent(); + } + + _select(selected, clicked_wants_append, true); } void SpatialEditorViewport::_select(Node *p_node, bool p_append, bool p_single) { @@ -511,6 +521,19 @@ void SpatialEditorViewport::_select_region() { item = item->get_owner(); } + // Replace the node by the group if grouped + if (item->is_class("Spatial")) { + Spatial *sel = Object::cast_to<Spatial>(item); + while (item && item != editor->get_edited_scene()->get_parent()) { + Spatial *selected_tmp = Object::cast_to<Spatial>(item); + if (selected_tmp && item->has_meta("_edit_group_")) { + sel = selected_tmp; + } + item = item->get_parent(); + } + item = sel; + } + if (selected.find(item) != -1) continue; Ref<EditorSpatialGizmo> seg = sp->get_gizmo(); @@ -1827,7 +1850,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (!sp) continue; - emit_signal("transform_key_request", sp, "", sp->get_transform()); + spatial_editor->emit_signal("transform_key_request", sp, "", sp->get_transform()); } set_message(TTR("Animation Key Inserted.")); @@ -2450,7 +2473,7 @@ void SpatialEditorViewport::_draw() { real_t max_speed = camera->get_zfar(); real_t scale_length = (max_speed - min_speed); - if (Math::abs(scale_length) > CMP_EPSILON) { + if (!Math::is_zero_approx(scale_length)) { real_t logscale_t = 1.0 - Math::log(1 + freelook_speed - min_speed) / Math::log(1 + scale_length); // There is no real maximum speed so that factor can become negative, @@ -2468,7 +2491,7 @@ void SpatialEditorViewport::_draw() { real_t max_distance = camera->get_zfar(); real_t scale_length = (max_distance - min_distance); - if (Math::abs(scale_length) > CMP_EPSILON) { + if (!Math::is_zero_approx(scale_length)) { real_t logscale_t = 1.0 - Math::log(1 + cursor.distance - min_distance) / Math::log(1 + scale_length); // There is no real maximum distance so that factor can become negative, @@ -4492,6 +4515,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { snap_selected_nodes_to_floor(); } break; case MENU_LOCK_SELECTED: { + undo_redo->create_action(TTR("Lock Selected")); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -4504,13 +4528,42 @@ void SpatialEditor::_menu_item_pressed(int p_option) { if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - spatial->set_meta("_edit_lock_", true); - emit_signal("item_lock_status_changed"); + undo_redo->add_do_method(spatial, "set_meta", "_edit_lock_", true); + undo_redo->add_undo_method(spatial, "remove_meta", "_edit_lock_"); + undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); } - _refresh_menu_icons(); + undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->commit_action(); } break; case MENU_UNLOCK_SELECTED: { + undo_redo->create_action(TTR("Unlock Selected")); + + List<Node *> &selection = editor_selection->get_selected_node_list(); + + for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { + + Spatial *spatial = Object::cast_to<Spatial>(E->get()); + if (!spatial || !spatial->is_visible_in_tree()) + continue; + + if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + continue; + + undo_redo->add_do_method(spatial, "remove_meta", "_edit_lock_"); + undo_redo->add_undo_method(spatial, "set_meta", "_edit_lock_", true); + undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); + } + + undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->commit_action(); + } break; + case MENU_GROUP_SELECTED: { + undo_redo->create_action(TTR("Group Selected")); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -4523,11 +4576,38 @@ void SpatialEditor::_menu_item_pressed(int p_option) { if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - spatial->set_meta("_edit_lock_", Variant()); - emit_signal("item_lock_status_changed"); + undo_redo->add_do_method(spatial, "set_meta", "_edit_group_", true); + undo_redo->add_undo_method(spatial, "remove_meta", "_edit_group_"); + undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); } - _refresh_menu_icons(); + undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->commit_action(); + } break; + case MENU_UNGROUP_SELECTED: { + undo_redo->create_action(TTR("Ungroup Selected")); + List<Node *> &selection = editor_selection->get_selected_node_list(); + + for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { + + Spatial *spatial = Object::cast_to<Spatial>(E->get()); + if (!spatial || !spatial->is_visible_in_tree()) + continue; + + if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + continue; + + undo_redo->add_do_method(spatial, "remove_meta", "_edit_group_"); + undo_redo->add_undo_method(spatial, "set_meta", "_edit_group_", true); + undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed"); + undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); + } + + undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->commit_action(); } break; } } @@ -4971,11 +5051,13 @@ bool SpatialEditor::is_any_freelook_active() const { void SpatialEditor::_refresh_menu_icons() { bool all_locked = true; + bool all_grouped = true; List<Node *> &selection = editor_selection->get_selected_node_list(); if (selection.empty()) { all_locked = false; + all_grouped = false; } else { for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { if (Object::cast_to<Spatial>(E->get()) && !Object::cast_to<Spatial>(E->get())->has_meta("_edit_lock_")) { @@ -4983,11 +5065,21 @@ void SpatialEditor::_refresh_menu_icons() { break; } } + for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { + if (Object::cast_to<Spatial>(E->get()) && !Object::cast_to<Spatial>(E->get())->has_meta("_edit_group_")) { + all_grouped = false; + break; + } + } } tool_button[TOOL_LOCK_SELECTED]->set_visible(!all_locked); tool_button[TOOL_LOCK_SELECTED]->set_disabled(selection.empty()); tool_button[TOOL_UNLOCK_SELECTED]->set_visible(all_locked); + + tool_button[TOOL_GROUP_SELECTED]->set_visible(!all_grouped); + tool_button[TOOL_GROUP_SELECTED]->set_disabled(selection.empty()); + tool_button[TOOL_UNGROUP_SELECTED]->set_visible(all_grouped); } template <typename T> @@ -5157,6 +5249,8 @@ void SpatialEditor::_notification(int p_what) { tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons")); tool_button[SpatialEditor::TOOL_LOCK_SELECTED]->set_icon(get_icon("Lock", "EditorIcons")); tool_button[SpatialEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_icon("Unlock", "EditorIcons")); + tool_button[SpatialEditor::TOOL_GROUP_SELECTED]->set_icon(get_icon("Group", "EditorIcons")); + tool_button[SpatialEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_icon("Ungroup", "EditorIcons")); tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons")); tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons")); @@ -5351,6 +5445,7 @@ void SpatialEditor::_bind_methods() { ADD_SIGNAL(MethodInfo("transform_key_request")); ADD_SIGNAL(MethodInfo("item_lock_status_changed")); + ADD_SIGNAL(MethodInfo("item_group_status_changed")); } void SpatialEditor::clear() { @@ -5464,6 +5559,18 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds); tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock the selected object (can be moved).")); + tool_button[TOOL_GROUP_SELECTED] = memnew(ToolButton); + hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]); + button_binds.write[0] = MENU_GROUP_SELECTED; + tool_button[TOOL_GROUP_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable.")); + + tool_button[TOOL_UNGROUP_SELECTED] = memnew(ToolButton); + hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]); + button_binds.write[0] = MENU_UNGROUP_SELECTED; + tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected.")); + hbc_menu->add_child(memnew(VSeparator)); tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(ToolButton); @@ -5498,7 +5605,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { ED_SHORTCUT("spatial_editor/front_view", TTR("Front View"), KEY_KP_1); ED_SHORTCUT("spatial_editor/left_view", TTR("Left View"), KEY_MASK_ALT + KEY_KP_3); ED_SHORTCUT("spatial_editor/right_view", TTR("Right View"), KEY_KP_3); - ED_SHORTCUT("spatial_editor/switch_perspective_orthogonal", TTR("Switch Perspective/Orthogonal view"), KEY_KP_5); + ED_SHORTCUT("spatial_editor/switch_perspective_orthogonal", TTR("Switch Perspective/Orthogonal View"), KEY_KP_5); ED_SHORTCUT("spatial_editor/insert_anim_key", TTR("Insert Animation Key"), KEY_K); ED_SHORTCUT("spatial_editor/focus_origin", TTR("Focus Origin"), KEY_O); ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), KEY_F); @@ -5519,7 +5626,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { hbc_menu->add_child(transform_menu); p = transform_menu->get_popup(); - p->add_shortcut(ED_SHORTCUT("spatial_editor/snap_to_floor", TTR("Snap object to floor"), KEY_PAGEDOWN), MENU_SNAP_TO_FLOOR); + p->add_shortcut(ED_SHORTCUT("spatial_editor/snap_to_floor", TTR("Snap Object to Floor"), KEY_PAGEDOWN), MENU_SNAP_TO_FLOOR); p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap...")), MENU_TRANSFORM_CONFIGURE_SNAP); p->add_separator(); p->add_shortcut(ED_SHORTCUT("spatial_editor/transform_dialog", TTR("Transform Dialog...")), MENU_TRANSFORM_DIALOG); @@ -5598,11 +5705,11 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { snap_dialog_vbc->add_margin_child(TTR("Translate Snap:"), snap_translate); snap_rotate = memnew(LineEdit); - snap_rotate->set_text("5"); + snap_rotate->set_text("15"); snap_dialog_vbc->add_margin_child(TTR("Rotate Snap (deg.):"), snap_rotate); snap_scale = memnew(LineEdit); - snap_scale->set_text("5"); + snap_scale->set_text("10"); snap_dialog_vbc->add_margin_child(TTR("Scale Snap (%):"), snap_scale); /* SETTINGS DIALOG */ @@ -5760,6 +5867,39 @@ Vector3 SpatialEditor::snap_point(Vector3 p_target, Vector3 p_start) const { return p_target; } +float SpatialEditor::get_translate_snap() const { + float snap_value; + if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + snap_value = snap_translate->get_text().to_double() / 10.0; + } else { + snap_value = snap_translate->get_text().to_double(); + } + + return snap_value; +} + +float SpatialEditor::get_rotate_snap() const { + float snap_value; + if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + snap_value = snap_rotate->get_text().to_double() / 3.0; + } else { + snap_value = snap_rotate->get_text().to_double(); + } + + return snap_value; +} + +float SpatialEditor::get_scale_snap() const { + float snap_value; + if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + snap_value = snap_scale->get_text().to_double() / 2.0; + } else { + snap_value = snap_scale->get_text().to_double(); + } + + return snap_value; +} + void SpatialEditorPlugin::_bind_methods() { ClassDB::bind_method("snap_cursor_to_plane", &SpatialEditorPlugin::snap_cursor_to_plane); @@ -5814,7 +5954,7 @@ SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) { editor->get_viewport()->add_child(spatial_editor); spatial_editor->hide(); - spatial_editor->connect("transform_key_request", editor, "_transform_keyed"); + spatial_editor->connect("transform_key_request", editor->get_inspector_dock(), "_transform_keyed"); } SpatialEditorPlugin::~SpatialEditorPlugin() { diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 4a9d34a7f7..f3a1e657cc 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -485,6 +485,8 @@ public: TOOL_MODE_LIST_SELECT, TOOL_LOCK_SELECTED, TOOL_UNLOCK_SELECTED, + TOOL_GROUP_SELECTED, + TOOL_UNGROUP_SELECTED, TOOL_MAX }; @@ -570,6 +572,8 @@ private: MENU_VIEW_CAMERA_SETTINGS, MENU_LOCK_SELECTED, MENU_UNLOCK_SELECTED, + MENU_GROUP_SELECTED, + MENU_UNGROUP_SELECTED, MENU_SNAP_TO_FLOOR }; @@ -673,9 +677,9 @@ public: ToolMode get_tool_mode() const { return tool_mode; } bool are_local_coords_enabled() const { return tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); } bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; } - float get_translate_snap() const { return snap_translate->get_text().to_double(); } - float get_rotate_snap() const { return snap_rotate->get_text().to_double(); } - float get_scale_snap() const { return snap_scale->get_text().to_double(); } + float get_translate_snap() const; + float get_rotate_snap() const; + float 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/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp index fbc72b1396..7642bfaf04 100644 --- a/editor/plugins/sprite_editor_plugin.cpp +++ b/editor/plugins/sprite_editor_plugin.cpp @@ -549,6 +549,7 @@ SpriteEditor::SpriteEditor() { options->get_popup()->add_item(TTR("Convert to Polygon2D"), MENU_OPTION_CONVERT_TO_POLYGON_2D); options->get_popup()->add_item(TTR("Create CollisionPolygon2D Sibling"), MENU_OPTION_CREATE_COLLISION_POLY_2D); options->get_popup()->add_item(TTR("Create LightOccluder2D Sibling"), MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D); + options->set_switch_on_hover(true); options->get_popup()->connect("id_pressed", this, "_menu_option"); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 5ba2fde763..c509202a88 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -38,23 +38,207 @@ void SpriteFramesEditor::_gui_input(Ref<InputEvent> p_event) { } -void SpriteFramesEditor::_notification(int p_what) { +void SpriteFramesEditor::_open_sprite_sheet() { + + file_split_sheet->clear_filters(); + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Texture", &extensions); + for (int i = 0; i < extensions.size(); i++) { + file_split_sheet->add_filter("*." + extensions[i]); + } + + file_split_sheet->popup_centered_ratio(); +} + +void SpriteFramesEditor::_sheet_preview_draw() { + + Size2i size = split_sheet_preview->get_size(); + int h = split_sheet_h->get_value(); + int v = split_sheet_v->get_value(); + int width = size.width / h; + int height = size.height / v; + const float a = 0.3; + for (int i = 1; i < h; i++) { + + int x = i * width; + split_sheet_preview->draw_line(Point2(x, 0), Point2(x, size.height), Color(1, 1, 1, a)); + split_sheet_preview->draw_line(Point2(x + 1, 0), Point2(x + 1, size.height), Color(0, 0, 0, a)); + + for (int j = 1; j < v; j++) { + + int y = j * height; + + split_sheet_preview->draw_line(Point2(0, y), Point2(size.width, y), Color(1, 1, 1, a)); + split_sheet_preview->draw_line(Point2(0, y + 1), Point2(size.width, y + 1), Color(0, 0, 0, a)); + } + } + + if (frames_selected.size() == 0) { + split_sheet_dialog->get_ok()->set_disabled(true); + split_sheet_dialog->get_ok()->set_text(TTR("No Frames Selected")); + return; + } + + Color accent = get_color("accent_color", "Editor"); + + for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) { + int idx = E->get(); + int xp = idx % h; + int yp = (idx - xp) / h; + int x = xp * width; + int y = yp * height; + + split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 0.35), true); + split_sheet_preview->draw_rect(Rect2(x + 0, y + 0, width - 0, height - 0), Color(0, 0, 0, 1), false); + split_sheet_preview->draw_rect(Rect2(x + 1, y + 1, width - 2, height - 2), Color(0, 0, 0, 1), false); + split_sheet_preview->draw_rect(Rect2(x + 2, y + 2, width - 4, height - 4), accent, false); + split_sheet_preview->draw_rect(Rect2(x + 3, y + 3, width - 6, height - 6), accent, false); + split_sheet_preview->draw_rect(Rect2(x + 4, y + 4, width - 8, height - 8), Color(0, 0, 0, 1), false); + split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 1), false); + } + + split_sheet_dialog->get_ok()->set_disabled(false); + split_sheet_dialog->get_ok()->set_text(vformat(TTR("Add %d Frame(s)"), frames_selected.size())); +} +void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { + + Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + Size2i size = split_sheet_preview->get_size(); + int h = split_sheet_h->get_value(); + int v = split_sheet_v->get_value(); + + int x = CLAMP(int(mb->get_position().x) * h / size.width, 0, h - 1); + int y = CLAMP(int(mb->get_position().y) * v / size.height, 0, v - 1); + + int idx = h * y + x; + + if (mb->get_shift() && last_frame_selected >= 0) { + //select multiple + int from = idx; + int to = last_frame_selected; + if (from > to) { + SWAP(from, to); + } + + for (int i = from; i <= to; i++) { + if (mb->get_control()) { + frames_selected.erase(i); + } else { + frames_selected.insert(i); + } + } + } else { + if (frames_selected.has(idx)) { + frames_selected.erase(idx); + } else { + frames_selected.insert(idx); + } + } + + last_frame_selected = idx; + split_sheet_preview->update(); + } +} - if (p_what == NOTIFICATION_ENTER_TREE) { +void SpriteFramesEditor::_sheet_add_frames() { - load->set_icon(get_icon("Load", "EditorIcons")); - copy->set_icon(get_icon("ActionCopy", "EditorIcons")); - paste->set_icon(get_icon("ActionPaste", "EditorIcons")); - empty->set_icon(get_icon("InsertBefore", "EditorIcons")); - empty2->set_icon(get_icon("InsertAfter", "EditorIcons")); - move_up->set_icon(get_icon("MoveLeft", "EditorIcons")); - move_down->set_icon(get_icon("MoveRight", "EditorIcons")); - _delete->set_icon(get_icon("Remove", "EditorIcons")); - new_anim->set_icon(get_icon("New", "EditorIcons")); - remove_anim->set_icon(get_icon("Remove", "EditorIcons")); - } else if (p_what == NOTIFICATION_READY) { + Size2i size = split_sheet_preview->get_size(); + int h = split_sheet_h->get_value(); + int v = split_sheet_v->get_value(); - add_constant_override("autohide", 1); // Fixes the dragger always showing up. + undo_redo->create_action(TTR("Add Frame")); + + int fc = frames->get_frame_count(edited_anim); + + for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) { + int idx = E->get(); + int width = size.width / h; + int height = size.height / v; + int xp = idx % h; + int yp = (idx - xp) / h; + int x = xp * width; + int y = yp * height; + + Ref<AtlasTexture> at; + at.instance(); + at->set_atlas(split_sheet_preview->get_texture()); + at->set_region(Rect2(x, y, width, height)); + + undo_redo->add_do_method(frames, "add_frame", edited_anim, at, -1); + undo_redo->add_undo_method(frames, "remove_frame", edited_anim, fc); + } + + undo_redo->add_do_method(this, "_update_library"); + undo_redo->add_undo_method(this, "_update_library"); + undo_redo->commit_action(); +} + +void SpriteFramesEditor::_sheet_select_clear_all_frames() { + + bool should_clear = true; + for (int i = 0; i < split_sheet_h->get_value() * split_sheet_v->get_value(); i++) { + if (!frames_selected.has(i)) { + frames_selected.insert(i); + should_clear = false; + } + } + if (should_clear) { + frames_selected.clear(); + } + + split_sheet_preview->update(); +} + +void SpriteFramesEditor::_sheet_spin_changed(double) { + + frames_selected.clear(); + last_frame_selected = -1; + split_sheet_preview->update(); +} + +void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { + + Ref<Resource> texture = ResourceLoader::load(p_file); + if (!texture.is_valid()) { + EditorNode::get_singleton()->show_warning("Unable to load images"); + ERR_FAIL_COND(!texture.is_valid()); + } + if (texture != split_sheet_preview->get_texture()) { + //different texture, reset to 4x4 + split_sheet_h->set_value(4); + split_sheet_v->set_value(4); + } + frames_selected.clear(); + last_frame_selected = -1; + + split_sheet_preview->set_texture(texture); + split_sheet_dialog->popup_centered_ratio(0.65); +} + +void SpriteFramesEditor::_notification(int p_what) { + + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + load->set_icon(get_icon("Load", "EditorIcons")); + load_sheet->set_icon(get_icon("SpriteSheet", "EditorIcons")); + copy->set_icon(get_icon("ActionCopy", "EditorIcons")); + paste->set_icon(get_icon("ActionPaste", "EditorIcons")); + empty->set_icon(get_icon("InsertBefore", "EditorIcons")); + empty2->set_icon(get_icon("InsertAfter", "EditorIcons")); + move_up->set_icon(get_icon("MoveLeft", "EditorIcons")); + move_down->set_icon(get_icon("MoveRight", "EditorIcons")); + _delete->set_icon(get_icon("Remove", "EditorIcons")); + new_anim->set_icon(get_icon("New", "EditorIcons")); + remove_anim->set_icon(get_icon("Remove", "EditorIcons")); + } // Fallthrough. + case NOTIFICATION_THEME_CHANGED: { + splite_sheet_scroll->add_style_override("bg", get_stylebox("bg", "Tree")); + } break; + case NOTIFICATION_READY: { + add_constant_override("autohide", 1); // Fixes the dragger always showing up. + } break; } } @@ -72,6 +256,7 @@ void SpriteFramesEditor::_file_load_request(const PoolVector<String> &p_path, in if (resource.is_null()) { dialog->set_text(TTR("ERROR: Couldn't load frame resource!")); dialog->set_title(TTR("Error!")); + //dialog->get_cancel()->set_text("Close"); dialog->get_ok()->set_text(TTR("Close")); dialog->popup_centered_minsize(); @@ -278,6 +463,10 @@ void SpriteFramesEditor::_animation_select() { if (updating) return; + double value = anim_speed->get_line_edit()->get_text().to_double(); + if (!Math::is_equal_approx(value, frames->get_animation_speed(edited_anim))) + _animation_fps_changed(value); + TreeItem *selected = animations->get_selected(); ERR_FAIL_COND(!selected); edited_anim = selected->get_text(0); @@ -655,6 +844,13 @@ void SpriteFramesEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw); ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw); ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpriteFramesEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("_prepare_sprite_sheet"), &SpriteFramesEditor::_prepare_sprite_sheet); + ClassDB::bind_method(D_METHOD("_open_sprite_sheet"), &SpriteFramesEditor::_open_sprite_sheet); + ClassDB::bind_method(D_METHOD("_sheet_preview_draw"), &SpriteFramesEditor::_sheet_preview_draw); + ClassDB::bind_method(D_METHOD("_sheet_preview_input"), &SpriteFramesEditor::_sheet_preview_input); + ClassDB::bind_method(D_METHOD("_sheet_spin_changed"), &SpriteFramesEditor::_sheet_spin_changed); + ClassDB::bind_method(D_METHOD("_sheet_add_frames"), &SpriteFramesEditor::_sheet_add_frames); + ClassDB::bind_method(D_METHOD("_sheet_select_clear_all_frames"), &SpriteFramesEditor::_sheet_select_clear_all_frames); } SpriteFramesEditor::SpriteFramesEditor() { @@ -712,9 +908,15 @@ SpriteFramesEditor::SpriteFramesEditor() { sub_vb->add_child(hbc); load = memnew(ToolButton); - load->set_tooltip(TTR("Load Resource")); + load->set_tooltip(TTR("Add a Texture from File")); hbc->add_child(load); + load_sheet = memnew(ToolButton); + load_sheet->set_tooltip(TTR("Add Frames from a Sprite Sheet")); + hbc->add_child(load_sheet); + + hbc->add_child(memnew(VSeparator)); + copy = memnew(ToolButton); copy->set_tooltip(TTR("Copy")); hbc->add_child(copy); @@ -723,6 +925,8 @@ SpriteFramesEditor::SpriteFramesEditor() { paste->set_tooltip(TTR("Paste")); hbc->add_child(paste); + hbc->add_spacer(false); + empty = memnew(ToolButton); empty->set_tooltip(TTR("Insert Empty (Before)")); hbc->add_child(empty); @@ -731,7 +935,7 @@ SpriteFramesEditor::SpriteFramesEditor() { empty2->set_tooltip(TTR("Insert Empty (After)")); hbc->add_child(empty2); - hbc->add_spacer(false); + hbc->add_child(memnew(VSeparator)); move_up = memnew(ToolButton); move_up->set_tooltip(TTR("Move (Before)")); @@ -766,6 +970,7 @@ SpriteFramesEditor::SpriteFramesEditor() { add_child(dialog); load->connect("pressed", this, "_load_pressed"); + load_sheet->connect("pressed", this, "_open_sprite_sheet"); _delete->connect("pressed", this, "_delete_pressed"); copy->connect("pressed", this, "_copy_pressed"); paste->connect("pressed", this, "_paste_pressed"); @@ -780,6 +985,66 @@ SpriteFramesEditor::SpriteFramesEditor() { updating = false; edited_anim = "default"; + + split_sheet_dialog = memnew(ConfirmationDialog); + add_child(split_sheet_dialog); + VBoxContainer *split_sheet_vb = memnew(VBoxContainer); + split_sheet_dialog->add_child(split_sheet_vb); + split_sheet_dialog->set_title(TTR("Select Frames")); + split_sheet_dialog->connect("confirmed", this, "_sheet_add_frames"); + + HBoxContainer *split_sheet_hb = memnew(HBoxContainer); + + Label *ss_label = memnew(Label(TTR("Horizontal:"))); + split_sheet_hb->add_child(ss_label); + split_sheet_h = memnew(SpinBox); + split_sheet_h->set_min(1); + split_sheet_h->set_max(128); + split_sheet_h->set_step(1); + split_sheet_hb->add_child(split_sheet_h); + split_sheet_h->connect("value_changed", this, "_sheet_spin_changed"); + + ss_label = memnew(Label(TTR("Vertical:"))); + split_sheet_hb->add_child(ss_label); + split_sheet_v = memnew(SpinBox); + split_sheet_v->set_min(1); + split_sheet_v->set_max(128); + split_sheet_v->set_step(1); + split_sheet_hb->add_child(split_sheet_v); + split_sheet_v->connect("value_changed", this, "_sheet_spin_changed"); + + split_sheet_hb->add_spacer(); + + Button *select_clear_all = memnew(Button); + select_clear_all->set_text(TTR("Select/Clear All Frames")); + select_clear_all->connect("pressed", this, "_sheet_select_clear_all_frames"); + split_sheet_hb->add_child(select_clear_all); + + split_sheet_vb->add_child(split_sheet_hb); + + split_sheet_preview = memnew(TextureRect); + split_sheet_preview->set_expand(false); + split_sheet_preview->set_mouse_filter(MOUSE_FILTER_PASS); + split_sheet_preview->connect("draw", this, "_sheet_preview_draw"); + split_sheet_preview->connect("gui_input", this, "_sheet_preview_input"); + + splite_sheet_scroll = memnew(ScrollContainer); + splite_sheet_scroll->set_enable_h_scroll(true); + splite_sheet_scroll->set_enable_v_scroll(true); + splite_sheet_scroll->set_v_size_flags(SIZE_EXPAND_FILL); + CenterContainer *cc = memnew(CenterContainer); + cc->add_child(split_sheet_preview); + cc->set_h_size_flags(SIZE_EXPAND_FILL); + cc->set_v_size_flags(SIZE_EXPAND_FILL); + splite_sheet_scroll->add_child(cc); + + split_sheet_vb->add_child(splite_sheet_scroll); + + file_split_sheet = memnew(EditorFileDialog); + file_split_sheet->set_title(TTR("Create Frames from Sprite Sheet")); + file_split_sheet->set_mode(EditorFileDialog::MODE_OPEN_FILE); + add_child(file_split_sheet); + file_split_sheet->connect("file_selected", this, "_prepare_sprite_sheet"); } void SpriteFramesEditorPlugin::edit(Object *p_object) { diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index 55dd10074e..d64431cde7 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -37,6 +37,7 @@ #include "scene/gui/dialogs.h" #include "scene/gui/file_dialog.h" #include "scene/gui/split_container.h" +#include "scene/gui/texture_rect.h" #include "scene/gui/tree.h" class SpriteFramesEditor : public HSplitContainer { @@ -44,6 +45,7 @@ class SpriteFramesEditor : public HSplitContainer { GDCLASS(SpriteFramesEditor, HSplitContainer); ToolButton *load; + ToolButton *load_sheet; ToolButton *_delete; ToolButton *copy; ToolButton *paste; @@ -71,6 +73,15 @@ class SpriteFramesEditor : public HSplitContainer { StringName edited_anim; + ConfirmationDialog *split_sheet_dialog; + ScrollContainer *splite_sheet_scroll; + TextureRect *split_sheet_preview; + SpinBox *split_sheet_h; + SpinBox *split_sheet_v; + EditorFileDialog *file_split_sheet; + Set<int> frames_selected; + int last_frame_selected; + void _load_pressed(); void _load_scene_pressed(); void _file_load_request(const PoolVector<String> &p_path, int p_at_pos = -1); @@ -99,6 +110,14 @@ class SpriteFramesEditor : public HSplitContainer { bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); + void _open_sprite_sheet(); + void _prepare_sprite_sheet(const String &p_file); + void _sheet_preview_draw(); + void _sheet_spin_changed(double); + void _sheet_preview_input(const Ref<InputEvent> &p_event); + void _sheet_add_frames(); + void _sheet_select_clear_all_frames(); + protected: void _notification(int p_what); void _gui_input(Ref<InputEvent> p_event); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index fe32c97a64..c5036b3c5e 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -66,7 +66,6 @@ void TextEditor::_change_syntax_highlighter(int p_idx) { el = el->next(); } set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]); - EditorSettings::get_singleton()->set_project_metadata("text_editor", "syntax_highlighter", p_idx); } void TextEditor::_load_theme_settings() { @@ -95,6 +94,7 @@ void TextEditor::_load_theme_settings() { Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color"); Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color"); + Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color"); Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color"); Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color"); Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); @@ -125,6 +125,7 @@ void TextEditor::_load_theme_settings() { text_edit->add_color_override("function_color", function_color); text_edit->add_color_override("member_variable_color", member_variable_color); text_edit->add_color_override("breakpoint_color", breakpoint_color); + text_edit->add_color_override("executing_line_color", executing_line_color); text_edit->add_color_override("mark_color", mark_color); text_edit->add_color_override("code_folding_color", code_folding_color); text_edit->add_color_override("search_result_color", search_result_color); @@ -201,7 +202,6 @@ void TextEditor::reload_text() { int v = te->get_v_scroll(); te->set_text(text_file->get_text()); - te->clear_undo_history(); te->cursor_set_line(row); te->cursor_set_column(column); te->set_h_scroll(h); @@ -234,6 +234,14 @@ Variant TextEditor::get_edit_state() { void TextEditor::set_edit_state(const Variant &p_state) { code_editor->set_edit_state(p_state); + + Dictionary state = p_state; + if (state.has("syntax_highlighter")) { + int idx = highlighter_menu->get_item_idx_from_text(state["syntax_highlighter"]); + if (idx >= 0) { + _change_syntax_highlighter(idx); + } + } } void TextEditor::trim_trailing_whitespace() { @@ -261,6 +269,15 @@ void TextEditor::goto_line(int p_line, bool p_with_error) { code_editor->goto_line(p_line); } +void TextEditor::set_executing_line(int p_line) { + + code_editor->set_executing_line(p_line); +} + +void TextEditor::clear_executing_line() { + code_editor->clear_executing_line(); +} + void TextEditor::ensure_focus() { code_editor->get_text_edit()->grab_focus(); @@ -299,7 +316,6 @@ void TextEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: _load_theme_settings(); - _change_syntax_highlighter(EditorSettings::get_singleton()->get_project_metadata("text_editor", "syntax_highlighter", 0)); break; } } diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 3c136277df..767001e2f6 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -123,6 +123,8 @@ public: virtual Vector<String> get_functions(); virtual void get_breakpoints(List<int> *p_breakpoints); virtual void goto_line(int p_line, bool p_with_error = false); + virtual void set_executing_line(int p_line); + virtual void clear_executing_line(); virtual void trim_trailing_whitespace(); virtual void convert_indent_to_spaces(); virtual void convert_indent_to_tabs(); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index f741040fa8..4e15bd5116 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -135,8 +135,7 @@ void TextureRegionEditor::_region_draw() { Ref<Texture> select_handle = get_icon("EditorHandle", "EditorIcons"); - Rect2 scroll_rect(Point2(), mtx.basis_xform(base_tex->get_size())); - scroll_rect.expand_to(mtx.basis_xform(edit_draw->get_size())); + Rect2 scroll_rect; Vector2 endpoints[4] = { mtx.basis_xform(rect.position), @@ -167,7 +166,9 @@ void TextureRegionEditor::_region_draw() { scroll_rect.expand_to(endpoints[i]); } - scroll_rect = scroll_rect.grow(200); + scroll_rect.position -= edit_draw->get_size(); + scroll_rect.size += edit_draw->get_size() * 2.0; + updating_scroll = true; hscroll->set_min(scroll_rect.position.x); hscroll->set_max(scroll_rect.position.x + scroll_rect.size.x); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index e9b9c03c1e..85743c96d6 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -36,7 +36,7 @@ void ThemeEditor::edit(const Ref<Theme> &p_theme) { theme = p_theme; - main_vb->set_theme(p_theme); + main_container->set_theme(p_theme); } void ThemeEditor::_propagate_redraw(Control *p_at) { @@ -53,7 +53,7 @@ void ThemeEditor::_propagate_redraw(Control *p_at) { void ThemeEditor::_refresh_interval() { - _propagate_redraw(main_vb); + _propagate_redraw(main_container); } void ThemeEditor::_type_menu_cbk(int p_option) { @@ -86,7 +86,7 @@ void ThemeEditor::_name_menu_about_to_show() { } name_menu->get_popup()->clear(); - + name_menu->get_popup()->set_size(Size2()); for (List<StringName>::Element *E = names.front(); E; E = E->next()) { name_menu->get_popup()->add_item(E->get()); @@ -574,7 +574,6 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { } } - //types.sort(); types.sort_custom<StringName::AlphCompare>(); for (List<StringName>::Element *E = types.front(); E; E = E->next()) { @@ -610,30 +609,14 @@ ThemeEditor::ThemeEditor() { time_left = 0; - scroll = memnew(ScrollContainer); - add_child(scroll); - scroll->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 3); - scroll->set_margin(MARGIN_TOP, 30 * EDSCALE); - //scroll->set_enable_h_scroll(true); - scroll->set_enable_v_scroll(true); - scroll->set_enable_h_scroll(false); - - Panel *panel = memnew(Panel); - scroll->add_child(panel); - panel->set_custom_minimum_size(Size2(500, 800) * EDSCALE); - panel->set_theme(Theme::get_default()); - panel->set_h_size_flags(SIZE_EXPAND_FILL); + HBoxContainer *top_menu = memnew(HBoxContainer); + add_child(top_menu); - main_vb = memnew(VBoxContainer); - panel->add_child(main_vb); - main_vb->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 4 * EDSCALE); - - HBoxContainer *hb_menu = memnew(HBoxContainer); - main_vb->add_child(hb_menu); + top_menu->add_child(memnew(Label(TTR("Preview:")))); + top_menu->add_spacer(false); theme_menu = memnew(MenuButton); - theme_menu->set_text(TTR("Edit theme...")); - theme_menu->set_flat(false); + theme_menu->set_text(TTR("Edit Theme")); theme_menu->set_tooltip(TTR("Theme editing menu.")); theme_menu->get_popup()->add_item(TTR("Add Item"), POPUP_ADD); theme_menu->get_popup()->add_item(TTR("Add Class Items"), POPUP_CLASS_ADD); @@ -643,27 +626,60 @@ ThemeEditor::ThemeEditor() { theme_menu->get_popup()->add_item(TTR("Create Empty Template"), POPUP_CREATE_EMPTY); theme_menu->get_popup()->add_item(TTR("Create Empty Editor Template"), POPUP_CREATE_EDITOR_EMPTY); theme_menu->get_popup()->add_item(TTR("Create From Current Editor Theme"), POPUP_IMPORT_EDITOR_THEME); - add_child(theme_menu); - theme_menu->set_position(Vector2(3, 3) * EDSCALE); + top_menu->add_child(theme_menu); theme_menu->get_popup()->connect("id_pressed", this, "_theme_menu_cbk"); + scroll = memnew(ScrollContainer); + add_child(scroll); + scroll->set_enable_v_scroll(true); + scroll->set_enable_h_scroll(false); + scroll->set_v_size_flags(SIZE_EXPAND_FILL); + + main_container = memnew(MarginContainer); + scroll->add_child(main_container); + main_container->set_clip_contents(true); + main_container->set_custom_minimum_size(Size2(700, 0) * EDSCALE); + main_container->set_v_size_flags(SIZE_EXPAND_FILL); + main_container->set_h_size_flags(SIZE_EXPAND_FILL); + + //// Preview Controls //// + + Panel *panel = memnew(Panel); + main_container->add_child(panel); + panel->set_theme(Theme::get_default()); + + MarginContainer *mc = memnew(MarginContainer); + main_container->add_child(mc); + mc->set_theme(Theme::get_default()); + mc->add_constant_override("margin_right", 4 * EDSCALE); + mc->add_constant_override("margin_top", 4 * EDSCALE); + mc->add_constant_override("margin_left", 4 * EDSCALE); + mc->add_constant_override("margin_bottom", 4 * EDSCALE); + HBoxContainer *main_hb = memnew(HBoxContainer); - main_vb->add_child(main_hb); + mc->add_child(main_hb); VBoxContainer *first_vb = memnew(VBoxContainer); - first_vb->set_h_size_flags(SIZE_EXPAND_FILL); main_hb->add_child(first_vb); - - //main_panel->add_child(panel); - //panel->set_anchors_and_margins_preset(Control::PRESET_WIDE); - //panel->set_margin( MARGIN_TOP,20 ); + first_vb->set_h_size_flags(SIZE_EXPAND_FILL); + first_vb->add_constant_override("separation", 10 * EDSCALE); first_vb->add_child(memnew(Label("Label"))); first_vb->add_child(memnew(Button("Button"))); + Button *bt = memnew(Button); + bt->set_text(TTR("Toggle Button")); + bt->set_toggle_mode(true); + bt->set_pressed(true); + first_vb->add_child(bt); + bt = memnew(Button); + bt->set_text(TTR("Disabled Button")); + bt->set_disabled(true); + first_vb->add_child(bt); ToolButton *tb = memnew(ToolButton); tb->set_text("ToolButton"); first_vb->add_child(tb); + CheckButton *cb = memnew(CheckButton); cb->set_text("CheckButton"); first_vb->add_child(cb); @@ -671,23 +687,11 @@ ThemeEditor::ThemeEditor() { cbx->set_text("CheckBox"); first_vb->add_child(cbx); - VBoxContainer *bg = memnew(VBoxContainer); - bg->set_v_size_flags(SIZE_EXPAND_FILL); - VBoxContainer *gbvb = memnew(VBoxContainer); - gbvb->set_v_size_flags(SIZE_EXPAND_FILL); - CheckBox *rbx1 = memnew(CheckBox); - rbx1->set_text(TTR("CheckBox Radio1")); - rbx1->set_pressed(true); - gbvb->add_child(rbx1); - CheckBox *rbx2 = memnew(CheckBox); - rbx2->set_text(TTR("CheckBox Radio2")); - gbvb->add_child(rbx2); - bg->add_child(gbvb); - first_vb->add_child(bg); - MenuButton *test_menu_button = memnew(MenuButton); test_menu_button->set_text("MenuButton"); test_menu_button->get_popup()->add_item(TTR("Item")); + test_menu_button->get_popup()->add_item(TTR("Disabled Item")); + test_menu_button->get_popup()->set_item_disabled(1, true); test_menu_button->get_popup()->add_separator(); test_menu_button->get_popup()->add_check_item(TTR("Check Item")); test_menu_button->get_popup()->add_check_item(TTR("Checked Item")); @@ -696,6 +700,14 @@ ThemeEditor::ThemeEditor() { test_menu_button->get_popup()->add_radio_check_item(TTR("Radio Item")); test_menu_button->get_popup()->add_radio_check_item(TTR("Checked Radio Item")); test_menu_button->get_popup()->set_item_checked(6, true); + test_menu_button->get_popup()->add_separator(TTR("Named Sep.")); + + PopupMenu *test_submenu = memnew(PopupMenu); + test_menu_button->get_popup()->add_child(test_submenu); + test_submenu->set_name("submenu"); + test_menu_button->get_popup()->add_submenu_item(TTR("Submenu"), "submenu"); + test_submenu->add_item(TTR("Item 1")); + test_submenu->add_item(TTR("Item 2")); first_vb->add_child(test_menu_button); OptionButton *test_option_button = memnew(OptionButton); @@ -705,21 +717,7 @@ ThemeEditor::ThemeEditor() { test_option_button->add_item(TTR("Many")); test_option_button->add_item(TTR("Options")); first_vb->add_child(test_option_button); - - ColorPickerButton *cpb = memnew(ColorPickerButton); - first_vb->add_child(cpb); - - first_vb->add_child(memnew(HSeparator)); - first_vb->add_child(memnew(HSlider)); - first_vb->add_child(memnew(HScrollBar)); - first_vb->add_child(memnew(SpinBox)); - ProgressBar *pb = memnew(ProgressBar); - pb->set_value(50); - first_vb->add_child(pb); - Panel *pn = memnew(Panel); - pn->set_custom_minimum_size(Size2(40, 40) * EDSCALE); - first_vb->add_child(pn); - first_vb->add_constant_override("separation", 10 * EDSCALE); + first_vb->add_child(memnew(ColorPickerButton)); VBoxContainer *second_vb = memnew(VBoxContainer); second_vb->set_h_size_flags(SIZE_EXPAND_FILL); @@ -728,50 +726,48 @@ ThemeEditor::ThemeEditor() { LineEdit *le = memnew(LineEdit); le->set_text("LineEdit"); second_vb->add_child(le); + le = memnew(LineEdit); + le->set_text(TTR("Disabled LineEdit")); + le->set_editable(false); + second_vb->add_child(le); TextEdit *te = memnew(TextEdit); te->set_text("TextEdit"); - //te->set_v_size_flags(SIZE_EXPAND_FILL); - te->set_custom_minimum_size(Size2(0, 160) * EDSCALE); + te->set_custom_minimum_size(Size2(0, 100) * EDSCALE); second_vb->add_child(te); + second_vb->add_child(memnew(SpinBox)); - Tree *test_tree = memnew(Tree); - second_vb->add_child(test_tree); - test_tree->set_custom_minimum_size(Size2(0, 160) * EDSCALE); - - TreeItem *item = test_tree->create_item(); - item->set_editable(0, true); - item->set_text(0, "Tree"); - item = test_tree->create_item(test_tree->get_root()); - item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - item->set_editable(0, true); - item->set_text(0, "Check"); - item = test_tree->create_item(test_tree->get_root()); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0, true); - item->set_range_config(0, 0, 20, 0.1); - item->set_range(0, 2); - item = test_tree->create_item(test_tree->get_root()); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0, true); - item->set_text(0, TTR("Has,Many,Options")); - item->set_range(0, 2); + HBoxContainer *vhb = memnew(HBoxContainer); + second_vb->add_child(vhb); + vhb->set_custom_minimum_size(Size2(0, 100) * EDSCALE); + vhb->add_child(memnew(VSlider)); + VScrollBar *vsb = memnew(VScrollBar); + vsb->set_page(25); + vhb->add_child(vsb); + vhb->add_child(memnew(VSeparator)); + VBoxContainer *hvb = memnew(VBoxContainer); + vhb->add_child(hvb); + hvb->set_alignment(ALIGN_CENTER); + hvb->set_h_size_flags(SIZE_EXPAND_FILL); + hvb->add_child(memnew(HSlider)); + HScrollBar *hsb = memnew(HScrollBar); + hsb->set_page(25); + hvb->add_child(hsb); + HSlider *hs = memnew(HSlider); + hs->set_editable(false); + hvb->add_child(hs); + hvb->add_child(memnew(HSeparator)); + ProgressBar *pb = memnew(ProgressBar); + pb->set_value(50); + hvb->add_child(pb); VBoxContainer *third_vb = memnew(VBoxContainer); third_vb->set_h_size_flags(SIZE_EXPAND_FILL); - third_vb->add_constant_override("separation", 10); - + third_vb->add_constant_override("separation", 10 * EDSCALE); main_hb->add_child(third_vb); - HBoxContainer *vhb = memnew(HBoxContainer); - vhb->set_custom_minimum_size(Size2(0, 160) * EDSCALE); - vhb->add_child(memnew(VSeparator)); - vhb->add_child(memnew(VSlider)); - vhb->add_child(memnew(VScrollBar)); - third_vb->add_child(vhb); - TabContainer *tc = memnew(TabContainer); third_vb->add_child(tc); - tc->set_custom_minimum_size(Size2(0, 160) * EDSCALE); + tc->set_custom_minimum_size(Size2(0, 135) * EDSCALE); Control *tcc = memnew(Control); tcc->set_name(TTR("Tab 1")); tc->add_child(tcc); @@ -781,9 +777,41 @@ ThemeEditor::ThemeEditor() { tcc = memnew(Control); tcc->set_name(TTR("Tab 3")); tc->add_child(tcc); + tc->set_tab_disabled(2, true); + + Tree *test_tree = memnew(Tree); + third_vb->add_child(test_tree); + test_tree->set_custom_minimum_size(Size2(0, 175) * EDSCALE); + test_tree->add_constant_override("draw_relationship_lines", 1); + + TreeItem *item = test_tree->create_item(); + item->set_text(0, "Tree"); + item = test_tree->create_item(test_tree->get_root()); + item->set_text(0, "Item"); + item = test_tree->create_item(test_tree->get_root()); + item->set_editable(0, true); + item->set_text(0, TTR("Editable Item")); + TreeItem *sub_tree = test_tree->create_item(test_tree->get_root()); + sub_tree->set_text(0, TTR("Subtree")); + item = test_tree->create_item(sub_tree); + item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); + item->set_editable(0, true); + item->set_text(0, "Check Item"); + item = test_tree->create_item(sub_tree); + item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); + item->set_editable(0, true); + item->set_range_config(0, 0, 20, 0.1); + item->set_range(0, 2); + item = test_tree->create_item(sub_tree); + item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); + item->set_editable(0, true); + item->set_text(0, TTR("Has,Many,Options")); + item->set_range(0, 2); main_hb->add_constant_override("separation", 20 * EDSCALE); + //////// + add_del_dialog = memnew(ConfirmationDialog); add_del_dialog->hide(); add_child(add_del_dialog); @@ -802,6 +830,7 @@ ThemeEditor::ThemeEditor() { type_edit->set_h_size_flags(SIZE_EXPAND_FILL); type_hbc->add_child(type_edit); type_menu = memnew(MenuButton); + type_menu->set_flat(false); type_menu->set_text(".."); type_hbc->add_child(type_menu); @@ -819,6 +848,7 @@ ThemeEditor::ThemeEditor() { name_edit->set_h_size_flags(SIZE_EXPAND_FILL); name_hbc->add_child(name_edit); name_menu = memnew(MenuButton); + type_menu->set_flat(false); name_menu->set_text(".."); name_hbc->add_child(name_menu); @@ -844,9 +874,6 @@ ThemeEditor::ThemeEditor() { file_dialog->add_filter("*.theme ; Theme File"); add_child(file_dialog); file_dialog->connect("file_selected", this, "_save_template_cbk"); - - //MenuButton *name_menu; - //LineEdit *name_edit; } void ThemeEditorPlugin::edit(Object *p_node) { @@ -886,7 +913,6 @@ ThemeEditorPlugin::ThemeEditorPlugin(EditorNode *p_node) { theme_editor = memnew(ThemeEditor); theme_editor->set_custom_minimum_size(Size2(0, 200)); - //p_node->get_viewport()->add_child(theme_editor); button = editor->add_bottom_panel_item(TTR("Theme"), theme_editor); button->hide(); } diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h index 352988d69e..cc236907a9 100644 --- a/editor/plugins/theme_editor_plugin.h +++ b/editor/plugins/theme_editor_plugin.h @@ -33,6 +33,7 @@ #include "scene/gui/check_box.h" #include "scene/gui/file_dialog.h" +#include "scene/gui/margin_container.h" #include "scene/gui/option_button.h" #include "scene/gui/scroll_container.h" #include "scene/gui/texture_rect.h" @@ -40,12 +41,12 @@ #include "editor/editor_node.h" -class ThemeEditor : public Control { +class ThemeEditor : public VBoxContainer { - GDCLASS(ThemeEditor, Control); + GDCLASS(ThemeEditor, VBoxContainer); ScrollContainer *scroll; - VBoxContainer *main_vb; + MarginContainer *main_container; Ref<Theme> theme; EditorFileDialog *file_dialog; diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 33e4bb2336..29a54f815d 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -66,6 +66,11 @@ void TileMapEditor::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { + paint_button->set_icon(get_icon("Edit", "EditorIcons")); + bucket_fill_button->set_icon(get_icon("Bucket", "EditorIcons")); + picker_button->set_icon(get_icon("ColorPick", "EditorIcons")); + select_button->set_icon(get_icon("ActionCopy", "EditorIcons")); + rotate_left_button->set_icon(get_icon("Rotate270", "EditorIcons")); rotate_right_button->set_icon(get_icon("Rotate90", "EditorIcons")); flip_horizontal_button->set_icon(get_icon("MirrorX", "EditorIcons")); @@ -76,9 +81,6 @@ void TileMapEditor::_notification(int p_what) { search_box->set_clear_button_enabled(true); PopupMenu *p = options->get_popup(); - p->set_item_icon(p->get_item_index(OPTION_PAINTING), get_icon("Edit", "EditorIcons")); - p->set_item_icon(p->get_item_index(OPTION_PICK_TILE), get_icon("ColorPick", "EditorIcons")); - p->set_item_icon(p->get_item_index(OPTION_SELECT), get_icon("ActionCopy", "EditorIcons")); p->set_item_icon(p->get_item_index(OPTION_CUT), get_icon("ActionCut", "EditorIcons")); p->set_item_icon(p->get_item_index(OPTION_COPY), get_icon("Duplicate", "EditorIcons")); p->set_item_icon(p->get_item_index(OPTION_ERASE_SELECTION), get_icon("Remove", "EditorIcons")); @@ -87,37 +89,54 @@ void TileMapEditor::_notification(int p_what) { } } -void TileMapEditor::_menu_option(int p_option) { +void TileMapEditor::_update_button_tool() { - switch (p_option) { - - case OPTION_PAINTING: { - // NOTE: We do not set tool = TOOL_PAINTING as this begins painting - // immediately without pressing the left mouse button first - tool = TOOL_NONE; - - CanvasItemEditor::get_singleton()->update_viewport(); + ToolButton *tb[4] = { paint_button, bucket_fill_button, picker_button, select_button }; + // Unpress all buttons + for (int i = 0; i < 4; i++) { + tb[i]->set_pressed(false); + } + // Press the good button + switch (tool) { + case TOOL_NONE: + case TOOL_PAINTING: { + paint_button->set_pressed(true); } break; - case OPTION_BUCKET: { - - tool = TOOL_BUCKET; - - CanvasItemEditor::get_singleton()->update_viewport(); + case TOOL_BUCKET: { + bucket_fill_button->set_pressed(true); + } break; + case TOOL_PICKING: { + picker_button->set_pressed(true); } break; - case OPTION_PICK_TILE: { + case TOOL_SELECTING: { + select_button->set_pressed(true); + } break; + default: + break; + } - tool = TOOL_PICKING; + if (tool != TOOL_PICKING) + last_tool = tool; +} - CanvasItemEditor::get_singleton()->update_viewport(); - } break; - case OPTION_SELECT: { +void TileMapEditor::_button_tool_select(int p_tool) { + tool = (Tool)p_tool; + _update_button_tool(); + switch (tool) { + case TOOL_SELECTING: { - tool = TOOL_SELECTING; selection_active = false; - - CanvasItemEditor::get_singleton()->update_viewport(); } break; + default: + break; + } + CanvasItemEditor::get_singleton()->update_viewport(); +} + +void TileMapEditor::_menu_option(int p_option) { + + switch (p_option) { case OPTION_COPY: { _update_copydata(); @@ -168,6 +187,7 @@ void TileMapEditor::_menu_option(int p_option) { } } break; } + _update_button_tool(); } void TileMapEditor::_palette_selected(int index) { @@ -220,22 +240,23 @@ void TileMapEditor::set_selected_tiles(Vector<int> p_tiles) { palette->ensure_current_is_visible(); } -void TileMapEditor::_create_set_cell_undo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new) { +Dictionary TileMapEditor::_create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord) { - Dictionary cell_old; - Dictionary cell_new; + Dictionary cell; - cell_old["id"] = p_cell_old.idx; - cell_old["flip_h"] = p_cell_old.xf; - cell_old["flip_y"] = p_cell_old.yf; - cell_old["transpose"] = p_cell_old.tr; - cell_old["auto_coord"] = p_cell_old.ac; + cell["id"] = tile; + cell["flip_h"] = flip_x; + cell["flip_y"] = flip_y; + cell["transpose"] = transpose; + cell["auto_coord"] = autotile_coord; + + return cell; +} - cell_new["id"] = p_cell_new.idx; - cell_new["flip_h"] = p_cell_new.xf; - cell_new["flip_y"] = p_cell_new.yf; - cell_new["transpose"] = p_cell_new.tr; - cell_new["auto_coord"] = p_cell_new.ac; +void TileMapEditor::_create_set_cell_undo_redo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new) { + + Dictionary cell_old = _create_cell_dictionary(p_cell_old.idx, p_cell_old.xf, p_cell_old.yf, p_cell_old.tr, p_cell_old.ac); + Dictionary cell_new = _create_cell_dictionary(p_cell_new.idx, p_cell_new.xf, p_cell_new.yf, p_cell_new.tr, p_cell_new.ac); undo_redo->add_undo_method(node, "_set_celld", p_vec, cell_old); undo_redo->add_do_method(node, "_set_celld", p_vec, cell_new); @@ -251,7 +272,7 @@ void TileMapEditor::_finish_undo() { if (undo_data.size()) { for (Map<Point2i, CellOp>::Element *E = undo_data.front(); E; E = E->next()) { - _create_set_cell_undo(E->key(), E->get(), _get_op_from_cell(E->key())); + _create_set_cell_undo_redo(E->key(), E->get(), _get_op_from_cell(E->key())); } undo_data.clear(); @@ -299,10 +320,7 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p } } - Variant v_pos_x = p_pos.x, v_pos_y = p_pos.y, v_tile = p_value, v_flip_h = p_flip_h, v_flip_v = p_flip_v, v_transpose = p_transpose, v_autotile_coord = Vector2(p_autotile_coord.x, p_autotile_coord.y); - const Variant *args[7] = { &v_pos_x, &v_pos_y, &v_tile, &v_flip_h, &v_flip_v, &v_transpose, &v_autotile_coord }; - Variant::CallError ce; - node->call("set_cell", args, 7, ce); + node->_set_celld(p_pos, _create_cell_dictionary(p_value, p_flip_h, p_flip_v, p_transpose, p_autotile_coord)); if (manual_autotile || (p_value != -1 && node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE)) { if (current != -1) { @@ -932,11 +950,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (mb->get_shift()) { -#ifdef APPLE_STYLE_KEYS if (mb->get_command()) -#else - if (mb->get_control()) -#endif tool = TOOL_RECTANGLE_PAINT; else tool = TOOL_LINE_PAINT; @@ -944,20 +958,20 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { selection_active = false; rectangle_begin = over_tile; + _update_button_tool(); return true; } -#ifdef APPLE_STYLE_KEYS + if (mb->get_command()) { -#else - if (mb->get_control()) { -#endif tool = TOOL_PICKING; _pick_tile(over_tile); + _update_button_tool(); return true; } tool = TOOL_PAINTING; + _update_button_tool(); } if (tool == TOOL_PAINTING) { @@ -979,6 +993,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { rectangle_begin = over_tile; } + _update_button_tool(); return true; } else { @@ -1075,6 +1090,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } tool = TOOL_NONE; + _update_button_tool(); return true; } @@ -1090,6 +1106,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { CanvasItemEditor::get_singleton()->update_viewport(); + _update_button_tool(); return true; } @@ -1100,6 +1117,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { CanvasItemEditor::get_singleton()->update_viewport(); + _update_button_tool(); return true; } @@ -1112,11 +1130,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { _start_undo(TTR("Erase TileMap")); if (mb->get_shift()) { -#ifdef APPLE_STYLE_KEYS if (mb->get_command()) -#else - if (mb->get_control()) -#endif tool = TOOL_RECTANGLE_ERASE; else tool = TOOL_LINE_ERASE; @@ -1130,6 +1144,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { _set_cell(local, invalid_cell); } + _update_button_tool(); return true; } @@ -1144,6 +1159,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { tool = TOOL_NONE; + _update_button_tool(); return true; } else if (tool == TOOL_BUCKET) { @@ -1318,6 +1334,14 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (k.is_valid() && k->is_pressed()) { + if (last_tool == TOOL_NONE && tool == TOOL_PICKING && k->get_scancode() == KEY_SHIFT && k->get_command()) { + // trying to draw a rectangle with the painting tool, so change to the correct tool + tool = last_tool; + + CanvasItemEditor::get_singleton()->update_viewport(); + _update_button_tool(); + } + if (k->get_scancode() == KEY_ESCAPE) { if (tool == TOOL_PASTING) @@ -1329,6 +1353,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { CanvasItemEditor::get_singleton()->update_viewport(); + _update_button_tool(); return true; } @@ -1343,17 +1368,20 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { tool = TOOL_NONE; CanvasItemEditor::get_singleton()->update_viewport(); + _update_button_tool(); return true; } if (ED_IS_SHORTCUT("tile_map_editor/bucket_fill", p_event)) { tool = TOOL_BUCKET; CanvasItemEditor::get_singleton()->update_viewport(); + _update_button_tool(); return true; } if (ED_IS_SHORTCUT("tile_map_editor/erase_selection", p_event)) { _menu_option(OPTION_ERASE_SELECTION); + _update_button_tool(); return true; } if (ED_IS_SHORTCUT("tile_map_editor/select", p_event)) { @@ -1362,6 +1390,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { CanvasItemEditor::get_singleton()->update_viewport(); + _update_button_tool(); return true; } if (ED_IS_SHORTCUT("tile_map_editor/copy_selection", p_event)) { @@ -1372,6 +1401,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { CanvasItemEditor::get_singleton()->update_viewport(); + _update_button_tool(); return true; } } @@ -1388,6 +1418,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { tool = TOOL_PASTING; CanvasItemEditor::get_singleton()->update_viewport(); + _update_button_tool(); return true; } } @@ -1415,8 +1446,30 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { CanvasItemEditor::get_singleton()->update_viewport(); return true; } - } + } else if (k.is_valid()) { // release event + + if (tool == TOOL_NONE) { + if (k->get_scancode() == KEY_SHIFT && k->get_command()) { + + tool = TOOL_PICKING; + _update_button_tool(); + } + } else if (tool == TOOL_PICKING) { + +#ifdef APPLE_STYLE_KEYS + if (k->get_scancode() == KEY_META) { +#else + if (k->get_scancode() == KEY_CONTROL) { +#endif + // go back to that last tool if KEY_CONTROL was released + tool = last_tool; + + CanvasItemEditor::get_singleton()->update_viewport(); + _update_button_tool(); + } + } + } return false; } @@ -1700,6 +1753,7 @@ void TileMapEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_text_entered"), &TileMapEditor::_text_entered); ClassDB::bind_method(D_METHOD("_text_changed"), &TileMapEditor::_text_changed); ClassDB::bind_method(D_METHOD("_sbox_input"), &TileMapEditor::_sbox_input); + ClassDB::bind_method(D_METHOD("_button_tool_select"), &TileMapEditor::_button_tool_select); ClassDB::bind_method(D_METHOD("_menu_option"), &TileMapEditor::_menu_option); ClassDB::bind_method(D_METHOD("_canvas_mouse_enter"), &TileMapEditor::_canvas_mouse_enter); ClassDB::bind_method(D_METHOD("_canvas_mouse_exit"), &TileMapEditor::_canvas_mouse_exit); @@ -1880,37 +1934,66 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { // Add menu items toolbar = memnew(HBoxContainer); - toolbar->set_h_size_flags(SIZE_EXPAND_FILL); - toolbar->set_alignment(BoxContainer::ALIGN_END); toolbar->hide(); CanvasItemEditor::get_singleton()->add_control_to_menu_panel(toolbar); + // Separator + toolbar->add_child(memnew(VSeparator)); + + // Tools + paint_button = memnew(ToolButton); + paint_button->set_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P)); + paint_button->set_tooltip(TTR("Shift+RMB: Line Draw\nShift+Ctrl+RMB: Rectangle Paint")); + paint_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_NONE)); + paint_button->set_toggle_mode(true); + toolbar->add_child(paint_button); + + bucket_fill_button = memnew(ToolButton); + bucket_fill_button->set_shortcut(ED_SHORTCUT("tile_map_editor/bucket_fill", TTR("Bucket Fill"), KEY_G)); + bucket_fill_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_BUCKET)); + bucket_fill_button->set_toggle_mode(true); + toolbar->add_child(bucket_fill_button); + + picker_button = memnew(ToolButton); + picker_button->set_shortcut(ED_SHORTCUT("tile_map_editor/pick_tile", TTR("Pick Tile"), KEY_CONTROL)); + picker_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_PICKING)); + picker_button->set_toggle_mode(true); + toolbar->add_child(picker_button); + + select_button = memnew(ToolButton); + select_button->set_shortcut(ED_SHORTCUT("tile_map_editor/select", TTR("Select"), KEY_MASK_CMD + KEY_B)); + select_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SELECTING)); + select_button->set_toggle_mode(true); + toolbar->add_child(select_button); + + _update_button_tool(); + + // Container to the right of the toolbar + toolbar_right = memnew(HBoxContainer); + toolbar_right->hide(); + toolbar_right->set_h_size_flags(SIZE_EXPAND_FILL); + toolbar_right->set_alignment(BoxContainer::ALIGN_END); + CanvasItemEditor::get_singleton()->add_control_to_menu_panel(toolbar_right); + // Tile position tile_info = memnew(Label); - toolbar->add_child(tile_info); + toolbar_right->add_child(tile_info); + // Menu options = memnew(MenuButton); options->set_text("TileMap"); options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("TileMap", "EditorIcons")); options->set_process_unhandled_key_input(false); + toolbar_right->add_child(options); PopupMenu *p = options->get_popup(); - - p->add_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P), OPTION_PAINTING); - p->add_shortcut(ED_SHORTCUT("tile_map_editor/bucket_fill", TTR("Bucket Fill"), KEY_G), OPTION_BUCKET); - p->add_separator(); - p->add_item(TTR("Pick Tile"), OPTION_PICK_TILE, KEY_CONTROL); - p->add_separator(); - p->add_shortcut(ED_SHORTCUT("tile_map_editor/select", TTR("Select"), KEY_MASK_CMD + KEY_B), OPTION_SELECT); p->add_shortcut(ED_SHORTCUT("tile_map_editor/cut_selection", TTR("Cut Selection"), KEY_MASK_CMD + KEY_X), OPTION_CUT); p->add_shortcut(ED_SHORTCUT("tile_map_editor/copy_selection", TTR("Copy Selection"), KEY_MASK_CMD + KEY_C), OPTION_COPY); p->add_shortcut(ED_GET_SHORTCUT("tile_map_editor/erase_selection"), OPTION_ERASE_SELECTION); p->add_separator(); p->add_item(TTR("Fix Invalid Tiles"), OPTION_FIX_INVALID); - p->connect("id_pressed", this, "_menu_option"); - toolbar->add_child(options); rotate_left_button = memnew(ToolButton); rotate_left_button->set_tooltip(TTR("Rotate left")); rotate_left_button->set_focus_mode(FOCUS_NONE); @@ -1984,10 +2067,12 @@ void TileMapEditorPlugin::make_visible(bool p_visible) { tile_map_editor->show(); tile_map_editor->get_toolbar()->show(); + tile_map_editor->get_toolbar_right()->show(); } else { tile_map_editor->hide(); tile_map_editor->get_toolbar()->hide(); + tile_map_editor->get_toolbar_right()->hide(); tile_map_editor->edit(NULL); } } diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index b30426eabe..fcdada1111 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -66,12 +66,8 @@ class TileMapEditor : public VBoxContainer { enum Options { - OPTION_BUCKET, - OPTION_PICK_TILE, - OPTION_SELECT, OPTION_COPY, OPTION_ERASE_SELECTION, - OPTION_PAINTING, OPTION_FIX_INVALID, OPTION_CUT }; @@ -90,10 +86,16 @@ class TileMapEditor : public VBoxContainer { ItemList *manual_palette; HBoxContainer *toolbar; + HBoxContainer *toolbar_right; Label *tile_info; MenuButton *options; + ToolButton *paint_button; + ToolButton *bucket_fill_button; + ToolButton *picker_button; + ToolButton *select_button; + ToolButton *flip_horizontal_button; ToolButton *flip_vertical_button; ToolButton *rotate_left_button; @@ -103,6 +105,7 @@ class TileMapEditor : public VBoxContainer { CheckBox *manual_button; Tool tool; + Tool last_tool; bool selection_active; bool mouse_over; @@ -184,13 +187,16 @@ class TileMapEditor : public VBoxContainer { void _text_changed(const String &p_text); void _sbox_input(const Ref<InputEvent> &p_ie); void _update_palette(); + void _update_button_tool(); + void _button_tool_select(int p_tool); void _menu_option(int p_option); void _palette_selected(int index); void _palette_multi_selected(int index, bool selected); + Dictionary _create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord); void _start_undo(const String &p_action); void _finish_undo(); - void _create_set_cell_undo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new); + void _create_set_cell_undo_redo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new); void _set_cell(const Point2i &p_pos, Vector<int> p_values, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false, const Point2i p_autotile_coord = Point2()); void _canvas_mouse_enter(); @@ -210,6 +216,7 @@ protected: public: HBoxContainer *get_toolbar() const { return toolbar; } + HBoxContainer *get_toolbar_right() const { return toolbar_right; } bool forward_gui_input(const Ref<InputEvent> &p_event); void forward_canvas_draw_over_viewport(Control *p_overlay); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 03277159fc..93c6614841 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -1038,25 +1038,26 @@ void TileSetEditor::_on_workspace_overlay_draw() { tileset->get_tile_list(tiles); for (List<int>::Element *E = tiles->front(); E; E = E->next()) { int t_id = E->get(); - if (tileset->tile_get_texture(t_id)->get_rid() == current_texture_rid) { - Rect2i region = tileset->tile_get_region(t_id); - region.position += WORKSPACE_MARGIN; - region.position *= workspace->get_scale().x; - Color c; - if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) - c = COLOR_SINGLE; - else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) - c = COLOR_AUTOTILE; - else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) - c = COLOR_ATLAS; - String tile_id_name = String::num(t_id, 0) + ": " + tileset->tile_get_name(t_id); - Ref<Font> font = get_font("font", "Label"); - region.set_size(font->get_string_size(tile_id_name)); - workspace_overlay->draw_rect(region, c); - region.position.y += region.size.y - 2; - c = Color(0.1, 0.1, 0.1); - workspace_overlay->draw_string(font, region.position, tile_id_name, c); - } + if (tileset->tile_get_texture(t_id)->get_rid() != current_texture_rid) + continue; + + Rect2 region = tileset->tile_get_region(t_id); + region.position += WORKSPACE_MARGIN; + region.position *= workspace->get_scale().x; + Color c; + if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) + c = COLOR_SINGLE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) + c = COLOR_AUTOTILE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) + c = COLOR_ATLAS; + String tile_id_name = String::num(t_id, 0) + ": " + tileset->tile_get_name(t_id); + Ref<Font> font = get_font("font", "Label"); + region.set_size(font->get_string_size(tile_id_name)); + workspace_overlay->draw_rect(region, c); + region.position.y += region.size.y - 2; + c = Color(0.1, 0.1, 0.1); + workspace_overlay->draw_string(font, region.position, tile_id_name, c); } } @@ -1560,13 +1561,42 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { _set_edited_collision_shape(Ref<ConvexPolygonShape2D>()); current_shape.resize(0); - current_shape.push_back(snap_point(shape_anchor)); - current_shape.push_back(snap_point(shape_anchor + Vector2(current_tile_region.size.x, 0))); - current_shape.push_back(snap_point(shape_anchor + current_tile_region.size)); - current_shape.push_back(snap_point(shape_anchor + Vector2(0, current_tile_region.size.y))); - close_shape(shape_anchor); + Vector2 pos = mb->get_position(); + pos = snap_point(pos); + current_shape.push_back(pos); + current_shape.push_back(pos); + current_shape.push_back(pos); + current_shape.push_back(pos); + creating_shape = true; workspace->update(); + return; } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) { + if (creating_shape) { + creating_shape = false; + _select_edited_shape_coord(); + workspace->update(); + } + } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (creating_shape) { + if ((current_shape[0] - current_shape[1]).length_squared() <= grab_threshold) { + current_shape.set(0, snap_point(shape_anchor)); + current_shape.set(1, snap_point(shape_anchor + Vector2(current_tile_region.size.x, 0))); + current_shape.set(2, snap_point(shape_anchor + current_tile_region.size)); + current_shape.set(3, snap_point(shape_anchor + Vector2(0, current_tile_region.size.y))); + } + close_shape(shape_anchor); + workspace->update(); + return; + } + } + } else if (mm.is_valid()) { + if (creating_shape) { + Vector2 pos = mm->get_position(); + pos = snap_point(pos); + Vector2 p = current_shape[2]; + current_shape.set(3, snap_point(Vector2(pos.x, p.y))); + current_shape.set(0, snap_point(pos)); + current_shape.set(1, snap_point(Vector2(p.x, pos.y))); workspace->update(); } } @@ -1624,7 +1654,7 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { edited_collision_shape = _convex; _set_edited_shape_points(_get_collision_shape_points(concave)); } else { - // Shoudn't haphen + // Shouldn't happen } for (int i = 0; i < sd.size(); i++) { if (sd[i].get("shape") == previous_shape) { @@ -1862,7 +1892,7 @@ void TileSetEditor::_update_toggle_shape_button() { tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConcavePolygonShape2D", "EditorIcons")); tools[SHAPE_TOGGLE_TYPE]->set_text("Make Concave"); } else { - // Shoudn't happen + // Shouldn't happen separator_shape_toggle->hide(); tools[SHAPE_TOGGLE_TYPE]->hide(); } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 0eeb104777..ad698be0a3 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -58,7 +58,15 @@ void VisualShaderNodePlugin::_bind_methods() { void VisualShaderEditor::edit(VisualShader *p_visual_shader) { + bool changed = false; if (p_visual_shader) { + if (visual_shader.is_null()) { + changed = true; + } else { + if (visual_shader.ptr() != p_visual_shader) { + changed = true; + } + } visual_shader = Ref<VisualShader>(p_visual_shader); } else { visual_shader.unref(); @@ -67,6 +75,9 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { if (visual_shader.is_null()) { hide(); } else { + if (changed) { // to avoid tree collapse + _update_options_menu(); + } _update_graph(); } } @@ -172,6 +183,13 @@ void VisualShaderEditor::_update_options_menu() { int item_count = 0; int item_count2 = 0; + bool is_first_item = true; + + int current_func = -1; + + if (!visual_shader.is_null()) { + current_func = visual_shader->get_mode(); + } for (int i = 0; i < add_options.size() + 1; i++) { @@ -197,6 +215,7 @@ void VisualShaderEditor::_update_options_menu() { prev_sub_category = ""; category = members->create_item(root); category->set_text(0, add_options[i].category); + category->set_selectable(0, false); if (!use_filter) category->set_collapsed(true); } @@ -212,15 +231,20 @@ void VisualShaderEditor::_update_options_menu() { item_count2 = 0; sub_category = members->create_item(category); sub_category->set_text(0, add_options[i].sub_category); + sub_category->set_selectable(0, false); if (!use_filter) sub_category->set_collapsed(true); } } if (sub_category != NULL) { - if (_is_available(add_options[i].mode)) { + if ((add_options[i].func == current_func || add_options[i].func == -1) && _is_available(add_options[i].mode)) { ++item_count2; TreeItem *item = members->create_item(sub_category); item->set_text(0, add_options[i].name); + if (is_first_item) { + item->select(0); + is_first_item = false; + } switch (add_options[i].return_type) { case VisualShaderNode::PORT_TYPE_SCALAR: item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons")); @@ -245,7 +269,7 @@ void VisualShaderEditor::_update_options_menu() { } } else { if (category != NULL) { - if (_is_available(add_options[i].mode)) { + if ((add_options[i].func == current_func || add_options[i].func == -1) && _is_available(add_options[i].mode)) { ++item_count; TreeItem *item = members->create_item(category); item->set_text(0, add_options[i].name); @@ -303,6 +327,21 @@ static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_ return style; } +void VisualShaderEditor::_update_created_node(GraphNode *node) { + + if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) { + Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode"); + Color c = sb->get_border_color(); + Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0); + mono_color.a = 0.85; + c = mono_color; + + node->add_color_override("title_color", c); + c.a = 0.7; + node->add_color_override("close_color", c); + } +} + void VisualShaderEditor::_update_graph() { if (updating) @@ -344,7 +383,6 @@ void VisualShaderEditor::_update_graph() { Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, nodes[n_i]); GraphNode *node = memnew(GraphNode); - graph->add_child(node); /*if (!vsnode->is_connected("changed", this, "_node_changed")) { vsnode->connect("changed", this, "_node_changed", varray(vsnode->get_instance_id()), CONNECT_DEFERRED); @@ -367,6 +405,9 @@ void VisualShaderEditor::_update_graph() { Ref<VisualShaderNodeUniform> uniform = vsnode; if (uniform.is_valid()) { + graph->add_child(node); + _update_created_node(node); + LineEdit *uniform_name = memnew(LineEdit); uniform_name->set_text(uniform->get_uniform_name()); node->add_child(uniform_name); @@ -484,7 +525,7 @@ void VisualShaderEditor::_update_graph() { } } - if (valid_right && edit_type->get_selected() == VisualShader::TYPE_FRAGMENT) { + if (valid_right && edit_type->get_selected() == VisualShader::TYPE_FRAGMENT && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM) { TextureButton *preview = memnew(TextureButton); preview->set_toggle_mode(true); preview->set_normal_texture(get_icon("GuiVisibilityHidden", "EditorIcons")); @@ -502,21 +543,9 @@ void VisualShaderEditor::_update_graph() { node->add_child(hb); node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]); - - if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) { - Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode"); - Color c = sb->get_border_color(); - Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0); - mono_color.a = 0.85; - c = mono_color; - - node->add_color_override("title_color", c); - c.a = 0.7; - node->add_color_override("close_color", c); - } } - if (vsnode->get_output_port_for_preview() >= 0) { + if (vsnode->get_output_port_for_preview() >= 0 && vsnode->get_output_port_type(vsnode->get_output_port_for_preview()) != VisualShaderNode::PORT_TYPE_TRANSFORM) { VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview); port_preview->setup(visual_shader, type, nodes[n_i], vsnode->get_output_port_for_preview()); port_preview->set_h_size_flags(SIZE_SHRINK_CENTER); @@ -530,6 +559,11 @@ void VisualShaderEditor::_update_graph() { error_label->set_text(error); node->add_child(error_label); } + + if (!uniform.is_valid()) { + graph->add_child(node); + _update_created_node(node); + } } for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { @@ -750,7 +784,6 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in int to = p_to.to_int(); if (!visual_shader->can_connect_nodes(type, from, p_from_index, to, p_to_index)) { - EditorNode::get_singleton()->show_warning(TTR("Unable to connect, port may be in use or connection may be invalid.")); return; } @@ -833,40 +866,56 @@ void VisualShaderEditor::_node_selected(Object *p_node) { //EditorNode::get_singleton()->push_item(vsnode.ptr(), "", true); } -void VisualShaderEditor::_member_gui_input(const Ref<InputEvent> p_event) { +void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> p_event) { + Ref<InputEventMouseButton> mb = p_event; - Ref<InputEventKey> key = p_event; - if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && mb->is_doubleclick()) { - _member_create(); - } - } else if (key.is_valid()) { - if (key->is_pressed() && key->get_scancode() == KEY_ENTER) { - _member_create(); - } - } + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) + _show_members_dialog(true); } -void VisualShaderEditor::_input(const Ref<InputEvent> p_event) { - if (graph->has_focus()) { - Ref<InputEventMouseButton> mb = p_event; +void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos) { - if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) { - saved_node_pos_dirty = true; - saved_node_pos = graph->get_local_mouse_position(); + members_dialog->popup(); - Point2 gpos = Input::get_singleton()->get_mouse_position(); - members_dialog->popup(); - members_dialog->set_position(gpos); - } + if (at_mouse_pos) { + saved_node_pos_dirty = true; + saved_node_pos = graph->get_local_mouse_position(); + + Point2 gpos = Input::get_singleton()->get_mouse_position(); + members_dialog->popup(); + members_dialog->set_position(gpos); + } else { + saved_node_pos_dirty = false; + members_dialog->set_position(graph->get_global_position() + Point2(5 * EDSCALE, 65 * EDSCALE)); } + + // keep dialog within window bounds + Size2 window_size = OS::get_singleton()->get_window_size(); + Rect2 dialog_rect = members_dialog->get_global_rect(); + if (dialog_rect.position.y + dialog_rect.size.y > window_size.y) { + int difference = dialog_rect.position.y + dialog_rect.size.y - window_size.y; + members_dialog->set_position(members_dialog->get_position() - Point2(0, difference)); + } + if (dialog_rect.position.x + dialog_rect.size.x > window_size.x) { + int difference = dialog_rect.position.x + dialog_rect.size.x - window_size.x; + members_dialog->set_position(members_dialog->get_position() - Point2(difference, 0)); + } + + node_filter->call_deferred("grab_focus"); // still not visible + node_filter->select_all(); } -void VisualShaderEditor::_show_members_dialog() { - saved_node_pos_dirty = false; - members_dialog->popup(); - members_dialog->set_position(graph->get_global_position() + Point2(5 * EDSCALE, 65 * EDSCALE)); +void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_ie) { + Ref<InputEventKey> ie = p_ie; + if (ie.is_valid() && (ie->get_scancode() == KEY_UP || + ie->get_scancode() == KEY_DOWN || + ie->get_scancode() == KEY_ENTER || + ie->get_scancode() == KEY_KP_ENTER)) { + + members->call("_gui_input", ie); + node_filter->accept_event(); + } } void VisualShaderEditor::_notification(int p_what) { @@ -1004,6 +1053,58 @@ void VisualShaderEditor::_duplicate_nodes() { } } +void VisualShaderEditor::_on_nodes_delete() { + + VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + List<int> to_erase; + + for (int i = 0; i < graph->get_child_count(); i++) { + GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); + if (gn) { + if (gn->is_selected() && gn->is_close_button_visible()) { + to_erase.push_back(gn->get_name().operator String().to_int()); + } + } + } + + if (to_erase.empty()) + return; + + undo_redo->create_action(TTR("Delete Nodes")); + + for (List<int>::Element *F = to_erase.front(); F; F = F->next()) { + undo_redo->add_do_method(visual_shader.ptr(), "remove_node", type, F->get()); + undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, visual_shader->get_node(type, F->get()), visual_shader->get_node_position(type, F->get()), F->get()); + } + + List<VisualShader::Connection> conns; + visual_shader->get_node_connections(type, &conns); + + List<VisualShader::Connection> used_conns; + for (List<int>::Element *F = to_erase.front(); F; F = F->next()) { + for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { + if (E->get().from_node == F->get() || E->get().to_node == F->get()) { + + bool cancel = false; + for (List<VisualShader::Connection>::Element *R = used_conns.front(); R; R = R->next()) { + if (R->get().from_node == E->get().from_node && R->get().from_port == E->get().from_port && R->get().to_node == E->get().to_node && R->get().to_port == E->get().to_port) { + cancel = true; // to avoid ERR_ALREADY_EXISTS warning + break; + } + } + if (!cancel) { + undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + used_conns.push_back(E->get()); + } + } + } + } + + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); +} + void VisualShaderEditor::_mode_selected(int p_id) { _update_options_menu(); _update_graph(); @@ -1166,8 +1267,8 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } void VisualShaderEditor::_bind_methods() { - ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph); + ClassDB::bind_method("_update_options_menu", &VisualShaderEditor::_update_options_menu); ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node); ClassDB::bind_method("_node_dragged", &VisualShaderEditor::_node_dragged); ClassDB::bind_method("_connection_request", &VisualShaderEditor::_connection_request); @@ -1175,6 +1276,7 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_node_selected", &VisualShaderEditor::_node_selected); ClassDB::bind_method("_scroll_changed", &VisualShaderEditor::_scroll_changed); ClassDB::bind_method("_delete_request", &VisualShaderEditor::_delete_request); + ClassDB::bind_method("_on_nodes_delete", &VisualShaderEditor::_on_nodes_delete); ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed); ClassDB::bind_method("_edit_port_default_input", &VisualShaderEditor::_edit_port_default_input); ClassDB::bind_method("_port_edited", &VisualShaderEditor::_port_edited); @@ -1185,7 +1287,7 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_mode_selected", &VisualShaderEditor::_mode_selected); ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item); ClassDB::bind_method("_preview_select_port", &VisualShaderEditor::_preview_select_port); - ClassDB::bind_method("_input", &VisualShaderEditor::_input); + ClassDB::bind_method("_graph_gui_input", &VisualShaderEditor::_graph_gui_input); ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw); ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw); @@ -1194,7 +1296,7 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available); ClassDB::bind_method("_tools_menu_option", &VisualShaderEditor::_tools_menu_option); ClassDB::bind_method("_show_members_dialog", &VisualShaderEditor::_show_members_dialog); - ClassDB::bind_method("_member_gui_input", &VisualShaderEditor::_member_gui_input); + ClassDB::bind_method("_sbox_input", &VisualShaderEditor::_sbox_input); ClassDB::bind_method("_member_filter_changed", &VisualShaderEditor::_member_filter_changed); ClassDB::bind_method("_member_selected", &VisualShaderEditor::_member_selected); ClassDB::bind_method("_member_unselected", &VisualShaderEditor::_member_unselected); @@ -1224,6 +1326,8 @@ VisualShaderEditor::VisualShaderEditor() { graph->connect("node_selected", this, "_node_selected"); graph->connect("scroll_offset_changed", this, "_scroll_changed"); graph->connect("duplicate_nodes_request", this, "_duplicate_nodes"); + graph->connect("delete_nodes_request", this, "_on_nodes_delete"); + graph->connect("gui_input", this, "_graph_gui_input"); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_BOOLEAN); @@ -1252,7 +1356,7 @@ VisualShaderEditor::VisualShaderEditor() { graph->get_zoom_hbox()->add_child(add_node); add_node->set_text(TTR("Add Node...")); graph->get_zoom_hbox()->move_child(add_node, 0); - add_node->connect("pressed", this, "_show_members_dialog"); + add_node->connect("pressed", this, "_show_members_dialog", varray(false)); /////////////////////////////////////// // SHADER NODES TREE @@ -1267,6 +1371,7 @@ VisualShaderEditor::VisualShaderEditor() { node_filter = memnew(LineEdit); filter_hb->add_child(node_filter); node_filter->connect("text_changed", this, "_member_filter_changed"); + node_filter->connect("gui_input", this, "_sbox_input"); node_filter->set_h_size_flags(SIZE_EXPAND_FILL); node_filter->set_placeholder(TTR("Search")); @@ -1286,9 +1391,9 @@ VisualShaderEditor::VisualShaderEditor() { members->set_allow_reselect(true); members->set_hide_folding(false); members->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE)); + members->connect("item_activated", this, "_member_create"); members->connect("item_selected", this, "_member_selected"); members->connect("nothing_selected", this, "_member_unselected"); - members->connect("gui_input", this, "_member_gui_input"); Label *desc_label = memnew(Label); members_vb->add_child(desc_label); @@ -1346,56 +1451,113 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR)); // BOOLEAN - - add_options.push_back(AddOption("BooleanConstant", "Boolean", "Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN)); - add_options.push_back(AddOption("BooleanUniform", "Boolean", "Variables", "VisualShaderNodeBooleanUniform", TTR("Boolean uniform."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN)); + add_options.push_back(AddOption("If", "Conditional", "Functions", "VisualShaderNodeIf", TTR("Returns an associated vector if the provided scalars are equal, greater or less."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("Switch", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated vector if the provided boolean value is true or false."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("BooleanConstant", "Conditional", "Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN)); + add_options.push_back(AddOption("BooleanUniform", "Conditional", "Variables", "VisualShaderNodeBooleanUniform", TTR("Boolean uniform."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN)); // INPUT - add_options.push_back(AddOption("Camera", "Input", "All", "VisualShaderNodeInput", TTR("'camera' input parameter for all shader modes."), "camera", VisualShaderNode::PORT_TYPE_TRANSFORM)); - add_options.push_back(AddOption("InvCamera", "Input", "All", "VisualShaderNodeInput", TTR("'inv_camera' input parameter for all shader modes."), "inv_camera", VisualShaderNode::PORT_TYPE_TRANSFORM)); - add_options.push_back(AddOption("InvProjection", "Input", "All", "VisualShaderNodeInput", TTR("'inv_projection' input parameter for all shader modes."), "inv_projection", VisualShaderNode::PORT_TYPE_TRANSFORM)); - add_options.push_back(AddOption("Normal", "Input", "All", "VisualShaderNodeInput", TTR("'normal' input parameter for all shader modes."), "normal", VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("Projection", "Input", "All", "VisualShaderNodeInput", TTR("'projection' input parameter for all shader modes."), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM)); - add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", TTR("'time' input parameter for all shader modes."), "time", VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("ViewportSize", "Input", "All", "VisualShaderNodeInput", TTR("'viewport_size' input parameter for all shader modes."), "viewport_size", VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("World", "Input", "All", "VisualShaderNodeInput", TTR("'world' input parameter for all shader modes."), "world", VisualShaderNode::PORT_TYPE_TRANSFORM)); + // SPATIAL-FOR-ALL + + add_options.push_back(AddOption("Camera", "Input", "All", "VisualShaderNodeInput", TTR("'camera' input parameter for all shader modes."), "camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("InvCamera", "Input", "All", "VisualShaderNodeInput", TTR("'inv_camera' input parameter for all shader modes."), "inv_camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("InvProjection", "Input", "All", "VisualShaderNodeInput", TTR("'inv_projection' input parameter for all shader modes."), "inv_projection", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Normal", "Input", "All", "VisualShaderNodeInput", TTR("'normal' input parameter for all shader modes."), "normal", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Projection", "Input", "All", "VisualShaderNodeInput", TTR("'projection' input parameter for all shader modes."), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", TTR("'time' input parameter for all shader modes."), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("ViewportSize", "Input", "All", "VisualShaderNodeInput", TTR("'viewport_size' input parameter for all shader modes."), "viewport_size", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("World", "Input", "All", "VisualShaderNodeInput", TTR("'world' input parameter for all shader modes."), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); + + // CANVASITEM-FOR-ALL + + add_options.push_back(AddOption("Alpha", "Input", "All", "VisualShaderNodeInput", TTR("'alpha' input parameter for all shader modes."), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Color", "Input", "All", "VisualShaderNodeInput", TTR("'color' input parameter for all shader modes."), "color", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("TexturePixelSize", "Input", "All", "VisualShaderNodeInput", TTR("'texture_pixel_size' input parameter for all shader modes."), "texture_pixel_size", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", TTR("'time' input parameter for all shader modes."), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("UV", "Input", "All", "VisualShaderNodeInput", TTR("'uv' input parameter for all shader modes."), "uv", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_CANVAS_ITEM)); + + ///////////////// add_options.push_back(AddOption("Input", "Input", "Common", "VisualShaderNodeInput", TTR("Input parameter."))); - add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", TTR("'alpha' input parameter for fragment shader mode."), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT)); - add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", TTR("'binormal' input parameter for fragment shader mode."), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT)); - add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", TTR("'color' input parameter for fragment shader mode."), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT)); - add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", TTR("'fragcoord' input parameter for fragment shader mode."), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT)); - add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", TTR("'point_coord' input parameter for fragment shader mode."), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT)); - add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", TTR("'screen_uv' input parameter for fragment shader mode."), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT)); - add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", TTR("'side' input parameter for fragment shader mode."), "side", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT)); - add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", TTR("'tangent' input parameter for fragment shader mode."), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT)); - add_options.push_back(AddOption("UV", "Input", "Fragment", "VisualShaderNodeInput", TTR("'uv' input parameter for fragment shader mode."), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT)); - add_options.push_back(AddOption("UV2", "Input", "Fragment", "VisualShaderNodeInput", TTR("'uv2' input parameter for fragment shader mode."), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT)); - add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", TTR("'vertex' input parameter for fragment shader mode."), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT)); - add_options.push_back(AddOption("View", "Input", "Fragment", "VisualShaderNodeInput", TTR("'view' input parameter for fragment shader mode."), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT)); - - add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", TTR("'albedo' input parameter for light shader mode."), "albedo", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT)); - add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", TTR("'attenuation' input parameter for light shader mode."), "attenuation", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT)); - add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", TTR("'diffuse' input parameter for light shader mode."), "diffuse", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT)); - add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", TTR("'fragcoord' input parameter for light shader mode."), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT)); - add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", TTR("'light' input parameter for light shader mode."), "light", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT)); - add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", TTR("'light_color' input parameter for light shader mode."), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT)); - add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", TTR("'roughness' input parameter for light shader mode."), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT)); - add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", TTR("'specular' input parameter for light shader mode."), "specular", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT)); - add_options.push_back(AddOption("Transmission", "Input", "Light", "VisualShaderNodeInput", TTR("'transmission' input parameter for light shader mode."), "transmission", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT)); - add_options.push_back(AddOption("View", "Input", "Light", "VisualShaderNodeInput", TTR("'view' input parameter for light shader mode."), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT)); - - add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", TTR("'alpha' input parameter for vertex shader mode."), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX)); - add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", TTR("'binormal' input parameter for vertex shader mode."), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX)); - add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", TTR("'color' input parameter for vertex shader mode."), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX)); - add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", TTR("'modelview' input parameter for vertex shader mode."), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX)); - add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", TTR("'point_size' input parameter for vertex shader mode."), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX)); - add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", TTR("'tangent' input parameter for vertex shader mode."), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX)); - add_options.push_back(AddOption("UV", "Input", "Vertex", "VisualShaderNodeInput", TTR("'uv' input parameter for vertex shader mode."), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX)); - add_options.push_back(AddOption("UV2", "Input", "Vertex", "VisualShaderNodeInput", TTR("'uv2' input parameter for vertex shader mode."), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX)); - add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", TTR("'vertex' input parameter for vertex shader mode."), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX)); + // SPATIAL INPUTS + + add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", TTR("'alpha' input parameter for vertex and fragment shader modes."), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", TTR("'binormal' input parameter for vertex and fragment shader modes."), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", TTR("'color' input parameter for vertex and fragment shader modes."), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", TTR("'fragcoord' input parameter for fragment and light shader modes."), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", TTR("'point_coord' input parameter for fragment shader mode."), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", TTR("'screen_uv' input parameter for fragment shader mode."), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", TTR("'side' input parameter for fragment shader mode."), "side", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", TTR("'tangent' input parameter for vertex and fragment shader modes."), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("UV", "Input", "Fragment", "VisualShaderNodeInput", TTR("'uv' input parameter for vertex and fragment shader modes."), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("UV2", "Input", "Fragment", "VisualShaderNodeInput", TTR("'uv2' input parameter for vertex and fragment shader modes."), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", TTR("'vertex' input parameter for vertex and fragment shader modes."), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("View", "Input", "Fragment", "VisualShaderNodeInput", TTR("'view' input parameter for fragment and light shader modes."), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + + add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", TTR("'albedo' input parameter for light shader mode."), "albedo", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", TTR("'attenuation' input parameter for light shader mode."), "attenuation", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", TTR("'diffuse' input parameter for light shader mode."), "diffuse", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", TTR("'fragcoord' input parameter for fragment and light shader modes."), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", TTR("'light' input parameter for light shader mode."), "light", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", TTR("'light_color' input parameter for light shader mode."), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", TTR("'roughness' input parameter for light shader mode."), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", TTR("'specular' input parameter for light shader mode."), "specular", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Transmission", "Input", "Light", "VisualShaderNodeInput", TTR("'transmission' input parameter for light shader mode."), "transmission", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("View", "Input", "Light", "VisualShaderNodeInput", TTR("'view' input parameter for fragment and light shader modes."), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + + add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", TTR("'alpha' input parameter for vertex and fragment shader modes."), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", TTR("'binormal' input parameter for vertex and fragment shader modes."), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", TTR("'color' input parameter for vertex and fragment shader modes."), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", TTR("'modelview' input parameter for vertex shader mode."), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", TTR("'point_size' input parameter for vertex shader mode."), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", TTR("'tangent' input parameter for vertex and fragment shader mode."), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("UV", "Input", "Vertex", "VisualShaderNodeInput", TTR("'uv' input parameter for vertex and fragment shader modes."), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("UV2", "Input", "Vertex", "VisualShaderNodeInput", TTR("'uv2' input parameter for vertex and fragment shader modes."), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", TTR("'vertex' input parameter for vertex and fragment shader modes."), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); + + // CANVASITEM INPUTS + + add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", TTR("'fragcoord' input parameter for fragment and light shader modes."), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightPass", "Input", "Fragment", "VisualShaderNodeInput", TTR("'light_pass' input parameter for vertex and fragment shader modes."), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", TTR("'point_coord' input parameter for fragment and light shader modes."), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ScreenPixelSize", "Input", "Fragment", "VisualShaderNodeInput", TTR("'screen_pixel_size' input parameter for fragment shader mode."), "screen_pixel_size", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", TTR("'screen_uv' input parameter for fragment and light shader modes."), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + + add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", TTR("'fragcoord' input parameter for fragment and light shader modes."), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightAlpha", "Input", "Light", "VisualShaderNodeInput", TTR("'light_alpha' input parameter for light shader mode."), "light_alpha", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", TTR("'light_color' input parameter for light shader mode."), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightHeight", "Input", "Light", "VisualShaderNodeInput", TTR("'light_height' input parameter for light shader mode."), "light_height", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightUV", "Input", "Light", "VisualShaderNodeInput", TTR("'light_uv' input parameter for light shader mode."), "light_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightVector", "Input", "Light", "VisualShaderNodeInput", TTR("'light_vec' input parameter for light shader mode."), "light_vec", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Normal", "Input", "Light", "VisualShaderNodeInput", TTR("'normal' input parameter for light shader mode."), "normal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("PointCoord", "Input", "Light", "VisualShaderNodeInput", TTR("'point_coord' input parameter for fragment and light shader modes."), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ScreenUV", "Input", "Light", "VisualShaderNodeInput", TTR("'screen_uv' input parameter for fragment and light shader modes."), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ShadowColor", "Input", "Light", "VisualShaderNodeInput", TTR("'shadow_color' input parameter for light shader mode."), "shadow_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); + + add_options.push_back(AddOption("Extra", "Input", "Vertex", "VisualShaderNodeInput", TTR("'extra' input parameter for vertex shader mode."), "extra", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightPass", "Input", "Vertex", "VisualShaderNodeInput", TTR("'light_pass' input parameter for vertex and fragment shader modes."), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", TTR("'point_size' input parameter for vertex shader mode."), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Projection", "Input", "Vertex", "VisualShaderNodeInput", TTR("'projection' input parameter for vertex shader mode."), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", TTR("'vertex' input parameter for vertex shader mode."), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", TTR("'world' input parameter for vertex shader mode."), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); + + // PARTICLES INPUTS + + add_options.push_back(AddOption("Active", "Input", "Vertex", "VisualShaderNodeInput", TTR("'active' input parameter for vertex shader mode."), "active", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", TTR("'alpha' input parameter for vertex shader mode."), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", TTR("'color' input parameter for vertex shader mode."), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Custom", "Input", "Vertex", "VisualShaderNodeInput", TTR("'custom' input parameter for vertex shader mode."), "custom", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("CustomAlpha", "Input", "Vertex", "VisualShaderNodeInput", TTR("'custom_alpha' input parameter for vertex shader mode."), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Delta", "Input", "Vertex", "VisualShaderNodeInput", TTR("'delta' input parameter for vertex shader mode."), "delta", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("EmissionTransform", "Input", "Vertex", "VisualShaderNodeInput", TTR("'emission_transform' input parameter for vertex shader mode."), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Index", "Input", "Vertex", "VisualShaderNodeInput", TTR("'index' input parameter for vertex shader mode."), "index", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("LifeTime", "Input", "Vertex", "VisualShaderNodeInput", TTR("'lifetime' input parameter for vertex shader mode."), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Restart", "Input", "Vertex", "VisualShaderNodeInput", TTR("'restart' input parameter for vertex shader mode."), "restart", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Time", "Input", "Vertex", "VisualShaderNodeInput", TTR("'time' input parameter for vertex shader mode."), "time", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Transform", "Input", "Vertex", "VisualShaderNodeInput", TTR("'transform' input parameter for vertex shader mode."), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Velocity", "Input", "Vertex", "VisualShaderNodeInput", TTR("'velocity' input parameter for vertex shader mode."), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); // SCALAR @@ -1426,6 +1588,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Min", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the lesser of two values."), VisualShaderNodeScalarOp::OP_MIN, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Mix", "Scalar", "Functions", "VisualShaderNodeScalarInterp", TTR("Linear interpolation between two scalars."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeScalarFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("OneMinus", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("1.0 - scalar"), VisualShaderNodeScalarFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Pow", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeScalarOp::OP_POW, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Radians", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeScalarFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Reciprocal", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("1.0 / scalar"), VisualShaderNodeScalarFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_SCALAR)); @@ -1515,6 +1678,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeVectorInterp", TTR("Linear interpolation between two vectors."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("OneMinus", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Pow", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeVectorOp::OP_POW, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Radians", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Reciprocal", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_VECTOR)); @@ -1546,6 +1710,8 @@ VisualShaderEditor::VisualShaderEditor() { // SPECIAL + add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT)); add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT)); @@ -1772,9 +1938,9 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<VisualShaderNode if (Object::cast_to<EditorPropertyResource>(prop)) { Object::cast_to<EditorPropertyResource>(prop)->set_use_sub_inspector(false); prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - } else if (Object::cast_to<EditorPropertyTransform>(prop)) { + } else if (Object::cast_to<EditorPropertyTransform>(prop) || Object::cast_to<EditorPropertyVector3>(prop)) { prop->set_custom_minimum_size(Size2(250 * EDSCALE, 0)); - } else if (Object::cast_to<EditorPropertyFloat>(prop) || Object::cast_to<EditorPropertyVector3>(prop)) { + } else if (Object::cast_to<EditorPropertyFloat>(prop)) { prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); } else if (Object::cast_to<EditorPropertyEnum>(prop)) { prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); @@ -1844,6 +2010,9 @@ void EditorPropertyShaderMode::_option_selected(int p_which) { } } + undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_update_options_menu"); + undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_update_options_menu"); + //update graph undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_update_graph"); undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_update_graph"); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 2709d72931..eb0dee7594 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -85,7 +85,7 @@ class VisualShaderEditor : public VBoxContainer { RichTextLabel *node_desc; void _tools_menu_option(int p_idx); - void _show_members_dialog(); + void _show_members_dialog(bool at_mouse_pos); void _update_graph(); @@ -100,8 +100,9 @@ class VisualShaderEditor : public VBoxContainer { Ref<Script> script; int mode; int return_type; + int func; - AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), int p_sub_func = -1, int p_return_type = -1, int p_mode = -1) { + AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), int p_sub_func = -1, int p_return_type = -1, int p_mode = -1, int p_func = -1) { name = p_name; type = p_type; category = p_category; @@ -110,9 +111,10 @@ class VisualShaderEditor : public VBoxContainer { sub_func = p_sub_func; return_type = p_return_type; mode = p_mode; + func = p_func; } - AddOption(const String &p_name, const String &p_category, const String &p_sub_category, const String &p_type, const String &p_description, const String &p_sub_func, int p_return_type = -1, int p_mode = -1) { + AddOption(const String &p_name, const String &p_category, const String &p_sub_category, const String &p_type, const String &p_description, const String &p_sub_func, int p_return_type = -1, int p_mode = -1, int p_func = -1) { name = p_name; type = p_type; category = p_category; @@ -121,6 +123,7 @@ class VisualShaderEditor : public VBoxContainer { sub_func_str = p_sub_func; return_type = p_return_type; mode = p_mode; + func = p_func; } }; @@ -143,6 +146,7 @@ class VisualShaderEditor : public VBoxContainer { void _node_selected(Object *p_node); void _delete_request(int); + void _on_nodes_delete(); void _removed_from_graph(); @@ -165,10 +169,10 @@ class VisualShaderEditor : public VBoxContainer { void _input_select_item(Ref<VisualShaderNodeInput> input, String name); void _preview_select_port(int p_node, int p_port); - void _input(const Ref<InputEvent> p_event); + void _graph_gui_input(const Ref<InputEvent> p_event); - void _member_gui_input(const Ref<InputEvent> p_event); void _member_filter_changed(const String &p_text); + void _sbox_input(const Ref<InputEvent> &p_ie); void _member_selected(); void _member_unselected(); void _member_create(); @@ -178,6 +182,7 @@ class VisualShaderEditor : public VBoxContainer { void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); bool _is_available(int p_flags); + void _update_created_node(GraphNode *node); protected: void _notification(int p_what); |
