summaryrefslogtreecommitdiff
path: root/editor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins')
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp14
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.h7
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp15
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.h12
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp25
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.h14
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp39
-rw-r--r--editor/plugins/animation_player_editor_plugin.h4
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp22
-rw-r--r--editor/plugins/animation_state_machine_editor.h12
-rw-r--r--editor/plugins/audio_stream_editor_plugin.cpp6
-rw-r--r--editor/plugins/audio_stream_editor_plugin.h4
-rw-r--r--editor/plugins/baked_lightmap_editor_plugin.cpp3
-rw-r--r--editor/plugins/baked_lightmap_editor_plugin.h2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp175
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h39
-rw-r--r--editor/plugins/collision_polygon_3d_editor_plugin.cpp9
-rw-r--r--editor/plugins/collision_polygon_3d_editor_plugin.h5
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp1
-rw-r--r--editor/plugins/debugger_editor_plugin.cpp7
-rw-r--r--editor/plugins/editor_preview_plugins.cpp3
-rw-r--r--editor/plugins/gi_probe_editor_plugin.cpp3
-rw-r--r--editor/plugins/gi_probe_editor_plugin.h2
-rw-r--r--editor/plugins/item_list_editor_plugin.cpp3
-rw-r--r--editor/plugins/item_list_editor_plugin.h2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp376
-rw-r--r--editor/plugins/node_3d_editor_plugin.h11
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp15
-rw-r--r--editor/plugins/path_2d_editor_plugin.h11
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp18
-rw-r--r--editor/plugins/path_3d_editor_plugin.h8
-rw-r--r--editor/plugins/physical_bone_3d_editor_plugin.cpp3
-rw-r--r--editor/plugins/physical_bone_3d_editor_plugin.h2
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp25
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.h10
-rw-r--r--editor/plugins/script_editor_plugin.cpp18
-rw-r--r--editor/plugins/script_editor_plugin.h9
-rw-r--r--editor/plugins/script_text_editor.cpp28
-rw-r--r--editor/plugins/script_text_editor.h1
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp558
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.h148
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp3
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp33
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h22
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp9
-rw-r--r--editor/plugins/texture_region_editor_plugin.h6
-rw-r--r--editor/plugins/theme_editor_plugin.cpp5
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp254
-rw-r--r--editor/plugins/tile_map_editor_plugin.h23
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp73
-rw-r--r--editor/plugins/tile_set_editor_plugin.h7
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp2
-rw-r--r--editor/plugins/version_control_editor_plugin.h4
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp8
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h4
55 files changed, 1588 insertions, 534 deletions
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 1abba45f9e..49e67f3605 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -31,6 +31,7 @@
#include "abstract_polygon_2d_editor.h"
#include "canvas_item_editor_plugin.h"
+#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
#include "editor/editor_scale.h"
@@ -368,7 +369,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
} else {
const real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius");
- if (!_is_line() && wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) {
+ if (!_is_line() && wip.size() > 1 && xform.xform(wip[0]).distance_to(xform.xform(cpoint)) < grab_threshold) {
//wip closed
_wip_close();
@@ -671,7 +672,7 @@ AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_edge_point(c
Vector2 segment[2] = { xform.xform(points[i] + offset),
xform.xform(points[(i + 1) % n_points] + offset) };
- Vector2 cp = Geometry::get_closest_point_to_segment_2d(p_pos, segment);
+ Vector2 cp = Geometry2D::get_closest_point_to_segment(p_pos, segment);
if (cp.distance_squared_to(segment[0]) < eps2 || cp.distance_squared_to(segment[1]) < eps2) {
continue; //not valid to reuse point
@@ -702,17 +703,20 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wi
edge_point = PosVertex();
add_child(memnew(VSeparator));
- button_create = memnew(ToolButton);
+ button_create = memnew(Button);
+ button_create->set_flat(true);
add_child(button_create);
button_create->connect("pressed", callable_mp(this, &AbstractPolygon2DEditor::_menu_option), varray(MODE_CREATE));
button_create->set_toggle_mode(true);
- button_edit = memnew(ToolButton);
+ button_edit = memnew(Button);
+ button_edit->set_flat(true);
add_child(button_edit);
button_edit->connect("pressed", callable_mp(this, &AbstractPolygon2DEditor::_menu_option), varray(MODE_EDIT));
button_edit->set_toggle_mode(true);
- button_delete = memnew(ToolButton);
+ button_delete = memnew(Button);
+ button_delete->set_flat(true);
add_child(button_delete);
button_delete->connect("pressed", callable_mp(this, &AbstractPolygon2DEditor::_menu_option), varray(MODE_DELETE));
button_delete->set_toggle_mode(true);
diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h
index d5b3a916d1..b3a17f7660 100644
--- a/editor/plugins/abstract_polygon_2d_editor.h
+++ b/editor/plugins/abstract_polygon_2d_editor.h
@@ -34,16 +34,15 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/2d/polygon_2d.h"
-#include "scene/gui/tool_button.h"
class CanvasItemEditor;
class AbstractPolygon2DEditor : public HBoxContainer {
GDCLASS(AbstractPolygon2DEditor, HBoxContainer);
- ToolButton *button_create;
- ToolButton *button_edit;
- ToolButton *button_delete;
+ Button *button_create;
+ Button *button_edit;
+ Button *button_delete;
struct Vertex {
Vertex() {}
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 75eacf56ec..959301907c 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -595,7 +595,8 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
Ref<ButtonGroup> bg;
bg.instance();
- tool_blend = memnew(ToolButton);
+ tool_blend = memnew(Button);
+ tool_blend->set_flat(true);
tool_blend->set_toggle_mode(true);
tool_blend->set_button_group(bg);
top_hb->add_child(tool_blend);
@@ -603,14 +604,16 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
tool_blend->set_tooltip(TTR("Set the blending position within the space"));
tool_blend->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch), varray(3));
- tool_select = memnew(ToolButton);
+ tool_select = memnew(Button);
+ tool_select->set_flat(true);
tool_select->set_toggle_mode(true);
tool_select->set_button_group(bg);
top_hb->add_child(tool_select);
tool_select->set_tooltip(TTR("Select and move points, create points with RMB."));
tool_select->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch), varray(0));
- tool_create = memnew(ToolButton);
+ tool_create = memnew(Button);
+ tool_create->set_flat(true);
tool_create->set_toggle_mode(true);
tool_create->set_button_group(bg);
top_hb->add_child(tool_create);
@@ -619,14 +622,16 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
tool_erase_sep = memnew(VSeparator);
top_hb->add_child(tool_erase_sep);
- tool_erase = memnew(ToolButton);
+ tool_erase = memnew(Button);
+ tool_erase->set_flat(true);
top_hb->add_child(tool_erase);
tool_erase->set_tooltip(TTR("Erase points."));
tool_erase->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_erase_selected));
top_hb->add_child(memnew(VSeparator));
- snap = memnew(ToolButton);
+ snap = memnew(Button);
+ snap->set_flat(true);
snap->set_toggle_mode(true);
top_hb->add_child(snap);
snap->set_pressed(true);
diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h
index 8cfd6714ad..c319b648ba 100644
--- a/editor/plugins/animation_blend_space_1d_editor.h
+++ b/editor/plugins/animation_blend_space_1d_editor.h
@@ -47,15 +47,15 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
Ref<AnimationNodeBlendSpace1D> blend_space;
HBoxContainer *goto_parent_hb;
- ToolButton *goto_parent;
+ Button *goto_parent;
PanelContainer *panel;
- ToolButton *tool_blend;
- ToolButton *tool_select;
- ToolButton *tool_create;
+ Button *tool_blend;
+ Button *tool_select;
+ Button *tool_create;
VSeparator *tool_erase_sep;
- ToolButton *tool_erase;
- ToolButton *snap;
+ Button *tool_erase;
+ Button *snap;
SpinBox *snap_value;
LineEdit *label_value;
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index df67482dfb..1ab114fc01 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -32,7 +32,7 @@
#include "core/input/input.h"
#include "core/io/resource_loader.h"
-#include "core/math/delaunay_2d.h"
+#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "editor/editor_scale.h"
@@ -165,7 +165,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
triangle.push_back(points[idx]);
}
- if (Geometry::is_point_in_triangle(mb->get_position(), triangle[0], triangle[1], triangle[2])) {
+ if (Geometry2D::is_point_in_triangle(mb->get_position(), triangle[0], triangle[1], triangle[2])) {
selected_triangle = i;
_update_tool_erase();
return;
@@ -819,7 +819,8 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
Ref<ButtonGroup> bg;
bg.instance();
- tool_blend = memnew(ToolButton);
+ tool_blend = memnew(Button);
+ tool_blend->set_flat(true);
tool_blend->set_toggle_mode(true);
tool_blend->set_button_group(bg);
top_hb->add_child(tool_blend);
@@ -827,21 +828,24 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_blend->set_tooltip(TTR("Set the blending position within the space"));
tool_blend->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch), varray(3));
- tool_select = memnew(ToolButton);
+ tool_select = memnew(Button);
+ tool_select->set_flat(true);
tool_select->set_toggle_mode(true);
tool_select->set_button_group(bg);
top_hb->add_child(tool_select);
tool_select->set_tooltip(TTR("Select and move points, create points with RMB."));
tool_select->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch), varray(0));
- tool_create = memnew(ToolButton);
+ tool_create = memnew(Button);
+ tool_create->set_flat(true);
tool_create->set_toggle_mode(true);
tool_create->set_button_group(bg);
top_hb->add_child(tool_create);
tool_create->set_tooltip(TTR("Create points."));
tool_create->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch), varray(1));
- tool_triangle = memnew(ToolButton);
+ tool_triangle = memnew(Button);
+ tool_triangle->set_flat(true);
tool_triangle->set_toggle_mode(true);
tool_triangle->set_button_group(bg);
top_hb->add_child(tool_triangle);
@@ -850,7 +854,8 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_erase_sep = memnew(VSeparator);
top_hb->add_child(tool_erase_sep);
- tool_erase = memnew(ToolButton);
+ tool_erase = memnew(Button);
+ tool_erase->set_flat(true);
top_hb->add_child(tool_erase);
tool_erase->set_tooltip(TTR("Erase points and triangles."));
tool_erase->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_erase_selected));
@@ -858,7 +863,8 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
top_hb->add_child(memnew(VSeparator));
- auto_triangles = memnew(ToolButton);
+ auto_triangles = memnew(Button);
+ auto_triangles->set_flat(true);
top_hb->add_child(auto_triangles);
auto_triangles->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled));
auto_triangles->set_toggle_mode(true);
@@ -866,7 +872,8 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
top_hb->add_child(memnew(VSeparator));
- snap = memnew(ToolButton);
+ snap = memnew(Button);
+ snap->set_flat(true);
snap->set_toggle_mode(true);
top_hb->add_child(snap);
snap->set_pressed(true);
diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h
index b430a12297..659b96cefa 100644
--- a/editor/plugins/animation_blend_space_2d_editor.h
+++ b/editor/plugins/animation_blend_space_2d_editor.h
@@ -47,18 +47,18 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
Ref<AnimationNodeBlendSpace2D> blend_space;
PanelContainer *panel;
- ToolButton *tool_blend;
- ToolButton *tool_select;
- ToolButton *tool_create;
- ToolButton *tool_triangle;
+ Button *tool_blend;
+ Button *tool_select;
+ Button *tool_create;
+ Button *tool_triangle;
VSeparator *tool_erase_sep;
- ToolButton *tool_erase;
- ToolButton *snap;
+ Button *tool_erase;
+ Button *snap;
SpinBox *snap_x;
SpinBox *snap_y;
OptionButton *interpolation;
- ToolButton *auto_triangles;
+ Button *auto_triangles;
LineEdit *label_x;
LineEdit *label_y;
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 1e0a9535e2..035526ca55 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -380,26 +380,25 @@ void AnimationPlayerEditor::_animation_save_as(const Ref<Resource> &p_resource)
file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper());
}
+ String path;
//file->set_current_path(current_path);
if (p_resource->get_path() != "") {
- file->set_current_path(p_resource->get_path());
+ path = p_resource->get_path();
if (extensions.size()) {
- String ext = p_resource->get_path().get_extension().to_lower();
- if (extensions.find(ext) == nullptr) {
- file->set_current_path(p_resource->get_path().replacen("." + ext, "." + extensions.front()->get()));
+ if (extensions.find(p_resource->get_path().get_extension().to_lower()) == nullptr) {
+ path = p_resource->get_path().get_base_dir() + p_resource->get_name() + "." + extensions.front()->get();
}
}
} else {
- String existing;
if (extensions.size()) {
if (p_resource->get_name() != "") {
- existing = p_resource->get_name() + "." + extensions.front()->get().to_lower();
+ path = p_resource->get_name() + "." + extensions.front()->get().to_lower();
} else {
- existing = "new_" + p_resource->get_class().to_lower() + "." + extensions.front()->get().to_lower();
+ path = "new_" + p_resource->get_class().to_lower() + "." + extensions.front()->get().to_lower();
}
}
- file->set_current_path(existing);
}
+ file->set_current_path(path);
file->popup_centered_ratio();
file->set_title(TTR("Save Resource As..."));
current_option = RESOURCE_SAVE;
@@ -1503,24 +1502,29 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
HBoxContainer *hb = memnew(HBoxContainer);
add_child(hb);
- play_bw_from = memnew(ToolButton);
+ play_bw_from = memnew(Button);
+ play_bw_from->set_flat(true);
play_bw_from->set_tooltip(TTR("Play selected animation backwards from current pos. (A)"));
hb->add_child(play_bw_from);
- play_bw = memnew(ToolButton);
+ play_bw = memnew(Button);
+ play_bw->set_flat(true);
play_bw->set_tooltip(TTR("Play selected animation backwards from end. (Shift+A)"));
hb->add_child(play_bw);
- stop = memnew(ToolButton);
+ stop = memnew(Button);
+ stop->set_flat(true);
stop->set_toggle_mode(true);
hb->add_child(stop);
stop->set_tooltip(TTR("Stop animation playback. (S)"));
- play = memnew(ToolButton);
+ play = memnew(Button);
+ play->set_flat(true);
play->set_tooltip(TTR("Play selected animation from start. (Shift+D)"));
hb->add_child(play);
- play_from = memnew(ToolButton);
+ play_from = memnew(Button);
+ play_from->set_flat(true);
play_from->set_tooltip(TTR("Play selected animation from current pos. (D)"));
hb->add_child(play_from);
@@ -1572,7 +1576,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
animation->set_tooltip(TTR("Display list of animations in player."));
animation->set_clip_text(true);
- autoplay = memnew(ToolButton);
+ autoplay = memnew(Button);
+ autoplay->set_flat(true);
hb->add_child(autoplay);
autoplay->set_tooltip(TTR("Autoplay on Load"));
@@ -1584,7 +1589,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
hb->add_child(memnew(VSeparator));
- onion_toggle = memnew(ToolButton);
+ onion_toggle = memnew(Button);
+ onion_toggle->set_flat(true);
onion_toggle->set_toggle_mode(true);
onion_toggle->set_tooltip(TTR("Enable Onion Skinning"));
onion_toggle->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu), varray(ONION_SKINNING_ENABLE));
@@ -1609,7 +1615,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
hb->add_child(memnew(VSeparator));
- pin = memnew(ToolButton);
+ pin = memnew(Button);
+ pin->set_flat(true);
pin->set_toggle_mode(true);
pin->set_tooltip(TTR("Pin AnimationPlayer"));
hb->add_child(pin);
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 18f2d3b25e..fe96deecf2 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -96,9 +96,9 @@ class AnimationPlayerEditor : public VBoxContainer {
Button *autoplay;
MenuButton *tool_anim;
- ToolButton *onion_toggle;
+ Button *onion_toggle;
MenuButton *onion_skinning;
- ToolButton *pin;
+ Button *pin;
SpinBox *frame;
LineEdit *scale;
LineEdit *name;
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index 652754a146..0970608853 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -32,7 +32,7 @@
#include "core/input/input.h"
#include "core/io/resource_loader.h"
-#include "core/math/delaunay_2d.h"
+#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "editor/editor_scale.h"
@@ -191,7 +191,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
transition_lines[i].from,
transition_lines[i].to
};
- Vector2 cpoint = Geometry::get_closest_point_to_segment_2d(mb->get_position(), s);
+ Vector2 cpoint = Geometry2D::get_closest_point_to_segment(mb->get_position(), s);
float d = cpoint.distance_to(mb->get_position());
if (d > transition_lines[i].width) {
continue;
@@ -1208,7 +1208,8 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
Ref<ButtonGroup> bg;
bg.instance();
- tool_select = memnew(ToolButton);
+ tool_select = memnew(Button);
+ tool_select->set_flat(true);
top_hb->add_child(tool_select);
tool_select->set_toggle_mode(true);
tool_select->set_button_group(bg);
@@ -1216,14 +1217,16 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
tool_select->set_tooltip(TTR("Select and move nodes.\nRMB to add new nodes.\nShift+LMB to create connections."));
tool_select->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), varray(), CONNECT_DEFERRED);
- tool_create = memnew(ToolButton);
+ tool_create = memnew(Button);
+ tool_create->set_flat(true);
top_hb->add_child(tool_create);
tool_create->set_toggle_mode(true);
tool_create->set_button_group(bg);
tool_create->set_tooltip(TTR("Create new nodes."));
tool_create->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), varray(), CONNECT_DEFERRED);
- tool_connect = memnew(ToolButton);
+ tool_connect = memnew(Button);
+ tool_connect->set_flat(true);
top_hb->add_child(tool_connect);
tool_connect->set_toggle_mode(true);
tool_connect->set_button_group(bg);
@@ -1233,7 +1236,8 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
tool_erase_hb = memnew(HBoxContainer);
top_hb->add_child(tool_erase_hb);
tool_erase_hb->add_child(memnew(VSeparator));
- tool_erase = memnew(ToolButton);
+ tool_erase = memnew(Button);
+ tool_erase->set_flat(true);
tool_erase->set_tooltip(TTR("Remove selected node or transition."));
tool_erase_hb->add_child(tool_erase);
tool_erase->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_erase_selected));
@@ -1241,13 +1245,15 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
tool_erase_hb->add_child(memnew(VSeparator));
- tool_autoplay = memnew(ToolButton);
+ tool_autoplay = memnew(Button);
+ tool_autoplay->set_flat(true);
tool_autoplay->set_tooltip(TTR("Toggle autoplay this animation on start, restart or seek to zero."));
tool_erase_hb->add_child(tool_autoplay);
tool_autoplay->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_autoplay_selected));
tool_autoplay->set_disabled(true);
- tool_end = memnew(ToolButton);
+ tool_end = memnew(Button);
+ tool_end->set_flat(true);
tool_end->set_tooltip(TTR("Set the end animation. This is useful for sub-transitions."));
tool_erase_hb->add_child(tool_end);
tool_end->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_end_selected));
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index 022c32ef48..c4caf2e52b 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -46,16 +46,16 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
Ref<AnimationNodeStateMachine> state_machine;
- ToolButton *tool_select;
- ToolButton *tool_create;
- ToolButton *tool_connect;
+ Button *tool_select;
+ Button *tool_create;
+ Button *tool_connect;
Popup *name_edit_popup;
LineEdit *name_edit;
HBoxContainer *tool_erase_hb;
- ToolButton *tool_erase;
- ToolButton *tool_autoplay;
- ToolButton *tool_end;
+ Button *tool_erase;
+ Button *tool_autoplay;
+ Button *tool_end;
OptionButton *transition_mode;
OptionButton *play_mode;
diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp
index 3b7a9320f0..b0f65af245 100644
--- a/editor/plugins/audio_stream_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_editor_plugin.cpp
@@ -220,12 +220,14 @@ AudioStreamEditor::AudioStreamEditor() {
hbox->add_theme_constant_override("separation", 0);
vbox->add_child(hbox);
- _play_button = memnew(ToolButton);
+ _play_button = memnew(Button);
+ _play_button->set_flat(true);
hbox->add_child(_play_button);
_play_button->set_focus_mode(Control::FOCUS_NONE);
_play_button->connect("pressed", callable_mp(this, &AudioStreamEditor::_play));
- _stop_button = memnew(ToolButton);
+ _stop_button = memnew(Button);
+ _stop_button->set_flat(true);
hbox->add_child(_stop_button);
_stop_button->set_focus_mode(Control::FOCUS_NONE);
_stop_button->connect("pressed", callable_mp(this, &AudioStreamEditor::_stop));
diff --git a/editor/plugins/audio_stream_editor_plugin.h b/editor/plugins/audio_stream_editor_plugin.h
index dd7caaa15e..de176aab49 100644
--- a/editor/plugins/audio_stream_editor_plugin.h
+++ b/editor/plugins/audio_stream_editor_plugin.h
@@ -47,8 +47,8 @@ class AudioStreamEditor : public ColorRect {
Label *_current_label;
Label *_duration_label;
- ToolButton *_play_button;
- ToolButton *_stop_button;
+ Button *_play_button;
+ Button *_stop_button;
float _current;
bool _dragging;
diff --git a/editor/plugins/baked_lightmap_editor_plugin.cpp b/editor/plugins/baked_lightmap_editor_plugin.cpp
index 8fbe1646f7..ee9feb7f74 100644
--- a/editor/plugins/baked_lightmap_editor_plugin.cpp
+++ b/editor/plugins/baked_lightmap_editor_plugin.cpp
@@ -117,7 +117,8 @@ void BakedLightmapEditorPlugin::_bind_methods() {
BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) {
editor = p_node;
- bake = memnew(ToolButton);
+ bake = memnew(Button);
+ bake->set_flat(true);
bake->set_icon(editor->get_gui_base()->get_theme_icon("Bake", "EditorIcons"));
bake->set_text(TTR("Bake Lightmaps"));
bake->hide();
diff --git a/editor/plugins/baked_lightmap_editor_plugin.h b/editor/plugins/baked_lightmap_editor_plugin.h
index 67fb368a86..54eb0f71ec 100644
--- a/editor/plugins/baked_lightmap_editor_plugin.h
+++ b/editor/plugins/baked_lightmap_editor_plugin.h
@@ -41,7 +41,7 @@ class BakedLightmapEditorPlugin : public EditorPlugin {
BakedLightmap *lightmap;
- ToolButton *bake;
+ Button *bake;
EditorNode *editor;
EditorFileDialog *file_dialog;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 744c7907af..3af0b0d4e1 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "canvas_item_editor_plugin.h"
#include "core/input/input.h"
+#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
#include "core/print_string.h"
#include "core/project_settings.h"
@@ -53,8 +54,10 @@
#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
-#define MIN_ZOOM 0.01
-#define MAX_ZOOM 100
+// Min and Max are power of two in order to play nicely with successive increment.
+// That way, we can naturally reach a 100% zoom from boundaries.
+#define MIN_ZOOM 1. / 128
+#define MAX_ZOOM 128
#define RULER_WIDTH (15 * EDSCALE)
#define SCALE_HANDLE_DISTANCE 25
@@ -86,7 +89,6 @@ public:
GridContainer *child_container;
set_title(TTR("Configure Snap"));
- get_ok()->set_text(TTR("Close"));
container = memnew(VBoxContainer);
add_child(container);
@@ -672,7 +674,7 @@ void CanvasItemEditor::_get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResu
}
// Check if the point is inside the Polygon2D
- if (Geometry::is_point_in_polygon(screen_pos, bone_shape)) {
+ if (Geometry2D::is_point_in_polygon(screen_pos, bone_shape)) {
// Check if the item is already in the list
bool duplicate = false;
for (int i = 0; i < r_items.size(); i++) {
@@ -1205,7 +1207,26 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bool p_already_accepted) {
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid() && !p_already_accepted) {
- bool pan_on_scroll = bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan")) && !b->get_control();
+ const bool pan_on_scroll = bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan")) && !b->get_control();
+
+ if (pan_on_scroll) {
+ // Perform horizontal scrolling first so we can check for Shift being held.
+ if (b->is_pressed() &&
+ (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_shift() && b->get_button_index() == BUTTON_WHEEL_UP))) {
+ // Pan left
+ view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
+ update_viewport();
+ return true;
+ }
+
+ if (b->is_pressed() &&
+ (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_shift() && b->get_button_index() == BUTTON_WHEEL_DOWN))) {
+ // Pan right
+ view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
+ update_viewport();
+ return true;
+ }
+ }
if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_DOWN) {
// Scroll or pan down
@@ -1213,7 +1234,11 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
update_viewport();
} else {
- _zoom_on_position(zoom * (1 - (0.05 * b->get_factor())), b->get_position());
+ float new_zoom = _get_next_zoom_value(-1);
+ if (b->get_factor() != 1.f) {
+ new_zoom = zoom * ((new_zoom / zoom - 1.f) * b->get_factor() + 1.f);
+ }
+ _zoom_on_position(new_zoom, b->get_position());
}
return true;
}
@@ -1224,29 +1249,15 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
update_viewport();
} else {
- _zoom_on_position(zoom * ((0.95 + (0.05 * b->get_factor())) / 0.95), b->get_position());
+ float new_zoom = _get_next_zoom_value(1);
+ if (b->get_factor() != 1.f) {
+ new_zoom = zoom * ((new_zoom / zoom - 1.f) * b->get_factor() + 1.f);
+ }
+ _zoom_on_position(new_zoom, b->get_position());
}
return true;
}
- if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_LEFT) {
- // Pan left
- if (pan_on_scroll) {
- view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- update_viewport();
- return true;
- }
- }
-
- if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_RIGHT) {
- // Pan right
- if (pan_on_scroll) {
- view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- update_viewport();
- return true;
- }
- }
-
if (!panning) {
if (b->is_pressed() &&
(b->get_button_index() == BUTTON_MIDDLE ||
@@ -1315,6 +1326,18 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
Ref<InputEventPanGesture> pan_gesture = p_event;
if (pan_gesture.is_valid() && !p_already_accepted) {
+ // If control key pressed, then zoom instead of pan
+ if (pan_gesture->get_control()) {
+ const float factor = pan_gesture->get_delta().y;
+ float new_zoom = _get_next_zoom_value(-1);
+
+ if (factor != 1.f) {
+ new_zoom = zoom * ((new_zoom / zoom - 1.f) * factor + 1.f);
+ }
+ _zoom_on_position(new_zoom, pan_gesture->get_position());
+ return true;
+ }
+
// Pan gesture
const Vector2 delta = (int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom) * pan_gesture->get_delta();
view_offset.x += delta.x;
@@ -2240,7 +2263,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
return true;
}
- if (k.is_valid() && !k->is_pressed() && drag_type == DRAG_KEY_MOVE && tool == TOOL_SELECT &&
+ if (k.is_valid() && !k->is_pressed() && drag_type == DRAG_KEY_MOVE && (tool == TOOL_SELECT || tool == TOOL_MOVE) &&
(k->get_keycode() == KEY_UP || k->get_keycode() == KEY_DOWN || k->get_keycode() == KEY_LEFT || k->get_keycode() == KEY_RIGHT)) {
// Confirm canvas items move by arrow keys
if ((!Input::get_singleton()->is_key_pressed(KEY_UP)) &&
@@ -4333,8 +4356,37 @@ void CanvasItemEditor::_set_anchors_preset(Control::LayoutPreset p_preset) {
undo_redo->commit_action();
}
+float CanvasItemEditor::_get_next_zoom_value(int p_increment_count) const {
+ // Base increment factor defined as the twelveth root of two.
+ // This allow a smooth geometric evolution of the zoom, with the advantage of
+ // visiting all integer power of two scale factors.
+ // note: this is analogous to the 'semitones' interval in the music world
+ // In order to avoid numerical imprecisions, we compute and edit a zoom index
+ // with the following relation: zoom = 2 ^ (index / 12)
+
+ if (zoom < CMP_EPSILON || p_increment_count == 0) {
+ return 1.f;
+ }
+
+ // Remove Editor scale from the index computation
+ float zoom_noscale = zoom / MAX(1, EDSCALE);
+
+ // zoom = 2**(index/12) => log2(zoom) = index/12
+ float closest_zoom_index = Math::round(Math::log(zoom_noscale) * 12.f / Math::log(2.f));
+
+ float new_zoom_index = closest_zoom_index + p_increment_count;
+ float new_zoom = Math::pow(2.f, new_zoom_index / 12.f);
+
+ // Restore Editor scale transformation
+ new_zoom *= MAX(1, EDSCALE);
+
+ return new_zoom;
+}
+
void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
- if (p_zoom < MIN_ZOOM || p_zoom > MAX_ZOOM) {
+ p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM);
+
+ if (p_zoom == zoom) {
return;
}
@@ -4376,7 +4428,7 @@ void CanvasItemEditor::_update_zoom_label() {
}
void CanvasItemEditor::_button_zoom_minus() {
- _zoom_on_position(zoom / Math_SQRT2, viewport_scrollable->get_size() / 2.0);
+ _zoom_on_position(_get_next_zoom_value(-6), viewport_scrollable->get_size() / 2.0);
}
void CanvasItemEditor::_button_zoom_reset() {
@@ -4384,7 +4436,7 @@ void CanvasItemEditor::_button_zoom_reset() {
}
void CanvasItemEditor::_button_zoom_plus() {
- _zoom_on_position(zoom * Math_SQRT2, viewport_scrollable->get_size() / 2.0);
+ _zoom_on_position(_get_next_zoom_value(6), viewport_scrollable->get_size() / 2.0);
}
void CanvasItemEditor::_button_toggle_smart_snap(bool p_status) {
@@ -4408,7 +4460,7 @@ void CanvasItemEditor::_button_override_camera(bool p_pressed) {
}
void CanvasItemEditor::_button_tool_select(int p_index) {
- ToolButton *tb[TOOL_MAX] = { select_button, list_select_button, move_button, scale_button, rotate_button, pivot_button, pan_button, ruler_button };
+ Button *tb[TOOL_MAX] = { select_button, list_select_button, move_button, scale_button, rotate_button, pivot_button, pan_button, ruler_button };
for (int i = 0; i < TOOL_MAX; i++) {
tb[i]->set_pressed(i == p_index);
}
@@ -5538,13 +5590,15 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
viewport->add_child(controls_vb);
- zoom_minus = memnew(ToolButton);
+ zoom_minus = memnew(Button);
+ zoom_minus->set_flat(true);
zoom_hb->add_child(zoom_minus);
zoom_minus->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_zoom_minus));
zoom_minus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_minus", TTR("Zoom Out"), KEY_MASK_CMD | KEY_MINUS));
zoom_minus->set_focus_mode(FOCUS_NONE);
- zoom_reset = memnew(ToolButton);
+ zoom_reset = memnew(Button);
+ zoom_reset->set_flat(true);
zoom_hb->add_child(zoom_reset);
zoom_reset->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_zoom_reset));
zoom_reset->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_reset", TTR("Zoom Reset"), KEY_MASK_CMD | KEY_0));
@@ -5553,7 +5607,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
// Prevent the button's size from changing when the text size changes
zoom_reset->set_custom_minimum_size(Size2(75 * EDSCALE, 0));
- zoom_plus = memnew(ToolButton);
+ zoom_plus = memnew(Button);
+ zoom_plus->set_flat(true);
zoom_hb->add_child(zoom_plus);
zoom_plus->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_zoom_plus));
zoom_plus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_plus", TTR("Zoom In"), KEY_MASK_CMD | KEY_EQUAL)); // Usually direct access key for PLUS
@@ -5561,7 +5616,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
updating_scroll = false;
- select_button = memnew(ToolButton);
+ select_button = memnew(Button);
+ select_button->set_flat(true);
hb->add_child(select_button);
select_button->set_toggle_mode(true);
select_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_SELECT));
@@ -5571,21 +5627,24 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(memnew(VSeparator));
- move_button = memnew(ToolButton);
+ move_button = memnew(Button);
+ move_button->set_flat(true);
hb->add_child(move_button);
move_button->set_toggle_mode(true);
move_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_MOVE));
move_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/move_mode", TTR("Move Mode"), KEY_W));
move_button->set_tooltip(TTR("Move Mode"));
- rotate_button = memnew(ToolButton);
+ rotate_button = memnew(Button);
+ rotate_button->set_flat(true);
hb->add_child(rotate_button);
rotate_button->set_toggle_mode(true);
rotate_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_ROTATE));
rotate_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/rotate_mode", TTR("Rotate Mode"), KEY_E));
rotate_button->set_tooltip(TTR("Rotate Mode"));
- scale_button = memnew(ToolButton);
+ scale_button = memnew(Button);
+ scale_button->set_flat(true);
hb->add_child(scale_button);
scale_button->set_toggle_mode(true);
scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_SCALE));
@@ -5594,25 +5653,30 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(memnew(VSeparator));
- list_select_button = memnew(ToolButton);
+ list_select_button = memnew(Button);
+ list_select_button->set_flat(true);
hb->add_child(list_select_button);
list_select_button->set_toggle_mode(true);
list_select_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_LIST_SELECT));
list_select_button->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode)."));
- pivot_button = memnew(ToolButton);
+ pivot_button = memnew(Button);
+ pivot_button->set_flat(true);
hb->add_child(pivot_button);
pivot_button->set_toggle_mode(true);
pivot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_EDIT_PIVOT));
pivot_button->set_tooltip(TTR("Click to change object's rotation pivot."));
- pan_button = memnew(ToolButton);
+ pan_button = memnew(Button);
+ pan_button->set_flat(true);
hb->add_child(pan_button);
pan_button->set_toggle_mode(true);
pan_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_PAN));
+ pan_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/pan_mode", TTR("Pan Mode"), KEY_G));
pan_button->set_tooltip(TTR("Pan Mode"));
- ruler_button = memnew(ToolButton);
+ ruler_button = memnew(Button);
+ ruler_button->set_flat(true);
hb->add_child(ruler_button);
ruler_button->set_toggle_mode(true);
ruler_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_RULER));
@@ -5621,14 +5685,16 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(memnew(VSeparator));
- smart_snap_button = memnew(ToolButton);
+ smart_snap_button = memnew(Button);
+ smart_snap_button->set_flat(true);
hb->add_child(smart_snap_button);
smart_snap_button->set_toggle_mode(true);
smart_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_smart_snap));
smart_snap_button->set_tooltip(TTR("Toggle smart snapping."));
smart_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_smart_snap", TTR("Use Smart Snap"), KEY_MASK_SHIFT | KEY_S));
- grid_snap_button = memnew(ToolButton);
+ grid_snap_button = memnew(Button);
+ grid_snap_button->set_flat(true);
hb->add_child(grid_snap_button);
grid_snap_button->set_toggle_mode(true);
grid_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_grid_snap));
@@ -5667,23 +5733,27 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(memnew(VSeparator));
- lock_button = memnew(ToolButton);
+ lock_button = memnew(Button);
+ lock_button->set_flat(true);
hb->add_child(lock_button);
lock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(LOCK_SELECTED));
lock_button->set_tooltip(TTR("Lock the selected object in place (can't be moved)."));
- unlock_button = memnew(ToolButton);
+ unlock_button = memnew(Button);
+ unlock_button->set_flat(true);
hb->add_child(unlock_button);
unlock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(UNLOCK_SELECTED));
unlock_button->set_tooltip(TTR("Unlock the selected object (can be moved)."));
- group_button = memnew(ToolButton);
+ group_button = memnew(Button);
+ group_button->set_flat(true);
hb->add_child(group_button);
group_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(GROUP_SELECTED));
group_button->set_tooltip(TTR("Makes sure the object's children are not selectable."));
- ungroup_button = memnew(ToolButton);
+ ungroup_button = memnew(Button);
+ ungroup_button->set_flat(true);
hb->add_child(ungroup_button);
ungroup_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(UNGROUP_SELECTED));
ungroup_button->set_tooltip(TTR("Restores the object's children's ability to be selected."));
@@ -5708,7 +5778,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(memnew(VSeparator));
- override_camera_button = memnew(ToolButton);
+ override_camera_button = memnew(Button);
+ override_camera_button->set_flat(true);
hb->add_child(override_camera_button);
override_camera_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_override_camera));
override_camera_button->set_toggle_mode(true);
@@ -5755,7 +5826,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
anchors_popup->set_name("Anchors");
anchors_popup->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback));
- anchor_mode_button = memnew(ToolButton);
+ anchor_mode_button = memnew(Button);
+ anchor_mode_button->set_flat(true);
hb->add_child(anchor_mode_button);
anchor_mode_button->set_toggle_mode(true);
anchor_mode_button->hide();
@@ -6077,6 +6149,11 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
Vector2 target_pos = canvas_item_editor->get_canvas_transform().affine_inverse().xform(p_point);
target_pos = canvas_item_editor->snap_point(target_pos);
target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos);
+ // Preserve instance position of the original scene.
+ CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instanced_scene);
+ if (instance_ci) {
+ target_pos += instance_ci->_edit_get_position();
+ }
editor_data->get_undo_redo().add_do_method(instanced_scene, "set_position", target_pos);
}
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index a686c98f65..c5d74c6fc9 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -228,9 +228,9 @@ private:
VScrollBar *v_scroll;
HBoxContainer *hb;
- ToolButton *zoom_minus;
- ToolButton *zoom_reset;
- ToolButton *zoom_plus;
+ Button *zoom_minus;
+ Button *zoom_reset;
+ Button *zoom_plus;
Map<Control *, Timer *> popup_temporarily_timers;
@@ -336,31 +336,31 @@ private:
};
List<PoseClipboard> pose_clipboard;
- ToolButton *select_button;
+ Button *select_button;
- ToolButton *move_button;
- ToolButton *scale_button;
- ToolButton *rotate_button;
+ Button *move_button;
+ Button *scale_button;
+ Button *rotate_button;
- ToolButton *list_select_button;
- ToolButton *pivot_button;
- ToolButton *pan_button;
+ Button *list_select_button;
+ Button *pivot_button;
+ Button *pan_button;
- ToolButton *ruler_button;
+ Button *ruler_button;
- ToolButton *smart_snap_button;
- ToolButton *grid_snap_button;
+ Button *smart_snap_button;
+ Button *grid_snap_button;
MenuButton *snap_config_menu;
PopupMenu *smartsnap_config_popup;
- ToolButton *lock_button;
- ToolButton *unlock_button;
+ Button *lock_button;
+ Button *unlock_button;
- ToolButton *group_button;
- ToolButton *ungroup_button;
+ Button *group_button;
+ Button *ungroup_button;
MenuButton *skeleton_menu;
- ToolButton *override_camera_button;
+ Button *override_camera_button;
MenuButton *view_menu;
HBoxContainer *animation_hb;
MenuButton *animation_menu;
@@ -369,7 +369,7 @@ private:
PopupMenu *anchors_and_margins_popup;
PopupMenu *anchors_popup;
- ToolButton *anchor_mode_button;
+ Button *anchor_mode_button;
Button *key_loc_button;
Button *key_rot_button;
@@ -528,6 +528,7 @@ private:
VBoxContainer *controls_vb;
HBoxContainer *zoom_hb;
+ float _get_next_zoom_value(int p_increment_count) const;
void _zoom_on_position(float p_zoom, Point2 p_position = Point2());
void _update_zoom_label();
void _button_zoom_minus();
diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.cpp b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
index c61d410d38..6eb17685f6 100644
--- a/editor/plugins/collision_polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "canvas_item_editor_plugin.h"
#include "core/input/input.h"
+#include "core/math/geometry_2d.h"
#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "editor/editor_settings.h"
@@ -196,7 +197,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
p_camera->unproject_position(gt.xform(Vector3(poly[(i + 1) % poly.size()].x, poly[(i + 1) % poly.size()].y, depth)))
};
- Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint, points);
+ Vector2 cp = Geometry2D::get_closest_point_to_segment(gpoint, points);
if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2) {
continue; //not valid to reuse point
}
@@ -500,12 +501,14 @@ CollisionPolygon3DEditor::CollisionPolygon3DEditor(EditorNode *p_editor) {
undo_redo = EditorNode::get_undo_redo();
add_child(memnew(VSeparator));
- button_create = memnew(ToolButton);
+ button_create = memnew(Button);
+ button_create->set_flat(true);
add_child(button_create);
button_create->connect("pressed", callable_mp(this, &CollisionPolygon3DEditor::_menu_option), varray(MODE_CREATE));
button_create->set_toggle_mode(true);
- button_edit = memnew(ToolButton);
+ button_edit = memnew(Button);
+ button_edit->set_flat(true);
add_child(button_edit);
button_edit->connect("pressed", callable_mp(this, &CollisionPolygon3DEditor::_menu_option), varray(MODE_EDIT));
button_edit->set_toggle_mode(true);
diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.h b/editor/plugins/collision_polygon_3d_editor_plugin.h
index 5215cbb678..05b8df520c 100644
--- a/editor/plugins/collision_polygon_3d_editor_plugin.h
+++ b/editor/plugins/collision_polygon_3d_editor_plugin.h
@@ -36,7 +36,6 @@
#include "scene/3d/collision_polygon_3d.h"
#include "scene/3d/immediate_geometry_3d.h"
#include "scene/3d/mesh_instance_3d.h"
-#include "scene/gui/tool_button.h"
class CanvasItemEditor;
@@ -53,8 +52,8 @@ class CollisionPolygon3DEditor : public HBoxContainer {
Mode mode;
- ToolButton *button_create;
- ToolButton *button_edit;
+ Button *button_create;
+ Button *button_edit;
Ref<StandardMaterial3D> line_material;
Ref<StandardMaterial3D> handle_material;
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index 0f381c06b4..596629f8e8 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -36,6 +36,7 @@
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
#include "scene/resources/line_shape_2d.h"
+#include "scene/resources/ray_shape_2d.h"
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/segment_shape_2d.h"
diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp
index 0ca479555d..0a4d173923 100644
--- a/editor/plugins/debugger_editor_plugin.cpp
+++ b/editor/plugins/debugger_editor_plugin.cpp
@@ -68,13 +68,10 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(EditorNode *p_editor, MenuButton *p_d
p->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION);
p->set_item_tooltip(p->get_item_count() - 1, TTR("Navigation meshes and polygons will be visible on the running game if this option is turned on."));
p->add_separator();
- //those are now on by default, since they are harmless
p->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Sync Scene Changes")), RUN_LIVE_DEBUG);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any changes made to the scene in the editor will be replicated in the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
- p->set_item_checked(p->get_item_count() - 1, true);
p->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Sync Script Changes")), RUN_RELOAD_SCRIPTS);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any script that is saved will be reloaded on the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
- p->set_item_checked(p->get_item_count() - 1, true);
// Multi-instance, start/stop
instances_menu = memnew(PopupMenu);
@@ -174,8 +171,8 @@ void DebuggerEditorPlugin::_update_debug_options() {
bool check_file_server = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_file_server", false);
bool check_debug_collisions = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_collisons", false);
bool check_debug_navigation = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_navigation", false);
- bool check_live_debug = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_live_debug", false);
- bool check_reload_scripts = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_reload_scripts", false);
+ bool check_live_debug = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_live_debug", true);
+ bool check_reload_scripts = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_reload_scripts", true);
int instances = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_instances", 1);
if (check_deploy_remote) {
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 9cb167b41c..2889cb50a0 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -127,7 +127,8 @@ Ref<Texture2D> EditorTexturePreviewPlugin::generate(const RES &p_from, const Siz
if (new_size.y > p_size.y) {
new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y);
}
- img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC);
+ Vector2i new_size_i(MAX(1, (int)new_size.x), MAX(1, (int)new_size.y));
+ img->resize(new_size_i.x, new_size_i.y, Image::INTERPOLATE_CUBIC);
post_process_preview(img);
diff --git a/editor/plugins/gi_probe_editor_plugin.cpp b/editor/plugins/gi_probe_editor_plugin.cpp
index 94f771e643..1b48e17772 100644
--- a/editor/plugins/gi_probe_editor_plugin.cpp
+++ b/editor/plugins/gi_probe_editor_plugin.cpp
@@ -144,7 +144,8 @@ GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) {
bake_hb = memnew(HBoxContainer);
bake_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
bake_hb->hide();
- bake = memnew(ToolButton);
+ bake = memnew(Button);
+ bake->set_flat(true);
bake->set_icon(editor->get_gui_base()->get_theme_icon("Bake", "EditorIcons"));
bake->set_text(TTR("Bake GI Probe"));
bake->connect("pressed", callable_mp(this, &GIProbeEditorPlugin::_bake));
diff --git a/editor/plugins/gi_probe_editor_plugin.h b/editor/plugins/gi_probe_editor_plugin.h
index 508c3d825b..e55f287908 100644
--- a/editor/plugins/gi_probe_editor_plugin.h
+++ b/editor/plugins/gi_probe_editor_plugin.h
@@ -43,7 +43,7 @@ class GIProbeEditorPlugin : public EditorPlugin {
HBoxContainer *bake_hb;
Label *bake_info;
- ToolButton *bake;
+ Button *bake;
EditorNode *editor;
EditorFileDialog *probe_file;
diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp
index 7402baad57..b4dcbdfe20 100644
--- a/editor/plugins/item_list_editor_plugin.cpp
+++ b/editor/plugins/item_list_editor_plugin.cpp
@@ -325,7 +325,8 @@ ItemListEditor::ItemListEditor() {
selected_idx = -1;
item_list = nullptr;
- toolbar_button = memnew(ToolButton);
+ toolbar_button = memnew(Button);
+ toolbar_button->set_flat(true);
toolbar_button->set_text(TTR("Items"));
add_child(toolbar_button);
toolbar_button->connect("pressed", callable_mp(this, &ItemListEditor::_edit_items));
diff --git a/editor/plugins/item_list_editor_plugin.h b/editor/plugins/item_list_editor_plugin.h
index 61dd617e3b..d89631633c 100644
--- a/editor/plugins/item_list_editor_plugin.h
+++ b/editor/plugins/item_list_editor_plugin.h
@@ -198,7 +198,7 @@ class ItemListEditor : public HBoxContainer {
Node *item_list;
- ToolButton *toolbar_button;
+ Button *toolbar_button;
AcceptDialog *dialog;
EditorInspector *property_editor;
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 3c12022854..b51ea9e1c6 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -328,17 +328,13 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
//-------
// Apply camera transform
- float tolerance = 0.001;
+ real_t tolerance = 0.001;
bool equal = true;
- if (Math::abs(old_camera_cursor.x_rot - camera_cursor.x_rot) > tolerance || Math::abs(old_camera_cursor.y_rot - camera_cursor.y_rot) > tolerance) {
+ if (!Math::is_equal_approx(old_camera_cursor.x_rot, camera_cursor.x_rot, tolerance) || !Math::is_equal_approx(old_camera_cursor.y_rot, camera_cursor.y_rot, tolerance)) {
equal = false;
- }
-
- if (equal && old_camera_cursor.pos.distance_squared_to(camera_cursor.pos) > tolerance * tolerance) {
+ } else if (!old_camera_cursor.pos.is_equal_approx(camera_cursor.pos)) {
equal = false;
- }
-
- if (equal && Math::abs(old_camera_cursor.distance - camera_cursor.distance) > tolerance) {
+ } else if (!Math::is_equal_approx(old_camera_cursor.distance, camera_cursor.distance, tolerance)) {
equal = false;
}
@@ -356,6 +352,7 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
update_transform_gizmo_view();
rotation_control->update();
}
+ spatial_editor->update_grid();
}
Transform Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) const {
@@ -490,6 +487,10 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, b
Vector3 pos = _get_ray_pos(p_pos);
Vector2 shrinked_pos = p_pos / subviewport_container->get_stretch_shrink();
+ if (viewport->get_debug_draw() == Viewport::DEBUG_DRAW_SDFGI_PROBES) {
+ RS::get_singleton()->sdfgi_set_debug_probe_select(pos, ray);
+ }
+
Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world_3d()->get_scenario());
Set<Ref<EditorNode3DGizmo>> found_gizmos;
@@ -835,7 +836,7 @@ bool Node3DEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_high
Vector3 r;
- if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
+ if (Geometry3D::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
float d = r.distance_to(ray_pos);
if (d < col_d) {
col_d = d;
@@ -932,7 +933,7 @@ bool Node3DEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_high
Vector3 r;
- if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
+ if (Geometry3D::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
float d = r.distance_to(ray_pos);
if (d < col_d) {
col_d = d;
@@ -2109,12 +2110,7 @@ void Node3DEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, cons
cursor.x_rot += p_relative.y * radians_per_pixel;
}
cursor.y_rot += p_relative.x * radians_per_pixel;
- if (cursor.x_rot > Math_PI / 2.0) {
- cursor.x_rot = Math_PI / 2.0;
- }
- if (cursor.x_rot < -Math_PI / 2.0) {
- cursor.x_rot = -Math_PI / 2.0;
- }
+ cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57);
name = "";
_update_name();
}
@@ -2142,12 +2138,7 @@ void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const
cursor.x_rot += p_relative.y * radians_per_pixel;
}
cursor.y_rot += p_relative.x * radians_per_pixel;
- if (cursor.x_rot > Math_PI / 2.0) {
- cursor.x_rot = Math_PI / 2.0;
- }
- if (cursor.x_rot < -Math_PI / 2.0) {
- cursor.x_rot = -Math_PI / 2.0;
- }
+ cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57);
// Look is like the opposite of Orbit: the focus point rotates around the camera
Transform camera_transform = to_camera_transform(cursor);
@@ -2177,6 +2168,8 @@ void Node3DEditorViewport::set_freelook_active(bool active_now) {
freelook_speed = base_speed * cursor.distance;
}
+ previous_mouse_position = get_local_mouse_position();
+
// Hide mouse like in an FPS (warping doesn't work)
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
@@ -2186,6 +2179,11 @@ void Node3DEditorViewport::set_freelook_active(bool active_now) {
// Restore mouse
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+
+ // Restore the previous mouse position when leaving freelook mode.
+ // This is done because leaving `Input.MOUSE_MODE_CAPTURED` will center the cursor
+ // due to OS limitations.
+ warp_mouse(previous_mouse_position);
}
freelook_active = active_now;
@@ -2344,13 +2342,6 @@ void Node3DEditorViewport::_notification(int p_what) {
call_deferred("update_transform_gizmo_view");
}
- if (p_what == NOTIFICATION_READY) {
- // The crosshair icon doesn't depend on the editor theme.
- crosshair->set_texture(get_theme_icon("Crosshair", "EditorIcons"));
- // Set the anchors and margins after changing the icon to ensure it's centered correctly.
- crosshair->set_anchors_and_margins_preset(PRESET_CENTER);
- }
-
if (p_what == NOTIFICATION_PROCESS) {
real_t delta = get_process_delta_time();
@@ -2476,10 +2467,6 @@ void Node3DEditorViewport::_notification(int p_what) {
current_camera = camera;
}
- // Display the crosshair only while freelooking. Hide it otherwise,
- // as the crosshair can be distracting.
- crosshair->set_visible(freelook_active);
-
if (show_info) {
String text;
text += "X: " + rtos(current_camera->get_translation().x).pad_decimals(1) + "\n";
@@ -2586,14 +2573,14 @@ void Node3DEditorViewport::_notification(int p_what) {
}
}
-static void draw_indicator_bar(Control &surface, real_t fill, Ref<Texture2D> icon) {
+static void draw_indicator_bar(Control &surface, real_t fill, const Ref<Texture2D> icon, const Ref<Font> font, const String &text) {
// Adjust bar size from control height
- Vector2 surface_size = surface.get_size();
- real_t h = surface_size.y / 2.0;
- real_t y = (surface_size.y - h) / 2.0;
+ const Vector2 surface_size = surface.get_size();
+ const real_t h = surface_size.y / 2.0;
+ const real_t y = (surface_size.y - h) / 2.0;
- Rect2 r(10, y, 6, h);
- real_t sy = r.size.y * fill;
+ const Rect2 r(10 * EDSCALE, y, 6 * EDSCALE, h);
+ const real_t sy = r.size.y * fill;
// Note: because this bar appears over the viewport, it has to stay readable for any background color
// Draw both neutral dark and bright colors to account this
@@ -2601,9 +2588,12 @@ static void draw_indicator_bar(Control &surface, real_t fill, Ref<Texture2D> ico
surface.draw_rect(Rect2(r.position.x, r.position.y + r.size.y - sy, r.size.x, sy), Color(1, 1, 1, 0.6));
surface.draw_rect(r.grow(1), Color(0, 0, 0, 0.7), false, Math::round(EDSCALE));
- Vector2 icon_size = icon->get_size();
- Vector2 icon_pos = Vector2(r.position.x - (icon_size.x - r.size.x) / 2, r.position.y + r.size.y + 2);
+ const Vector2 icon_size = icon->get_size();
+ const Vector2 icon_pos = Vector2(r.position.x - (icon_size.x - r.size.x) / 2, r.position.y + r.size.y + 2 * EDSCALE);
surface.draw_texture(icon, icon_pos);
+
+ // Draw text below the bar (for speed/zoom information).
+ surface.draw_string(font, Vector2(icon_pos.x, icon_pos.y + icon_size.y + 16 * EDSCALE), text);
}
void Node3DEditorViewport::_draw() {
@@ -2700,7 +2690,14 @@ void Node3DEditorViewport::_draw() {
logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0);
}
- draw_indicator_bar(*surface, 1.0 - logscale_t, get_theme_icon("ViewportSpeed", "EditorIcons"));
+ // Display the freelook speed to help the user get a better sense of scale.
+ const int precision = freelook_speed < 1.0 ? 2 : 1;
+ draw_indicator_bar(
+ *surface,
+ 1.0 - logscale_t,
+ get_theme_icon("ViewportSpeed", "EditorIcons"),
+ get_theme_font("font", "Label"),
+ vformat("%s u/s", String::num(freelook_speed).pad_decimals(precision)));
}
} else {
@@ -2719,7 +2716,14 @@ void Node3DEditorViewport::_draw() {
logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0);
}
- draw_indicator_bar(*surface, logscale_t, get_theme_icon("ViewportZoom", "EditorIcons"));
+ // Display the zoom center distance to help the user get a better sense of scale.
+ const int precision = cursor.distance < 1.0 ? 2 : 1;
+ draw_indicator_bar(
+ *surface,
+ logscale_t,
+ get_theme_icon("ViewportZoom", "EditorIcons"),
+ get_theme_font("font", "Label"),
+ vformat("%s u", String::num(cursor.distance).pad_decimals(precision)));
}
}
}
@@ -2984,7 +2988,9 @@ void Node3DEditorViewport::_menu_option(int p_option) {
case VIEW_DISPLAY_DEBUG_SSAO:
case VIEW_DISPLAY_DEBUG_PSSM_SPLITS:
case VIEW_DISPLAY_DEBUG_DECAL_ATLAS:
- case VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER: {
+ case VIEW_DISPLAY_DEBUG_SDFGI:
+ case VIEW_DISPLAY_DEBUG_SDFGI_PROBES:
+ case VIEW_DISPLAY_DEBUG_GI_BUFFER: {
static const int display_options[] = {
VIEW_DISPLAY_NORMAL,
VIEW_DISPLAY_WIREFRAME,
@@ -3000,9 +3006,11 @@ void Node3DEditorViewport::_menu_option(int p_option) {
VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION,
VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
VIEW_DISPLAY_DEBUG_SSAO,
- VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER,
+ VIEW_DISPLAY_DEBUG_GI_BUFFER,
VIEW_DISPLAY_DEBUG_PSSM_SPLITS,
VIEW_DISPLAY_DEBUG_DECAL_ATLAS,
+ VIEW_DISPLAY_DEBUG_SDFGI,
+ VIEW_DISPLAY_DEBUG_SDFGI_PROBES,
VIEW_MAX
};
static const Viewport::DebugDraw debug_draw_modes[] = {
@@ -3020,9 +3028,11 @@ void Node3DEditorViewport::_menu_option(int p_option) {
Viewport::DEBUG_DRAW_GI_PROBE_EMISSION,
Viewport::DEBUG_DRAW_SCENE_LUMINANCE,
Viewport::DEBUG_DRAW_SSAO,
- Viewport::DEBUG_DRAW_ROUGHNESS_LIMITER,
+ Viewport::DEBUG_DRAW_GI_BUFFER,
Viewport::DEBUG_DRAW_PSSM_SPLITS,
Viewport::DEBUG_DRAW_DECAL_ATLAS,
+ Viewport::DEBUG_DRAW_SDFGI,
+ Viewport::DEBUG_DRAW_SDFGI_PROBES,
};
int idx = 0;
@@ -3208,7 +3218,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
Plane p(camera_xform.origin, camz);
- float gizmo_d = Math::abs(p.distance_to(xform.origin));
+ float gizmo_d = MAX(Math::abs(p.distance_to(xform.origin)), CMP_EPSILON);
float d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y;
float d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y;
float dd = Math::abs(d0 - d1);
@@ -3422,11 +3432,7 @@ void Node3DEditorViewport::reset() {
last_message = "";
name = "";
- cursor.x_rot = 0.5;
- cursor.y_rot = 0.5;
- cursor.distance = 4;
- cursor.region_select = false;
- cursor.pos = Vector3();
+ cursor = Cursor();
_update_name();
}
@@ -3661,15 +3667,19 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name);
editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
- Transform global_transform;
- Node3D *parent_spatial = Object::cast_to<Node3D>(parent);
- if (parent_spatial) {
- global_transform = parent_spatial->get_global_gizmo_transform();
- }
+ Node3D *node3d = Object::cast_to<Node3D>(instanced_scene);
+ if (node3d) {
+ Transform global_transform;
+ Node3D *parent_node3d = Object::cast_to<Node3D>(parent);
+ if (parent_node3d) {
+ global_transform = parent_node3d->get_global_gizmo_transform();
+ }
- global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
+ global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
+ global_transform.basis *= node3d->get_transform().basis;
- editor_data->get_undo_redo().add_do_method(instanced_scene, "set_global_transform", global_transform);
+ editor_data->get_undo_redo().add_do_method(instanced_scene, "set_global_transform", global_transform);
+ }
return true;
}
@@ -3852,10 +3862,6 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
camera->make_current();
surface->set_focus_mode(FOCUS_ALL);
- crosshair = memnew(TextureRect);
- crosshair->set_mouse_filter(MOUSE_FILTER_IGNORE);
- surface->add_child(crosshair);
-
VBoxContainer *vbox = memnew(VBoxContainer);
surface->add_child(vbox);
vbox->set_position(Point2(10, 10) * EDSCALE);
@@ -3902,11 +3908,14 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
display_submenu->add_radio_check_item(TTR("GIProbe Albedo"), VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO);
display_submenu->add_radio_check_item(TTR("GIProbe Emission"), VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION);
display_submenu->add_separator();
+ display_submenu->add_radio_check_item(TTR("SDFGI Cascades"), VIEW_DISPLAY_DEBUG_SDFGI);
+ display_submenu->add_radio_check_item(TTR("SDFGI Probes"), VIEW_DISPLAY_DEBUG_SDFGI_PROBES);
+ display_submenu->add_separator();
display_submenu->add_radio_check_item(TTR("Scene Luminance"), VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE);
display_submenu->add_separator();
display_submenu->add_radio_check_item(TTR("SSAO"), VIEW_DISPLAY_DEBUG_SSAO);
display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("Roughness Limiter"), VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER);
+ display_submenu->add_radio_check_item(TTR("GI Buffer"), VIEW_DISPLAY_DEBUG_GI_BUFFER);
display_submenu->set_name("display_advanced");
view_menu->get_popup()->add_submenu_item(TTR("Display Advanced..."), "display_advanced", VIEW_DISPLAY_ADVANCED);
view_menu->get_popup()->add_separator();
@@ -4929,8 +4938,10 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
for (int i = 0; i < 3; ++i) {
if (grid_enable[i]) {
- RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], grid_enabled);
grid_visible[i] = grid_enabled;
+ if (grid_instance[i].is_valid()) {
+ RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], grid_enabled);
+ }
}
}
@@ -4950,7 +4961,7 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
Node3D *spatial = Object::cast_to<Node3D>(E->get());
- if (!spatial || !spatial->is_visible_in_tree()) {
+ if (!spatial || !spatial->is_inside_tree()) {
continue;
}
@@ -4964,8 +4975,8 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
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->add_do_method(this, "_refresh_menu_icons");
+ undo_redo->add_undo_method(this, "_refresh_menu_icons");
undo_redo->commit_action();
} break;
case MENU_UNLOCK_SELECTED: {
@@ -4975,7 +4986,7 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
Node3D *spatial = Object::cast_to<Node3D>(E->get());
- if (!spatial || !spatial->is_visible_in_tree()) {
+ if (!spatial || !spatial->is_inside_tree()) {
continue;
}
@@ -4989,8 +5000,8 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
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->add_do_method(this, "_refresh_menu_icons");
+ undo_redo->add_undo_method(this, "_refresh_menu_icons");
undo_redo->commit_action();
} break;
case MENU_GROUP_SELECTED: {
@@ -5000,7 +5011,7 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
Node3D *spatial = Object::cast_to<Node3D>(E->get());
- if (!spatial || !spatial->is_visible_in_tree()) {
+ if (!spatial || !spatial->is_inside_tree()) {
continue;
}
@@ -5014,8 +5025,8 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
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->add_do_method(this, "_refresh_menu_icons");
+ undo_redo->add_undo_method(this, "_refresh_menu_icons");
undo_redo->commit_action();
} break;
case MENU_UNGROUP_SELECTED: {
@@ -5024,7 +5035,7 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
Node3D *spatial = Object::cast_to<Node3D>(E->get());
- if (!spatial || !spatial->is_visible_in_tree()) {
+ if (!spatial || !spatial->is_inside_tree()) {
continue;
}
@@ -5038,8 +5049,8 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
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->add_do_method(this, "_refresh_menu_icons");
+ undo_redo->add_undo_method(this, "_refresh_menu_icons");
undo_redo->commit_action();
} break;
}
@@ -5054,6 +5065,7 @@ void Node3DEditor::_init_indicators() {
indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ indicator_mat->set_transparency(StandardMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS);
Vector<Color> origin_colors;
Vector<Vector3> origin_points;
@@ -5082,12 +5094,27 @@ void Node3DEditor::_init_indicators() {
origin_colors.push_back(origin_color);
origin_colors.push_back(origin_color);
- origin_points.push_back(axis * 4096);
- origin_points.push_back(axis * -4096);
- }
-
- grid_enable[1] = true;
- grid_visible[1] = true;
+ origin_colors.push_back(origin_color);
+ origin_colors.push_back(origin_color);
+ origin_colors.push_back(origin_color);
+ origin_colors.push_back(origin_color);
+ // To both allow having a large origin size and avoid jitter
+ // at small scales, we should segment the line into pieces.
+ // 3 pieces seems to do the trick, and let's use powers of 2.
+ origin_points.push_back(axis * 1048576);
+ origin_points.push_back(axis * 1024);
+ origin_points.push_back(axis * 1024);
+ origin_points.push_back(axis * -1024);
+ origin_points.push_back(axis * -1024);
+ origin_points.push_back(axis * -1048576);
+ }
+
+ grid_enable[0] = EditorSettings::get_singleton()->get("editors/3d/grid_xy_plane");
+ grid_enable[1] = EditorSettings::get_singleton()->get("editors/3d/grid_yz_plane");
+ grid_enable[2] = EditorSettings::get_singleton()->get("editors/3d/grid_xz_plane");
+ grid_visible[0] = grid_enable[0];
+ grid_visible[1] = grid_enable[1];
+ grid_visible[2] = grid_enable[2];
_init_grid();
@@ -5382,6 +5409,9 @@ void Node3DEditor::_update_gizmos_menu() {
const int plugin_state = gizmo_plugins_by_name[i]->get_state();
gizmos_menu->add_multistate_item(TTR(plugin_name), 3, plugin_state, i);
const int idx = gizmos_menu->get_item_index(i);
+ gizmos_menu->set_item_tooltip(
+ idx,
+ TTR("Click to toggle between visibility states.\n\nOpen eye: Gizmo is visible.\nClosed eye: Gizmo is hidden.\nHalf-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."));
switch (plugin_state) {
case EditorNode3DGizmoPlugin::VISIBLE:
gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_visible"));
@@ -5418,6 +5448,15 @@ void Node3DEditor::_update_gizmos_menu_theme() {
}
void Node3DEditor::_init_grid() {
+ if (!grid_enabled) {
+ return;
+ }
+ Camera3D *camera = get_editor_viewport(0)->camera;
+ Vector3 camera_position = camera->get_translation();
+ if (camera_position == Vector3()) {
+ return; // Camera3D is invalid, don't draw the grid.
+ }
+
Vector<Color> grid_colors[3];
Vector<Vector3> grid_points[3];
@@ -5426,52 +5465,111 @@ void Node3DEditor::_init_grid() {
int grid_size = EditorSettings::get_singleton()->get("editors/3d/grid_size");
int primary_grid_steps = EditorSettings::get_singleton()->get("editors/3d/primary_grid_steps");
- for (int i = 0; i < 3; i++) {
- Vector3 axis;
- axis[i] = 1;
- Vector3 axis_n1;
- axis_n1[(i + 1) % 3] = 1;
- Vector3 axis_n2;
- axis_n2[(i + 2) % 3] = 1;
-
- for (int j = -grid_size; j <= grid_size; j++) {
- Vector3 p1 = axis_n1 * j + axis_n2 * -grid_size;
- Vector3 p1_dest = p1 * (-axis_n2 + axis_n1);
- Vector3 p2 = axis_n2 * j + axis_n1 * -grid_size;
- Vector3 p2_dest = p2 * (-axis_n1 + axis_n2);
-
- Color line_color = secondary_grid_color;
- if (origin_enabled && j == 0) {
- // Don't draw the center lines of the grid if the origin is enabled
- // The origin would overlap the grid lines in this case, causing flickering
- continue;
- } else if (j % primary_grid_steps == 0) {
- line_color = primary_grid_color;
+ // Which grid planes are enabled? Which should we generate?
+ grid_enable[0] = grid_visible[0] = EditorSettings::get_singleton()->get("editors/3d/grid_xy_plane");
+ grid_enable[1] = grid_visible[1] = EditorSettings::get_singleton()->get("editors/3d/grid_yz_plane");
+ grid_enable[2] = grid_visible[2] = EditorSettings::get_singleton()->get("editors/3d/grid_xz_plane");
+
+ // Offsets division_level for bigger or smaller grids.
+ // Default value is -0.2. -1.0 gives Blender-like behavior, 0.5 gives huge grids.
+ real_t division_level_bias = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_bias");
+ // Default largest grid size is 100m, 10^2 (default value is 2).
+ int division_level_max = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_max");
+ // Default smallest grid size is 1cm, 10^-2 (default value is -2).
+ int division_level_min = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_min");
+ ERR_FAIL_COND_MSG(division_level_max < division_level_min, "The 3D grid's maximum division level cannot be lower than its minimum division level.");
+
+ if (primary_grid_steps != 10) { // Log10 of 10 is 1.
+ // Change of base rule, divide by ln(10).
+ real_t div = Math::log((real_t)primary_grid_steps) / (real_t)2.302585092994045901094;
+ // Trucation (towards zero) is intentional.
+ division_level_max = (int)(division_level_max / div);
+ division_level_min = (int)(division_level_min / div);
+ }
+
+ for (int a = 0; a < 3; a++) {
+ if (!grid_enable[a]) {
+ continue; // If this grid plane is disabled, skip generation.
+ }
+ int b = (a + 1) % 3;
+ int c = (a + 2) % 3;
+
+ real_t division_level = Math::log(Math::abs(camera_position[c])) / Math::log((double)primary_grid_steps) + division_level_bias;
+ division_level = CLAMP(division_level, division_level_min, division_level_max);
+ real_t division_level_floored = Math::floor(division_level);
+ real_t division_level_decimals = division_level - division_level_floored;
+
+ real_t small_step_size = Math::pow(primary_grid_steps, division_level_floored);
+ real_t large_step_size = small_step_size * primary_grid_steps;
+ real_t center_a = large_step_size * (int)(camera_position[a] / large_step_size);
+ real_t center_b = large_step_size * (int)(camera_position[b] / large_step_size);
+
+ real_t bgn_a = center_a - grid_size * small_step_size;
+ real_t end_a = center_a + grid_size * small_step_size;
+ real_t bgn_b = center_b - grid_size * small_step_size;
+ real_t end_b = center_b + grid_size * small_step_size;
+
+ // In each iteration of this loop, draw one line in each direction (so two lines per loop, in each if statement).
+ for (int i = -grid_size; i <= grid_size; i++) {
+ Color line_color;
+ // Is this a primary line? Set the appropriate color.
+ if (i % primary_grid_steps == 0) {
+ line_color = primary_grid_color.lerp(secondary_grid_color, division_level_decimals);
+ } else {
+ line_color = secondary_grid_color;
+ line_color.a = line_color.a * (1 - division_level_decimals);
+ }
+ // Makes lines farther from the center fade out.
+ // Due to limitations of lines, any that come near the camera have full opacity always.
+ // This should eventually be replaced by some kind of "distance fade" system, outside of this function.
+ // But the effect is still somewhat convincing...
+ line_color.a *= 1 - (1 - division_level_decimals * 0.9) * (Math::abs(i / (float)grid_size));
+
+ real_t position_a = center_a + i * small_step_size;
+ real_t position_b = center_b + i * small_step_size;
+
+ // Don't draw lines over the origin if it's enabled.
+ if (!(origin_enabled && Math::is_zero_approx(position_a))) {
+ Vector3 line_bgn = Vector3();
+ Vector3 line_end = Vector3();
+ line_bgn[a] = position_a;
+ line_end[a] = position_a;
+ line_bgn[b] = bgn_b;
+ line_end[b] = end_b;
+ grid_points[c].push_back(line_bgn);
+ grid_points[c].push_back(line_end);
+ grid_colors[c].push_back(line_color);
+ grid_colors[c].push_back(line_color);
}
- grid_points[i].push_back(p1);
- grid_points[i].push_back(p1_dest);
- grid_colors[i].push_back(line_color);
- grid_colors[i].push_back(line_color);
-
- grid_points[i].push_back(p2);
- grid_points[i].push_back(p2_dest);
- grid_colors[i].push_back(line_color);
- grid_colors[i].push_back(line_color);
+ if (!(origin_enabled && Math::is_zero_approx(position_b))) {
+ Vector3 line_bgn = Vector3();
+ Vector3 line_end = Vector3();
+ line_bgn[b] = position_b;
+ line_end[b] = position_b;
+ line_bgn[a] = bgn_a;
+ line_end[a] = end_a;
+ grid_points[c].push_back(line_bgn);
+ grid_points[c].push_back(line_end);
+ grid_colors[c].push_back(line_color);
+ grid_colors[c].push_back(line_color);
+ }
}
- grid[i] = RenderingServer::get_singleton()->mesh_create();
+ // Create a mesh from the pushed vector points and colors.
+ grid[c] = RenderingServer::get_singleton()->mesh_create();
Array d;
d.resize(RS::ARRAY_MAX);
- d[RenderingServer::ARRAY_VERTEX] = grid_points[i];
- d[RenderingServer::ARRAY_COLOR] = grid_colors[i];
- RenderingServer::get_singleton()->mesh_add_surface_from_arrays(grid[i], RenderingServer::PRIMITIVE_LINES, d);
- RenderingServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat->get_rid());
- grid_instance[i] = RenderingServer::get_singleton()->instance_create2(grid[i], get_tree()->get_root()->get_world_3d()->get_scenario());
+ d[RenderingServer::ARRAY_VERTEX] = grid_points[c];
+ d[RenderingServer::ARRAY_COLOR] = grid_colors[c];
+ RenderingServer::get_singleton()->mesh_add_surface_from_arrays(grid[c], RenderingServer::PRIMITIVE_LINES, d);
+ RenderingServer::get_singleton()->mesh_surface_set_material(grid[c], 0, indicator_mat->get_rid());
+ grid_instance[c] = RenderingServer::get_singleton()->instance_create2(grid[c], get_tree()->get_root()->get_world_3d()->get_scenario());
- RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], grid_visible[i]);
- RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
- RS::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
+ // Yes, the end of this line is supposed to be a.
+ RenderingServer::get_singleton()->instance_set_visible(grid_instance[c], grid_visible[a]);
+ RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[c], RS::SHADOW_CASTING_SETTING_OFF);
+ RS::get_singleton()->instance_set_layer_mask(grid_instance[c], 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
}
}
@@ -5489,6 +5587,11 @@ void Node3DEditor::_finish_grid() {
}
}
+void Node3DEditor::update_grid() {
+ _finish_grid();
+ _init_grid();
+}
+
bool Node3DEditor::is_any_freelook_active() const {
for (unsigned int i = 0; i < VIEWPORTS_COUNT; ++i) {
if (viewports[i]->is_freelook_active()) {
@@ -5889,6 +5992,7 @@ void Node3DEditor::_bind_methods() {
ClassDB::bind_method("_unhandled_key_input", &Node3DEditor::_unhandled_key_input);
ClassDB::bind_method("_get_editor_data", &Node3DEditor::_get_editor_data);
ClassDB::bind_method("_request_gizmo", &Node3DEditor::_request_gizmo);
+ ClassDB::bind_method("_refresh_menu_icons", &Node3DEditor::_refresh_menu_icons);
ADD_SIGNAL(MethodInfo("transform_key_request"));
ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
@@ -5948,7 +6052,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
button_binds.resize(1);
String sct;
- tool_button[TOOL_MODE_SELECT] = memnew(ToolButton);
+ tool_button[TOOL_MODE_SELECT] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_MODE_SELECT]);
tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true);
tool_button[TOOL_MODE_SELECT]->set_flat(true);
@@ -5960,7 +6064,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
hbc_menu->add_child(memnew(VSeparator));
- tool_button[TOOL_MODE_MOVE] = memnew(ToolButton);
+ tool_button[TOOL_MODE_MOVE] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_MODE_MOVE]);
tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true);
tool_button[TOOL_MODE_MOVE]->set_flat(true);
@@ -5968,7 +6072,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_MOVE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), KEY_W));
- tool_button[TOOL_MODE_ROTATE] = memnew(ToolButton);
+ tool_button[TOOL_MODE_ROTATE] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]);
tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true);
tool_button[TOOL_MODE_ROTATE]->set_flat(true);
@@ -5976,7 +6080,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_ROTATE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), KEY_E));
- tool_button[TOOL_MODE_SCALE] = memnew(ToolButton);
+ tool_button[TOOL_MODE_SCALE] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]);
tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true);
tool_button[TOOL_MODE_SCALE]->set_flat(true);
@@ -5986,7 +6090,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
hbc_menu->add_child(memnew(VSeparator));
- tool_button[TOOL_MODE_LIST_SELECT] = memnew(ToolButton);
+ tool_button[TOOL_MODE_LIST_SELECT] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_MODE_LIST_SELECT]);
tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true);
tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true);
@@ -5994,33 +6098,37 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode)."));
- tool_button[TOOL_LOCK_SELECTED] = memnew(ToolButton);
+ tool_button[TOOL_LOCK_SELECTED] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_LOCK_SELECTED]);
+ tool_button[TOOL_LOCK_SELECTED]->set_flat(true);
button_binds.write[0] = MENU_LOCK_SELECTED;
tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock the selected object in place (can't be moved)."));
- tool_button[TOOL_UNLOCK_SELECTED] = memnew(ToolButton);
+ tool_button[TOOL_UNLOCK_SELECTED] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]);
+ tool_button[TOOL_UNLOCK_SELECTED]->set_flat(true);
button_binds.write[0] = MENU_UNLOCK_SELECTED;
tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_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);
+ tool_button[TOOL_GROUP_SELECTED] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]);
+ tool_button[TOOL_GROUP_SELECTED]->set_flat(true);
button_binds.write[0] = MENU_GROUP_SELECTED;
tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_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);
+ tool_button[TOOL_UNGROUP_SELECTED] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
+ tool_button[TOOL_UNGROUP_SELECTED]->set_flat(true);
button_binds.write[0] = MENU_UNGROUP_SELECTED;
tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_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);
+ tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(Button);
hbc_menu->add_child(tool_option_button[TOOL_OPT_LOCAL_COORDS]);
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_toggle_mode(true);
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true);
@@ -6028,7 +6136,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_option_button[TOOL_OPT_LOCAL_COORDS]->connect("toggled", callable_mp(this, &Node3DEditor::_menu_item_toggled), button_binds);
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Use Local Space"), KEY_T));
- tool_option_button[TOOL_OPT_USE_SNAP] = memnew(ToolButton);
+ tool_option_button[TOOL_OPT_USE_SNAP] = memnew(Button);
hbc_menu->add_child(tool_option_button[TOOL_OPT_USE_SNAP]);
tool_option_button[TOOL_OPT_USE_SNAP]->set_toggle_mode(true);
tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true);
@@ -6038,7 +6146,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
hbc_menu->add_child(memnew(VSeparator));
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(ToolButton);
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(Button);
hbc_menu->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]);
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true);
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_flat(true);
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 3d92e7e7e1..a40de78795 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -214,9 +214,11 @@ class Node3DEditorViewport : public Control {
VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION,
VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
VIEW_DISPLAY_DEBUG_SSAO,
- VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER,
VIEW_DISPLAY_DEBUG_PSSM_SPLITS,
VIEW_DISPLAY_DEBUG_DECAL_ATLAS,
+ VIEW_DISPLAY_DEBUG_SDFGI,
+ VIEW_DISPLAY_DEBUG_SDFGI_PROBES,
+ VIEW_DISPLAY_DEBUG_GI_BUFFER,
VIEW_LOCK_ROTATION,
VIEW_CINEMATIC_PREVIEW,
VIEW_AUTO_ORTHOGONAL,
@@ -284,8 +286,8 @@ private:
bool freelook_active;
real_t freelook_speed;
+ Vector2 previous_mouse_position;
- TextureRect *crosshair;
Label *info_label;
Label *cinema_label;
Label *locked_label;
@@ -391,7 +393,9 @@ private:
Point2 region_begin, region_end;
Cursor() {
- x_rot = y_rot = 0.5;
+ // These rotations place the camera in +X +Y +Z, aka south east, facing north west.
+ x_rot = 0.5;
+ y_rot = -0.5;
distance = 4;
region_select = false;
}
@@ -766,6 +770,7 @@ public:
Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; }
Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; }
+ void update_grid();
void update_transform_gizmo();
void update_all_gizmos(Node *p_node = nullptr);
void snap_selected_nodes_to_floor();
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index a3dab665b8..f79098ce5d 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -532,35 +532,40 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) {
sep = memnew(VSeparator);
base_hb->add_child(sep);
- curve_edit = memnew(ToolButton);
+ curve_edit = memnew(Button);
+ curve_edit->set_flat(true);
curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveEdit", "EditorIcons"));
curve_edit->set_toggle_mode(true);
curve_edit->set_focus_mode(Control::FOCUS_NONE);
curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point"));
curve_edit->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_EDIT));
base_hb->add_child(curve_edit);
- curve_edit_curve = memnew(ToolButton);
+ curve_edit_curve = memnew(Button);
+ curve_edit_curve->set_flat(true);
curve_edit_curve->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCurve", "EditorIcons"));
curve_edit_curve->set_toggle_mode(true);
curve_edit_curve->set_focus_mode(Control::FOCUS_NONE);
curve_edit_curve->set_tooltip(TTR("Select Control Points (Shift+Drag)"));
curve_edit_curve->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_EDIT_CURVE));
base_hb->add_child(curve_edit_curve);
- curve_create = memnew(ToolButton);
+ curve_create = memnew(Button);
+ curve_create->set_flat(true);
curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCreate", "EditorIcons"));
curve_create->set_toggle_mode(true);
curve_create->set_focus_mode(Control::FOCUS_NONE);
curve_create->set_tooltip(TTR("Add Point (in empty space)"));
curve_create->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_CREATE));
base_hb->add_child(curve_create);
- curve_del = memnew(ToolButton);
+ curve_del = memnew(Button);
+ curve_del->set_flat(true);
curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveDelete", "EditorIcons"));
curve_del->set_toggle_mode(true);
curve_del->set_focus_mode(Control::FOCUS_NONE);
curve_del->set_tooltip(TTR("Delete Point"));
curve_del->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_DELETE));
base_hb->add_child(curve_del);
- curve_close = memnew(ToolButton);
+ curve_close = memnew(Button);
+ curve_close->set_flat(true);
curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveClose", "EditorIcons"));
curve_close->set_focus_mode(Control::FOCUS_NONE);
curve_close->set_tooltip(TTR("Close Curve"));
diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h
index 390dfdfdf7..d0c02b28d4 100644
--- a/editor/plugins/path_2d_editor_plugin.h
+++ b/editor/plugins/path_2d_editor_plugin.h
@@ -34,7 +34,6 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/2d/path_2d.h"
-#include "scene/gui/tool_button.h"
class CanvasItemEditor;
@@ -60,11 +59,11 @@ class Path2DEditor : public HBoxContainer {
};
Mode mode;
- ToolButton *curve_create;
- ToolButton *curve_edit;
- ToolButton *curve_edit_curve;
- ToolButton *curve_del;
- ToolButton *curve_close;
+ Button *curve_create;
+ Button *curve_edit;
+ Button *curve_edit_curve;
+ Button *curve_del;
+ Button *curve_close;
MenuButton *handle_menu;
bool mirror_handle_angle;
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index a44fe69ff6..f53130c24d 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -30,6 +30,8 @@
#include "path_3d_editor_plugin.h"
+#include "core/math/geometry_2d.h"
+#include "core/math/geometry_3d.h"
#include "core/os/keyboard.h"
#include "node_3d_editor_plugin.h"
#include "scene/resources/curve.h"
@@ -344,7 +346,7 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
Vector2 s[2];
s[0] = p_camera->unproject_position(from);
s[1] = p_camera->unproject_position(to);
- Vector2 inters = Geometry::get_closest_point_to_segment_2d(mbpos, s);
+ Vector2 inters = Geometry2D::get_closest_point_to_segment(mbpos, s);
float d = inters.distance_to(mbpos);
if (d < 10 && d < closest_d) {
@@ -354,7 +356,7 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
Vector3 ray_dir = p_camera->project_ray_normal(mbpos);
Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(ray_from, ray_from + ray_dir * 4096, from, to, ra, rb);
+ Geometry3D::get_closest_points_between_segments(ray_from, ray_from + ray_dir * 4096, from, to, ra, rb);
closest_seg_point = it.xform(rb);
}
@@ -555,28 +557,32 @@ Path3DEditorPlugin::Path3DEditorPlugin(EditorNode *p_node) {
sep = memnew(VSeparator);
sep->hide();
Node3DEditor::get_singleton()->add_control_to_menu_panel(sep);
- curve_edit = memnew(ToolButton);
+ curve_edit = memnew(Button);
+ curve_edit->set_flat(true);
curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveEdit", "EditorIcons"));
curve_edit->set_toggle_mode(true);
curve_edit->hide();
curve_edit->set_focus_mode(Control::FOCUS_NONE);
curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_edit);
- curve_create = memnew(ToolButton);
+ curve_create = memnew(Button);
+ curve_create->set_flat(true);
curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCreate", "EditorIcons"));
curve_create->set_toggle_mode(true);
curve_create->hide();
curve_create->set_focus_mode(Control::FOCUS_NONE);
curve_create->set_tooltip(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_create);
- curve_del = memnew(ToolButton);
+ curve_del = memnew(Button);
+ curve_del->set_flat(true);
curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveDelete", "EditorIcons"));
curve_del->set_toggle_mode(true);
curve_del->hide();
curve_del->set_focus_mode(Control::FOCUS_NONE);
curve_del->set_tooltip(TTR("Delete Point"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_del);
- curve_close = memnew(ToolButton);
+ curve_close = memnew(Button);
+ curve_close->set_flat(true);
curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveClose", "EditorIcons"));
curve_close->hide();
curve_close->set_focus_mode(Control::FOCUS_NONE);
diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h
index 8bec5df797..3a75717b73 100644
--- a/editor/plugins/path_3d_editor_plugin.h
+++ b/editor/plugins/path_3d_editor_plugin.h
@@ -68,10 +68,10 @@ class Path3DEditorPlugin : public EditorPlugin {
GDCLASS(Path3DEditorPlugin, EditorPlugin);
Separator *sep;
- ToolButton *curve_create;
- ToolButton *curve_edit;
- ToolButton *curve_del;
- ToolButton *curve_close;
+ Button *curve_create;
+ Button *curve_edit;
+ Button *curve_del;
+ Button *curve_close;
MenuButton *handle_menu;
EditorNode *editor;
diff --git a/editor/plugins/physical_bone_3d_editor_plugin.cpp b/editor/plugins/physical_bone_3d_editor_plugin.cpp
index bcbf88e7dc..30bf827b3c 100644
--- a/editor/plugins/physical_bone_3d_editor_plugin.cpp
+++ b/editor/plugins/physical_bone_3d_editor_plugin.cpp
@@ -55,7 +55,8 @@ PhysicalBone3DEditor::PhysicalBone3DEditor(EditorNode *p_editor) :
spatial_editor_hb->add_child(memnew(VSeparator));
- button_transform_joint = memnew(ToolButton);
+ button_transform_joint = memnew(Button);
+ button_transform_joint->set_flat(true);
spatial_editor_hb->add_child(button_transform_joint);
button_transform_joint->set_text(TTR("Move Joint"));
diff --git a/editor/plugins/physical_bone_3d_editor_plugin.h b/editor/plugins/physical_bone_3d_editor_plugin.h
index 79c7cc4bb1..8699176fe0 100644
--- a/editor/plugins/physical_bone_3d_editor_plugin.h
+++ b/editor/plugins/physical_bone_3d_editor_plugin.h
@@ -38,7 +38,7 @@ class PhysicalBone3DEditor : public Object {
EditorNode *editor;
HBoxContainer *spatial_editor_hb;
- ToolButton *button_transform_joint;
+ Button *button_transform_joint;
PhysicalBone3D *selected = nullptr;
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 7ee695b9fe..633863041f 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "canvas_item_editor_plugin.h"
#include "core/input/input.h"
+#include "core/math/geometry_2d.h"
#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "editor/editor_scale.h"
@@ -484,7 +485,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
} else {
Vector2 tuv = mtx.affine_inverse().xform(snap_point(Vector2(mb->get_position().x, mb->get_position().y)));
- if (points_prev.size() > 2 && tuv.distance_to(points_prev[0]) < 8) {
+ // Close the polygon if selected point is near start. Threshold for closing scaled by zoom level
+ if (points_prev.size() > 2 && tuv.distance_to(points_prev[0]) < (8 / uv_draw_zoom)) {
undo_redo->create_action(TTR("Create Polygon & UV"));
undo_redo->add_do_method(node, "set_uv", node->get_uv());
undo_redo->add_undo_method(node, "set_uv", uv_create_uv_prev);
@@ -693,7 +695,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
polys.write[j] = mtx.xform(points_prev[idx]);
}
- if (Geometry::is_point_in_polygon(Vector2(mb->get_position().x, mb->get_position().y), polys)) {
+ if (Geometry2D::is_point_in_polygon(Vector2(mb->get_position().x, mb->get_position().y), polys)) {
erase_index = i;
break;
}
@@ -1213,7 +1215,8 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
use_snap = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_enabled", false);
snap_show_grid = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "show_grid", false);
- button_uv = memnew(ToolButton);
+ button_uv = memnew(Button);
+ button_uv->set_flat(true);
add_child(button_uv);
button_uv->set_tooltip(TTR("Open Polygon 2D UV editor."));
button_uv->connect("pressed", callable_mp(this, &Polygon2DEditor::_menu_option), varray(MODE_EDIT_UV));
@@ -1230,16 +1233,16 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
uv_edit_group.instance();
- uv_edit_mode[0] = memnew(ToolButton);
+ uv_edit_mode[0] = memnew(Button);
uv_mode_hb->add_child(uv_edit_mode[0]);
uv_edit_mode[0]->set_toggle_mode(true);
- uv_edit_mode[1] = memnew(ToolButton);
+ uv_edit_mode[1] = memnew(Button);
uv_mode_hb->add_child(uv_edit_mode[1]);
uv_edit_mode[1]->set_toggle_mode(true);
- uv_edit_mode[2] = memnew(ToolButton);
+ uv_edit_mode[2] = memnew(Button);
uv_mode_hb->add_child(uv_edit_mode[2]);
uv_edit_mode[2]->set_toggle_mode(true);
- uv_edit_mode[3] = memnew(ToolButton);
+ uv_edit_mode[3] = memnew(Button);
uv_mode_hb->add_child(uv_edit_mode[3]);
uv_edit_mode[3]->set_toggle_mode(true);
@@ -1263,7 +1266,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
uv_main_vb->add_child(uv_mode_hb);
for (int i = 0; i < UV_MODE_MAX; i++) {
- uv_button[i] = memnew(ToolButton);
+ uv_button[i] = memnew(Button);
uv_button[i]->set_toggle_mode(true);
uv_mode_hb->add_child(uv_button[i]);
uv_button[i]->connect("pressed", callable_mp(this, &Polygon2DEditor::_uv_mode), varray(i));
@@ -1333,7 +1336,8 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
uv_mode_hb->add_child(memnew(VSeparator));
- b_snap_enable = memnew(ToolButton);
+ b_snap_enable = memnew(Button);
+ b_snap_enable->set_flat(true);
uv_mode_hb->add_child(b_snap_enable);
b_snap_enable->set_text(TTR("Snap"));
b_snap_enable->set_focus_mode(FOCUS_NONE);
@@ -1342,7 +1346,8 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
b_snap_enable->set_tooltip(TTR("Enable Snap"));
b_snap_enable->connect("toggled", callable_mp(this, &Polygon2DEditor::_set_use_snap));
- b_snap_grid = memnew(ToolButton);
+ b_snap_grid = memnew(Button);
+ b_snap_grid->set_flat(true);
uv_mode_hb->add_child(b_snap_grid);
b_snap_grid->set_text(TTR("Grid"));
b_snap_grid->set_focus_mode(FOCUS_NONE);
diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h
index b94ae53e2b..33ea7722ac 100644
--- a/editor/plugins/polygon_2d_editor_plugin.h
+++ b/editor/plugins/polygon_2d_editor_plugin.h
@@ -60,16 +60,16 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
UV_MODE_MAX
};
- ToolButton *uv_edit_mode[4];
+ Button *uv_edit_mode[4];
Ref<ButtonGroup> uv_edit_group;
Polygon2D *node;
UVMode uv_mode;
AcceptDialog *uv_edit;
- ToolButton *uv_button[UV_MODE_MAX];
- ToolButton *b_snap_enable;
- ToolButton *b_snap_grid;
+ Button *uv_button[UV_MODE_MAX];
+ Button *b_snap_enable;
+ Button *b_snap_grid;
Panel *uv_edit_draw;
HSlider *uv_zoom;
SpinBox *uv_zoom_value;
@@ -115,7 +115,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
AcceptDialog *error;
- ToolButton *button_uv;
+ Button *button_uv;
bool use_snap;
bool snap_show_grid;
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 8d6dac3907..96079d5418 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -837,7 +837,6 @@ void ScriptEditor::_file_dialog_action(String p_file) {
Error err;
FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
if (err) {
- memdelete(file);
editor->show_warning(TTR("Error writing TextFile:") + "\n" + p_file, TTR("Error!"));
break;
}
@@ -2989,7 +2988,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
filename->add_theme_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("normal", "LineEdit"));
buttons_hbox->add_child(filename);
- members_overview_alphabeta_sort_button = memnew(ToolButton);
+ members_overview_alphabeta_sort_button = memnew(Button);
+ members_overview_alphabeta_sort_button->set_flat(true);
members_overview_alphabeta_sort_button->set_tooltip(TTR("Toggle alphabetical sorting of the method list."));
members_overview_alphabeta_sort_button->set_toggle_mode(true);
members_overview_alphabeta_sort_button->set_pressed(EditorSettings::get_singleton()->get("text_editor/tools/sort_members_outline_alphabetically"));
@@ -3050,7 +3050,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
file_menu->get_popup()->add_separator();
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KEY_MASK_ALT | KEY_MASK_CMD | KEY_S), FILE_SAVE);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As...")), FILE_SAVE_AS);
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_S), FILE_SAVE_ALL);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_S), FILE_SAVE_ALL);
file_menu->get_popup()->add_separator();
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_R), FILE_TOOL_RELOAD_SOFT);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/copy_path", TTR("Copy Script Path")), FILE_COPY_PATH);
@@ -3116,13 +3116,15 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
menu_hb->add_spacer();
- site_search = memnew(ToolButton);
+ site_search = memnew(Button);
+ site_search->set_flat(true);
site_search->set_text(TTR("Online Docs"));
site_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option), varray(SEARCH_WEBSITE));
menu_hb->add_child(site_search);
site_search->set_tooltip(TTR("Open Godot online documentation."));
- help_search = memnew(ToolButton);
+ help_search = memnew(Button);
+ help_search->set_flat(true);
help_search->set_text(TTR("Search Help"));
help_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option), varray(SEARCH_HELP));
menu_hb->add_child(help_search);
@@ -3130,13 +3132,15 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
menu_hb->add_child(memnew(VSeparator));
- script_back = memnew(ToolButton);
+ script_back = memnew(Button);
+ script_back->set_flat(true);
script_back->connect("pressed", callable_mp(this, &ScriptEditor::_history_back));
menu_hb->add_child(script_back);
script_back->set_disabled(true);
script_back->set_tooltip(TTR("Go to previous edited document."));
- script_forward = memnew(ToolButton);
+ script_forward = memnew(Button);
+ script_forward->set_flat(true);
script_forward->connect("pressed", callable_mp(this, &ScriptEditor::_history_forward));
menu_hb->add_child(script_forward);
script_forward->set_disabled(true);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index f7352be7e8..8c4b7de27d 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -43,7 +43,6 @@
#include "scene/gui/split_container.h"
#include "scene/gui/tab_container.h"
#include "scene/gui/text_edit.h"
-#include "scene/gui/tool_button.h"
#include "scene/gui/tree.h"
#include "scene/main/timer.h"
#include "scene/resources/text_file.h"
@@ -211,7 +210,7 @@ class ScriptEditor : public PanelContainer {
VBoxContainer *overview_vbox;
HBoxContainer *buttons_hbox;
Label *filename;
- ToolButton *members_overview_alphabeta_sort_button;
+ Button *members_overview_alphabeta_sort_button;
bool members_overview_enabled;
ItemList *help_overview;
bool help_overview_enabled;
@@ -221,15 +220,15 @@ class ScriptEditor : public PanelContainer {
AcceptDialog *error_dialog;
ConfirmationDialog *erase_tab_confirm;
ScriptCreateDialog *script_create_dialog;
- ToolButton *scripts_visible;
+ Button *scripts_visible;
String current_theme;
TextureRect *script_icon;
Label *script_name_label;
- ToolButton *script_back;
- ToolButton *script_forward;
+ Button *script_back;
+ Button *script_forward;
FindInFilesDialog *find_in_files_dialog;
FindInFilesPanel *find_in_files;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index e7f8a56e5e..1c9dadc0dd 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -383,10 +383,6 @@ void ScriptTextEditor::_show_warnings_panel(bool p_show) {
warnings_panel->set_visible(p_show);
}
-void ScriptTextEditor::_error_pressed() {
- code_editor->goto_error();
-}
-
void ScriptTextEditor::_warning_clicked(Variant p_line) {
if (p_line.get_type() == Variant::INT) {
code_editor->get_text_edit()->cursor_set_line(p_line.operator int64_t());
@@ -609,6 +605,18 @@ void ScriptTextEditor::_validate_script() {
for (List<ScriptLanguage::Warning>::Element *E = warnings.front(); E; E = E->next()) {
ScriptLanguage::Warning w = E->get();
+ Dictionary ignore_meta;
+ ignore_meta["line"] = w.line;
+ ignore_meta["code"] = w.string_code.to_lower();
+ warnings_panel->push_cell();
+ warnings_panel->push_meta(ignore_meta);
+ warnings_panel->push_color(
+ warnings_panel->get_theme_color("accent_color", "Editor").lerp(warnings_panel->get_theme_color("mono_color", "Editor"), 0.5));
+ warnings_panel->add_text(TTR("[Ignore]"));
+ warnings_panel->pop(); // Color.
+ warnings_panel->pop(); // Meta ignore.
+ warnings_panel->pop(); // Cell.
+
warnings_panel->push_cell();
warnings_panel->push_meta(w.line - 1);
warnings_panel->push_color(warnings_panel->get_theme_color("warning_color", "Editor"));
@@ -621,15 +629,6 @@ void ScriptTextEditor::_validate_script() {
warnings_panel->push_cell();
warnings_panel->add_text(w.message);
warnings_panel->pop(); // Cell.
-
- Dictionary ignore_meta;
- ignore_meta["line"] = w.line;
- ignore_meta["code"] = w.string_code.to_lower();
- warnings_panel->push_cell();
- warnings_panel->push_meta(ignore_meta);
- warnings_panel->add_text(TTR("(ignore)"));
- warnings_panel->pop(); // Meta ignore.
- warnings_panel->pop(); // Cell.
}
warnings_panel->pop(); // Table.
@@ -1747,6 +1746,8 @@ ScriptTextEditor::ScriptTextEditor() {
warnings_panel = memnew(RichTextLabel);
editor_box->add_child(warnings_panel);
+ warnings_panel->add_theme_font_override(
+ "normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts"));
warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE));
warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL);
warnings_panel->set_meta_underline(true);
@@ -1754,7 +1755,6 @@ ScriptTextEditor::ScriptTextEditor() {
warnings_panel->set_focus_mode(FOCUS_CLICK);
warnings_panel->hide();
- code_editor->connect("error_pressed", callable_mp(this, &ScriptTextEditor::_error_pressed));
code_editor->connect("show_warnings_panel", callable_mp(this, &ScriptTextEditor::_show_warnings_panel));
warnings_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_warning_clicked));
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index adcd0218bc..8fa380b64d 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -159,7 +159,6 @@ protected:
void _load_theme_settings();
void _set_theme_for_script();
void _show_warnings_panel(bool p_show);
- void _error_pressed();
void _warning_clicked(Variant p_line);
void _notification(int p_what);
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index c256acd17b..52da8dea19 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -30,13 +30,289 @@
#include "skeleton_3d_editor_plugin.h"
+#include "core/io/resource_saver.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_properties.h"
+#include "editor/editor_scale.h"
+#include "editor/plugins/animation_player_editor_plugin.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/3d/physics_joint_3d.h"
#include "scene/resources/capsule_shape_3d.h"
#include "scene/resources/sphere_shape_3d.h"
+void BoneTransformEditor::create_editors() {
+ const Color section_color = get_theme_color("prop_subsection", "Editor");
+
+ section = memnew(EditorInspectorSection);
+ section->setup("trf_properties", label, this, section_color, true);
+ add_child(section);
+
+ key_button = memnew(Button);
+ key_button->set_text(TTR("Key Transform"));
+ key_button->set_visible(keyable);
+ key_button->set_icon(get_theme_icon("Key", "EditorIcons"));
+ key_button->set_flat(true);
+ section->get_vbox()->add_child(key_button);
+
+ enabled_checkbox = memnew(CheckBox(TTR("Pose Enabled")));
+ enabled_checkbox->set_flat(true);
+ enabled_checkbox->set_visible(toggle_enabled);
+ section->get_vbox()->add_child(enabled_checkbox);
+
+ // Translation property
+ translation_property = memnew(EditorPropertyVector3());
+ translation_property->setup(-10000, 10000, 0.001f, true);
+ translation_property->set_label("Translation");
+ translation_property->set_use_folding(true);
+ translation_property->set_read_only(false);
+ translation_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed_vector3));
+ section->get_vbox()->add_child(translation_property);
+
+ // Rotation property
+ rotation_property = memnew(EditorPropertyVector3());
+ rotation_property->setup(-10000, 10000, 0.001f, true);
+ rotation_property->set_label("Rotation Degrees");
+ rotation_property->set_use_folding(true);
+ rotation_property->set_read_only(false);
+ rotation_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed_vector3));
+ section->get_vbox()->add_child(rotation_property);
+
+ // Scale property
+ scale_property = memnew(EditorPropertyVector3());
+ scale_property->setup(-10000, 10000, 0.001f, true);
+ scale_property->set_label("Scale");
+ scale_property->set_use_folding(true);
+ scale_property->set_read_only(false);
+ scale_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed_vector3));
+ section->get_vbox()->add_child(scale_property);
+
+ // Transform/Matrix section
+ transform_section = memnew(EditorInspectorSection);
+ transform_section->setup("trf_properties_transform", "Matrix", this, section_color, true);
+ section->get_vbox()->add_child(transform_section);
+
+ // Transform/Matrix property
+ transform_property = memnew(EditorPropertyTransform());
+ transform_property->setup(-10000, 10000, 0.001f, true);
+ transform_property->set_label("Transform");
+ transform_property->set_use_folding(true);
+ transform_property->set_read_only(false);
+ transform_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed_transform));
+ transform_section->get_vbox()->add_child(transform_property);
+}
+
+void BoneTransformEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ create_editors();
+ key_button->connect("pressed", callable_mp(this, &BoneTransformEditor::_key_button_pressed));
+ enabled_checkbox->connect("toggled", callable_mp(this, &BoneTransformEditor::_checkbox_toggled));
+ [[fallthrough]];
+ }
+ case NOTIFICATION_SORT_CHILDREN: {
+ const Ref<Font> font = get_theme_font("font", "Tree");
+
+ Point2 buffer;
+ buffer.x += get_theme_constant("inspector_margin", "Editor");
+ buffer.y += font->get_height();
+ buffer.y += get_theme_constant("vseparation", "Tree");
+
+ const float vector_height = translation_property->get_size().y;
+ const float transform_height = transform_property->get_size().y;
+ const float button_height = key_button->get_size().y;
+
+ const float width = get_size().x - get_theme_constant("inspector_margin", "Editor");
+ Vector<Rect2> input_rects;
+ if (keyable && section->get_vbox()->is_visible()) {
+ input_rects.push_back(Rect2(key_button->get_position() + buffer, Size2(width, button_height)));
+ } else {
+ input_rects.push_back(Rect2(0, 0, 0, 0));
+ }
+
+ if (section->get_vbox()->is_visible()) {
+ input_rects.push_back(Rect2(translation_property->get_position() + buffer, Size2(width, vector_height)));
+ input_rects.push_back(Rect2(rotation_property->get_position() + buffer, Size2(width, vector_height)));
+ input_rects.push_back(Rect2(scale_property->get_position() + buffer, Size2(width, vector_height)));
+ input_rects.push_back(Rect2(transform_property->get_position() + buffer, Size2(width, transform_height)));
+ } else {
+ const int32_t start = input_rects.size();
+ const int32_t empty_input_rect_elements = 4;
+ const int32_t end = start + empty_input_rect_elements;
+ for (int i = start; i < end; ++i) {
+ input_rects.push_back(Rect2(0, 0, 0, 0));
+ }
+ }
+
+ for (int32_t i = 0; i < input_rects.size(); i++) {
+ background_rects[i] = input_rects[i];
+ }
+
+ update();
+ break;
+ }
+ case NOTIFICATION_DRAW: {
+ const Color dark_color = get_theme_color("dark_color_2", "Editor");
+
+ for (int i = 0; i < 5; ++i) {
+ draw_rect(background_rects[i], dark_color);
+ }
+
+ break;
+ }
+ }
+}
+
+void BoneTransformEditor::_value_changed(const double p_value) {
+ if (updating)
+ return;
+
+ Transform tform = compute_transform_from_vector3s();
+ _change_transform(tform);
+}
+
+void BoneTransformEditor::_value_changed_vector3(const String p_property_name, const Vector3 p_vector, const StringName p_edited_property_name, const bool p_boolean) {
+ if (updating)
+ return;
+ Transform tform = compute_transform_from_vector3s();
+ _change_transform(tform);
+}
+
+Transform BoneTransformEditor::compute_transform_from_vector3s() const {
+ // Convert rotation from degrees to radians.
+ Vector3 prop_rotation = rotation_property->get_vector();
+ prop_rotation.x = Math::deg2rad(prop_rotation.x);
+ prop_rotation.y = Math::deg2rad(prop_rotation.y);
+ prop_rotation.z = Math::deg2rad(prop_rotation.z);
+
+ return Transform(
+ Basis(prop_rotation, scale_property->get_vector()),
+ translation_property->get_vector());
+}
+
+void BoneTransformEditor::_value_changed_transform(const String p_property_name, const Transform p_transform, const StringName p_edited_property_name, const bool p_boolean) {
+ if (updating)
+ return;
+ _change_transform(p_transform);
+}
+
+void BoneTransformEditor::_change_transform(Transform p_new_transform) {
+ if (property.get_slicec('/', 0) == "bones" && property.get_slicec('/', 2) == "custom_pose") {
+ undo_redo->create_action(TTR("Set Custom Bone Pose Transform"), UndoRedo::MERGE_ENDS);
+ undo_redo->add_undo_method(skeleton, "set_bone_custom_pose", property.get_slicec('/', 1).to_int(), skeleton->get_bone_custom_pose(property.get_slicec('/', 1).to_int()));
+ undo_redo->add_do_method(skeleton, "set_bone_custom_pose", property.get_slicec('/', 1).to_int(), p_new_transform);
+ undo_redo->commit_action();
+ } else if (property.get_slicec('/', 0) == "bones") {
+ undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
+ undo_redo->add_undo_property(skeleton, property, skeleton->get(property));
+ undo_redo->add_do_property(skeleton, property, p_new_transform);
+ undo_redo->commit_action();
+ }
+}
+
+void BoneTransformEditor::update_enabled_checkbox() {
+ if (enabled_checkbox) {
+ const String path = "bones/" + property.get_slicec('/', 1) + "/enabled";
+ const bool is_enabled = skeleton->get(path);
+ enabled_checkbox->set_pressed(is_enabled);
+ }
+}
+
+void BoneTransformEditor::_update_properties() {
+ if (updating)
+ return;
+
+ if (skeleton == nullptr)
+ return;
+
+ updating = true;
+
+ Transform tform = skeleton->get(property);
+ _update_transform_properties(tform);
+}
+
+void BoneTransformEditor::_update_custom_pose_properties() {
+ if (updating)
+ return;
+
+ if (skeleton == nullptr)
+ return;
+
+ updating = true;
+
+ Transform tform = skeleton->get_bone_custom_pose(property.to_int());
+ _update_transform_properties(tform);
+}
+
+void BoneTransformEditor::_update_transform_properties(Transform tform) {
+ Basis rotation_basis = tform.get_basis();
+ Vector3 rotation_radians = rotation_basis.get_rotation_euler();
+ Vector3 rotation_degrees = Vector3(Math::rad2deg(rotation_radians.x), Math::rad2deg(rotation_radians.y), Math::rad2deg(rotation_radians.z));
+ Vector3 translation = tform.get_origin();
+ Vector3 scale = tform.basis.get_scale();
+
+ translation_property->update_using_vector(translation);
+ rotation_property->update_using_vector(rotation_degrees);
+ scale_property->update_using_vector(scale);
+ transform_property->update_using_transform(tform);
+
+ update_enabled_checkbox();
+ updating = false;
+}
+
+BoneTransformEditor::BoneTransformEditor(Skeleton3D *p_skeleton) :
+ skeleton(p_skeleton),
+ key_button(nullptr),
+ enabled_checkbox(nullptr),
+ keyable(false),
+ toggle_enabled(false),
+ updating(false) {
+ undo_redo = EditorNode::get_undo_redo();
+}
+
+void BoneTransformEditor::set_target(const String &p_prop) {
+ property = p_prop;
+}
+
+void BoneTransformEditor::set_keyable(const bool p_keyable) {
+ keyable = p_keyable;
+ if (key_button) {
+ key_button->set_visible(p_keyable);
+ }
+}
+
+void BoneTransformEditor::set_toggle_enabled(const bool p_enabled) {
+ toggle_enabled = p_enabled;
+ if (enabled_checkbox) {
+ enabled_checkbox->set_visible(p_enabled);
+ }
+}
+
+void BoneTransformEditor::_key_button_pressed() {
+ if (skeleton == nullptr)
+ return;
+
+ const BoneId bone_id = property.get_slicec('/', 1).to_int();
+ const String name = skeleton->get_bone_name(bone_id);
+
+ if (name.empty())
+ return;
+
+ // Need to normalize the basis before you key it
+ Transform tform = compute_transform_from_vector3s();
+ tform.orthonormalize();
+ AnimationPlayerEditor::singleton->get_track_editor()->insert_transform_key(skeleton, name, tform);
+}
+
+void BoneTransformEditor::_checkbox_toggled(const bool p_toggled) {
+ if (enabled_checkbox) {
+ const String path = "bones/" + property.get_slicec('/', 1) + "/enabled";
+ skeleton->set(path, p_toggled);
+ }
+}
+
void Skeleton3DEditor::_on_click_option(int p_option) {
if (!skeleton) {
return;
@@ -45,12 +321,14 @@ void Skeleton3DEditor::_on_click_option(int p_option) {
switch (p_option) {
case MENU_OPTION_CREATE_PHYSICAL_SKELETON: {
create_physical_skeleton();
- } break;
+ break;
+ }
}
}
void Skeleton3DEditor::create_physical_skeleton() {
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ERR_FAIL_COND(!get_tree());
Node *owner = skeleton == get_tree()->get_edited_scene_root() ? skeleton : skeleton->get_owner();
const int bc = skeleton->get_bone_count();
@@ -124,28 +402,163 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
return physical_bone;
}
-void Skeleton3DEditor::edit(Skeleton3D *p_node) {
- skeleton = p_node;
+Variant Skeleton3DEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+ TreeItem *selected = joint_tree->get_selected();
+
+ if (!selected)
+ return Variant();
+
+ Ref<Texture> icon = selected->get_icon(0);
+
+ VBoxContainer *vb = memnew(VBoxContainer);
+ HBoxContainer *hb = memnew(HBoxContainer);
+ TextureRect *tf = memnew(TextureRect);
+ tf->set_texture(icon);
+ tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
+ hb->add_child(tf);
+ Label *label = memnew(Label(selected->get_text(0)));
+ hb->add_child(label);
+ vb->add_child(hb);
+ hb->set_modulate(Color(1, 1, 1, 1));
+
+ set_drag_preview(vb);
+ Dictionary drag_data;
+ drag_data["type"] = "nodes";
+ drag_data["node"] = selected;
+
+ return drag_data;
}
-void Skeleton3DEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed));
+bool Skeleton3DEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ TreeItem *target = joint_tree->get_item_at_position(p_point);
+ if (!target)
+ return false;
+
+ const String path = target->get_metadata(0);
+ if (!path.begins_with("bones/"))
+ return false;
+
+ TreeItem *selected = Object::cast_to<TreeItem>(Dictionary(p_data)["node"]);
+ if (target == selected)
+ return false;
+
+ const String path2 = target->get_metadata(0);
+ if (!path2.begins_with("bones/"))
+ return false;
+
+ return true;
+}
+
+void Skeleton3DEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+ if (!can_drop_data_fw(p_point, p_data, p_from))
+ return;
+
+ TreeItem *target = joint_tree->get_item_at_position(p_point);
+ TreeItem *selected = Object::cast_to<TreeItem>(Dictionary(p_data)["node"]);
+
+ const BoneId target_boneidx = String(target->get_metadata(0)).get_slicec('/', 1).to_int();
+ const BoneId selected_boneidx = String(selected->get_metadata(0)).get_slicec('/', 1).to_int();
+
+ move_skeleton_bone(skeleton->get_path(), selected_boneidx, target_boneidx);
+}
+
+void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx) {
+ Node *node = get_node_or_null(p_skeleton_path);
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
+ ERR_FAIL_NULL(skeleton);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Bone Parentage"));
+ // If the target is a child of ourselves, we move only *us* and not our children
+ if (skeleton->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) {
+ const BoneId parent_idx = skeleton->get_bone_parent(p_selected_boneidx);
+ const int bone_count = skeleton->get_bone_count();
+ for (BoneId i = 0; i < bone_count; ++i) {
+ if (skeleton->get_bone_parent(i) == p_selected_boneidx) {
+ ur->add_undo_method(skeleton, "set_bone_parent", i, skeleton->get_bone_parent(i));
+ ur->add_do_method(skeleton, "set_bone_parent", i, parent_idx);
+ skeleton->set_bone_parent(i, parent_idx);
+ }
+ }
}
+ ur->add_undo_method(skeleton, "set_bone_parent", p_selected_boneidx, skeleton->get_bone_parent(p_selected_boneidx));
+ ur->add_do_method(skeleton, "set_bone_parent", p_selected_boneidx, p_target_boneidx);
+ skeleton->set_bone_parent(p_selected_boneidx, p_target_boneidx);
+
+ update_joint_tree();
+ ur->commit_action();
}
-void Skeleton3DEditor::_node_removed(Node *p_node) {
- if (p_node == skeleton) {
- skeleton = nullptr;
- options->hide();
+void Skeleton3DEditor::_joint_tree_selection_changed() {
+ TreeItem *selected = joint_tree->get_selected();
+ const String path = selected->get_metadata(0);
+
+ if (path.begins_with("bones/")) {
+ const int b_idx = path.get_slicec('/', 1).to_int();
+ const String bone_path = "bones/" + itos(b_idx) + "/";
+
+ pose_editor->set_target(bone_path + "pose");
+ rest_editor->set_target(bone_path + "rest");
+ custom_pose_editor->set_target(bone_path + "custom_pose");
+
+ pose_editor->set_visible(true);
+ rest_editor->set_visible(true);
+ custom_pose_editor->set_visible(true);
}
}
-void Skeleton3DEditor::_bind_methods() {
+void Skeleton3DEditor::_joint_tree_rmb_select(const Vector2 &p_pos) {
+}
+
+void Skeleton3DEditor::_update_properties() {
+ if (rest_editor)
+ rest_editor->_update_properties();
+ if (pose_editor)
+ pose_editor->_update_properties();
+ if (custom_pose_editor)
+ custom_pose_editor->_update_custom_pose_properties();
+}
+
+void Skeleton3DEditor::update_joint_tree() {
+ joint_tree->clear();
+
+ if (skeleton == nullptr)
+ return;
+
+ TreeItem *root = joint_tree->create_item();
+
+ Map<int, TreeItem *> items;
+
+ items.insert(-1, root);
+
+ const Vector<int> &joint_porder = skeleton->get_bone_process_orders();
+ Ref<Texture> bone_icon = get_theme_icon("BoneAttachment3D", "EditorIcons");
+
+ for (int i = 0; i < joint_porder.size(); ++i) {
+ const int b_idx = joint_porder[i];
+
+ const int p_idx = skeleton->get_bone_parent(b_idx);
+ TreeItem *p_item = items.find(p_idx)->get();
+
+ TreeItem *joint_item = joint_tree->create_item(p_item);
+ items.insert(b_idx, joint_item);
+
+ joint_item->set_text(0, skeleton->get_bone_name(b_idx));
+ joint_item->set_icon(0, bone_icon);
+ joint_item->set_selectable(0, true);
+ joint_item->set_metadata(0, "bones/" + itos(b_idx));
+ }
}
-Skeleton3DEditor::Skeleton3DEditor() {
- skeleton = nullptr;
+void Skeleton3DEditor::update_editors() {
+}
+
+void Skeleton3DEditor::create_editors() {
+ set_h_size_flags(SIZE_EXPAND_FILL);
+ add_theme_constant_override("separation", 0);
+
+ set_focus_mode(FOCUS_ALL);
+
+ // Create Top Menu Bar
options = memnew(MenuButton);
Node3DEditor::get_singleton()->add_control_to_menu_panel(options);
@@ -155,32 +568,119 @@ Skeleton3DEditor::Skeleton3DEditor() {
options->get_popup()->add_item(TTR("Create physical skeleton"), MENU_OPTION_CREATE_PHYSICAL_SKELETON);
options->get_popup()->connect("id_pressed", callable_mp(this, &Skeleton3DEditor::_on_click_option));
- options->hide();
+
+ const Color section_color = get_theme_color("prop_subsection", "Editor");
+
+ EditorInspectorSection *bones_section = memnew(EditorInspectorSection);
+ bones_section->setup("bones", "Bones", skeleton, section_color, true);
+ add_child(bones_section);
+ bones_section->unfold();
+
+ ScrollContainer *s_con = memnew(ScrollContainer);
+ s_con->set_h_size_flags(SIZE_EXPAND_FILL);
+ s_con->set_custom_minimum_size(Size2(1, 350) * EDSCALE);
+ bones_section->get_vbox()->add_child(s_con);
+
+ joint_tree = memnew(Tree);
+ joint_tree->set_columns(1);
+ joint_tree->set_focus_mode(Control::FocusMode::FOCUS_NONE);
+ joint_tree->set_select_mode(Tree::SELECT_SINGLE);
+ joint_tree->set_hide_root(true);
+ joint_tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ joint_tree->set_h_size_flags(SIZE_EXPAND_FILL);
+ joint_tree->set_allow_rmb_select(true);
+ joint_tree->set_drag_forwarding(this);
+ s_con->add_child(joint_tree);
+
+ pose_editor = memnew(BoneTransformEditor(skeleton));
+ pose_editor->set_label(TTR("Bone Pose"));
+ pose_editor->set_keyable(AnimationPlayerEditor::singleton->get_track_editor()->has_keying());
+ pose_editor->set_toggle_enabled(true);
+ pose_editor->set_visible(false);
+ add_child(pose_editor);
+
+ rest_editor = memnew(BoneTransformEditor(skeleton));
+ rest_editor->set_label(TTR("Bone Rest"));
+ rest_editor->set_visible(false);
+ add_child(rest_editor);
+
+ custom_pose_editor = memnew(BoneTransformEditor(skeleton));
+ custom_pose_editor->set_label(TTR("Bone Custom Pose"));
+ custom_pose_editor->set_visible(false);
+ add_child(custom_pose_editor);
+}
+
+void Skeleton3DEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ create_editors();
+ update_joint_tree();
+ update_editors();
+
+ get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Vector<Variant>(), Object::CONNECT_ONESHOT);
+ joint_tree->connect("item_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_selection_changed));
+ joint_tree->connect("item_rmb_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_rmb_select));
+#ifdef TOOLS_ENABLED
+ skeleton->connect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties));
+#endif // TOOLS_ENABLED
+
+ break;
+ }
+ }
}
-Skeleton3DEditor::~Skeleton3DEditor() {}
+void Skeleton3DEditor::_node_removed(Node *p_node) {
+ if (skeleton && p_node == skeleton) {
+ skeleton = nullptr;
+ options->hide();
+ }
+
+ _update_properties();
+}
-void Skeleton3DEditorPlugin::edit(Object *p_object) {
- skeleton_editor->edit(Object::cast_to<Skeleton3D>(p_object));
+void Skeleton3DEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_node_removed"), &Skeleton3DEditor::_node_removed);
+ ClassDB::bind_method(D_METHOD("_joint_tree_selection_changed"), &Skeleton3DEditor::_joint_tree_selection_changed);
+ ClassDB::bind_method(D_METHOD("_joint_tree_rmb_select"), &Skeleton3DEditor::_joint_tree_rmb_select);
+ ClassDB::bind_method(D_METHOD("_update_properties"), &Skeleton3DEditor::_update_properties);
+ ClassDB::bind_method(D_METHOD("_on_click_option"), &Skeleton3DEditor::_on_click_option);
+
+ ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &Skeleton3DEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Skeleton3DEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("drop_data_fw"), &Skeleton3DEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("move_skeleton_bone"), &Skeleton3DEditor::move_skeleton_bone);
}
-bool Skeleton3DEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("Skeleton3D");
+Skeleton3DEditor::Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton3D *p_skeleton) :
+ editor(p_editor),
+ editor_plugin(e_plugin),
+ skeleton(p_skeleton) {
}
-void Skeleton3DEditorPlugin::make_visible(bool p_visible) {
- if (p_visible) {
- skeleton_editor->options->show();
- } else {
- skeleton_editor->options->hide();
- skeleton_editor->edit(nullptr);
+Skeleton3DEditor::~Skeleton3DEditor() {
+ if (options) {
+ Node3DEditor::get_singleton()->remove_control_from_menu_panel(options);
}
}
+bool EditorInspectorPluginSkeleton::can_handle(Object *p_object) {
+ return Object::cast_to<Skeleton3D>(p_object) != nullptr;
+}
+
+void EditorInspectorPluginSkeleton::parse_begin(Object *p_object) {
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_object);
+ ERR_FAIL_COND(!skeleton);
+
+ Skeleton3DEditor *skel_editor = memnew(Skeleton3DEditor(this, editor, skeleton));
+ add_custom_control(skel_editor);
+}
+
Skeleton3DEditorPlugin::Skeleton3DEditorPlugin(EditorNode *p_node) {
editor = p_node;
- skeleton_editor = memnew(Skeleton3DEditor);
- editor->get_viewport()->add_child(skeleton_editor);
-}
-Skeleton3DEditorPlugin::~Skeleton3DEditorPlugin() {}
+ Ref<EditorInspectorPluginSkeleton> skeleton_plugin;
+ skeleton_plugin.instance();
+ skeleton_plugin->editor = editor;
+
+ EditorInspector::add_inspector_plugin(skeleton_plugin);
+}
diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h
index af9ebb6246..a5b8ce80a9 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.h
+++ b/editor/plugins/skeleton_3d_editor_plugin.h
@@ -35,11 +35,91 @@
#include "editor/editor_plugin.h"
#include "scene/3d/skeleton_3d.h"
+class EditorInspectorPluginSkeleton;
+class Joint;
class PhysicalBone3D;
-class Joint3D;
+class Skeleton3DEditorPlugin;
+class Button;
+class CheckBox;
+class EditorPropertyTransform;
+class EditorPropertyVector3;
-class Skeleton3DEditor : public Node {
- GDCLASS(Skeleton3DEditor, Node);
+class BoneTransformEditor : public VBoxContainer {
+ GDCLASS(BoneTransformEditor, VBoxContainer);
+
+ EditorInspectorSection *section;
+
+ EditorPropertyVector3 *translation_property;
+ EditorPropertyVector3 *rotation_property;
+ EditorPropertyVector3 *scale_property;
+ EditorInspectorSection *transform_section;
+ EditorPropertyTransform *transform_property;
+
+ Rect2 background_rects[5];
+
+ Skeleton3D *skeleton;
+ String property;
+
+ UndoRedo *undo_redo;
+
+ Button *key_button;
+ CheckBox *enabled_checkbox;
+
+ bool keyable;
+ bool toggle_enabled;
+ bool updating;
+
+ String label;
+
+ void create_editors();
+
+ // Called when one of the EditorSpinSliders are changed.
+ void _value_changed(const double p_value);
+ // Called when the one of the EditorPropertyVector3 are updated.
+ void _value_changed_vector3(const String p_property_name, const Vector3 p_vector, const StringName p_edited_property_name, const bool p_boolean);
+ // Called when the transform_property is updated.
+ void _value_changed_transform(const String p_property_name, const Transform p_transform, const StringName p_edited_property_name, const bool p_boolean);
+ // Changes the transform to the given transform and updates the UI accordingly.
+ void _change_transform(Transform p_new_transform);
+ // Creates a Transform using the EditorPropertyVector3 properties.
+ Transform compute_transform_from_vector3s() const;
+
+ void update_enabled_checkbox();
+
+protected:
+ void _notification(int p_what);
+
+public:
+ BoneTransformEditor(Skeleton3D *p_skeleton);
+
+ // Which transform target to modify
+ void set_target(const String &p_prop);
+ void set_label(const String &p_label) { label = p_label; }
+
+ void _update_properties();
+ void _update_custom_pose_properties();
+ void _update_transform_properties(Transform p_transform);
+
+ // Can/cannot modify the spinner values for the Transform
+ void set_read_only(const bool p_read_only);
+
+ // Transform can be keyed, whether or not to show the button
+ void set_keyable(const bool p_keyable);
+
+ // Bone can be toggled enabled or disabled, whether or not to show the checkbox
+ void set_toggle_enabled(const bool p_enabled);
+
+ // Key Transform Button pressed
+ void _key_button_pressed();
+
+ // Bone Enabled Checkbox toggled
+ void _checkbox_toggled(const bool p_toggled);
+};
+
+class Skeleton3DEditor : public VBoxContainer {
+ GDCLASS(Skeleton3DEditor, VBoxContainer);
+
+ friend class Skeleton3DEditorPlugin;
enum Menu {
MENU_OPTION_CREATE_PHYSICAL_SKELETON
@@ -51,44 +131,78 @@ class Skeleton3DEditor : public Node {
BoneInfo() {}
};
+ EditorNode *editor;
+ EditorInspectorPluginSkeleton *editor_plugin;
+
Skeleton3D *skeleton;
+ Tree *joint_tree;
+ BoneTransformEditor *rest_editor;
+ BoneTransformEditor *pose_editor;
+ BoneTransformEditor *custom_pose_editor;
+
MenuButton *options;
+ EditorFileDialog *file_dialog;
+
+ UndoRedo *undo_redo;
void _on_click_option(int p_option);
+ void _file_selected(const String &p_file);
- friend class Skeleton3DEditorPlugin;
+ EditorFileDialog *file_export_lib;
+
+ void update_joint_tree();
+ void update_editors();
+
+ void create_editors();
+
+ void create_physical_skeleton();
+ PhysicalBone3D *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos);
+
+ Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
+ 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);
protected:
void _notification(int p_what);
void _node_removed(Node *p_node);
static void _bind_methods();
- void create_physical_skeleton();
- PhysicalBone3D *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos);
-
public:
- void edit(Skeleton3D *p_node);
+ void move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx);
+
+ Skeleton3D *get_skeleton() const { return skeleton; };
- Skeleton3DEditor();
+ void _joint_tree_selection_changed();
+ void _joint_tree_rmb_select(const Vector2 &p_pos);
+
+ void _update_properties();
+
+ Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton3D *skeleton);
~Skeleton3DEditor();
};
+class EditorInspectorPluginSkeleton : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorPluginSkeleton, EditorInspectorPlugin);
+
+ friend class Skeleton3DEditorPlugin;
+
+ EditorNode *editor;
+
+public:
+ virtual bool can_handle(Object *p_object);
+ virtual void parse_begin(Object *p_object);
+};
+
class Skeleton3DEditorPlugin : public EditorPlugin {
GDCLASS(Skeleton3DEditorPlugin, EditorPlugin);
EditorNode *editor;
- Skeleton3DEditor *skeleton_editor;
public:
- virtual String get_name() const { return "Skeleton3D"; }
- virtual bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
Skeleton3DEditorPlugin(EditorNode *p_node);
- ~Skeleton3DEditorPlugin();
+
+ virtual String get_name() const { return "Skeleton3D"; }
};
#endif // SKELETON_3D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index b21586a6b0..f5fafb68a5 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "sprite_2d_editor_plugin.h"
#include "canvas_item_editor_plugin.h"
+#include "core/math/geometry_2d.h"
#include "editor/editor_scale.h"
#include "scene/2d/collision_polygon_2d.h"
#include "scene/2d/light_occluder_2d.h"
@@ -233,7 +234,7 @@ void Sprite2DEditor::_update_mesh_data() {
computed_vertices.push_back(vtx);
}
- Vector<int> poly = Geometry::triangulate_polygon(lines[j]);
+ Vector<int> poly = Geometry2D::triangulate_polygon(lines[j]);
for (int i = 0; i < poly.size(); i += 3) {
for (int k = 0; k < 3; k++) {
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 859fec1628..7102faf58a 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -873,12 +873,14 @@ SpriteFramesEditor::SpriteFramesEditor() {
HBoxContainer *hbc_animlist = memnew(HBoxContainer);
sub_vb->add_child(hbc_animlist);
- new_anim = memnew(ToolButton);
+ new_anim = memnew(Button);
+ new_anim->set_flat(true);
new_anim->set_tooltip(TTR("New Animation"));
hbc_animlist->add_child(new_anim);
new_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_add));
- remove_anim = memnew(ToolButton);
+ remove_anim = memnew(Button);
+ remove_anim->set_flat(true);
remove_anim->set_tooltip(TTR("Remove Animation"));
hbc_animlist->add_child(remove_anim);
remove_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_remove));
@@ -913,45 +915,54 @@ SpriteFramesEditor::SpriteFramesEditor() {
HBoxContainer *hbc = memnew(HBoxContainer);
sub_vb->add_child(hbc);
- load = memnew(ToolButton);
+ load = memnew(Button);
+ load->set_flat(true);
load->set_tooltip(TTR("Add a Texture from File"));
hbc->add_child(load);
- load_sheet = memnew(ToolButton);
+ load_sheet = memnew(Button);
+ load_sheet->set_flat(true);
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 = memnew(Button);
+ copy->set_flat(true);
copy->set_tooltip(TTR("Copy"));
hbc->add_child(copy);
- paste = memnew(ToolButton);
+ paste = memnew(Button);
+ paste->set_flat(true);
paste->set_tooltip(TTR("Paste"));
hbc->add_child(paste);
hbc->add_child(memnew(VSeparator));
- empty = memnew(ToolButton);
+ empty = memnew(Button);
+ empty->set_flat(true);
empty->set_tooltip(TTR("Insert Empty (Before)"));
hbc->add_child(empty);
- empty2 = memnew(ToolButton);
+ empty2 = memnew(Button);
+ empty2->set_flat(true);
empty2->set_tooltip(TTR("Insert Empty (After)"));
hbc->add_child(empty2);
hbc->add_child(memnew(VSeparator));
- move_up = memnew(ToolButton);
+ move_up = memnew(Button);
+ move_up->set_flat(true);
move_up->set_tooltip(TTR("Move (Before)"));
hbc->add_child(move_up);
- move_down = memnew(ToolButton);
+ move_down = memnew(Button);
+ move_down->set_flat(true);
move_down->set_tooltip(TTR("Move (After)"));
hbc->add_child(move_down);
- _delete = memnew(ToolButton);
+ _delete = memnew(Button);
+ _delete->set_flat(true);
_delete->set_tooltip(TTR("Delete"));
hbc->add_child(_delete);
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index 45646eb9e4..c050ae484b 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -43,22 +43,22 @@
class SpriteFramesEditor : public HSplitContainer {
GDCLASS(SpriteFramesEditor, HSplitContainer);
- ToolButton *load;
- ToolButton *load_sheet;
- ToolButton *_delete;
- ToolButton *copy;
- ToolButton *paste;
- ToolButton *empty;
- ToolButton *empty2;
- ToolButton *move_up;
- ToolButton *move_down;
+ Button *load;
+ Button *load_sheet;
+ Button *_delete;
+ Button *copy;
+ Button *paste;
+ Button *empty;
+ Button *empty2;
+ Button *move_up;
+ Button *move_down;
ItemList *tree;
bool loading_scene;
int sel;
HSplitContainer *split;
- ToolButton *new_anim;
- ToolButton *remove_anim;
+ Button *new_anim;
+ Button *remove_anim;
Tree *animations;
SpinBox *anim_speed;
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 9b8b111be5..3a92818779 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -1037,17 +1037,20 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
edit_draw->add_child(zoom_hb);
zoom_hb->set_begin(Point2(5, 5));
- zoom_out = memnew(ToolButton);
+ zoom_out = memnew(Button);
+ zoom_out->set_flat(true);
zoom_out->set_tooltip(TTR("Zoom Out"));
zoom_out->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_out));
zoom_hb->add_child(zoom_out);
- zoom_reset = memnew(ToolButton);
+ zoom_reset = memnew(Button);
+ zoom_reset->set_flat(true);
zoom_reset->set_tooltip(TTR("Zoom Reset"));
zoom_reset->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_reset));
zoom_hb->add_child(zoom_reset);
- zoom_in = memnew(ToolButton);
+ zoom_in = memnew(Button);
+ zoom_in->set_flat(true);
zoom_in->set_tooltip(TTR("Zoom In"));
zoom_in->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_in));
zoom_hb->add_child(zoom_in);
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index 93da23fd50..8991603c0f 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -56,9 +56,9 @@ class TextureRegionEditor : public VBoxContainer {
friend class TextureRegionEditorPlugin;
OptionButton *snap_mode_button;
- ToolButton *zoom_in;
- ToolButton *zoom_reset;
- ToolButton *zoom_out;
+ Button *zoom_in;
+ Button *zoom_reset;
+ Button *zoom_out;
HBoxContainer *hb_grid; //For showing/hiding the grid controls when changing the SnapMode
SpinBox *sb_step_y;
SpinBox *sb_step_x;
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index eb028659fd..43ace737c0 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -672,8 +672,9 @@ ThemeEditor::ThemeEditor() {
bt->set_text(TTR("Disabled Button"));
bt->set_disabled(true);
first_vb->add_child(bt);
- ToolButton *tb = memnew(ToolButton);
- tb->set_text("ToolButton");
+ Button *tb = memnew(Button);
+ tb->set_flat(true);
+ tb->set_text("Button");
first_vb->add_child(tb);
CheckButton *cb = memnew(CheckButton);
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 3010d72d81..307a8a9001 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -64,6 +64,8 @@ void TileMapEditor::_notification(int p_what) {
}
paint_button->set_icon(get_theme_icon("Edit", "EditorIcons"));
+ line_button->set_icon(get_theme_icon("CurveLinear", "EditorIcons"));
+ rectangle_button->set_icon(get_theme_icon("RectangleShape2D", "EditorIcons"));
bucket_fill_button->set_icon(get_theme_icon("Bucket", "EditorIcons"));
picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons"));
select_button->set_icon(get_theme_icon("ActionCopy", "EditorIcons"));
@@ -91,9 +93,10 @@ void TileMapEditor::_notification(int p_what) {
}
void TileMapEditor::_update_button_tool() {
- ToolButton *tb[4] = { paint_button, bucket_fill_button, picker_button, select_button };
+ Button *tb[6] = { paint_button, line_button, rectangle_button, bucket_fill_button, picker_button, select_button };
+
// Unpress all buttons
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < 6; i++) {
tb[i]->set_pressed(false);
}
@@ -103,6 +106,12 @@ void TileMapEditor::_update_button_tool() {
case TOOL_PAINTING: {
paint_button->set_pressed(true);
} break;
+ case TOOL_LINE_PAINT: {
+ line_button->set_pressed(true);
+ } break;
+ case TOOL_RECTANGLE_PAINT: {
+ rectangle_button->set_pressed(true);
+ } break;
case TOOL_BUCKET: {
bucket_fill_button->set_pressed(true);
} break;
@@ -194,6 +203,21 @@ void TileMapEditor::_palette_multi_selected(int index, bool selected) {
_update_palette();
}
+void TileMapEditor::_palette_input(const Ref<InputEvent> &p_event) {
+ const Ref<InputEventMouseButton> mb = p_event;
+
+ // Zoom in/out using Ctrl + mouse wheel.
+ if (mb.is_valid() && mb->is_pressed() && mb->get_command()) {
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ size_slider->set_value(size_slider->get_value() + 0.2);
+ }
+
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ size_slider->set_value(size_slider->get_value() - 0.2);
+ }
+ }
+}
+
void TileMapEditor::_canvas_mouse_enter() {
mouse_over = true;
CanvasItemEditor::get_singleton()->update_viewport();
@@ -978,19 +1002,8 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
if (tool == TOOL_NONE) {
- if (mb->get_shift()) {
- if (mb->get_command()) {
- tool = TOOL_RECTANGLE_PAINT;
- } else {
- tool = TOOL_LINE_PAINT;
- }
-
- selection_active = false;
- rectangle_begin = over_tile;
-
- _update_button_tool();
- return true;
- }
+ tool = TOOL_PAINTING;
+ _update_button_tool();
if (mb->get_command()) {
tool = TOOL_PICKING;
@@ -999,12 +1012,14 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return true;
}
-
- tool = TOOL_PAINTING;
- _update_button_tool();
}
- if (tool == TOOL_PAINTING) {
+ if (tool == TOOL_LINE_PAINT || tool == TOOL_RECTANGLE_PAINT) {
+ selection_active = false;
+ rectangle_begin = over_tile;
+
+ mouse_down = true;
+ } else if (tool == TOOL_PAINTING) {
Vector<int> ids = get_selected_tiles();
if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
@@ -1035,6 +1050,10 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
paint_undo.clear();
}
} else if (tool == TOOL_LINE_PAINT) {
+ if (!mouse_down) {
+ return true;
+ }
+
Vector<int> ids = get_selected_tiles();
if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
@@ -1047,8 +1066,17 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
paint_undo.clear();
CanvasItemEditor::get_singleton()->update_viewport();
+
+ mouse_down = false;
+ return true;
}
+
+ mouse_down = false;
} else if (tool == TOOL_RECTANGLE_PAINT) {
+ if (!mouse_down) {
+ return true;
+ }
+
Vector<int> ids = get_selected_tiles();
if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
@@ -1061,7 +1089,12 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
_finish_undo();
CanvasItemEditor::get_singleton()->update_viewport();
+
+ mouse_down = false;
+ return true;
}
+
+ mouse_down = false;
} else if (tool == TOOL_PASTING) {
Point2 ofs = over_tile - rectangle.position;
Vector<int> ids;
@@ -1126,6 +1159,28 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (tool == TOOL_PASTING) {
tool = TOOL_NONE;
+
+ CanvasItemEditor::get_singleton()->update_viewport();
+
+ _update_button_tool();
+ return true;
+ }
+
+ if (tool == TOOL_LINE_PAINT) {
+ tool = TOOL_LINE_ERASE;
+ mouse_down = true;
+ rectangle_begin = over_tile;
+
+ CanvasItemEditor::get_singleton()->update_viewport();
+
+ _update_button_tool();
+ return true;
+ }
+
+ if (tool == TOOL_RECTANGLE_PAINT) {
+ tool = TOOL_RECTANGLE_ERASE;
+ mouse_down = true;
+ rectangle_begin = over_tile;
copydata.clear();
CanvasItemEditor::get_singleton()->update_viewport();
@@ -1140,39 +1195,74 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Point2 local = node->world_to_map(xform_inv.xform(mb->get_position()));
_start_undo(TTR("Erase TileMap"));
+ tool = TOOL_ERASING;
+ _set_cell(local, invalid_cell);
- if (mb->get_shift()) {
- if (mb->get_command()) {
- tool = TOOL_RECTANGLE_ERASE;
- } else {
- tool = TOOL_LINE_ERASE;
+ _update_button_tool();
+ return true;
+ }
+
+ } else {
+ if (tool == TOOL_LINE_ERASE) {
+ if (!mouse_down) {
+ return true;
+ }
+
+ tool = TOOL_LINE_PAINT;
+ _update_button_tool();
+
+ Vector<int> ids = get_selected_tiles();
+
+ if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
+ _start_undo(TTR("Line Erase"));
+ for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
+ _set_cell(E->key(), invalid_cell, flip_h, flip_v, transpose);
}
+ _finish_undo();
+ paint_undo.clear();
- selection_active = false;
- rectangle_begin = local;
- } else {
- tool = TOOL_ERASING;
+ CanvasItemEditor::get_singleton()->update_viewport();
- _set_cell(local, invalid_cell);
+ mouse_down = false;
+ return true;
}
+ mouse_down = false;
+ } else if (tool == TOOL_RECTANGLE_ERASE) {
+ if (!mouse_down) {
+ return true;
+ }
+
+ tool = TOOL_RECTANGLE_PAINT;
_update_button_tool();
- return true;
- }
- } else {
- if (tool == TOOL_ERASING || tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) {
- _finish_undo();
+ Vector<int> ids = get_selected_tiles();
+
+ if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
+ _start_undo(TTR("Rectangle Erase"));
+ for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
+ for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
+ _set_cell(Point2i(j, i), invalid_cell, flip_h, flip_v, transpose);
+ }
+ }
+ _finish_undo();
+ paint_undo.clear();
- if (tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) {
CanvasItemEditor::get_singleton()->update_viewport();
+
+ mouse_down = false;
+ return true;
}
- tool = TOOL_NONE;
+ mouse_down = false;
+ tool = TOOL_RECTANGLE_PAINT;
+ }
+ if (tool == TOOL_ERASING) {
+ tool = TOOL_NONE;
_update_button_tool();
- return true;
+ return true;
} else if (tool == TOOL_BUCKET) {
Vector<int> ids;
ids.push_back(node->get_cell(over_tile.x, over_tile.y));
@@ -1263,6 +1353,10 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Vector<int> tmp_cell;
bool erasing = (tool == TOOL_LINE_ERASE);
+ if (!mouse_down) {
+ return true;
+ }
+
tmp_cell.push_back(0);
if (erasing && paint_undo.size()) {
for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
@@ -1293,7 +1387,20 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Vector<int> tmp_cell;
tmp_cell.push_back(0);
- _select(rectangle_begin, over_tile);
+ Point2i end_tile = over_tile;
+
+ if (!mouse_down) {
+ return true;
+ }
+
+ if (mm->get_shift()) {
+ int size = fmax(ABS(end_tile.x - rectangle_begin.x), ABS(end_tile.y - rectangle_begin.y));
+ int xDirection = MAX(MIN(end_tile.x - rectangle_begin.x, 1), -1);
+ int yDirection = MAX(MIN(end_tile.y - rectangle_begin.y, 1), -1);
+ end_tile = rectangle_begin + Point2i(xDirection * size, yDirection * size);
+ }
+
+ _select(rectangle_begin, end_tile);
if (tool == TOOL_RECTANGLE_ERASE) {
if (paint_undo.size()) {
@@ -1364,6 +1471,20 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
_update_button_tool();
return true;
}
+ if (ED_IS_SHORTCUT("tile_map_editor/line_fill", p_event)) {
+ tool = TOOL_LINE_PAINT;
+ CanvasItemEditor::get_singleton()->update_viewport();
+
+ _update_button_tool();
+ return true;
+ }
+ if (ED_IS_SHORTCUT("tile_map_editor/rectangle_fill", p_event)) {
+ tool = TOOL_RECTANGLE_PAINT;
+ 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();
@@ -1622,6 +1743,10 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
}
if (tool == TOOL_LINE_PAINT) {
+ if (!mouse_down) {
+ return;
+ }
+
if (paint_undo.empty()) {
return;
}
@@ -1637,6 +1762,10 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
}
} else if (tool == TOOL_RECTANGLE_PAINT) {
+ if (!mouse_down) {
+ return;
+ }
+
Vector<int> ids = get_selected_tiles();
if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL) {
@@ -1850,6 +1979,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
tool = TOOL_NONE;
selection_active = false;
mouse_over = false;
+ mouse_down = false;
flip_h = false;
flip_v = false;
@@ -1913,6 +2043,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
palette->add_theme_constant_override("vseparation", 8 * EDSCALE);
palette->connect("item_selected", callable_mp(this, &TileMapEditor::_palette_selected));
palette->connect("multi_selected", callable_mp(this, &TileMapEditor::_palette_multi_selected));
+ palette->connect("gui_input", callable_mp(this, &TileMapEditor::_palette_input));
palette_container->add_child(palette);
// Add message for when no texture is selected.
@@ -1943,26 +2074,46 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
toolbar->add_child(memnew(VSeparator));
// Tools.
- paint_button = memnew(ToolButton);
+ paint_button = memnew(Button);
+ paint_button->set_flat(true);
paint_button->set_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P));
- paint_button->set_tooltip(TTR("Shift+LMB: Line Draw\nShift+Ctrl+LMB: Rectangle Paint"));
+ paint_button->set_tooltip(TTR("RMB: Erase"));
paint_button->connect("pressed", callable_mp(this, &TileMapEditor::_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));
+ line_button = memnew(Button);
+ line_button->set_flat(true);
+ line_button->set_shortcut(ED_SHORTCUT("tile_map_editor/line_fill", TTR("Line Fill"), KEY_L));
+ line_button->set_tooltip(TTR("RMB: Erase"));
+ line_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_LINE_PAINT));
+ line_button->set_toggle_mode(true);
+ toolbar->add_child(line_button);
+
+ rectangle_button = memnew(Button);
+ rectangle_button->set_flat(true);
+ rectangle_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rectangle_fill", TTR("Rectangle Fill"), KEY_O));
+ rectangle_button->set_tooltip(TTR("Shift+LMB: Keep 1:1 proporsions\nRMB: Erase"));
+ rectangle_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_RECTANGLE_PAINT));
+ rectangle_button->set_toggle_mode(true);
+ toolbar->add_child(rectangle_button);
+
+ bucket_fill_button = memnew(Button);
+ bucket_fill_button->set_flat(true);
+ bucket_fill_button->set_shortcut(ED_SHORTCUT("tile_map_editor/bucket_fill", TTR("Bucket Fill"), KEY_B));
bucket_fill_button->connect("pressed", callable_mp(this, &TileMapEditor::_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 = memnew(Button);
+ picker_button->set_flat(true);
picker_button->set_shortcut(ED_SHORTCUT("tile_map_editor/pick_tile", TTR("Pick Tile"), KEY_I));
picker_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_PICKING));
picker_button->set_toggle_mode(true);
toolbar->add_child(picker_button);
- select_button = memnew(ToolButton);
+ select_button = memnew(Button);
+ select_button->set_flat(true);
select_button->set_shortcut(ED_SHORTCUT("tile_map_editor/select", TTR("Select"), KEY_M));
select_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_SELECTING));
select_button->set_toggle_mode(true);
@@ -2001,35 +2152,40 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
p->add_item(TTR("Fix Invalid Tiles"), OPTION_FIX_INVALID);
p->connect("id_pressed", callable_mp(this, &TileMapEditor::_menu_option));
- rotate_left_button = memnew(ToolButton);
+ rotate_left_button = memnew(Button);
+ rotate_left_button->set_flat(true);
rotate_left_button->set_tooltip(TTR("Rotate Left"));
rotate_left_button->set_focus_mode(FOCUS_NONE);
rotate_left_button->connect("pressed", callable_mp(this, &TileMapEditor::_rotate), varray(-1));
rotate_left_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rotate_left", TTR("Rotate Left"), KEY_A));
tool_hb->add_child(rotate_left_button);
- rotate_right_button = memnew(ToolButton);
+ rotate_right_button = memnew(Button);
+ rotate_right_button->set_flat(true);
rotate_right_button->set_tooltip(TTR("Rotate Right"));
rotate_right_button->set_focus_mode(FOCUS_NONE);
rotate_right_button->connect("pressed", callable_mp(this, &TileMapEditor::_rotate), varray(1));
rotate_right_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rotate_right", TTR("Rotate Right"), KEY_S));
tool_hb->add_child(rotate_right_button);
- flip_horizontal_button = memnew(ToolButton);
+ flip_horizontal_button = memnew(Button);
+ flip_horizontal_button->set_flat(true);
flip_horizontal_button->set_tooltip(TTR("Flip Horizontally"));
flip_horizontal_button->set_focus_mode(FOCUS_NONE);
flip_horizontal_button->connect("pressed", callable_mp(this, &TileMapEditor::_flip_horizontal));
flip_horizontal_button->set_shortcut(ED_SHORTCUT("tile_map_editor/flip_horizontal", TTR("Flip Horizontally"), KEY_X));
tool_hb->add_child(flip_horizontal_button);
- flip_vertical_button = memnew(ToolButton);
+ flip_vertical_button = memnew(Button);
+ flip_vertical_button->set_flat(true);
flip_vertical_button->set_tooltip(TTR("Flip Vertically"));
flip_vertical_button->set_focus_mode(FOCUS_NONE);
flip_vertical_button->connect("pressed", callable_mp(this, &TileMapEditor::_flip_vertical));
flip_vertical_button->set_shortcut(ED_SHORTCUT("tile_map_editor/flip_vertical", TTR("Flip Vertically"), KEY_Z));
tool_hb->add_child(flip_vertical_button);
- clear_transform_button = memnew(ToolButton);
+ clear_transform_button = memnew(Button);
+ clear_transform_button->set_flat(true);
clear_transform_button->set_tooltip(TTR("Clear Transform"));
clear_transform_button->set_focus_mode(FOCUS_NONE);
clear_transform_button->connect("pressed", callable_mp(this, &TileMapEditor::_clear_transform));
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
index 5f82d7bfb8..135a9bd5a5 100644
--- a/editor/plugins/tile_map_editor_plugin.h
+++ b/editor/plugins/tile_map_editor_plugin.h
@@ -38,7 +38,6 @@
#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/menu_button.h"
-#include "scene/gui/tool_button.h"
class TileMapEditor : public VBoxContainer {
GDCLASS(TileMapEditor, VBoxContainer);
@@ -88,16 +87,18 @@ class TileMapEditor : public VBoxContainer {
Label *tile_info;
MenuButton *options;
- ToolButton *paint_button;
- ToolButton *bucket_fill_button;
- ToolButton *picker_button;
- ToolButton *select_button;
+ Button *paint_button;
+ Button *line_button;
+ Button *rectangle_button;
+ Button *bucket_fill_button;
+ Button *picker_button;
+ Button *select_button;
- ToolButton *flip_horizontal_button;
- ToolButton *flip_vertical_button;
- ToolButton *rotate_left_button;
- ToolButton *rotate_right_button;
- ToolButton *clear_transform_button;
+ Button *flip_horizontal_button;
+ Button *flip_vertical_button;
+ Button *rotate_left_button;
+ Button *rotate_right_button;
+ Button *clear_transform_button;
CheckBox *manual_button;
CheckBox *priority_button;
@@ -107,6 +108,7 @@ class TileMapEditor : public VBoxContainer {
bool selection_active;
bool mouse_over;
+ bool mouse_down;
bool flip_h;
bool flip_v;
@@ -182,6 +184,7 @@ class TileMapEditor : public VBoxContainer {
void _menu_option(int p_option);
void _palette_selected(int index);
void _palette_multi_selected(int index, bool selected);
+ void _palette_input(const Ref<InputEvent> &p_event);
Dictionary _create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord);
void _start_undo(const String &p_action);
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 644facd5bd..a37cf7e426 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -341,12 +341,12 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
HBoxContainer *tileset_toolbar_container = memnew(HBoxContainer);
left_container->add_child(tileset_toolbar_container);
- tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE] = memnew(ToolButton);
+ tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE] = memnew(Button);
tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_button_pressed), varray(TOOL_TILESET_ADD_TEXTURE));
tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]);
tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_tooltip(TTR("Add Texture(s) to TileSet."));
- tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE] = memnew(ToolButton);
+ tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE] = memnew(Button);
tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_button_pressed), varray(TOOL_TILESET_REMOVE_TEXTURE));
tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]);
tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_tooltip(TTR("Remove selected Texture from TileSet."));
@@ -402,13 +402,13 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
tool_hb->add_child(spacer);
tool_hb->move_child(spacer, WORKSPACE_CREATE_SINGLE);
- tools[SELECT_NEXT] = memnew(ToolButton);
+ tools[SELECT_NEXT] = memnew(Button);
tool_hb->add_child(tools[SELECT_NEXT]);
tool_hb->move_child(tools[SELECT_NEXT], WORKSPACE_CREATE_SINGLE);
tools[SELECT_NEXT]->set_shortcut(ED_SHORTCUT("tileset_editor/next_shape", TTR("Next Coordinate"), KEY_PAGEDOWN));
tools[SELECT_NEXT]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SELECT_NEXT));
tools[SELECT_NEXT]->set_tooltip(TTR("Select the next shape, subtile, or Tile."));
- tools[SELECT_PREVIOUS] = memnew(ToolButton);
+ tools[SELECT_PREVIOUS] = memnew(Button);
tool_hb->add_child(tools[SELECT_PREVIOUS]);
tool_hb->move_child(tools[SELECT_PREVIOUS], WORKSPACE_CREATE_SINGLE);
tools[SELECT_PREVIOUS]->set_shortcut(ED_SHORTCUT("tileset_editor/previous_shape", TTR("Previous Coordinate"), KEY_PAGEUP));
@@ -465,7 +465,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
toolbar = memnew(HBoxContainer);
Ref<ButtonGroup> tg(memnew(ButtonGroup));
- tools[TOOL_SELECT] = memnew(ToolButton);
+ tools[TOOL_SELECT] = memnew(Button);
toolbar->add_child(tools[TOOL_SELECT]);
tools[TOOL_SELECT]->set_toggle_mode(true);
tools[TOOL_SELECT]->set_button_group(tg);
@@ -474,40 +474,42 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
separator_bitmask = memnew(VSeparator);
toolbar->add_child(separator_bitmask);
- tools[BITMASK_COPY] = memnew(ToolButton);
+ tools[BITMASK_COPY] = memnew(Button);
tools[BITMASK_COPY]->set_tooltip(TTR("Copy bitmask."));
tools[BITMASK_COPY]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_COPY));
toolbar->add_child(tools[BITMASK_COPY]);
- tools[BITMASK_PASTE] = memnew(ToolButton);
+ tools[BITMASK_PASTE] = memnew(Button);
tools[BITMASK_PASTE]->set_tooltip(TTR("Paste bitmask."));
tools[BITMASK_PASTE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_PASTE));
toolbar->add_child(tools[BITMASK_PASTE]);
- tools[BITMASK_CLEAR] = memnew(ToolButton);
+ tools[BITMASK_CLEAR] = memnew(Button);
tools[BITMASK_CLEAR]->set_tooltip(TTR("Erase bitmask."));
tools[BITMASK_CLEAR]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_CLEAR));
toolbar->add_child(tools[BITMASK_CLEAR]);
- tools[SHAPE_NEW_RECTANGLE] = memnew(ToolButton);
+ tools[SHAPE_NEW_RECTANGLE] = memnew(Button);
toolbar->add_child(tools[SHAPE_NEW_RECTANGLE]);
tools[SHAPE_NEW_RECTANGLE]->set_toggle_mode(true);
tools[SHAPE_NEW_RECTANGLE]->set_button_group(tg);
tools[SHAPE_NEW_RECTANGLE]->set_tooltip(TTR("Create a new rectangle."));
+ tools[SHAPE_NEW_RECTANGLE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_NEW_RECTANGLE));
- tools[SHAPE_NEW_POLYGON] = memnew(ToolButton);
+ tools[SHAPE_NEW_POLYGON] = memnew(Button);
toolbar->add_child(tools[SHAPE_NEW_POLYGON]);
tools[SHAPE_NEW_POLYGON]->set_toggle_mode(true);
tools[SHAPE_NEW_POLYGON]->set_button_group(tg);
tools[SHAPE_NEW_POLYGON]->set_tooltip(TTR("Create a new polygon."));
+ tools[SHAPE_NEW_POLYGON]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_NEW_POLYGON));
separator_shape_toggle = memnew(VSeparator);
toolbar->add_child(separator_shape_toggle);
- tools[SHAPE_TOGGLE_TYPE] = memnew(ToolButton);
+ tools[SHAPE_TOGGLE_TYPE] = memnew(Button);
tools[SHAPE_TOGGLE_TYPE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_TOGGLE_TYPE));
toolbar->add_child(tools[SHAPE_TOGGLE_TYPE]);
separator_delete = memnew(VSeparator);
toolbar->add_child(separator_delete);
- tools[SHAPE_DELETE] = memnew(ToolButton);
+ tools[SHAPE_DELETE] = memnew(Button);
tools[SHAPE_DELETE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_DELETE));
toolbar->add_child(tools[SHAPE_DELETE]);
@@ -531,12 +533,12 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
separator_grid = memnew(VSeparator);
toolbar->add_child(separator_grid);
- tools[SHAPE_KEEP_INSIDE_TILE] = memnew(ToolButton);
+ tools[SHAPE_KEEP_INSIDE_TILE] = memnew(Button);
tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true);
tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true);
tools[SHAPE_KEEP_INSIDE_TILE]->set_tooltip(TTR("Keep polygon inside region Rect."));
toolbar->add_child(tools[SHAPE_KEEP_INSIDE_TILE]);
- tools[TOOL_GRID_SNAP] = memnew(ToolButton);
+ tools[TOOL_GRID_SNAP] = memnew(Button);
tools[TOOL_GRID_SNAP]->set_toggle_mode(true);
tools[TOOL_GRID_SNAP]->set_tooltip(TTR("Enable snap and show grid (configurable via the Inspector)."));
tools[TOOL_GRID_SNAP]->connect("toggled", callable_mp(this, &TileSetEditor::_on_grid_snap_toggled));
@@ -546,20 +548,20 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
separator->set_h_size_flags(SIZE_EXPAND_FILL);
toolbar->add_child(separator);
- tools[ZOOM_OUT] = memnew(ToolButton);
+ tools[ZOOM_OUT] = memnew(Button);
tools[ZOOM_OUT]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_out));
toolbar->add_child(tools[ZOOM_OUT]);
tools[ZOOM_OUT]->set_tooltip(TTR("Zoom Out"));
- tools[ZOOM_1] = memnew(ToolButton);
+ tools[ZOOM_1] = memnew(Button);
tools[ZOOM_1]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_reset));
toolbar->add_child(tools[ZOOM_1]);
tools[ZOOM_1]->set_tooltip(TTR("Zoom Reset"));
- tools[ZOOM_IN] = memnew(ToolButton);
+ tools[ZOOM_IN] = memnew(Button);
tools[ZOOM_IN]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_in));
toolbar->add_child(tools[ZOOM_IN]);
tools[ZOOM_IN]->set_tooltip(TTR("Zoom In"));
- tools[VISIBLE_INFO] = memnew(ToolButton);
+ tools[VISIBLE_INFO] = memnew(Button);
tools[VISIBLE_INFO]->set_toggle_mode(true);
tools[VISIBLE_INFO]->set_tooltip(TTR("Display Tile Names (Hold Alt Key)"));
toolbar->add_child(tools[VISIBLE_INFO]);
@@ -569,6 +571,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
scroll = memnew(ScrollContainer);
main_vb->add_child(scroll);
scroll->set_v_size_flags(SIZE_EXPAND_FILL);
+ scroll->connect("gui_input", callable_mp(this, &TileSetEditor::_on_scroll_container_input));
scroll->set_clip_contents(true);
empty_message = memnew(Label);
@@ -1198,6 +1201,27 @@ bool TileSetEditor::is_within_grabbing_distance_of_first_point(const Vector2 &p_
return distance < p_grab_threshold;
}
+void TileSetEditor::_on_scroll_container_input(const Ref<InputEvent> &p_event) {
+ const Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid()) {
+ // Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer
+ // to allow performing this action anywhere, even if the cursor isn't
+ // hovering the texture in the workspace.
+ if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
+ print_line("zooming in");
+ _zoom_in();
+ // Don't scroll up after zooming in.
+ accept_event();
+ } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
+ print_line("zooming out");
+ _zoom_out();
+ // Don't scroll down after zooming out.
+ accept_event();
+ }
+ }
+}
+
void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if (tileset.is_null() || !get_current_texture().is_valid()) {
return;
@@ -1214,8 +1238,8 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
current_tile_region.position += WORKSPACE_MARGIN;
- Ref<InputEventMouseButton> mb = p_ie;
- Ref<InputEventMouseMotion> mm = p_ie;
+ const Ref<InputEventMouseButton> mb = p_ie;
+ const Ref<InputEventMouseMotion> mm = p_ie;
if (mb.is_valid()) {
if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && !creating_shape) {
@@ -1239,13 +1263,6 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
delete tiles;
}
}
-
- // Mouse Wheel Event
- if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
- _zoom_in();
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
- _zoom_out();
- }
}
// Drag Middle Mouse
if (mm.is_valid()) {
@@ -1893,7 +1910,7 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
}
}
}
- } else if (p_tool == TOOL_SELECT) {
+ } else if (p_tool == TOOL_SELECT || p_tool == SHAPE_NEW_POLYGON || p_tool == SHAPE_NEW_RECTANGLE) {
if (creating_shape) {
// Cancel Creation
creating_shape = false;
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index 827325cfd7..d2687e7a4b 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -46,7 +46,7 @@ class TileSetEditor : public HSplitContainer {
GDCLASS(TileSetEditor, HSplitContainer);
- enum TextureToolButtons {
+ enum TextureButtons {
TOOL_TILESET_ADD_TEXTURE,
TOOL_TILESET_REMOVE_TEXTURE,
TOOL_TILESET_CREATE_SCENE,
@@ -111,7 +111,7 @@ class TileSetEditor : public HSplitContainer {
ItemList *texture_list;
int option;
- ToolButton *tileset_toolbar_buttons[TOOL_TILESET_MAX];
+ Button *tileset_toolbar_buttons[TOOL_TILESET_MAX];
MenuButton *tileset_toolbar_tools;
Map<RID, Ref<Texture2D>> texture_map;
@@ -146,7 +146,7 @@ class TileSetEditor : public HSplitContainer {
Button *tool_editmode[EDITMODE_MAX];
HSeparator *separator_editmode;
HBoxContainer *toolbar;
- ToolButton *tools[TOOL_MAX];
+ Button *tools[TOOL_MAX];
VSeparator *separator_shape_toggle;
VSeparator *separator_bitmask;
VSeparator *separator_delete;
@@ -200,6 +200,7 @@ private:
void _on_workspace_overlay_draw();
void _on_workspace_draw();
void _on_workspace_process();
+ void _on_scroll_container_input(const Ref<InputEvent> &p_event);
void _on_workspace_input(const Ref<InputEvent> &p_ie);
void _on_tool_clicked(int p_tool);
void _on_priority_changed(float val);
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index a1436e123d..cfbe54ef61 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -300,7 +300,7 @@ void VersionControlEditorPlugin::register_editor() {
TabContainer *dock_vbc = (TabContainer *)version_commit_dock->get_parent_control();
dock_vbc->set_tab_title(version_commit_dock->get_index(), TTR("Commit"));
- ToolButton *vc = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock);
+ Button *vc = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock);
set_version_control_tool_button(vc);
}
}
diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h
index 664e38d65f..248a1435fd 100644
--- a/editor/plugins/version_control_editor_plugin.h
+++ b/editor/plugins/version_control_editor_plugin.h
@@ -90,7 +90,7 @@ private:
Label *commit_status;
PanelContainer *version_control_dock;
- ToolButton *version_control_dock_button;
+ Button *version_control_dock_button;
VBoxContainer *diff_vbc;
HBoxContainer *diff_hbc;
Button *diff_refresh_button;
@@ -121,7 +121,7 @@ public:
static VersionControlEditorPlugin *get_singleton();
void popup_vcs_set_up_dialog(const Control *p_gui_base);
- void set_version_control_tool_button(ToolButton *p_button) { version_control_dock_button = p_button; }
+ void set_version_control_tool_button(Button *p_button) { version_control_dock_button = p_button; }
PopupMenu *get_version_control_actions_panel() const { return version_control_actions; }
VBoxContainer *get_version_commit_dock() const { return version_commit_dock; }
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 92bdba93e7..89ab747cde 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -2341,13 +2341,15 @@ VisualShaderEditor::VisualShaderEditor() {
graph->get_zoom_hbox()->add_child(edit_type);
graph->get_zoom_hbox()->move_child(edit_type, 0);
- add_node = memnew(ToolButton);
+ add_node = memnew(Button);
+ add_node->set_flat(true);
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", callable_mp(this, &VisualShaderEditor::_show_members_dialog), varray(false));
- preview_shader = memnew(ToolButton);
+ preview_shader = memnew(Button);
+ preview_shader->set_flat(true);
preview_shader->set_toggle_mode(true);
preview_shader->set_tooltip(TTR("Show resulted shader code."));
graph->get_zoom_hbox()->add_child(preview_shader);
@@ -2750,8 +2752,10 @@ VisualShaderEditor::VisualShaderEditor() {
texture_node_option_idx = add_options.size();
add_options.push_back(AddOption("Texture2D", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the texture lookup."), -1, -1));
add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubemapUniform", TTR("Cubic texture uniform lookup."), -1, -1));
+ add_options.push_back(AddOption("Texture2DArray", "Textures", "Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), -1, -1, -1, -1, -1));
add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), -1, -1));
add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), -1, -1, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Texture2DArrayUniform", "Textures", "Variables", "VisualShaderNodeTexture2DArrayUniform", TTR("2D array of textures uniform lookup."), -1, -1, -1, -1, -1));
// TRANSFORM
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index d2f10d9407..b7c0fb8e45 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -60,8 +60,8 @@ class VisualShaderEditor : public VBoxContainer {
Ref<VisualShader> visual_shader;
HSplitContainer *main_box;
GraphEdit *graph;
- ToolButton *add_node;
- ToolButton *preview_shader;
+ Button *add_node;
+ Button *preview_shader;
OptionButton *edit_type;