summaryrefslogtreecommitdiff
path: root/editor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins')
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp6
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp6
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp4
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp8
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp8
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp2
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp16
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp44
-rw-r--r--editor/plugins/collision_polygon_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/curve_editor_plugin.cpp6
-rw-r--r--editor/plugins/editor_preview_plugins.cpp12
-rw-r--r--editor/plugins/font_editor_plugin.cpp4
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp14
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp4
-rw-r--r--editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp2
-rw-r--r--editor/plugins/gradient_editor_plugin.cpp2
-rw-r--r--editor/plugins/material_editor_plugin.cpp34
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp4
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp152
-rw-r--r--editor/plugins/node_3d_editor_plugin.h7
-rw-r--r--editor/plugins/occluder_instance_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/ot_features_plugin.cpp2
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp4
-rw-r--r--editor/plugins/script_editor_plugin.cpp26
-rw-r--r--editor/plugins/script_editor_plugin.h3
-rw-r--r--editor/plugins/script_text_editor.cpp129
-rw-r--r--editor/plugins/script_text_editor.h3
-rw-r--r--editor/plugins/shader_editor_plugin.cpp16
-rw-r--r--editor/plugins/shader_file_editor_plugin.cpp2
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp6
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp56
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h1
-rw-r--r--editor/plugins/style_box_editor_plugin.cpp2
-rw-r--r--editor/plugins/text_editor.cpp8
-rw-r--r--editor/plugins/texture_3d_editor_plugin.cpp6
-rw-r--r--editor/plugins/texture_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp10
-rw-r--r--editor/plugins/theme_editor_plugin.cpp37
-rw-r--r--editor/plugins/theme_editor_plugin.h4
-rw-r--r--editor/plugins/theme_editor_preview.cpp4
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp199
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h19
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp2468
-rw-r--r--editor/plugins/tiles/tile_data_editors.h359
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp55
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp1215
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h30
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp104
-rw-r--r--editor/plugins/tiles/tile_set_editor.h12
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp27
55 files changed, 4099 insertions, 1061 deletions
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index f7c0ebcfaf..b6dd9474d3 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -386,7 +386,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
} else {
String type = menu->get_item_metadata(p_index);
- Object *obj = ClassDB::instance(type);
+ Object *obj = ClassDB::instantiate(type);
ERR_FAIL_COND(!obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
ERR_FAIL_COND(!an);
@@ -413,7 +413,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) {
Ref<AnimationNodeAnimation> anim;
- anim.instance();
+ anim.instantiate();
anim->set_animation(animations_to_add[p_index]);
@@ -594,7 +594,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
add_child(top_hb);
Ref<ButtonGroup> bg;
- bg.instance();
+ bg.instantiate();
tool_blend = memnew(Button);
tool_blend->set_flat(true);
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index e719df53d5..359df95bce 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -308,7 +308,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
} else {
String type = menu->get_item_metadata(p_index);
- Object *obj = ClassDB::instance(type);
+ Object *obj = ClassDB::instantiate(type);
ERR_FAIL_COND(!obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
ERR_FAIL_COND(!an);
@@ -335,7 +335,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
Ref<AnimationNodeAnimation> anim;
- anim.instance();
+ anim.instantiate();
anim->set_animation(animations_to_add[p_index]);
@@ -818,7 +818,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
add_child(top_hb);
Ref<ButtonGroup> bg;
- bg.instance();
+ bg.instantiate();
tool_blend = memnew(Button);
tool_blend->set_flat(true);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 867c701733..dcde89f177 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -288,14 +288,14 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
ERR_FAIL_COND(!anode.is_valid());
base_name = anode->get_class();
} else if (add_options[p_idx].type != String()) {
- AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instance(add_options[p_idx].type));
+ AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instantiate(add_options[p_idx].type));
ERR_FAIL_COND(!an);
anode = Ref<AnimationNode>(an);
base_name = add_options[p_idx].name;
} else {
ERR_FAIL_COND(add_options[p_idx].script.is_null());
String base_type = add_options[p_idx].script->get_instance_base_type();
- AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instance(base_type));
+ AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instantiate(base_type));
ERR_FAIL_COND(!an);
anode = Ref<AnimationNode>(an);
anode->set_script(add_options[p_idx].script);
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 4a3f3212fa..48d7cfdee2 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -121,11 +121,11 @@ void AnimationPlayerEditor::_notification(int p_what) {
Ref<Image> reset_img = reset_icon->get_image();
Ref<Image> autoplay_reset_img;
Size2 icon_size = Size2(autoplay_img->get_width(), autoplay_img->get_height());
- autoplay_reset_img.instance();
+ autoplay_reset_img.instantiate();
autoplay_reset_img->create(icon_size.x * 2, icon_size.y, false, autoplay_img->get_format());
autoplay_reset_img->blit_rect(autoplay_img, Rect2(Point2(), icon_size), Point2());
autoplay_reset_img->blit_rect(reset_img, Rect2(Point2(), icon_size), Point2(icon_size.x, 0));
- autoplay_reset_icon.instance();
+ autoplay_reset_icon.instantiate();
autoplay_reset_icon->create_from_image(autoplay_reset_img);
}
stop->set_icon(get_theme_icon("Stop", "EditorIcons"));
@@ -569,8 +569,8 @@ void AnimationPlayerEditor::_animation_blend() {
blend_editor.dialog->popup_centered(Size2(400, 400) * EDSCALE);
blend_editor.tree->set_hide_root(true);
- blend_editor.tree->set_column_min_width(0, 10);
- blend_editor.tree->set_column_min_width(1, 3);
+ blend_editor.tree->set_column_custom_minimum_width(0, 10);
+ blend_editor.tree->set_column_custom_minimum_width(1, 3);
List<StringName> anims;
player->get_animation_list(&anims);
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index fe5a0cab4d..94e526922d 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -257,7 +257,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
} else {
Ref<AnimationNodeStateMachineTransition> tr;
- tr.instance();
+ tr.instantiate();
tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()));
updating = true;
@@ -423,7 +423,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
} else {
String type = menu->get_item_metadata(p_index);
- Object *obj = ClassDB::instance(type);
+ Object *obj = ClassDB::instantiate(type);
ERR_FAIL_COND(!obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
ERR_FAIL_COND(!an);
@@ -462,7 +462,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
Ref<AnimationNodeAnimation> anim;
- anim.instance();
+ anim.instantiate();
anim->set_animation(animations_to_add[p_index]);
@@ -1213,7 +1213,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
add_child(top_hb);
Ref<ButtonGroup> bg;
- bg.instance();
+ bg.instantiate();
tool_select = memnew(Button);
tool_select->set_flat(true);
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index c33b06ff32..e90665f84d 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -76,7 +76,7 @@ void AnimationTreeEditor::_update_path() {
}
Ref<ButtonGroup> group;
- group.instance();
+ group.instantiate();
Button *b = memnew(Button);
b->set_text("Root");
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 93bb170128..cd61ebd418 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -86,7 +86,7 @@ void EditorAssetLibraryItem::_bind_methods() {
EditorAssetLibraryItem::EditorAssetLibraryItem() {
Ref<StyleBoxEmpty> border;
- border.instance();
+ border.instantiate();
border->set_default_margin(SIDE_LEFT, 5 * EDSCALE);
border->set_default_margin(SIDE_RIGHT, 5 * EDSCALE);
border->set_default_margin(SIDE_BOTTOM, 5 * EDSCALE);
@@ -155,7 +155,7 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const
thumbnail->blend_rect(overlay, overlay->get_used_rect(), overlay_pos);
Ref<ImageTexture> tex;
- tex.instance();
+ tex.instantiate();
tex->create_from_image(thumbnail);
preview_images[i].button->set_icon(tex);
@@ -761,7 +761,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
}
Ref<ImageTexture> tex;
- tex.instance();
+ tex.instantiate();
tex->create_from_image(image);
obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, tex);
@@ -1098,11 +1098,9 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
Dictionary d;
{
- Variant js;
- String errs;
- int errl;
- JSON::parse(str, js, errs, errl);
- d = js;
+ JSON json;
+ json.parse(str);
+ d = json.get_data();
}
RequestType requested = requesting;
@@ -1437,7 +1435,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
library_scroll_bg->add_child(library_scroll);
Ref<StyleBoxEmpty> border2;
- border2.instance();
+ border2.instantiate();
border2->set_default_margin(SIDE_LEFT, 15 * EDSCALE);
border2->set_default_margin(SIDE_RIGHT, 35 * EDSCALE);
border2->set_default_margin(SIDE_BOTTOM, 15 * EDSCALE);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index e648ffff29..033a3e4fab 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -5478,7 +5478,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p = view_menu->get_popup();
p->set_hide_on_checkable_item_selection(false);
- p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Always Show Grid"), KEY_MASK_CTRL | KEY_G), SHOW_GRID);
+ p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Always Show Grid"), KEY_MASK_CMD | KEY_G), SHOW_GRID);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show Helpers"), KEY_H), SHOW_HELPERS);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show Rulers")), SHOW_RULERS);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_guides", TTR("Show Guides"), KEY_Y), SHOW_GUIDES);
@@ -5698,7 +5698,7 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons
label_desc->show();
} else {
if (scene.is_valid()) {
- Node *instance = scene->instance();
+ Node *instance = scene->instantiate();
if (instance) {
preview_node->add_child(instance);
}
@@ -5811,26 +5811,26 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
return false;
}
- Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
- if (!instanced_scene) { // error on instancing
+ Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ if (!instantiated_scene) { // error on instancing
return false;
}
if (editor->get_edited_scene()->get_filename() != "") { // cyclical instancing
- if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instanced_scene)) {
- memdelete(instanced_scene);
+ if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instantiated_scene)) {
+ memdelete(instantiated_scene);
return false;
}
}
- instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path));
+ instantiated_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path));
- editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene);
- editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", editor->get_edited_scene());
- editor_data->get_undo_redo().add_do_reference(instanced_scene);
- editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene);
+ editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene);
+ editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", editor->get_edited_scene());
+ editor_data->get_undo_redo().add_do_reference(instantiated_scene);
+ editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene);
- String new_name = parent->validate_child_name(instanced_scene);
+ String new_name = parent->validate_child_name(instantiated_scene);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
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));
@@ -5841,11 +5841,11 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
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);
+ CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instantiated_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);
+ editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_position", target_pos);
}
return true;
@@ -5928,7 +5928,7 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
if (d.has("type")) {
if (String(d["type"]) == "files") {
Vector<String> files = d["files"];
- bool can_instance = false;
+ bool can_instantiate = false;
for (int i = 0; i < files.size(); i++) { // check if dragged files contain resource or scene can be created at least once
RES res = ResourceLoader::load(files[i]);
if (res.is_null()) {
@@ -5937,11 +5937,11 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
String type = res->get_class();
if (type == "PackedScene") {
Ref<PackedScene> sdata = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
- if (!instanced_scene) {
+ Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ if (!instantiated_scene) {
continue;
}
- memdelete(instanced_scene);
+ memdelete(instantiated_scene);
} else if (type == "Texture2D" ||
type == "ImageTexture" ||
type == "ViewportTexture" ||
@@ -5956,10 +5956,10 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
} else {
continue;
}
- can_instance = true;
+ can_instantiate = true;
break;
}
- if (can_instance) {
+ if (can_instantiate) {
if (!preview_node->get_parent()) { // create preview only once
_create_preview(files);
}
@@ -5967,7 +5967,7 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
preview_node->set_position((p_point - trans.get_origin()) / trans.get_scale().x);
label->set_text(vformat(TTR("Adding %s..."), default_type));
}
- return can_instance;
+ return can_instantiate;
}
}
label->hide();
@@ -6092,7 +6092,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
vbc->add_child(btn_group);
btn_group->set_h_size_flags(0);
- button_group.instance();
+ button_group.instantiate();
for (int i = 0; i < types.size(); i++) {
CheckBox *check = memnew(CheckBox);
btn_group->add_child(check);
diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.cpp b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
index a0df7e289e..7873c1b136 100644
--- a/editor/plugins/collision_polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
@@ -537,7 +537,7 @@ CollisionPolygon3DEditor::CollisionPolygon3DEditor(EditorNode *p_editor) {
pointsm = memnew(MeshInstance3D);
imgeom->add_child(pointsm);
- m.instance();
+ m.instantiate();
pointsm->set_mesh(m);
pointsm->set_transform(Transform3D(Basis(), Vector3(0, 0, 0.00001)));
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index 3403aeceba..6a56cd31d1 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -74,7 +74,7 @@ void CPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
void CPUParticles2DEditorPlugin::_generate_emission_mask() {
Ref<Image> img;
- img.instance();
+ img.instantiate();
Error err = ImageLoader::load_image(source_emission_file, img);
ERR_FAIL_COND_MSG(err != OK, "Error loading image '" + source_emission_file + "'.");
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 7a38fd2bd5..706243fe25 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -127,6 +127,8 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) {
case MOUSE_BUTTON_LEFT:
_dragging = true;
break;
+ default:
+ break;
}
}
@@ -776,7 +778,7 @@ void EditorInspectorPluginCurve::parse_begin(Object *p_object) {
CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) {
Ref<EditorInspectorPluginCurve> curve_plugin;
- curve_plugin.instance();
+ curve_plugin.instantiate();
EditorInspector::add_inspector_plugin(curve_plugin);
get_editor_interface()->get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator));
@@ -798,7 +800,7 @@ Ref<Texture2D> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, cons
int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
Ref<Image> img_ref;
- img_ref.instance();
+ img_ref.instantiate();
Image &im = **img_ref;
im.create(thumbnail_size, thumbnail_size / 2, false, Image::FORMAT_RGBA8);
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 235ccb18cb..a233d66d82 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -174,7 +174,7 @@ Ref<Texture2D> EditorImagePreviewPlugin::generate(const RES &p_from, const Size2
post_process_preview(img);
Ref<ImageTexture> ptex;
- ptex.instance();
+ ptex.instantiate();
ptex->create_from_image(img);
return ptex;
@@ -219,7 +219,7 @@ Ref<Texture2D> EditorBitmapPreviewPlugin::generate(const RES &p_from, const Size
}
Ref<Image> img;
- img.instance();
+ img.instantiate();
img->create(bm->get_size().width, bm->get_size().height, false, Image::FORMAT_L8, data);
if (img->is_compressed()) {
@@ -278,7 +278,7 @@ Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String &
}
Ref<Image> img;
- img.instance();
+ img.instantiate();
Error err = img->load(path);
if (err == OK) {
Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
@@ -501,7 +501,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
int line = 0;
int col = 0;
Ref<Image> img;
- img.instance();
+ img.instantiate();
int thumbnail_size = MAX(p_size.x, p_size.y);
img->create(thumbnail_size, thumbnail_size, false, Image::FORMAT_RGBA8);
@@ -688,7 +688,7 @@ Ref<Texture2D> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const
Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
Ref<Image> image;
- image.instance();
+ image.instantiate();
image->create(w, h, false, Image::FORMAT_RGB8, img);
ptex->create_from_image(image);
return ptex;
@@ -881,7 +881,7 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path,
if (res->is_class("Font")) {
sampled_font = res->duplicate();
} else if (res->is_class("FontData")) {
- sampled_font.instance();
+ sampled_font.instantiate();
sampled_font->add_data(res->duplicate());
}
diff --git a/editor/plugins/font_editor_plugin.cpp b/editor/plugins/font_editor_plugin.cpp
index 8de7dc2447..9b0af37abb 100644
--- a/editor/plugins/font_editor_plugin.cpp
+++ b/editor/plugins/font_editor_plugin.cpp
@@ -119,7 +119,7 @@ void FontDataPreview::set_data(const Ref<FontData> &p_data) {
}
FontDataPreview::FontDataPreview() {
- line.instance();
+ line.instantiate();
}
/*************************************************************************/
@@ -326,6 +326,6 @@ bool EditorInspectorPluginFont::parse_property(Object *p_object, Variant::Type p
FontEditorPlugin::FontEditorPlugin(EditorNode *p_node) {
Ref<EditorInspectorPluginFont> fd_plugin;
- fd_plugin.instance();
+ fd_plugin.instantiate();
EditorInspector::add_inspector_plugin(fd_plugin);
}
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
index b447304a3f..37f900280b 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -146,7 +146,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
}
Ref<Image> img;
- img.instance();
+ img.instantiate();
Error err = ImageLoader::load_image(source_emission_file, img);
ERR_FAIL_COND_MSG(err != OK, "Error loading image '" + source_emission_file + "'.");
@@ -270,11 +270,11 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
}
}
- img.instance();
+ img.instantiate();
img->create(w, h, false, Image::FORMAT_RGF, texdata);
Ref<ImageTexture> imgt;
- imgt.instance();
+ imgt.instantiate();
imgt->create_from_image(img);
pm->set_emission_point_texture(imgt);
@@ -291,10 +291,10 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
}
}
- img.instance();
+ img.instantiate();
img->create(w, h, false, Image::FORMAT_RGBA8, colordata);
- imgt.instance();
+ imgt.instantiate();
imgt->create_from_image(img);
pm->set_emission_color_texture(imgt);
}
@@ -314,10 +314,10 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
}
}
- img.instance();
+ img.instantiate();
img->create(w, h, false, Image::FORMAT_RGF, normdata);
- imgt.instance();
+ imgt.instantiate();
imgt->create_from_image(img);
pm->set_emission_normal_texture(imgt);
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index 17c7397729..571bcf9c4a 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -359,7 +359,7 @@ void GPUParticles3DEditor::_generate_emission_points() {
Ref<Image> image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img));
Ref<ImageTexture> tex;
- tex.instance();
+ tex.instantiate();
Ref<ParticlesMaterial> material = node->get_process_material();
ERR_FAIL_COND(material.is_null());
@@ -387,7 +387,7 @@ void GPUParticles3DEditor::_generate_emission_points() {
Ref<Image> image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2));
Ref<ImageTexture> tex2;
- tex2.instance();
+ tex2.instantiate();
material->set_emission_normal_texture(tex2);
} else {
diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
index 8c4928b7cb..a2dee4a1dc 100644
--- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
@@ -137,7 +137,7 @@ void GPUParticlesCollisionSDFEditorPlugin::_sdf_save_path_and_bake(const String
Ref<ConfigFile> config;
- config.instance();
+ config.instantiate();
if (FileAccess::exists(p_path + ".import")) {
config->load(p_path + ".import");
}
diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp
index 46fa00f730..355bdb69d8 100644
--- a/editor/plugins/gradient_editor_plugin.cpp
+++ b/editor/plugins/gradient_editor_plugin.cpp
@@ -92,6 +92,6 @@ void EditorInspectorPluginGradient::parse_begin(Object *p_object) {
GradientEditorPlugin::GradientEditorPlugin(EditorNode *p_node) {
Ref<EditorInspectorPluginGradient> plugin;
- plugin.instance();
+ plugin.instantiate();
add_inspector_plugin(plugin);
}
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 81f0ecacf2..17a634ee14 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -111,7 +111,7 @@ MaterialEditor::MaterialEditor() {
vc->set_anchors_and_offsets_preset(PRESET_WIDE);
viewport = memnew(SubViewport);
Ref<World3D> world_3d;
- world_3d.instance();
+ world_3d.instantiate();
viewport->set_world_3d(world_3d); //use own world
vc->add_child(viewport);
viewport->set_disable_input(true);
@@ -146,9 +146,9 @@ MaterialEditor::MaterialEditor() {
box_xform.origin.y = 0.2;
box_instance->set_transform(box_xform);
- sphere_mesh.instance();
+ sphere_mesh.instantiate();
sphere_instance->set_mesh(sphere_mesh);
- box_mesh.instance();
+ box_mesh.instantiate();
box_instance->set_mesh(box_mesh);
set_custom_minimum_size(Size2(1, 150) * EDSCALE);
@@ -223,7 +223,7 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) {
}
EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() {
- env.instance();
+ env.instantiate();
Ref<Sky> sky = memnew(Sky());
env->set_sky(sky);
env->set_background(Environment::BG_COLOR);
@@ -233,7 +233,7 @@ EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() {
MaterialEditorPlugin::MaterialEditorPlugin(EditorNode *p_node) {
Ref<EditorInspectorPluginMaterial> plugin;
- plugin.instance();
+ plugin.instantiate();
add_inspector_plugin(plugin);
}
@@ -251,10 +251,10 @@ Ref<Resource> StandardMaterial3DConversionPlugin::convert(const Ref<Resource> &p
ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
Ref<ShaderMaterial> smat;
- smat.instance();
+ smat.instantiate();
Ref<Shader> shader;
- shader.instance();
+ shader.instantiate();
String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
@@ -295,10 +295,10 @@ Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_
ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
Ref<ShaderMaterial> smat;
- smat.instance();
+ smat.instantiate();
Ref<Shader> shader;
- shader.instance();
+ shader.instantiate();
String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
@@ -332,10 +332,10 @@ Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p
ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
Ref<ShaderMaterial> smat;
- smat.instance();
+ smat.instantiate();
Ref<Shader> shader;
- shader.instance();
+ shader.instantiate();
String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
@@ -369,10 +369,10 @@ Ref<Resource> ProceduralSkyMaterialConversionPlugin::convert(const Ref<Resource>
ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
Ref<ShaderMaterial> smat;
- smat.instance();
+ smat.instantiate();
Ref<Shader> shader;
- shader.instance();
+ shader.instantiate();
String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
@@ -406,10 +406,10 @@ Ref<Resource> PanoramaSkyMaterialConversionPlugin::convert(const Ref<Resource> &
ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
Ref<ShaderMaterial> smat;
- smat.instance();
+ smat.instantiate();
Ref<Shader> shader;
- shader.instance();
+ shader.instantiate();
String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
@@ -443,10 +443,10 @@ Ref<Resource> PhysicalSkyMaterialConversionPlugin::convert(const Ref<Resource> &
ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
Ref<ShaderMaterial> smat;
- smat.instance();
+ smat.instantiate();
Ref<Shader> shader;
- shader.instance();
+ shader.instantiate();
String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index 8d488dce20..fcc6b84efb 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -110,7 +110,7 @@ void MeshEditor::_bind_methods() {
MeshEditor::MeshEditor() {
viewport = memnew(SubViewport);
Ref<World3D> world_3d;
- world_3d.instance();
+ world_3d.instantiate();
viewport->set_world_3d(world_3d); //use own world
add_child(viewport);
viewport->set_disable_input(true);
@@ -182,6 +182,6 @@ void EditorInspectorPluginMesh::parse_begin(Object *p_object) {
MeshEditorPlugin::MeshEditorPlugin(EditorNode *p_node) {
Ref<EditorInspectorPluginMesh> plugin;
- plugin.instance();
+ plugin.instantiate();
add_inspector_plugin(plugin);
}
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index e64992759d..5d1d29cbc8 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -193,7 +193,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
void MeshLibraryEditor::_import_scene_cbk(const String &p_str) {
Ref<PackedScene> ps = ResourceLoader::load(p_str, "PackedScene");
ERR_FAIL_COND(ps.is_null());
- Node *scene = ps->instance();
+ Node *scene = ps->instantiate();
ERR_FAIL_COND_MSG(!scene, "Cannot create an instance from PackedScene '" + p_str + "'.");
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 911c5147bf..59c0d81ae7 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/math/camera_matrix.h"
+#include "core/math/math_funcs.h"
#include "core/os/keyboard.h"
#include "core/string/print_string.h"
#include "core/templates/sort_array.h"
@@ -1397,6 +1398,8 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
} break;
+ default:
+ break;
}
}
@@ -3713,7 +3716,7 @@ void Node3DEditorViewport::_create_preview(const Vector<String> &files) const {
preview_node->add_child(mesh_instance);
} else {
if (scene.is_valid()) {
- Node *instance = scene->instance();
+ Node *instance = scene->instantiate();
if (instance) {
preview_node->add_child(instance);
}
@@ -3758,49 +3761,49 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
- Node *instanced_scene = nullptr;
+ Node *instantiated_scene = nullptr;
if (mesh != nullptr || scene != nullptr) {
if (mesh != nullptr) {
MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
mesh_instance->set_mesh(mesh);
mesh_instance->set_name(path.get_file().get_basename());
- instanced_scene = mesh_instance;
+ instantiated_scene = mesh_instance;
} else {
if (!scene.is_valid()) { // invalid scene
return false;
} else {
- instanced_scene = scene->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ instantiated_scene = scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
}
}
}
- if (instanced_scene == nullptr) {
+ if (instantiated_scene == nullptr) {
return false;
}
if (editor->get_edited_scene()->get_filename() != "") { // cyclical instancing
- if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instanced_scene)) {
- memdelete(instanced_scene);
+ if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instantiated_scene)) {
+ memdelete(instantiated_scene);
return false;
}
}
if (scene != nullptr) {
- instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path));
+ instantiated_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path));
}
- editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene);
- editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", editor->get_edited_scene());
- editor_data->get_undo_redo().add_do_reference(instanced_scene);
- editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene);
+ editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene);
+ editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", editor->get_edited_scene());
+ editor_data->get_undo_redo().add_do_reference(instantiated_scene);
+ editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene);
- String new_name = parent->validate_child_name(instanced_scene);
+ String new_name = parent->validate_child_name(instantiated_scene);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
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));
- Node3D *node3d = Object::cast_to<Node3D>(instanced_scene);
+ Node3D *node3d = Object::cast_to<Node3D>(instantiated_scene);
if (node3d) {
Transform3D global_transform;
Node3D *parent_node3d = Object::cast_to<Node3D>(parent);
@@ -3811,7 +3814,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
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(instantiated_scene, "set_global_transform", global_transform);
}
return true;
@@ -3854,7 +3857,7 @@ void Node3DEditorViewport::_perform_drop_data() {
}
bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
- bool can_instance = false;
+ bool can_instantiate = false;
if (!preview_node->is_inside_tree()) {
Dictionary d = p_data;
@@ -3876,11 +3879,11 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
String type = res->get_class();
if (type == "PackedScene") {
Ref<PackedScene> sdata = ResourceLoader::load(files[i]);
- Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
- if (!instanced_scene) {
+ Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ if (!instantiated_scene) {
continue;
}
- memdelete(instanced_scene);
+ memdelete(instantiated_scene);
} else if (type == "Mesh" || type == "ArrayMesh" || type == "PrimitiveMesh") {
Ref<Mesh> mesh = ResourceLoader::load(files[i]);
if (!mesh.is_valid()) {
@@ -3889,24 +3892,24 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
} else {
continue;
}
- can_instance = true;
+ can_instantiate = true;
break;
}
}
- if (can_instance) {
+ if (can_instantiate) {
_create_preview(files);
}
}
} else {
- can_instance = true;
+ can_instantiate = true;
}
- if (can_instance) {
+ if (can_instantiate) {
Transform3D global_transform = Transform3D(Basis(), _get_instance_position(p_point));
preview_node->set_global_transform(global_transform);
}
- return can_instance;
+ return can_instantiate;
}
void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
@@ -5316,7 +5319,7 @@ void Node3DEditor::_init_indicators() {
origin_enabled = true;
grid_enabled = true;
- indicator_mat.instance();
+ indicator_mat.instantiate();
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);
@@ -5396,7 +5399,7 @@ void Node3DEditor::_init_indicators() {
"}");
for (int i = 0; i < 3; i++) {
- grid_mat[i].instance();
+ grid_mat[i].instantiate();
grid_mat[i]->set_shader(grid_shader);
}
@@ -6547,9 +6550,11 @@ void Node3DEditor::clear() {
void Node3DEditor::_sun_direction_draw() {
sun_direction->draw_rect(Rect2(Vector2(), sun_direction->get_size()), Color(1, 1, 1, 1));
- sun_direction_material->set_shader_param("sun_direction", -preview_sun->get_transform().basis.get_axis(Vector3::AXIS_Z));
- float nrg = sun_energy->get_value();
- sun_direction_material->set_shader_param("sun_color", Vector3(sun_color->get_pick_color().r * nrg, sun_color->get_pick_color().g * nrg, sun_color->get_pick_color().b * nrg));
+ Vector3 z_axis = preview_sun->get_transform().basis.get_axis(Vector3::AXIS_Z);
+ z_axis = get_editor_viewport(0)->camera->get_camera_transform().basis.xform_inv(z_axis);
+ sun_direction_material->set_shader_param("sun_direction", Vector3(z_axis.x, -z_axis.y, z_axis.z));
+ Color color = sun_color->get_pick_color() * sun_energy->get_value();
+ sun_direction_material->set_shader_param("sun_color", Vector3(color.r, color.g, color.b));
}
void Node3DEditor::_preview_settings_changed() {
@@ -6559,7 +6564,7 @@ void Node3DEditor::_preview_settings_changed() {
{ // preview sun
Transform3D t;
- t.basis = sun_rotation;
+ t.basis = Basis(Vector3(sun_rotation.x, sun_rotation.y, 0));
preview_sun->set_transform(t);
sun_direction->update();
preview_sun->set_param(Light3D::PARAM_ENERGY, sun_energy->get_value());
@@ -6581,11 +6586,20 @@ void Node3DEditor::_preview_settings_changed() {
environment->set_tonemapper(environ_tonemap_button->is_pressed() ? Environment::TONE_MAPPER_FILMIC : Environment::TONE_MAPPER_LINEAR);
}
}
+
void Node3DEditor::_load_default_preview_settings() {
sun_environ_updating = true;
- sun_rotation = Basis(Vector3(0, 1, 0), Math_PI * 3.0 / 4) * Basis(Vector3(1, 0, 0), -Math_PI / 4);
+ // These default rotations place the preview sun at an angular altitude
+ // of 60 degrees (must be negative) and an azimuth of 30 degrees clockwise
+ // from north (or 150 CCW from south), from north east, facing south west.
+ // On any not-tidally-locked planet, a sun would have an angular altitude
+ // of 60 degrees as the average of all points on the sphere at noon.
+ // The azimuth choice is arbitrary, but ideally shouldn't be on an axis.
+ sun_rotation = Vector2(-Math::deg2rad(60.0), Math::deg2rad(150.0));
+ sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x));
+ sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y));
sun_direction->update();
environ_sky_color->set_pick_color(Color::hex(0x91b2ceff));
environ_ground_color->set_pick_color(Color::hex(0x1f1f21ff));
@@ -6628,6 +6642,9 @@ void Node3DEditor::_update_preview_environment() {
}
}
+ sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x));
+ sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y));
+
bool disable_env = world_env_count > 0 || environ_button->is_pressed();
environ_button->set_disabled(world_env_count > 0);
@@ -6656,17 +6673,21 @@ void Node3DEditor::_update_preview_environment() {
void Node3DEditor::_sun_direction_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
- float x = -mm->get_relative().y * 0.02 * EDSCALE;
- float y = mm->get_relative().x * 0.02 * EDSCALE;
-
- Basis rot = Basis(Vector3(0, 1, 0), y) * Basis(Vector3(1, 0, 0), x);
-
- sun_rotation = rot * sun_rotation;
- sun_rotation.orthonormalize();
+ sun_rotation.x += mm->get_relative().y * (0.02 * EDSCALE);
+ sun_rotation.y -= mm->get_relative().x * (0.02 * EDSCALE);
+ sun_rotation.x = CLAMP(sun_rotation.x, -Math_TAU / 4, Math_TAU / 4);
+ sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x));
+ sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y));
_preview_settings_changed();
}
}
+void Node3DEditor::_sun_direction_angle_set() {
+ sun_rotation.x = Math::deg2rad(-sun_angle_altitude->get_value());
+ sun_rotation.y = Math::deg2rad(180.0 - sun_angle_azimuth->get_value());
+ _preview_settings_changed();
+}
+
Node3DEditor::Node3DEditor(EditorNode *p_editor) {
gizmo.visible = true;
gizmo.scale = 1.0;
@@ -6896,7 +6917,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
- p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid")), MENU_VIEW_GRID);
+ p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid"), KEY_MASK_CMD + KEY_G), MENU_VIEW_GRID);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS);
@@ -7096,14 +7117,43 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
sun_direction->set_default_cursor_shape(CURSOR_MOVE);
String sun_dir_shader_code = "shader_type canvas_item; uniform vec3 sun_direction; uniform vec3 sun_color; void fragment() { vec3 n; n.xy = UV * 2.0 - 1.0; n.z = sqrt(max(0.0, 1.0 - dot(n.xy, n.xy))); COLOR.rgb = dot(n,sun_direction) * sun_color; COLOR.a = 1.0 - smoothstep(0.99,1.0,length(n.xy)); }";
- sun_direction_shader.instance();
+ sun_direction_shader.instantiate();
sun_direction_shader->set_code(sun_dir_shader_code);
- sun_direction_material.instance();
+ sun_direction_material.instantiate();
sun_direction_material->set_shader(sun_direction_shader);
sun_direction_material->set_shader_param("sun_direction", Vector3(0, 0, 1));
sun_direction_material->set_shader_param("sun_color", Vector3(1, 1, 1));
sun_direction->set_material(sun_direction_material);
+ HBoxContainer *sun_angle_hbox = memnew(HBoxContainer);
+ VBoxContainer *sun_angle_altitude_vbox = memnew(VBoxContainer);
+ Label *sun_angle_altitude_label = memnew(Label);
+ sun_angle_altitude_label->set_text(TTR("Angular Altitude"));
+ sun_angle_altitude_vbox->add_child(sun_angle_altitude_label);
+ sun_angle_altitude = memnew(EditorSpinSlider);
+ sun_angle_altitude->set_max(90);
+ sun_angle_altitude->set_min(-90);
+ sun_angle_altitude->set_step(0.1);
+ sun_angle_altitude->connect("value_changed", callable_mp(this, &Node3DEditor::_sun_direction_angle_set).unbind(1));
+ sun_angle_altitude_vbox->add_child(sun_angle_altitude);
+ sun_angle_hbox->add_child(sun_angle_altitude_vbox);
+ VBoxContainer *sun_angle_azimuth_vbox = memnew(VBoxContainer);
+ sun_angle_azimuth_vbox->set_custom_minimum_size(Vector2(100, 0));
+ Label *sun_angle_azimuth_label = memnew(Label);
+ sun_angle_azimuth_label->set_text(TTR("Azimuth"));
+ sun_angle_azimuth_vbox->add_child(sun_angle_azimuth_label);
+ sun_angle_azimuth = memnew(EditorSpinSlider);
+ sun_angle_azimuth->set_max(180);
+ sun_angle_azimuth->set_min(-180);
+ sun_angle_azimuth->set_step(0.1);
+ sun_angle_azimuth->set_allow_greater(true);
+ sun_angle_azimuth->set_allow_lesser(true);
+ sun_angle_azimuth->connect("value_changed", callable_mp(this, &Node3DEditor::_sun_direction_angle_set).unbind(1));
+ sun_angle_azimuth_vbox->add_child(sun_angle_azimuth);
+ sun_angle_hbox->add_child(sun_angle_azimuth_vbox);
+ sun_angle_hbox->add_theme_constant_override("separation", 10);
+ sun_vb->add_child(sun_angle_hbox);
+
sun_color = memnew(ColorPickerButton);
sun_color->set_edit_alpha(false);
sun_vb->add_margin_child(TTR("Sun Color"), sun_color);
@@ -7200,11 +7250,11 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
preview_sun->set_shadow(true);
preview_sun->set_shadow_mode(DirectionalLight3D::SHADOW_PARALLEL_4_SPLITS);
preview_environment = memnew(WorldEnvironment);
- environment.instance();
+ environment.instantiate();
preview_environment->set_environment(environment);
Ref<Sky> sky;
- sky.instance();
- sky_material.instance();
+ sky.instantiate();
+ sky_material.instantiate();
sky->set_material(sky_material);
environment->set_sky(sky);
environment->set_background(Environment::BG_SKY);
@@ -7335,17 +7385,17 @@ Node3DEditorPlugin::~Node3DEditorPlugin() {
}
void EditorNode3DGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) {
- Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6));
+ Color instantiated_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6));
Vector<Ref<StandardMaterial3D>> mats;
for (int i = 0; i < 4; i++) {
bool selected = i % 2 == 1;
- bool instanced = i < 2;
+ bool instantiated = i < 2;
Ref<StandardMaterial3D> material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
- Color color = instanced ? instanced_color : p_color;
+ Color color = instantiated ? instantiated_color : p_color;
if (!selected) {
color.a *= 0.3;
@@ -7377,17 +7427,17 @@ void EditorNode3DGizmoPlugin::create_material(const String &p_name, const Color
}
void EditorNode3DGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture2D> &p_texture, bool p_on_top, const Color &p_albedo) {
- Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6));
+ Color instantiated_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6));
Vector<Ref<StandardMaterial3D>> icons;
for (int i = 0; i < 4; i++) {
bool selected = i % 2 == 1;
- bool instanced = i < 2;
+ bool instantiated = i < 2;
Ref<StandardMaterial3D> icon = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
- Color color = instanced ? instanced_color : p_albedo;
+ Color color = instantiated ? instantiated_color : p_albedo;
if (!selected) {
color.a *= 0.85;
@@ -7546,7 +7596,7 @@ Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::create_gizmo(Node3D *p_spatial)
Ref<EditorNode3DGizmo> ref;
if (has_gizmo(p_spatial)) {
- ref.instance();
+ ref.instantiate();
}
return ref;
}
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 20a0c501df..fa432a5868 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -52,7 +52,7 @@ class EditorNode3DGizmo : public Node3DGizmo {
GDCLASS(EditorNode3DGizmo, Node3DGizmo);
bool selected;
- bool instanced;
+ bool instantiated;
public:
void set_selected(bool p_selected) { selected = p_selected; }
@@ -764,6 +764,8 @@ private:
VBoxContainer *sun_vb;
Popup *sun_environ_popup;
Control *sun_direction;
+ EditorSpinSlider *sun_angle_altitude;
+ EditorSpinSlider *sun_angle_azimuth;
ColorPickerButton *sun_color;
EditorSpinSlider *sun_energy;
EditorSpinSlider *sun_max_distance;
@@ -771,8 +773,9 @@ private:
void _sun_direction_draw();
void _sun_direction_input(const Ref<InputEvent> &p_event);
+ void _sun_direction_angle_set();
- Basis sun_rotation;
+ Vector2 sun_rotation;
Ref<Shader> sun_direction_shader;
Ref<ShaderMaterial> sun_direction_material;
diff --git a/editor/plugins/occluder_instance_3d_editor_plugin.cpp b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
index 0821f140b3..b0cafd83be 100644
--- a/editor/plugins/occluder_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
@@ -56,7 +56,7 @@ void OccluderInstance3DEditorPlugin::_bake_select_file(const String &p_file) {
} break;
case OccluderInstance3D::BAKE_ERROR_NO_MESHES: {
- EditorNode::get_singleton()->show_warning(TTR("No meshes to bake."));
+ EditorNode::get_singleton()->show_warning(TTR("No meshes to bake.\nMake sure there is at least one MeshInstance3D node in the scene whose visual layers are part of the OccluderInstance3D's Bake Mask property."));
break;
}
default: {
diff --git a/editor/plugins/ot_features_plugin.cpp b/editor/plugins/ot_features_plugin.cpp
index ebfdf2c7cd..baab9bc438 100644
--- a/editor/plugins/ot_features_plugin.cpp
+++ b/editor/plugins/ot_features_plugin.cpp
@@ -208,6 +208,6 @@ bool EditorInspectorPluginOpenTypeFeatures::parse_property(Object *p_object, Var
OpenTypeFeaturesEditorPlugin::OpenTypeFeaturesEditorPlugin(EditorNode *p_node) {
Ref<EditorInspectorPluginOpenTypeFeatures> ftr_plugin;
- ftr_plugin.instance();
+ ftr_plugin.instantiate();
EditorInspector::add_inspector_plugin(ftr_plugin);
}
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index b0eb13c3c6..82b51f8a06 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -554,7 +554,7 @@ Path3DEditorPlugin::Path3DEditorPlugin(EditorNode *p_node) {
mirror_handle_length = true;
Ref<Path3DGizmoPlugin> gizmo_plugin;
- gizmo_plugin.instance();
+ gizmo_plugin.instantiate();
Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
sep = memnew(VSeparator);
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 8a14db0cfd..1a13a028c8 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -162,7 +162,7 @@ void Polygon2DEditor::_update_bone_list() {
}
Ref<ButtonGroup> bg;
- bg.instance();
+ bg.instantiate();
for (int i = 0; i < node->get_bone_count(); i++) {
CheckBox *cb = memnew(CheckBox);
NodePath np = node->get_bone_path(i);
@@ -1231,7 +1231,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
uv_edit->add_child(uv_main_vb);
HBoxContainer *uv_mode_hb = memnew(HBoxContainer);
- uv_edit_group.instance();
+ uv_edit_group.instantiate();
uv_edit_mode[0] = memnew(Button);
uv_mode_hb->add_child(uv_edit_mode[0]);
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index b8b2c6d343..a7c11f8521 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -367,8 +367,8 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() {
tree = memnew(Tree);
tree->connect("button_pressed", callable_mp(this, &ResourcePreloaderEditor::_cell_button_pressed));
tree->set_columns(2);
- tree->set_column_min_width(0, 2);
- tree->set_column_min_width(1, 3);
+ tree->set_column_custom_minimum_width(0, 2);
+ tree->set_column_custom_minimum_width(1, 3);
tree->set_column_expand(0, true);
tree->set_column_expand(1, true);
tree->set_v_size_flags(SIZE_EXPAND_FILL);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 0410ab3a45..498d5b0711 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -71,7 +71,7 @@ Array EditorSyntaxHighlighter::_get_supported_languages() const {
Ref<EditorSyntaxHighlighter> EditorSyntaxHighlighter::_create() const {
Ref<EditorSyntaxHighlighter> syntax_highlighter;
- syntax_highlighter.instance();
+ syntax_highlighter.instantiate();
if (get_script_instance()) {
syntax_highlighter->set_script(get_script_instance()->get_script());
}
@@ -201,7 +201,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
Ref<EditorSyntaxHighlighter> EditorStandardSyntaxHighlighter::_create() const {
Ref<EditorStandardSyntaxHighlighter> syntax_highlighter;
- syntax_highlighter.instance();
+ syntax_highlighter.instantiate();
return syntax_highlighter;
}
@@ -209,7 +209,7 @@ Ref<EditorSyntaxHighlighter> EditorStandardSyntaxHighlighter::_create() const {
Ref<EditorSyntaxHighlighter> EditorPlainTextSyntaxHighlighter::_create() const {
Ref<EditorPlainTextSyntaxHighlighter> syntax_highlighter;
- syntax_highlighter.instance();
+ syntax_highlighter.instantiate();
return syntax_highlighter;
}
@@ -760,6 +760,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
_update_members_overview_visibility();
_update_help_overview_visibility();
_save_layout();
+ _update_find_replace_bar();
}
void ScriptEditor::_close_current_tab(bool p_save) {
@@ -829,6 +830,7 @@ void ScriptEditor::_close_all_tabs() {
_close_current_tab(false);
}
+ _update_find_replace_bar();
}
void ScriptEditor::_ask_close_current_unsaved_tab(ScriptEditorBase *current) {
@@ -1629,7 +1631,7 @@ void ScriptEditor::_help_overview_selected(int p_idx) {
}
void ScriptEditor::_script_selected(int p_idx) {
- grab_focus_block = !Input::get_singleton()->is_mouse_button_pressed(1); //amazing hack, simply amazing
+ grab_focus_block = !Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT); //amazing hack, simply amazing
_go_to_tab(script_list->get_item_metadata(p_idx));
grab_focus_block = false;
@@ -1640,15 +1642,13 @@ void ScriptEditor::ensure_select_current() {
ScriptEditorBase *se = _get_current_editor();
if (se) {
se->enable_editor();
- se->set_find_replace_bar(find_replace_bar);
if (!grab_focus_block && is_visible_in_tree()) {
se->ensure_focus();
}
- } else {
- find_replace_bar->hide();
}
}
+ _update_find_replace_bar();
_update_selected_editor_menu();
}
@@ -2520,6 +2520,16 @@ void ScriptEditor::_file_removed(const String &p_removed_file) {
}
}
+void ScriptEditor::_update_find_replace_bar() {
+ ScriptEditorBase *se = _get_current_editor();
+ if (se) {
+ se->set_find_replace_bar(find_replace_bar);
+ } else {
+ find_replace_bar->set_text_edit(nullptr);
+ find_replace_bar->hide();
+ }
+}
+
void ScriptEditor::_autosave_scripts() {
save_all_scripts();
}
@@ -2771,6 +2781,8 @@ void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
case MOUSE_BUTTON_RIGHT: {
_make_script_list_context_menu();
} break;
+ default:
+ break;
}
}
}
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 1d379059d4..72a649ffbf 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -80,7 +80,7 @@ public:
virtual Ref<EditorSyntaxHighlighter> _create() const override;
- EditorStandardSyntaxHighlighter() { highlighter.instance(); }
+ EditorStandardSyntaxHighlighter() { highlighter.instantiate(); }
};
class EditorPlainTextSyntaxHighlighter : public EditorSyntaxHighlighter {
@@ -328,6 +328,7 @@ class ScriptEditor : public PanelContainer {
void _show_error_dialog(String p_path);
void _close_tab(int p_idx, bool p_save = true, bool p_history_back = true);
+ void _update_find_replace_bar();
void _close_current_tab(bool p_save = true);
void _close_discard_current_tab(const String &p_str);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 3ec20ae68e..5fc1f74089 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -109,13 +109,11 @@ ConnectionInfoDialog::ConnectionInfoDialog() {
////////////////////////////////////////////////////////////////////////////////
Vector<String> ScriptTextEditor::get_functions() {
- String errortxt;
- int line = -1, col;
CodeEdit *te = code_editor->get_text_editor();
String text = te->get_text();
List<String> fnc;
- if (script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc)) {
+ if (script->get_language()->validate(text, script->get_path(), &fnc)) {
//if valid rewrite functions to latest
functions.clear();
for (List<String>::Element *E = fnc.front(); E; E = E->next()) {
@@ -168,7 +166,6 @@ void ScriptTextEditor::enable_editor() {
void ScriptTextEditor::_load_theme_settings() {
CodeEdit *text_edit = code_editor->get_text_editor();
- text_edit->clear_keywords();
Color updated_marked_line_color = EDITOR_GET("text_editor/highlighting/mark_color");
Color updated_safe_line_number_color = EDITOR_GET("text_editor/highlighting/safe_line_number_color");
@@ -222,47 +219,10 @@ void ScriptTextEditor::_set_theme_for_script() {
String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
text_edit->add_comment_delimiter(beg, end, end == "");
}
+}
- /* add keywords for auto completion */
- // singleton autoloads (as types, just as engine singletons are)
- Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
- for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
- const ProjectSettings::AutoloadInfo &info = E->value();
- if (info.is_singleton) {
- text_edit->add_keyword(info.name);
- }
- }
-
- // engine types
- List<StringName> types;
- ClassDB::get_class_list(&types);
- for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
- String n = E->get();
- if (n.begins_with("_")) {
- n = n.substr(1, n.length());
- }
- text_edit->add_keyword(n);
- }
-
- // user types
- List<StringName> global_classes;
- ScriptServer::get_global_class_list(&global_classes);
- for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) {
- text_edit->add_keyword(E->get());
- }
-
- List<String> keywords;
- script->get_language()->get_reserved_words(&keywords);
- for (List<String>::Element *E = keywords.front(); E; E = E->next()) {
- text_edit->add_keyword(E->get());
- }
-
- // core types
- List<String> core_types;
- script->get_language()->get_core_type_words(&core_types);
- for (List<String>::Element *E = core_types.front(); E; E = E->next()) {
- text_edit->add_keyword(E->get());
- }
+void ScriptTextEditor::_show_errors_panel(bool p_show) {
+ errors_panel->set_visible(p_show);
}
void ScriptTextEditor::_show_warnings_panel(bool p_show) {
@@ -279,6 +239,12 @@ void ScriptTextEditor::_warning_clicked(Variant p_line) {
}
}
+void ScriptTextEditor::_error_clicked(Variant p_line) {
+ if (p_line.get_type() == Variant::INT) {
+ code_editor->get_text_editor()->cursor_set_line(p_line.operator int64_t());
+ }
+}
+
void ScriptTextEditor::reload_text() {
ERR_FAIL_COND(script.is_null());
@@ -429,23 +395,21 @@ Ref<Texture2D> ScriptTextEditor::get_theme_icon() {
}
void ScriptTextEditor::_validate_script() {
- String errortxt;
- int line = -1, col;
CodeEdit *te = code_editor->get_text_editor();
String text = te->get_text();
List<String> fnc;
Set<int> safe_lines;
List<ScriptLanguage::Warning> warnings;
+ List<ScriptLanguage::ScriptError> errors;
- if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc, &warnings, &safe_lines)) {
- String error_text = "error(" + itos(line) + "," + itos(col) + "): " + errortxt;
+ if (!script->get_language()->validate(text, script->get_path(), &fnc, &errors, &warnings, &safe_lines)) {
+ String error_text = TTR("Error at ") + "(" + itos(errors[0].line) + "," + itos(errors[0].column) + "): " + errors[0].message;
code_editor->set_error(error_text);
- code_editor->set_error_pos(line - 1, col - 1);
+ code_editor->set_error_pos(errors[0].line - 1, errors[0].column - 1);
script_is_valid = false;
} else {
code_editor->set_error("");
- line = -1;
if (!script->is_tool()) {
script->set_source_code(text);
script->update_exports();
@@ -487,7 +451,8 @@ void ScriptTextEditor::_validate_script() {
}
}
- code_editor->set_warning_nb(warning_nb);
+ code_editor->set_error_count(errors.size());
+ code_editor->set_warning_count(warning_nb);
// Add script warnings.
warnings_panel->push_table(3);
@@ -521,23 +486,52 @@ void ScriptTextEditor::_validate_script() {
}
warnings_panel->pop(); // Table.
- line--;
+ errors_panel->clear();
+ errors_panel->push_table(2);
+ for (List<ScriptLanguage::ScriptError>::Element *E = errors.front(); E; E = E->next()) {
+ ScriptLanguage::ScriptError err = E->get();
+
+ errors_panel->push_cell();
+ errors_panel->push_meta(err.line - 1);
+ errors_panel->push_color(warnings_panel->get_theme_color("error_color", "Editor"));
+ errors_panel->add_text(TTR("Line") + " " + itos(err.line) + ":");
+ errors_panel->pop(); // Color.
+ errors_panel->pop(); // Meta goto.
+ errors_panel->pop(); // Cell.
+
+ errors_panel->push_cell();
+ errors_panel->add_text(err.message);
+ errors_panel->pop(); // Cell.
+ }
+ errors_panel->pop(); // Table
+
bool highlight_safe = EDITOR_DEF("text_editor/highlighting/highlight_type_safe_lines", true);
bool last_is_safe = false;
for (int i = 0; i < te->get_line_count(); i++) {
- te->set_line_background_color(i, (line == i) ? marked_line_color : Color(0, 0, 0, 0));
+ if (errors.is_empty()) {
+ te->set_line_background_color(i, Color(0, 0, 0, 0));
+ } else {
+ for (List<ScriptLanguage::ScriptError>::Element *E = errors.front(); E; E = E->next()) {
+ bool error_line = i == E->get().line - 1;
+ te->set_line_background_color(i, error_line ? marked_line_color : Color(0, 0, 0, 0));
+ if (error_line) {
+ break;
+ }
+ }
+ }
+
if (highlight_safe) {
if (safe_lines.has(i + 1)) {
te->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color);
last_is_safe = true;
- } else if (last_is_safe && (te->is_line_comment(i) || te->get_line(i).strip_edges().is_empty())) {
+ } else if (last_is_safe && (te->is_in_comment(i) != -1 || te->get_line(i).strip_edges().is_empty())) {
te->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color);
} else {
te->set_line_gutter_item_color(i, line_number_gutter, default_line_number_color);
last_is_safe = false;
}
} else {
- te->set_line_gutter_item_color(line, 1, default_line_number_color);
+ te->set_line_gutter_item_color(i, 1, default_line_number_color);
}
}
@@ -1044,7 +1038,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
return;
}
- tx->indent_selected_lines_left();
+ tx->unindent_lines();
} break;
case EDIT_INDENT_RIGHT: {
Ref<Script> scr = script;
@@ -1052,7 +1046,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
return;
}
- tx->indent_selected_lines_right();
+ tx->indent_lines();
} break;
case EDIT_DELETE_LINE: {
code_editor->delete_lines();
@@ -1675,6 +1669,7 @@ void ScriptTextEditor::_enable_code_editor() {
editor_box->set_v_size_flags(SIZE_EXPAND_FILL);
editor_box->add_child(code_editor);
+ code_editor->connect("show_errors_panel", callable_mp(this, &ScriptTextEditor::_show_errors_panel));
code_editor->connect("show_warnings_panel", callable_mp(this, &ScriptTextEditor::_show_warnings_panel));
code_editor->connect("validate_script", callable_mp(this, &ScriptTextEditor::_validate_script));
code_editor->connect("load_theme_settings", callable_mp(this, &ScriptTextEditor::_load_theme_settings));
@@ -1695,6 +1690,13 @@ void ScriptTextEditor::_enable_code_editor() {
"normal_font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size("main_size", "EditorFonts"));
warnings_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_warning_clicked));
+ editor_box->add_child(errors_panel);
+ errors_panel->add_theme_font_override(
+ "normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts"));
+ errors_panel->add_theme_font_size_override(
+ "normal_font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size("main_size", "EditorFonts"));
+ errors_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_error_clicked));
+
add_child(context_menu);
context_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
@@ -1826,6 +1828,14 @@ ScriptTextEditor::ScriptTextEditor() {
warnings_panel->set_focus_mode(FOCUS_CLICK);
warnings_panel->hide();
+ errors_panel = memnew(RichTextLabel);
+ errors_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE));
+ errors_panel->set_h_size_flags(SIZE_EXPAND_FILL);
+ errors_panel->set_meta_underline(true);
+ errors_panel->set_selection_enabled(true);
+ errors_panel->set_focus_mode(FOCUS_CLICK);
+ errors_panel->hide();
+
update_settings();
code_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"));
@@ -1851,11 +1861,11 @@ ScriptTextEditor::ScriptTextEditor() {
highlighter_menu->set_name("highlighter_menu");
Ref<EditorPlainTextSyntaxHighlighter> plain_highlighter;
- plain_highlighter.instance();
+ plain_highlighter.instantiate();
add_syntax_highlighter(plain_highlighter);
Ref<EditorStandardSyntaxHighlighter> highlighter;
- highlighter.instance();
+ highlighter.instantiate();
add_syntax_highlighter(highlighter);
set_syntax_highlighter(highlighter);
@@ -1886,6 +1896,7 @@ ScriptTextEditor::~ScriptTextEditor() {
if (!editor_enabled) {
memdelete(code_editor);
memdelete(warnings_panel);
+ memdelete(errors_panel);
memdelete(context_menu);
memdelete(color_panel);
memdelete(edit_hb);
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 7bb961bf19..8a8e9aa737 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -55,6 +55,7 @@ class ScriptTextEditor : public ScriptEditorBase {
CodeTextEditor *code_editor = nullptr;
RichTextLabel *warnings_panel = nullptr;
+ RichTextLabel *errors_panel = nullptr;
Ref<Script> script;
bool script_is_valid = false;
@@ -161,7 +162,9 @@ protected:
void _load_theme_settings();
void _set_theme_for_script();
+ void _show_errors_panel(bool p_show);
void _show_warnings_panel(bool p_show);
+ void _error_clicked(Variant p_line);
void _warning_clicked(Variant p_line);
void _notification(int p_what);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index e4a5a3796e..173f1dd7fb 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -240,7 +240,7 @@ void ShaderTextEditor::_validate_script() {
warnings.sort_custom<WarningsComparator>();
_update_warning_panel();
} else {
- set_warning_nb(0);
+ set_warning_count(0);
}
emit_signal("script_changed");
}
@@ -280,14 +280,14 @@ void ShaderTextEditor::_update_warning_panel() {
}
warnings_panel->pop(); // Table.
- set_warning_nb(warning_count);
+ set_warning_count(warning_count);
}
void ShaderTextEditor::_bind_methods() {
}
ShaderTextEditor::ShaderTextEditor() {
- syntax_highlighter.instance();
+ syntax_highlighter.instantiate();
get_text_editor()->set_syntax_highlighter(syntax_highlighter);
}
@@ -323,19 +323,13 @@ void ShaderEditor::_menu_option(int p_option) {
if (shader.is_null()) {
return;
}
-
- CodeEdit *tx = shader_editor->get_text_editor();
- tx->indent_selected_lines_left();
-
+ shader_editor->get_text_editor()->unindent_lines();
} break;
case EDIT_INDENT_RIGHT: {
if (shader.is_null()) {
return;
}
-
- CodeEdit *tx = shader_editor->get_text_editor();
- tx->indent_selected_lines_right();
-
+ shader_editor->get_text_editor()->indent_lines();
} break;
case EDIT_DELETE_LINE: {
shader_editor->delete_lines();
diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp
index 47d7f8204b..85ccc5b798 100644
--- a/editor/plugins/shader_file_editor_plugin.cpp
+++ b/editor/plugins/shader_file_editor_plugin.cpp
@@ -272,7 +272,7 @@ ShaderFileEditor::ShaderFileEditor(EditorNode *p_node) {
main_vb->add_child(stage_hb);
Ref<ButtonGroup> bg;
- bg.instance();
+ bg.instantiate();
for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
Button *button = memnew(Button(stage_str[i]));
button->set_toggle_mode(true);
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index a97584ebce..0b04c2e50e 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -700,7 +700,7 @@ Skeleton3DEditorPlugin::Skeleton3DEditorPlugin(EditorNode *p_node) {
editor = p_node;
Ref<EditorInspectorPluginSkeleton> skeleton_plugin;
- skeleton_plugin.instance();
+ skeleton_plugin.instantiate();
skeleton_plugin->editor = editor;
EditorInspector::add_inspector_plugin(skeleton_plugin);
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index 4a7f6c0f7e..ef328bcfe2 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -186,7 +186,7 @@ void Sprite2DEditor::_update_mesh_data() {
}
Ref<BitMap> bm;
- bm.instance();
+ bm.instantiate();
bm->create_from_image_alpha(image);
int shrink = shrink_pixels->get_value();
@@ -322,7 +322,7 @@ void Sprite2DEditor::_convert_to_mesh_2d_node() {
}
Ref<ArrayMesh> mesh;
- mesh.instance();
+ mesh.instantiate();
Array a;
a.resize(Mesh::ARRAY_MAX);
@@ -435,7 +435,7 @@ void Sprite2DEditor::_create_light_occluder_2d_node() {
Vector<Vector2> outline = computed_outline_lines[i];
Ref<OccluderPolygon2D> polygon;
- polygon.instance();
+ polygon.instantiate();
PackedVector2Array a;
a.resize(outline.size());
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index a5a3d624ec..70c7b3072b 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -103,17 +103,16 @@ void SpriteFramesEditor::_sheet_preview_draw() {
}
void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
- Ref<InputEventMouseButton> mb = p_event;
-
+ const Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- Size2i size = split_sheet_preview->get_size();
- int h = split_sheet_h->get_value();
- int v = split_sheet_v->get_value();
+ const Size2i size = split_sheet_preview->get_size();
+ const int h = split_sheet_h->get_value();
+ const int v = split_sheet_v->get_value();
- int x = CLAMP(int(mb->get_position().x) * h / size.width, 0, h - 1);
- int y = CLAMP(int(mb->get_position().y) * v / size.height, 0, v - 1);
+ const int x = CLAMP(int(mb->get_position().x) * h / size.width, 0, h - 1);
+ const int y = CLAMP(int(mb->get_position().y) * v / size.height, 0, v - 1);
- int idx = h * y + x;
+ const int idx = h * y + x;
if (mb->is_shift_pressed() && last_frame_selected >= 0) {
//select multiple
@@ -124,6 +123,9 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
}
for (int i = from; i <= to; i++) {
+ // Prevent double-toggling the same frame when moving the mouse when the mouse button is still held.
+ frames_toggled_by_mouse_hover.insert(idx);
+
if (mb->is_ctrl_pressed()) {
frames_selected.erase(i);
} else {
@@ -131,6 +133,9 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
}
}
} else {
+ // Prevent double-toggling the same frame when moving the mouse when the mouse button is still held.
+ frames_toggled_by_mouse_hover.insert(idx);
+
if (frames_selected.has(idx)) {
frames_selected.erase(idx);
} else {
@@ -141,6 +146,39 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
last_frame_selected = idx;
split_sheet_preview->update();
}
+
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ frames_toggled_by_mouse_hover.clear();
+ }
+
+ const Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
+ // Select by holding down the mouse button on frames.
+ const Size2i size = split_sheet_preview->get_size();
+ const int h = split_sheet_h->get_value();
+ const int v = split_sheet_v->get_value();
+
+ const int x = CLAMP(int(mm->get_position().x) * h / size.width, 0, h - 1);
+ const int y = CLAMP(int(mm->get_position().y) * v / size.height, 0, v - 1);
+
+ const int idx = h * y + x;
+
+ if (!frames_toggled_by_mouse_hover.has(idx)) {
+ // Only allow toggling each tile once per mouse hold.
+ // Otherwise, the selection would constantly "flicker" in and out when moving the mouse cursor.
+ // The mouse button must be released before it can be toggled again.
+ frames_toggled_by_mouse_hover.insert(idx);
+
+ if (frames_selected.has(idx)) {
+ frames_selected.erase(idx);
+ } else {
+ frames_selected.insert(idx);
+ }
+
+ last_frame_selected = idx;
+ split_sheet_preview->update();
+ }
+ }
}
void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) {
@@ -189,7 +227,7 @@ void SpriteFramesEditor::_sheet_add_frames() {
int y = (yp * height) + region_rect.position.y;
Ref<AtlasTexture> at;
- at.instance();
+ at.instantiate();
at->set_atlas(split_sheet_preview->get_texture());
at->set_region(Rect2(x, y, width, height));
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index 77cdbb4af6..e6c59e3533 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -87,6 +87,7 @@ class SpriteFramesEditor : public HSplitContainer {
Button *split_sheet_zoom_in;
EditorFileDialog *file_split_sheet;
Set<int> frames_selected;
+ Set<int> frames_toggled_by_mouse_hover;
int last_frame_selected;
float scale_ratio;
diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp
index 64df982d5d..6954cacac6 100644
--- a/editor/plugins/style_box_editor_plugin.cpp
+++ b/editor/plugins/style_box_editor_plugin.cpp
@@ -93,6 +93,6 @@ StyleBoxPreview::StyleBoxPreview() {
StyleBoxEditorPlugin::StyleBoxEditorPlugin(EditorNode *p_node) {
Ref<EditorInspectorPluginStyleBox> inspector_plugin;
- inspector_plugin.instance();
+ inspector_plugin.instantiate();
add_inspector_plugin(inspector_plugin);
}
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 621f843e6f..d62be993af 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -320,10 +320,10 @@ void TextEditor::_edit_option(int p_op) {
code_editor->move_lines_down();
} break;
case EDIT_INDENT_LEFT: {
- tx->indent_selected_lines_left();
+ tx->unindent_lines();
} break;
case EDIT_INDENT_RIGHT: {
- tx->indent_selected_lines_right();
+ tx->indent_lines();
} break;
case EDIT_DELETE_LINE: {
code_editor->delete_lines();
@@ -581,11 +581,11 @@ TextEditor::TextEditor() {
highlighter_menu->connect("id_pressed", callable_mp(this, &TextEditor::_change_syntax_highlighter));
Ref<EditorPlainTextSyntaxHighlighter> plain_highlighter;
- plain_highlighter.instance();
+ plain_highlighter.instantiate();
add_syntax_highlighter(plain_highlighter);
Ref<EditorStandardSyntaxHighlighter> highlighter;
- highlighter.instance();
+ highlighter.instantiate();
add_syntax_highlighter(highlighter);
set_syntax_highlighter(plain_highlighter);
diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp
index 36297c8a4a..696aa88e23 100644
--- a/editor/plugins/texture_3d_editor_plugin.cpp
+++ b/editor/plugins/texture_3d_editor_plugin.cpp
@@ -85,9 +85,9 @@ void Texture3DEditor::_make_shaders() {
" COLOR = textureLod(tex,vec3(UV,layer),0.0);\n"
"}";
- shader.instance();
+ shader.instantiate();
shader->set_code(shader_3d);
- material.instance();
+ material.instantiate();
material->set_shader(shader);
}
@@ -207,6 +207,6 @@ void EditorInspectorPlugin3DTexture::parse_begin(Object *p_object) {
Texture3DEditorPlugin::Texture3DEditorPlugin(EditorNode *p_node) {
Ref<EditorInspectorPlugin3DTexture> plugin;
- plugin.instance();
+ plugin.instantiate();
add_inspector_plugin(plugin);
}
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index ecf7370834..10b942d9ee 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -160,6 +160,6 @@ void EditorInspectorPluginTexture::parse_begin(Object *p_object) {
TextureEditorPlugin::TextureEditorPlugin(EditorNode *p_node) {
Ref<EditorInspectorPluginTexture> plugin;
- plugin.instance();
+ plugin.instantiate();
add_inspector_plugin(plugin);
}
diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp
index 89ed98d53e..3f46cd64a2 100644
--- a/editor/plugins/texture_layered_editor_plugin.cpp
+++ b/editor/plugins/texture_layered_editor_plugin.cpp
@@ -112,7 +112,7 @@ void TextureLayeredEditor::_make_shaders() {
" COLOR = textureLod(tex,vec3(UV,layer),0.0);\n"
"}";
- shaders[0].instance();
+ shaders[0].instantiate();
shaders[0]->set_code(shader_2d_array);
String shader_cube = ""
@@ -125,7 +125,7 @@ void TextureLayeredEditor::_make_shaders() {
" COLOR = textureLod(tex,n,0.0);\n"
"}";
- shaders[1].instance();
+ shaders[1].instantiate();
shaders[1]->set_code(shader_cube);
String shader_cube_array = ""
@@ -139,11 +139,11 @@ void TextureLayeredEditor::_make_shaders() {
" COLOR = textureLod(tex,vec4(n,layer),0.0);\n"
"}";
- shaders[2].instance();
+ shaders[2].instantiate();
shaders[2]->set_code(shader_cube_array);
for (int i = 0; i < 3; i++) {
- materials[i].instance();
+ materials[i].instantiate();
materials[i]->set_shader(shaders[i]);
}
}
@@ -271,6 +271,6 @@ void EditorInspectorPluginLayeredTexture::parse_begin(Object *p_object) {
TextureLayeredEditorPlugin::TextureLayeredEditorPlugin(EditorNode *p_node) {
Ref<EditorInspectorPluginLayeredTexture> plugin;
- plugin.instance();
+ plugin.instantiate();
add_inspector_plugin(plugin);
}
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 22b39c59f5..99d7267eac 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -932,9 +932,9 @@ ThemeItemImportTree::ThemeItemImportTree() {
import_items_tree->set_column_expand(0, true);
import_items_tree->set_column_expand(IMPORT_ITEM, false);
import_items_tree->set_column_expand(IMPORT_ITEM_DATA, false);
- import_items_tree->set_column_min_width(0, 160 * EDSCALE);
- import_items_tree->set_column_min_width(IMPORT_ITEM, 80 * EDSCALE);
- import_items_tree->set_column_min_width(IMPORT_ITEM_DATA, 80 * EDSCALE);
+ import_items_tree->set_column_custom_minimum_width(0, 160 * EDSCALE);
+ import_items_tree->set_column_custom_minimum_width(IMPORT_ITEM, 80 * EDSCALE);
+ import_items_tree->set_column_custom_minimum_width(IMPORT_ITEM_DATA, 80 * EDSCALE);
ScrollContainer *import_bulk_sc = memnew(ScrollContainer);
import_bulk_sc->set_custom_minimum_size(Size2(260.0, 0.0) * EDSCALE);
@@ -2263,7 +2263,7 @@ void ThemeTypeEditor::_update_type_items() {
} else {
item_editor->set_edited_resource(RES());
}
- item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item), varray(item_control));
+ item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed), varray(E.key()));
} else {
if (Theme::get_default()->has_font(E.key(), edited_type)) {
@@ -2334,7 +2334,7 @@ void ThemeTypeEditor::_update_type_items() {
} else {
item_editor->set_edited_resource(RES());
}
- item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item), varray(item_control));
+ item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed), varray(E.key()));
} else {
if (Theme::get_default()->has_icon(E.key(), edited_type)) {
@@ -2381,7 +2381,7 @@ void ThemeTypeEditor::_update_type_items() {
} else {
item_editor->set_edited_resource(RES());
}
- item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item), varray(item_control));
+ item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed), varray(leading_stylebox.item_name));
stylebox_items_list->add_child(item_control);
@@ -2408,7 +2408,7 @@ void ThemeTypeEditor::_update_type_items() {
} else {
item_editor->set_edited_resource(RES());
}
- item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item), varray(item_control));
+ item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed), varray(E.key()));
Button *pin_leader_button = memnew(Button);
@@ -2417,7 +2417,7 @@ void ThemeTypeEditor::_update_type_items() {
pin_leader_button->set_icon(get_theme_icon("Pin", "EditorIcons"));
pin_leader_button->set_tooltip(TTR("Pin this StyleBox as a main style. Editing its properties will update the same properties in all other StyleBoxes of this type."));
item_control->add_child(pin_leader_button);
- pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_pin_leading_stylebox), varray(stylebox_value, E.key()));
+ pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_pin_leading_stylebox), varray(item_editor, E.key()));
} else {
if (Theme::get_default()->has_stylebox(E.key(), edited_type)) {
item_editor->set_edited_resource(Theme::get_default()->get_stylebox(E.key(), edited_type));
@@ -2612,6 +2612,10 @@ void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) {
} break;
case Theme::DATA_TYPE_STYLEBOX: {
edited_theme->clear_stylebox(p_item_name, edited_type);
+
+ if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) {
+ _unpin_leading_stylebox();
+ }
} break;
}
}
@@ -2661,6 +2665,10 @@ void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name
} break;
case Theme::DATA_TYPE_STYLEBOX: {
edited_theme->rename_stylebox(p_item_name, new_name, edited_type);
+
+ if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) {
+ leading_stylebox.item_name = new_name;
+ }
} break;
}
}
@@ -2695,7 +2703,7 @@ void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name)
edited_theme->set_font_size(p_item_name, edited_type, int(p_value));
}
-void ThemeTypeEditor::_edit_resource_item(RES p_resource, Control *p_editor) {
+void ThemeTypeEditor::_edit_resource_item(RES p_resource) {
EditorNode::get_singleton()->edit_resource(p_resource);
}
@@ -2723,16 +2731,21 @@ void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_ite
}
}
-void ThemeTypeEditor::_pin_leading_stylebox(Ref<StyleBox> p_stylebox, String p_item_name) {
+void ThemeTypeEditor::_pin_leading_stylebox(Control *p_editor, String p_item_name) {
if (leading_stylebox.stylebox.is_valid()) {
leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
}
+ Ref<StyleBox> stylebox;
+ if (Object::cast_to<EditorResourcePicker>(p_editor)) {
+ stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource();
+ }
+
LeadingStylebox leader;
leader.pinned = true;
leader.item_name = p_item_name;
- leader.stylebox = p_stylebox;
- leader.ref_stylebox = (p_stylebox.is_valid() ? p_stylebox->duplicate() : RES());
+ leader.stylebox = stylebox;
+ leader.ref_stylebox = (stylebox.is_valid() ? stylebox->duplicate() : RES());
leading_stylebox = leader;
if (leading_stylebox.stylebox.is_valid()) {
diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h
index 77baf46395..cdedbbec8d 100644
--- a/editor/plugins/theme_editor_plugin.h
+++ b/editor/plugins/theme_editor_plugin.h
@@ -329,11 +329,11 @@ class ThemeTypeEditor : public MarginContainer {
void _color_item_changed(Color p_value, String p_item_name);
void _constant_item_changed(float p_value, String p_item_name);
void _font_size_item_changed(float p_value, String p_item_name);
- void _edit_resource_item(RES p_resource, Control *p_editor);
+ void _edit_resource_item(RES p_resource);
void _font_item_changed(Ref<Font> p_value, String p_item_name);
void _icon_item_changed(Ref<Texture2D> p_value, String p_item_name);
void _stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name);
- void _pin_leading_stylebox(Ref<StyleBox> p_stylebox, String p_item_name);
+ void _pin_leading_stylebox(Control *p_editor, String p_item_name);
void _unpin_leading_stylebox();
void _update_stylebox_from_leading();
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
index cb7b5949d1..0b02150444 100644
--- a/editor/plugins/theme_editor_preview.cpp
+++ b/editor/plugins/theme_editor_preview.cpp
@@ -403,7 +403,7 @@ void SceneThemeEditorPreview::_reload_scene() {
preview_content->remove_child(node);
}
- Node *instance = loaded_scene->instance();
+ Node *instance = loaded_scene->instantiate();
if (!instance || !Object::cast_to<Control>(instance)) {
EditorNode::get_singleton()->show_warning(TTR("Invalid PackedScene resource, must have a Control node at its root."));
emit_signal("scene_invalidated");
@@ -435,7 +435,7 @@ bool SceneThemeEditorPreview::set_preview_scene(const String &p_path) {
return false;
}
- Node *instance = loaded_scene->instance();
+ Node *instance = loaded_scene->instantiate();
if (!instance || !Object::cast_to<Control>(instance)) {
EditorNode::get_singleton()->show_warning(TTR("Invalid PackedScene resource, must have a Control node at its root."));
return false;
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index 78f181e321..374a255df3 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -33,7 +33,6 @@
#include "core/input/input.h"
#include "core/os/keyboard.h"
#include "scene/gui/box_container.h"
-#include "scene/gui/center_container.h"
#include "scene/gui/label.h"
#include "scene/gui/panel.h"
#include "scene/gui/texture_rect.h"
@@ -44,21 +43,41 @@
void TileAtlasView::_gui_input(const Ref<InputEvent> &p_event) {
bool ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);
- Ref<InputEventMouseButton> b = p_event;
- if (b.is_valid()) {
- if (ctrl && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ drag_type = DRAG_TYPE_NONE;
+ if (ctrl && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
// Zoom out
zoom_widget->set_zoom_by_increments(-2);
- emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll()));
- _update_zoom(zoom_widget->get_zoom(), true);
+ emit_signal("transform_changed", zoom_widget->get_zoom(), panning);
+ _update_zoom_and_panning(true);
accept_event();
}
- if (ctrl && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ if (ctrl && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
// Zoom in
zoom_widget->set_zoom_by_increments(2);
- emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll()));
- _update_zoom(zoom_widget->get_zoom(), true);
+ emit_signal("transform_changed", zoom_widget->get_zoom(), panning);
+ _update_zoom_and_panning(true);
+ accept_event();
+ }
+
+ if (mb->get_button_index() == MOUSE_BUTTON_MIDDLE || mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (mb->is_pressed()) {
+ drag_type = DRAG_TYPE_PAN;
+ } else {
+ drag_type = DRAG_TYPE_NONE;
+ }
+ accept_event();
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ if (drag_type == DRAG_TYPE_PAN) {
+ panning += mm->get_relative();
+ _update_zoom_and_panning();
+ emit_signal("transform_changed", zoom_widget->get_zoom(), panning);
accept_event();
}
}
@@ -103,25 +122,27 @@ Size2i TileAtlasView::_compute_alternative_tiles_control_size() {
return size;
}
-void TileAtlasView::_update_zoom(float p_zoom, bool p_zoom_on_mouse_pos, Vector2i p_scroll) {
+void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) {
+ float zoom = zoom_widget->get_zoom();
+
// Compute the minimum sizes.
Size2i base_tiles_control_size = _compute_base_tiles_control_size();
- base_tiles_root_control->set_custom_minimum_size(Vector2(base_tiles_control_size) * p_zoom);
+ base_tiles_root_control->set_custom_minimum_size(Vector2(base_tiles_control_size) * zoom);
Size2i alternative_tiles_control_size = _compute_alternative_tiles_control_size();
- alternative_tiles_root_control->set_custom_minimum_size(Vector2(alternative_tiles_control_size) * p_zoom);
+ alternative_tiles_root_control->set_custom_minimum_size(Vector2(alternative_tiles_control_size) * zoom);
// Set the texture for the base tiles.
Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
// Set the scales.
if (base_tiles_control_size.x > 0 && base_tiles_control_size.y > 0) {
- base_tiles_drawing_root->set_scale(Vector2(p_zoom, p_zoom));
+ base_tiles_drawing_root->set_scale(Vector2(zoom, zoom));
} else {
base_tiles_drawing_root->set_scale(Vector2(1, 1));
}
if (alternative_tiles_control_size.x > 0 && alternative_tiles_control_size.y > 0) {
- alternative_tiles_drawing_root->set_scale(Vector2(p_zoom, p_zoom));
+ alternative_tiles_drawing_root->set_scale(Vector2(zoom, zoom));
} else {
alternative_tiles_drawing_root->set_scale(Vector2(1, 1));
}
@@ -129,64 +150,40 @@ void TileAtlasView::_update_zoom(float p_zoom, bool p_zoom_on_mouse_pos, Vector2
// Update the margin container's margins.
const char *constants[] = { "margin_left", "margin_top", "margin_right", "margin_bottom" };
for (int i = 0; i < 4; i++) {
- margin_container->add_theme_constant_override(constants[i], margin_container_paddings[i] * p_zoom);
+ margin_container->add_theme_constant_override(constants[i], margin_container_paddings[i] * zoom);
}
// Update the backgrounds.
background_left->update();
background_right->update();
- if (p_scroll != Vector2i(-1, -1)) {
- scroll_container->set_h_scroll(p_scroll.x);
- scroll_container->set_v_scroll(p_scroll.y);
- }
-
// Zoom on the position.
- if (previous_zoom != p_zoom) {
- // TODO: solve this.
- // There is however an issue with scrollcainter preventing this, as it seems
- // that the scrollbars are not updated right aways after its children update.
-
- // Compute point on previous area.
- /*Vector2 max = Vector2(scroll_container->get_h_scrollbar()->get_max(), scroll_container->get_v_scrollbar()->get_max());
- Vector2 min = Vector2(scroll_container->get_h_scrollbar()->get_min(), scroll_container->get_v_scrollbar()->get_min());
- Vector2 value = Vector2(scroll_container->get_h_scrollbar()->get_value(), scroll_container->get_v_scrollbar()->get_value());
-
- Vector2 old_max = max * previous_zoom / p_zoom;
-
- Vector2 max_pixel_change = max - old_max;
- Vector2 ratio = ((value + scroll_container->get_local_mouse_position()) / old_max).max(Vector2()).min(Vector2(1,1));
- Vector2 offset = max_pixel_change * ratio;
-
- print_line("--- ZOOMED ---");
- print_line(vformat("max: %s", max));
- print_line(vformat("min: %s", min));
- print_line(vformat("value: %s", value));
- print_line(vformat("size: %s", scroll_container->get_size()));
- print_line(vformat("mouse_pos: %s", scroll_container->get_local_mouse_position()));
-
- print_line(vformat("ratio: %s", ratio));
- print_line(vformat("max_pixel_change: %s", max_pixel_change));
- print_line(vformat("offset: %s", offset));
-
+ if (p_zoom_on_mouse_pos) {
+ // Offset the panning relative to the center of panel.
+ Vector2 relative_mpos = get_local_mouse_position() - get_size() / 2;
+ panning = (panning - relative_mpos) * zoom / previous_zoom + relative_mpos;
+ } else {
+ // Center of panel.
+ panning = panning * zoom / previous_zoom;
+ }
+ button_center_view->set_disabled(panning.is_equal_approx(Vector2()));
- print_line(vformat("value before: %s", Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll())));
- scroll_container->set_h_scroll(10000);//scroll_container->get_h_scroll()+offset.x);
- scroll_container->set_v_scroll(10000);//scroll_container->get_v_scroll()+offset.y);
- print_line(vformat("value after: %s", Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll())));
- */
+ previous_zoom = zoom;
- previous_zoom = p_zoom;
- }
+ center_container->set_begin(panning - center_container->get_minimum_size() / 2);
+ center_container->set_size(center_container->get_minimum_size());
}
-void TileAtlasView::_scroll_changed() {
- emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll()));
+void TileAtlasView::_zoom_widget_changed() {
+ _update_zoom_and_panning();
+ emit_signal("transform_changed", zoom_widget->get_zoom(), panning);
}
-void TileAtlasView::_zoom_widget_changed() {
- _update_zoom(zoom_widget->get_zoom());
- emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll()));
+void TileAtlasView::_center_view() {
+ panning = Vector2();
+ button_center_view->set_disabled(true);
+ _update_zoom_and_panning();
+ emit_signal("transform_changed", zoom_widget->get_zoom(), panning);
}
void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) {
@@ -415,7 +412,7 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_
_update_alternative_tiles_rect_cache();
// Update everything.
- _update_zoom(zoom_widget->get_zoom());
+ _update_zoom_and_panning();
// Change children control size.
Size2i base_tiles_control_size = _compute_base_tiles_control_size();
@@ -448,9 +445,10 @@ float TileAtlasView::get_zoom() const {
return zoom_widget->get_zoom();
};
-void TileAtlasView::set_transform(float p_zoom, Vector2i p_scroll) {
+void TileAtlasView::set_transform(float p_zoom, Vector2i p_panning) {
zoom_widget->set_zoom(p_zoom);
- _update_zoom(zoom_widget->get_zoom(), false, p_scroll);
+ panning = p_panning;
+ _update_zoom_and_panning();
};
void TileAtlasView::set_padding(Side p_side, int p_padding) {
@@ -525,7 +523,7 @@ Rect2i TileAtlasView::get_alternative_tile_rect(const Vector2i p_coords, int p_a
}
void TileAtlasView::update() {
- scroll_container->update();
+ base_tiles_draw->update();
base_tiles_texture_grid->update();
base_tiles_shape_grid->update();
base_tiles_dark->update();
@@ -534,124 +532,149 @@ void TileAtlasView::update() {
background_right->update();
}
+void TileAtlasView::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_READY:
+ button_center_view->set_icon(get_theme_icon("CenterView", "EditorIcons"));
+ break;
+ }
+}
+
void TileAtlasView::_bind_methods() {
+ ClassDB::bind_method("_gui_input", &TileAtlasView::_gui_input);
+
ADD_SIGNAL(MethodInfo("transform_changed", PropertyInfo(Variant::FLOAT, "zoom"), PropertyInfo(Variant::VECTOR2, "scroll")));
}
TileAtlasView::TileAtlasView() {
- Panel *panel_container = memnew(Panel);
- panel_container->set_h_size_flags(SIZE_EXPAND_FILL);
- panel_container->set_v_size_flags(SIZE_EXPAND_FILL);
- panel_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
- add_child(panel_container);
-
- //Scrolling
- scroll_container = memnew(ScrollContainer);
- scroll_container->get_h_scrollbar()->connect("value_changed", callable_mp(this, &TileAtlasView::_scroll_changed).unbind(1));
- scroll_container->get_v_scrollbar()->connect("value_changed", callable_mp(this, &TileAtlasView::_scroll_changed).unbind(1));
- panel_container->add_child(scroll_container);
- scroll_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
+
+ Panel *panel = memnew(Panel);
+ panel->set_clip_contents(true);
+ panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ panel->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ panel->set_h_size_flags(SIZE_EXPAND_FILL);
+ panel->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(panel);
+ // Scrollingsc
zoom_widget = memnew(EditorZoomWidget);
add_child(zoom_widget);
zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);
zoom_widget->connect("zoom_changed", callable_mp(this, &TileAtlasView::_zoom_widget_changed).unbind(1));
- CenterContainer *center_container = memnew(CenterContainer);
- center_container->set_h_size_flags(SIZE_EXPAND_FILL);
- center_container->set_v_size_flags(SIZE_EXPAND_FILL);
+ button_center_view = memnew(Button);
+ button_center_view->set_icon(get_theme_icon("CenterView", "EditorIcons"));
+ button_center_view->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT, Control::PRESET_MODE_MINSIZE, 5);
+ button_center_view->connect("pressed", callable_mp(this, &TileAtlasView::_center_view));
+ button_center_view->set_flat(true);
+ button_center_view->set_disabled(true);
+ add_child(button_center_view);
+
+ center_container = memnew(CenterContainer);
+ center_container->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ center_container->set_anchors_preset(Control::PRESET_CENTER);
center_container->connect("gui_input", callable_mp(this, &TileAtlasView::_gui_input));
- scroll_container->add_child(center_container);
+ panel->add_child(center_container);
missing_source_label = memnew(Label);
missing_source_label->set_text(TTR("No atlas source with a valid texture selected."));
center_container->add_child(missing_source_label);
margin_container = memnew(MarginContainer);
+ margin_container->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
center_container->add_child(margin_container);
hbox = memnew(HBoxContainer);
+ hbox->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
hbox->add_theme_constant_override("separation", 10);
hbox->hide();
margin_container->add_child(hbox);
VBoxContainer *left_vbox = memnew(VBoxContainer);
+ left_vbox->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
hbox->add_child(left_vbox);
VBoxContainer *right_vbox = memnew(VBoxContainer);
+ right_vbox->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
hbox->add_child(right_vbox);
// Base tiles.
Label *base_tile_label = memnew(Label);
+ base_tile_label->set_mouse_filter(Control::MOUSE_FILTER_PASS);
base_tile_label->set_text(TTR("Base Tiles"));
base_tile_label->set_align(Label::ALIGN_CENTER);
left_vbox->add_child(base_tile_label);
base_tiles_root_control = memnew(Control);
+ base_tiles_root_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
base_tiles_root_control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
base_tiles_root_control->connect("gui_input", callable_mp(this, &TileAtlasView::_base_tiles_root_control_gui_input));
left_vbox->add_child(base_tiles_root_control);
background_left = memnew(Control);
+ background_left->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
background_left->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
background_left->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
- background_left->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
background_left->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_left));
base_tiles_root_control->add_child(background_left);
base_tiles_drawing_root = memnew(Control);
+ base_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
base_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
base_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
- base_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
base_tiles_root_control->add_child(base_tiles_drawing_root);
base_tiles_draw = memnew(Control);
+ base_tiles_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
base_tiles_draw->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
base_tiles_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles));
- base_tiles_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
base_tiles_drawing_root->add_child(base_tiles_draw);
base_tiles_texture_grid = memnew(Control);
+ base_tiles_texture_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
base_tiles_texture_grid->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
base_tiles_texture_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_texture_grid));
- base_tiles_texture_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
base_tiles_drawing_root->add_child(base_tiles_texture_grid);
base_tiles_shape_grid = memnew(Control);
+ base_tiles_shape_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
base_tiles_shape_grid->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
base_tiles_shape_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_shape_grid));
- base_tiles_shape_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
base_tiles_drawing_root->add_child(base_tiles_shape_grid);
base_tiles_dark = memnew(Control);
+ base_tiles_dark->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
base_tiles_dark->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
base_tiles_dark->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_dark));
- base_tiles_dark->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
base_tiles_drawing_root->add_child(base_tiles_dark);
// Alternative tiles.
Label *alternative_tiles_label = memnew(Label);
+ alternative_tiles_label->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
alternative_tiles_label->set_text(TTR("Alternative Tiles"));
alternative_tiles_label->set_align(Label::ALIGN_CENTER);
right_vbox->add_child(alternative_tiles_label);
alternative_tiles_root_control = memnew(Control);
+ alternative_tiles_root_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
alternative_tiles_root_control->connect("gui_input", callable_mp(this, &TileAtlasView::_alternative_tiles_root_control_gui_input));
right_vbox->add_child(alternative_tiles_root_control);
background_right = memnew(Control);
+ background_right->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
background_right->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
background_right->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_right));
- background_right->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+
alternative_tiles_root_control->add_child(background_right);
alternative_tiles_drawing_root = memnew(Control);
- alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
alternative_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
alternative_tiles_root_control->add_child(alternative_tiles_drawing_root);
alternatives_draw = memnew(Control);
- alternatives_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_alternatives));
alternatives_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ alternatives_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_alternatives));
alternative_tiles_drawing_root->add_child(alternatives_draw);
}
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
index 28fd3ed1e0..bafc2b3985 100644
--- a/editor/plugins/tiles/tile_atlas_view.h
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -34,6 +34,7 @@
#include "editor/editor_zoom_widget.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
+#include "scene/gui/center_container.h"
#include "scene/gui/label.h"
#include "scene/gui/margin_container.h"
#include "scene/gui/scroll_container.h"
@@ -48,17 +49,24 @@ private:
TileSetAtlasSource *tile_set_atlas_source;
int source_id = -1;
+ enum DragType {
+ DRAG_TYPE_NONE,
+ DRAG_TYPE_PAN,
+ };
+ DragType drag_type = DRAG_TYPE_NONE;
float previous_zoom = 1.0;
EditorZoomWidget *zoom_widget;
+ Button *button_center_view;
+ CenterContainer *center_container;
+ Vector2 panning;
+ void _update_zoom_and_panning(bool p_zoom_on_mouse_pos = false);
void _zoom_widget_changed();
- void _scroll_changed();
- void _update_zoom(float p_zoom, bool p_zoom_on_mouse_pos = false, Vector2i p_scroll = Vector2i(-1, -1));
+ void _center_view();
void _gui_input(const Ref<InputEvent> &p_event);
Map<Vector2, Map<int, Rect2i>> alternative_tiles_rect_cache;
void _update_alternative_tiles_rect_cache();
- ScrollContainer *scroll_container;
MarginContainer *margin_container;
int margin_container_paddings[4] = { 0, 0, 0, 0 };
HBoxContainer *hbox;
@@ -102,16 +110,15 @@ private:
Size2i _compute_alternative_tiles_control_size();
protected:
+ void _notification(int p_what);
static void _bind_methods();
public:
// Global.
void set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id);
- ScrollContainer *get_scroll_container() { return scroll_container; };
-
float get_zoom() const;
- void set_transform(float p_zoom, Vector2i p_scroll);
+ void set_transform(float p_zoom, Vector2i p_panning);
void set_padding(Side p_side, int p_padding);
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index 61457e3e59..d9d0e48fb3 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -32,202 +32,2436 @@
#include "tile_set_editor.h"
-TileData *TileDataEditor::_get_tile_data(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile) {
- ERR_FAIL_COND_V(!p_tile_set, nullptr);
- ERR_FAIL_COND_V(!p_tile_set->has_source(p_atlas_source_id), nullptr);
+#include "core/math/geometry_2d.h"
+#include "core/os/keyboard.h"
+
+#include "editor/editor_properties.h"
+#include "editor/editor_scale.h"
+
+void TileDataEditor::_call_tile_set_changed() {
+ _tile_set_changed();
+}
+
+TileData *TileDataEditor::_get_tile_data(TileMapCell p_cell) {
+ ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr);
+ ERR_FAIL_COND_V(!tile_set->has_source(p_cell.source_id), nullptr);
TileData *td = nullptr;
- TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id);
+ TileSetSource *source = *tile_set->get_source(p_cell.source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
- ERR_FAIL_COND_V(!atlas_source->has_tile(p_atlas_coords), nullptr);
- ERR_FAIL_COND_V(!atlas_source->has_alternative_tile(p_atlas_coords, p_alternative_tile), nullptr);
- td = Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile));
+ ERR_FAIL_COND_V(!atlas_source->has_tile(p_cell.get_atlas_coords()), nullptr);
+ ERR_FAIL_COND_V(!atlas_source->has_alternative_tile(p_cell.get_atlas_coords(), p_cell.alternative_tile), nullptr);
+ td = Object::cast_to<TileData>(atlas_source->get_tile_data(p_cell.get_atlas_coords(), p_cell.alternative_tile));
}
return td;
}
-void TileDataEditor::edit(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
+void TileDataEditor::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("needs_redraw"));
}
-void TileDataTextureOffsetEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
- TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
- ERR_FAIL_COND(!tile_data);
+void TileDataEditor::set_tile_set(Ref<TileSet> p_tile_set) {
+ if (tile_set.is_valid()) {
+ tile_set->disconnect("changed", callable_mp(this, &TileDataEditor::_call_tile_set_changed));
+ }
+ tile_set = p_tile_set;
+ if (tile_set.is_valid()) {
+ tile_set->connect("changed", callable_mp(this, &TileDataEditor::_call_tile_set_changed));
+ }
+ _call_tile_set_changed();
+}
- bool valid;
- Variant value = tile_data->get(p_property, &valid);
- if (!valid) {
- return;
+bool DummyObject::_set(const StringName &p_name, const Variant &p_value) {
+ if (properties.has(p_name)) {
+ properties[p_name] = p_value;
+ return true;
}
- ERR_FAIL_COND(value.get_type() != Variant::VECTOR2I);
+ return false;
+}
- Vector2i tile_set_tile_size = p_tile_set->get_tile_size();
- Rect2i rect = Rect2i(-tile_set_tile_size / 2, tile_set_tile_size);
- p_tile_set->draw_tile_shape(p_canvas_item, p_transform.xform(rect), Color(1.0, 0.0, 0.0));
+bool DummyObject::_get(const StringName &p_name, Variant &r_ret) const {
+ if (properties.has(p_name)) {
+ r_ret = properties[p_name];
+ return true;
+ }
+ return false;
+}
+
+bool DummyObject::has_dummy_property(StringName p_name) {
+ return properties.has(p_name);
+}
+
+void DummyObject::add_dummy_property(StringName p_name) {
+ ERR_FAIL_COND(properties.has(p_name));
+ properties[p_name] = Variant();
+}
+
+void DummyObject::remove_dummy_property(StringName p_name) {
+ ERR_FAIL_COND(!properties.has(p_name));
+ properties.erase(p_name);
+}
+
+void DummyObject::clear_dummy_properties() {
+ properties.clear();
+}
+
+void GenericTilePolygonEditor::_base_control_draw() {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius");
+
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ const Ref<Texture2D> handle = get_theme_icon("EditorPathSharpHandle", "EditorIcons");
+ const Ref<Texture2D> add_handle = get_theme_icon("EditorHandleAdd", "EditorIcons");
+
+ Size2 tile_size = tile_set->get_tile_size();
+
+ Transform2D xform;
+ xform.set_origin(base_control->get_size() / 2 + panning);
+ xform.set_scale(Vector2(editor_zoom_widget->get_zoom(), editor_zoom_widget->get_zoom()));
+ base_control->draw_set_transform_matrix(xform);
+
+ // Draw the tile shape filled.
+ tile_set->draw_tile_shape(base_control, Rect2(-tile_size / 2, tile_size), Color(1.0, 1.0, 1.0, 0.3), true);
+
+ // Draw the background.
+ if (background_texture.is_valid()) {
+ base_control->draw_texture_rect_region(background_texture, Rect2(-background_region.size / 2 - background_offset, background_region.size), background_region, background_modulate, background_transpose);
+ }
+
+ // Draw the polygons.
+ for (unsigned int i = 0; i < polygons.size(); i++) {
+ const Vector<Vector2> &polygon = polygons[i];
+ Color color = polygon_color;
+ if (!in_creation_polygon.is_empty()) {
+ color = color.darkened(0.3);
+ }
+ color.a = 0.5;
+ Vector<Color> v_color;
+ v_color.push_back(color);
+ base_control->draw_polygon(polygon, v_color);
+
+ color.a = 0.7;
+ for (int j = 0; j < polygon.size(); j++) {
+ base_control->draw_line(polygon[j], polygon[(j + 1) % polygon.size()], color);
+ }
+ }
+
+ // Draw the polygon in creation.
+ if (!in_creation_polygon.is_empty()) {
+ for (int i = 0; i < in_creation_polygon.size() - 1; i++) {
+ base_control->draw_line(in_creation_polygon[i], in_creation_polygon[i + 1], Color(1.0, 1.0, 1.0));
+ }
+ }
+
+ Point2 in_creation_point = xform.affine_inverse().xform(base_control->get_local_mouse_position());
+ float in_creation_distance = grab_threshold * 2.0;
+ _snap_to_tile_shape(in_creation_point, in_creation_distance, grab_threshold / editor_zoom_widget->get_zoom());
+ if (button_pixel_snap->is_pressed()) {
+ _snap_to_half_pixel(in_creation_point);
+ }
+
+ if (drag_type == DRAG_TYPE_CREATE_POINT && !in_creation_polygon.is_empty()) {
+ base_control->draw_line(in_creation_polygon[in_creation_polygon.size() - 1], in_creation_point, Color(1.0, 1.0, 1.0));
+ }
+
+ // Draw the handles.
+ int tinted_polygon_index = -1;
+ int tinted_point_index = -1;
+ if (drag_type == DRAG_TYPE_DRAG_POINT) {
+ tinted_polygon_index = drag_polygon_index;
+ tinted_point_index = drag_point_index;
+ } else if (hovered_point_index >= 0) {
+ tinted_polygon_index = hovered_polygon_index;
+ tinted_point_index = hovered_point_index;
+ }
+
+ base_control->draw_set_transform_matrix(Transform2D());
+ if (!in_creation_polygon.is_empty()) {
+ for (int i = 0; i < in_creation_polygon.size(); i++) {
+ base_control->draw_texture(handle, xform.xform(in_creation_polygon[i]) - handle->get_size() / 2);
+ }
+ } else {
+ for (int i = 0; i < (int)polygons.size(); i++) {
+ const Vector<Vector2> &polygon = polygons[i];
+ for (int j = 0; j < polygon.size(); j++) {
+ const Color modulate = (tinted_polygon_index == i && tinted_point_index == j) ? Color(0.5, 1, 2) : Color(1, 1, 1);
+ base_control->draw_texture(handle, xform.xform(polygon[j]) - handle->get_size() / 2, modulate);
+ }
+ }
+ }
+
+ // Draw the text on top of the selected point.
+ if (tinted_polygon_index >= 0) {
+ Ref<Font> font = get_theme_font("font", "Label");
+ int font_size = get_theme_font_size("font_size", "Label");
+ String text = multiple_polygon_mode ? vformat("%d:%d", tinted_polygon_index, tinted_point_index) : vformat("%d", tinted_point_index);
+ Size2 text_size = font->get_string_size(text, font_size);
+ base_control->draw_string(font, xform.xform(polygons[tinted_polygon_index][tinted_point_index]) - text_size * 0.5, text, HALIGN_LEFT, -1, font_size, Color(1.0, 1.0, 1.0, 0.5));
+ }
+
+ if (drag_type == DRAG_TYPE_CREATE_POINT) {
+ base_control->draw_texture(handle, xform.xform(in_creation_point) - handle->get_size() / 2, Color(0.5, 1, 2));
+ }
+
+ // Draw the point creation preview in edit mode.
+ if (hovered_segment_index >= 0) {
+ base_control->draw_texture(add_handle, xform.xform(hovered_segment_point) - add_handle->get_size() / 2);
+ }
+
+ // Draw the tile shape line.
+ base_control->draw_set_transform_matrix(xform);
+ tile_set->draw_tile_shape(base_control, Rect2(-tile_size / 2, tile_size), grid_color, false);
+ base_control->draw_set_transform_matrix(Transform2D());
+}
+
+void GenericTilePolygonEditor::_center_view() {
+ panning = Vector2();
+ base_control->update();
+ button_center_view->set_disabled(true);
+}
+
+void GenericTilePolygonEditor::_zoom_changed() {
+ base_control->update();
+}
+
+void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
+ switch (p_item_pressed) {
+ case RESET_TO_DEFAULT_TILE:
+ undo_redo->create_action(TTR("Edit Polygons"));
+ undo_redo->add_do_method(this, "clear_polygons");
+ undo_redo->add_do_method(this, "add_polygon", tile_set->get_tile_shape_polygon());
+ undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(this, "emit_signal", "polygons_changed");
+ undo_redo->add_undo_method(this, "clear_polygons");
+ for (unsigned int i = 0; i < polygons.size(); i++) {
+ undo_redo->add_undo_method(this, "add_polygon", polygons[i]);
+ }
+ undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(this, "emit_signal", "polygons_changed");
+ undo_redo->commit_action(true);
+ break;
+ case CLEAR_TILE:
+ undo_redo->create_action(TTR("Edit Polygons"));
+ undo_redo->add_do_method(this, "clear_polygons");
+ undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(this, "emit_signal", "polygons_changed");
+ undo_redo->add_undo_method(this, "clear_polygons");
+ for (unsigned int i = 0; i < polygons.size(); i++) {
+ undo_redo->add_undo_method(this, "add_polygon", polygons[i]);
+ }
+ undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(this, "emit_signal", "polygons_changed");
+ undo_redo->commit_action(true);
+ break;
+ default:
+ break;
+ }
+}
+
+void GenericTilePolygonEditor::_grab_polygon_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_point_index) {
+ const real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius");
+ r_polygon_index = -1;
+ r_point_index = -1;
+ float closest_distance = grab_threshold + 1.0;
+ for (unsigned int i = 0; i < polygons.size(); i++) {
+ const Vector<Vector2> &polygon = polygons[i];
+ for (int j = 0; j < polygon.size(); j++) {
+ float distance = p_pos.distance_to(p_polygon_xform.xform(polygon[j]));
+ if (distance < grab_threshold && distance < closest_distance) {
+ r_polygon_index = i;
+ r_point_index = j;
+ closest_distance = distance;
+ }
+ }
+ }
+}
+
+void GenericTilePolygonEditor::_grab_polygon_segment_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_segment_index, Vector2 &r_point) {
+ const real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius");
+
+ Point2 point = p_polygon_xform.affine_inverse().xform(p_pos);
+ r_polygon_index = -1;
+ r_segment_index = -1;
+ float closest_distance = grab_threshold * 2.0;
+ for (unsigned int i = 0; i < polygons.size(); i++) {
+ const Vector<Vector2> &polygon = polygons[i];
+ for (int j = 0; j < polygon.size(); j++) {
+ Vector2 segment[2] = { polygon[j], polygon[(j + 1) % polygon.size()] };
+ Vector2 closest_point = Geometry2D::get_closest_point_to_segment(point, segment);
+ float distance = closest_point.distance_to(point);
+ if (distance < grab_threshold / editor_zoom_widget->get_zoom() && distance < closest_distance) {
+ r_polygon_index = i;
+ r_segment_index = j;
+ r_point = closest_point;
+ closest_distance = distance;
+ }
+ }
+ }
+}
+
+void GenericTilePolygonEditor::_snap_to_tile_shape(Point2 &r_point, float &r_current_snapped_dist, float p_snap_dist) {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ Vector<Point2> polygon = tile_set->get_tile_shape_polygon();
+ Point2 snapped_point = r_point;
+
+ // Snap to polygon vertices.
+ bool snapped = false;
+ for (int i = 0; i < polygon.size(); i++) {
+ float distance = r_point.distance_to(polygon[i]);
+ if (distance < p_snap_dist && distance < r_current_snapped_dist) {
+ snapped_point = polygon[i];
+ r_current_snapped_dist = distance;
+ snapped = true;
+ }
+ }
+
+ // Snap to edges if we did not snap to vertices.
+ if (!snapped) {
+ for (int i = 0; i < polygon.size(); i++) {
+ Point2 segment[2] = { polygon[i], polygon[(i + 1) % polygon.size()] };
+ Point2 point = Geometry2D::get_closest_point_to_segment(r_point, segment);
+ float distance = r_point.distance_to(point);
+ if (distance < p_snap_dist && distance < r_current_snapped_dist) {
+ snapped_point = point;
+ r_current_snapped_dist = distance;
+ }
+ }
+ }
+
+ r_point = snapped_point;
+}
+
+void GenericTilePolygonEditor::_snap_to_half_pixel(Point2 &r_point) {
+ r_point = (r_point * 2).round() / 2.0;
+}
+
+void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) {
+ real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius");
+
+ hovered_polygon_index = -1;
+ hovered_point_index = -1;
+ hovered_segment_index = -1;
+ hovered_segment_point = Vector2();
+
+ Transform2D xform;
+ xform.set_origin(base_control->get_size() / 2 + panning);
+ xform.set_scale(Vector2(editor_zoom_widget->get_zoom(), editor_zoom_widget->get_zoom()));
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ if (drag_type == DRAG_TYPE_DRAG_POINT) {
+ ERR_FAIL_INDEX(drag_polygon_index, (int)polygons.size());
+ ERR_FAIL_INDEX(drag_point_index, polygons[drag_polygon_index].size());
+ Point2 point = xform.affine_inverse().xform(mm->get_position());
+ float distance = grab_threshold * 2.0;
+ _snap_to_tile_shape(point, distance, grab_threshold / editor_zoom_widget->get_zoom());
+ if (button_pixel_snap->is_pressed()) {
+ _snap_to_half_pixel(point);
+ }
+ polygons[drag_polygon_index].write[drag_point_index] = point;
+ } else if (drag_type == DRAG_TYPE_PAN) {
+ panning += mm->get_position() - drag_last_pos;
+ drag_last_pos = mm->get_position();
+ button_center_view->set_disabled(panning.is_equal_approx(Vector2()));
+ } else {
+ // Update hovered point.
+ _grab_polygon_point(mm->get_position(), xform, hovered_polygon_index, hovered_point_index);
+
+ // If we have no hovered point, check if we hover a segment.
+ if (hovered_point_index == -1) {
+ _grab_polygon_segment_point(mm->get_position(), xform, hovered_polygon_index, hovered_segment_index, hovered_segment_point);
+ }
+ }
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_ctrl_pressed()) {
+ editor_zoom_widget->set_zoom_by_increments(1);
+ _zoom_changed();
+ accept_event();
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_ctrl_pressed()) {
+ editor_zoom_widget->set_zoom_by_increments(-1);
+ _zoom_changed();
+ accept_event();
+ } else if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ if (tools_button_group->get_pressed_button() != button_create) {
+ in_creation_polygon.clear();
+ }
+ if (tools_button_group->get_pressed_button() == button_create) {
+ // Create points.
+ if (in_creation_polygon.size() >= 3 && mb->get_position().distance_to(xform.xform(in_creation_polygon[0])) < grab_threshold) {
+ // Closes and create polygon.
+ if (!multiple_polygon_mode) {
+ clear_polygons();
+ }
+ int added = add_polygon(in_creation_polygon);
+
+ in_creation_polygon.clear();
+ button_edit->set_pressed(true);
+ undo_redo->create_action(TTR("Edit Polygons"));
+ if (!multiple_polygon_mode) {
+ undo_redo->add_do_method(this, "clear_polygons");
+ }
+ undo_redo->add_do_method(this, "add_polygon", in_creation_polygon);
+ undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_undo_method(this, "remove_polygon", added);
+ undo_redo->add_undo_method(base_control, "update");
+ undo_redo->commit_action(false);
+ emit_signal("polygons_changed");
+ } else {
+ // Create a new point.
+ drag_type = DRAG_TYPE_CREATE_POINT;
+ }
+ } else if (tools_button_group->get_pressed_button() == button_edit) {
+ // Edit points.
+ int closest_polygon;
+ int closest_point;
+ _grab_polygon_point(mb->get_position(), xform, closest_polygon, closest_point);
+ if (closest_polygon >= 0) {
+ drag_type = DRAG_TYPE_DRAG_POINT;
+ drag_polygon_index = closest_polygon;
+ drag_point_index = closest_point;
+ drag_old_polygon = polygons[drag_polygon_index];
+ } else {
+ // Create a point.
+ Vector2 point_to_create;
+ _grab_polygon_segment_point(mb->get_position(), xform, closest_polygon, closest_point, point_to_create);
+ if (closest_polygon >= 0) {
+ polygons[closest_polygon].insert(closest_point + 1, point_to_create);
+ drag_type = DRAG_TYPE_DRAG_POINT;
+ drag_polygon_index = closest_polygon;
+ drag_point_index = closest_point + 1;
+ drag_old_polygon = polygons[closest_polygon];
+ }
+ }
+ } else if (tools_button_group->get_pressed_button() == button_delete) {
+ // Remove point.
+ int closest_polygon;
+ int closest_point;
+ _grab_polygon_point(mb->get_position(), xform, closest_polygon, closest_point);
+ if (closest_polygon >= 0) {
+ PackedVector2Array old_polygon = polygons[closest_polygon];
+ polygons[closest_polygon].remove(closest_point);
+ undo_redo->create_action(TTR("Edit Polygons"));
+ if (polygons[closest_polygon].size() < 3) {
+ remove_polygon(closest_polygon);
+ undo_redo->add_do_method(this, "remove_polygon", closest_polygon);
+ undo_redo->add_undo_method(this, "add_polygon", old_polygon, closest_polygon);
+ } else {
+ undo_redo->add_do_method(this, "set_polygon", closest_polygon, polygons[closest_polygon]);
+ undo_redo->add_undo_method(this, "set_polygon", closest_polygon, old_polygon);
+ }
+ undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_undo_method(base_control, "update");
+ undo_redo->commit_action(false);
+ emit_signal("polygons_changed");
+ }
+ }
+ } else {
+ if (drag_type == DRAG_TYPE_DRAG_POINT) {
+ undo_redo->create_action(TTR("Edit Polygons"));
+ undo_redo->add_do_method(this, "set_polygon", drag_polygon_index, polygons[drag_polygon_index]);
+ undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_undo_method(this, "set_polygon", drag_polygon_index, drag_old_polygon);
+ undo_redo->add_undo_method(base_control, "update");
+ undo_redo->commit_action(false);
+ emit_signal("polygons_changed");
+ } else if (drag_type == DRAG_TYPE_CREATE_POINT) {
+ Point2 point = xform.affine_inverse().xform(mb->get_position());
+ float distance = grab_threshold * 2;
+ _snap_to_tile_shape(point, distance, grab_threshold / editor_zoom_widget->get_zoom());
+ if (button_pixel_snap->is_pressed()) {
+ _snap_to_half_pixel(point);
+ }
+ in_creation_polygon.push_back(point);
+ }
+ drag_type = DRAG_TYPE_NONE;
+ drag_point_index = -1;
+ }
+
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (mb->is_pressed()) {
+ if (tools_button_group->get_pressed_button() == button_edit) {
+ // Remove point or pan.
+ int closest_polygon;
+ int closest_point;
+ _grab_polygon_point(mb->get_position(), xform, closest_polygon, closest_point);
+ if (closest_polygon >= 0) {
+ PackedVector2Array old_polygon = polygons[closest_polygon];
+ polygons[closest_polygon].remove(closest_point);
+ undo_redo->create_action(TTR("Edit Polygons"));
+ if (polygons[closest_polygon].size() < 3) {
+ remove_polygon(closest_polygon);
+ undo_redo->add_do_method(this, "remove_polygon", closest_polygon);
+ undo_redo->add_undo_method(this, "add_polygon", old_polygon, closest_polygon);
+ } else {
+ undo_redo->add_do_method(this, "set_polygon", closest_polygon, polygons[closest_polygon]);
+ undo_redo->add_undo_method(this, "set_polygon", closest_polygon, old_polygon);
+ }
+ undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_undo_method(base_control, "update");
+ undo_redo->commit_action(false);
+ emit_signal("polygons_changed");
+ } else {
+ drag_type = DRAG_TYPE_PAN;
+ drag_last_pos = mb->get_position();
+ }
+ } else {
+ drag_type = DRAG_TYPE_PAN;
+ drag_last_pos = mb->get_position();
+ }
+ } else {
+ drag_type = DRAG_TYPE_NONE;
+ }
+ } else if (mb->get_button_index() == MOUSE_BUTTON_MIDDLE) {
+ if (mb->is_pressed()) {
+ drag_type = DRAG_TYPE_PAN;
+ drag_last_pos = mb->get_position();
+ } else {
+ drag_type = DRAG_TYPE_NONE;
+ }
+ }
+ }
+
+ base_control->update();
+}
+
+void GenericTilePolygonEditor::set_tile_set(Ref<TileSet> p_tile_set) {
+ if (tile_set != p_tile_set) {
+ // Set the default tile shape
+ clear_polygons();
+ if (p_tile_set.is_valid()) {
+ add_polygon(p_tile_set->get_tile_shape_polygon());
+ }
+ }
+ tile_set = p_tile_set;
+}
+
+void GenericTilePolygonEditor::set_background(Ref<Texture2D> p_texture, Rect2 p_region, Vector2 p_offset, bool p_flip_h, bool p_flip_v, bool p_transpose, Color p_modulate) {
+ background_texture = p_texture;
+ background_region = p_region;
+ background_offset = p_offset;
+ background_h_flip = p_flip_h;
+ background_v_flip = p_flip_v;
+ background_transpose = p_transpose;
+ background_modulate = p_modulate;
+ base_control->update();
+}
+
+int GenericTilePolygonEditor::get_polygon_count() {
+ return polygons.size();
+}
+
+int GenericTilePolygonEditor::add_polygon(Vector<Point2> p_polygon, int p_index) {
+ ERR_FAIL_COND_V(p_polygon.size() < 3, -1);
+ ERR_FAIL_COND_V(!multiple_polygon_mode && polygons.size() >= 1, -1);
+
+ if (p_index < 0) {
+ polygons.push_back(p_polygon);
+ base_control->update();
+ button_edit->set_pressed(true);
+ return polygons.size() - 1;
+ } else {
+ polygons.insert(p_index, p_polygon);
+ button_edit->set_pressed(true);
+ base_control->update();
+ return p_index;
+ }
+}
+
+void GenericTilePolygonEditor::remove_polygon(int p_index) {
+ ERR_FAIL_INDEX(p_index, (int)polygons.size());
+ polygons.remove(p_index);
+
+ if (polygons.size() == 0) {
+ button_create->set_pressed(true);
+ }
+ base_control->update();
+}
+
+void GenericTilePolygonEditor::clear_polygons() {
+ polygons.clear();
+ base_control->update();
+}
+
+void GenericTilePolygonEditor::set_polygon(int p_polygon_index, Vector<Point2> p_polygon) {
+ ERR_FAIL_INDEX(p_polygon_index, (int)polygons.size());
+ ERR_FAIL_COND(p_polygon.size() < 3);
+ polygons[p_polygon_index] = p_polygon;
+ button_edit->set_pressed(true);
+ base_control->update();
}
-void TileDataIntegerEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
- TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+Vector<Point2> GenericTilePolygonEditor::get_polygon(int p_polygon_index) {
+ ERR_FAIL_INDEX_V(p_polygon_index, (int)polygons.size(), Vector<Point2>());
+ return polygons[p_polygon_index];
+}
+
+void GenericTilePolygonEditor::set_polygons_color(Color p_color) {
+ polygon_color = p_color;
+ base_control->update();
+}
+
+void GenericTilePolygonEditor::set_multiple_polygon_mode(bool p_multiple_polygon_mode) {
+ multiple_polygon_mode = p_multiple_polygon_mode;
+}
+
+void GenericTilePolygonEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_READY:
+ button_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCreate", "EditorIcons"));
+ button_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveEdit", "EditorIcons"));
+ button_delete->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveDelete", "EditorIcons"));
+ button_center_view->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CenterView", "EditorIcons"));
+ button_pixel_snap->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Snap", "EditorIcons"));
+ button_advanced_menu->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("GuiTabMenu", "EditorIcons"));
+ break;
+ }
+}
+
+void GenericTilePolygonEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_polygon_count"), &GenericTilePolygonEditor::get_polygon_count);
+ ClassDB::bind_method(D_METHOD("add_polygon", "polygon", "index"), &GenericTilePolygonEditor::add_polygon, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("remove_polygon", "index"), &GenericTilePolygonEditor::remove_polygon);
+ ClassDB::bind_method(D_METHOD("clear_polygons"), &GenericTilePolygonEditor::clear_polygons);
+ ClassDB::bind_method(D_METHOD("set_polygon", "index", "polygon"), &GenericTilePolygonEditor::set_polygon);
+ ClassDB::bind_method(D_METHOD("get_polygon", "index"), &GenericTilePolygonEditor::set_polygon);
+
+ ADD_SIGNAL(MethodInfo("polygons_changed"));
+}
+
+GenericTilePolygonEditor::GenericTilePolygonEditor() {
+ toolbar = memnew(HBoxContainer);
+ add_child(toolbar);
+
+ tools_button_group.instantiate();
+
+ button_create = memnew(Button);
+ button_create->set_flat(true);
+ button_create->set_toggle_mode(true);
+ button_create->set_button_group(tools_button_group);
+ button_create->set_pressed(true);
+ toolbar->add_child(button_create);
+
+ button_edit = memnew(Button);
+ button_edit->set_flat(true);
+ button_edit->set_toggle_mode(true);
+ button_edit->set_button_group(tools_button_group);
+ toolbar->add_child(button_edit);
+
+ button_delete = memnew(Button);
+ button_delete->set_flat(true);
+ button_delete->set_toggle_mode(true);
+ button_delete->set_button_group(tools_button_group);
+ toolbar->add_child(button_delete);
+
+ button_advanced_menu = memnew(MenuButton);
+ button_advanced_menu->set_flat(true);
+ button_advanced_menu->set_toggle_mode(true);
+ button_advanced_menu->get_popup()->add_item(TTR("Reset to default tile shape"), RESET_TO_DEFAULT_TILE);
+ button_advanced_menu->get_popup()->add_item(TTR("Clear"), CLEAR_TILE);
+ button_advanced_menu->get_popup()->connect("id_pressed", callable_mp(this, &GenericTilePolygonEditor::_advanced_menu_item_pressed));
+ toolbar->add_child(button_advanced_menu);
+
+ toolbar->add_child(memnew(VSeparator));
+
+ button_pixel_snap = memnew(Button);
+ button_pixel_snap->set_flat(true);
+ button_pixel_snap->set_toggle_mode(true);
+ button_pixel_snap->set_pressed(true);
+ toolbar->add_child(button_pixel_snap);
+
+ Control *root = memnew(Control);
+ root->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ root->set_custom_minimum_size(Size2(0, 200 * EDSCALE));
+ root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ add_child(root);
+
+ panel = memnew(Panel);
+ panel->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ root->add_child(panel);
+
+ base_control = memnew(Control);
+ base_control->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
+ base_control->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ base_control->connect("draw", callable_mp(this, &GenericTilePolygonEditor::_base_control_draw));
+ base_control->connect("gui_input", callable_mp(this, &GenericTilePolygonEditor::_base_control_gui_input));
+ base_control->set_clip_contents(true);
+ root->add_child(base_control);
+
+ editor_zoom_widget = memnew(EditorZoomWidget);
+ editor_zoom_widget->set_position(Vector2(5, 5));
+ editor_zoom_widget->connect("zoom_changed", callable_mp(this, &GenericTilePolygonEditor::_zoom_changed).unbind(1));
+ root->add_child(editor_zoom_widget);
+
+ button_center_view = memnew(Button);
+ button_center_view->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CenterView", "EditorIcons"));
+ button_center_view->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT, Control::PRESET_MODE_MINSIZE, 5);
+ button_center_view->connect("pressed", callable_mp(this, &GenericTilePolygonEditor::_center_view));
+ button_center_view->set_flat(true);
+ button_center_view->set_disabled(true);
+ root->add_child(button_center_view);
+}
+
+void TileDataDefaultEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) {
+ ERR_FAIL_COND(!dummy_object);
+ dummy_object->set(p_property, p_value);
+}
+
+Variant TileDataDefaultEditor::_get_painted_value() {
+ ERR_FAIL_COND_V(!dummy_object, Variant());
+ return dummy_object->get(property);
+}
+
+void TileDataDefaultEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
ERR_FAIL_COND(!tile_data);
+ Variant value = tile_data->get(property);
+ dummy_object->set(property, value);
+ if (property_editor) {
+ property_editor->update_property();
+ }
+}
- bool valid;
- Variant value = tile_data->get(p_property, &valid);
- if (!valid) {
- return;
+void TileDataDefaultEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ ERR_FAIL_COND(!tile_data);
+ tile_data->set(property, p_value);
+}
+
+Variant TileDataDefaultEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ ERR_FAIL_COND_V(!tile_data, Variant());
+ return tile_data->get(property);
+}
+
+void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) {
+ for (Map<TileMapCell, Variant>::Element *E = p_previous_values.front(); E; E = E->next()) {
+ Vector2i coords = E->key().get_atlas_coords();
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/%s", coords.x, coords.y, E->key().alternative_tile, property), E->get());
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/%s", coords.x, coords.y, E->key().alternative_tile, property), p_new_value);
}
- ERR_FAIL_COND(value.get_type() != Variant::INT);
+}
- Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts");
- int height = font->get_height();
- int width = 200;
- p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-width / 2, height / 2), vformat("%d", value), HALIGN_CENTER, width, -1, Color(1, 1, 1), 1, Color(0, 0, 0, 1));
+void TileDataDefaultEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) {
+ if (drag_type == DRAG_TYPE_PAINT_RECT) {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+
+ p_canvas_item->draw_set_transform_matrix(p_transform);
+
+ Rect2i rect;
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position())));
+ rect = rect.abs();
+
+ Set<TileMapCell> edited;
+ for (int x = rect.get_position().x; x <= rect.get_end().x; x++) {
+ for (int y = rect.get_position().y; y <= rect.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+ edited.insert(cell);
+ }
+ }
+ }
+
+ for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) {
+ Vector2i coords = E->get().get_atlas_coords();
+ p_canvas_item->draw_rect(p_tile_set_atlas_source->get_tile_texture_region(coords), selection_color, false);
+ }
+ p_canvas_item->draw_set_transform_matrix(Transform2D());
+ }
+};
+
+void TileDataDefaultEditor::forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform){
+
+};
+
+void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, const Ref<InputEvent> &p_event) {
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ if (drag_type == DRAG_TYPE_PAINT) {
+ Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position()));
+ for (int i = 0; i < line.size(); i++) {
+ Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+ if (!drag_modified.has(cell)) {
+ drag_modified[cell] = _get_value(p_tile_set_atlas_source, coords, 0);
+ }
+ _set_value(p_tile_set_atlas_source, coords, 0, drag_painted_value);
+ }
+ }
+ drag_last_pos = mm->get_position();
+ }
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ if (picker_button->is_pressed()) {
+ Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
+ coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ _set_painted_value(p_tile_set_atlas_source, coords, 0);
+ picker_button->set_pressed(false);
+ }
+ } else if (mb->is_ctrl_pressed()) {
+ drag_type = DRAG_TYPE_PAINT_RECT;
+ drag_modified.clear();
+ drag_painted_value = _get_painted_value();
+ drag_start_pos = mb->get_position();
+ } else {
+ drag_type = DRAG_TYPE_PAINT;
+ drag_modified.clear();
+ drag_painted_value = _get_painted_value();
+ Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
+ coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+ drag_modified[cell] = _get_value(p_tile_set_atlas_source, coords, 0);
+ _set_value(p_tile_set_atlas_source, coords, 0, drag_painted_value);
+ }
+ drag_last_pos = mb->get_position();
+ }
+ } else {
+ if (drag_type == DRAG_TYPE_PAINT_RECT) {
+ Rect2i rect;
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()));
+ rect = rect.abs();
+
+ drag_modified.clear();
+ for (int x = rect.get_position().x; x <= rect.get_end().x; x++) {
+ for (int y = rect.get_position().y; y <= rect.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+ drag_modified[cell] = _get_value(p_tile_set_atlas_source, coords, 0);
+ }
+ }
+ }
+ undo_redo->create_action(TTR("Painting Tiles Property"));
+ _setup_undo_redo_action(p_tile_set_atlas_source, drag_modified, drag_painted_value);
+ undo_redo->commit_action(true);
+ drag_type = DRAG_TYPE_NONE;
+ } else if (drag_type == DRAG_TYPE_PAINT) {
+ undo_redo->create_action(TTR("Painting Tiles Property"));
+ _setup_undo_redo_action(p_tile_set_atlas_source, drag_modified, drag_painted_value);
+ undo_redo->commit_action(false);
+ drag_type = DRAG_TYPE_NONE;
+ }
+ }
+ }
+ }
}
-void TileDataFloatEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
- TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+void TileDataDefaultEditor::forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, const Ref<InputEvent> &p_event) {
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ if (drag_type == DRAG_TYPE_PAINT) {
+ Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mm->get_position());
+ Vector2i coords = Vector2i(tile.x, tile.y);
+ int alternative_tile = tile.z;
+
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = alternative_tile;
+ if (!drag_modified.has(cell)) {
+ drag_modified[cell] = _get_value(p_tile_set_atlas_source, coords, alternative_tile);
+ }
+ _set_value(p_tile_set_atlas_source, coords, alternative_tile, drag_painted_value);
+ }
+
+ drag_last_pos = mm->get_position();
+ }
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ if (picker_button->is_pressed()) {
+ Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mb->get_position());
+ Vector2i coords = Vector2i(tile.x, tile.y);
+ int alternative_tile = tile.z;
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ _set_painted_value(p_tile_set_atlas_source, coords, alternative_tile);
+ picker_button->set_pressed(false);
+ }
+ } else {
+ drag_type = DRAG_TYPE_PAINT;
+ drag_modified.clear();
+ drag_painted_value = _get_painted_value();
+
+ Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mb->get_position());
+ Vector2i coords = Vector2i(tile.x, tile.y);
+ int alternative_tile = tile.z;
+
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = alternative_tile;
+ drag_modified[cell] = _get_value(p_tile_set_atlas_source, coords, alternative_tile);
+ _set_value(p_tile_set_atlas_source, coords, alternative_tile, drag_painted_value);
+ }
+ drag_last_pos = mb->get_position();
+ }
+ } else {
+ undo_redo->create_action(TTR("Painting Tiles Property"));
+ _setup_undo_redo_action(p_tile_set_atlas_source, drag_modified, drag_painted_value);
+ undo_redo->commit_action(false);
+ drag_type = DRAG_TYPE_NONE;
+ }
+ }
+ }
+}
+
+void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
+ TileData *tile_data = _get_tile_data(p_cell);
ERR_FAIL_COND(!tile_data);
bool valid;
- Variant value = tile_data->get(p_property, &valid);
+ Variant value = tile_data->get(property, &valid);
if (!valid) {
return;
}
- ERR_FAIL_COND(value.get_type() != Variant::FLOAT);
- Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts");
- int height = font->get_height();
- int width = 200;
- p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-width / 2, height / 2), vformat("%.2f", value), HALIGN_CENTER, width, -1, Color(1, 1, 1), 1, Color(0, 0, 0, 1));
+ if (value.get_type() == Variant::BOOL) {
+ Ref<Texture2D> texture = (bool)value ? tile_bool_checked : tile_bool_unchecked;
+ int size = MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 3;
+ Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2), Vector2(size, size)));
+ p_canvas_item->draw_texture_rect(texture, rect);
+ } else if (value.get_type() == Variant::COLOR) {
+ int size = MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 3;
+ Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2), Vector2(size, size)));
+ p_canvas_item->draw_rect(rect, value);
+ } else {
+ Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts");
+ String text;
+ switch (value.get_type()) {
+ case Variant::INT:
+ text = vformat("%d", value);
+ break;
+ case Variant::FLOAT:
+ text = vformat("%.2f", value);
+ break;
+ case Variant::STRING:
+ case Variant::STRING_NAME:
+ text = value;
+ break;
+ default:
+ return;
+ break;
+ }
+
+ Color color = Color(1, 1, 1);
+ if (p_selected) {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+ selection_color.set_v(0.9);
+ color = selection_color;
+ } else if (is_visible_in_tree()) {
+ Variant painted_value = _get_painted_value();
+ bool equal = (painted_value.get_type() == Variant::FLOAT && value.get_type() == Variant::FLOAT) ? Math::is_equal_approx(float(painted_value), float(value)) : painted_value == value;
+ if (equal) {
+ color = Color(0.7, 0.7, 0.7);
+ }
+ }
+
+ Vector2 string_size = font->get_string_size(text);
+ p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-string_size.x / 2, string_size.y / 2), text, HALIGN_CENTER, string_size.x, -1, color, 1, Color(0, 0, 0, 1));
+ }
}
-void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
- TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, String p_property, String p_label, Variant p_default_value) {
+ ERR_FAIL_COND_MSG(!property.is_empty(), "Cannot setup TileDataDefaultEditor twice");
+ property = p_property;
+
+ // Update everything.
+ if (property_editor) {
+ property_editor->queue_delete();
+ }
+
+ // Update the dummy object.
+ dummy_object->add_dummy_property(p_property);
+
+ // Get the default value for the type.
+ if (p_default_value == Variant()) {
+ Callable::CallError error;
+ Variant painted_value;
+ Variant::construct(p_type, painted_value, nullptr, 0, error);
+ dummy_object->set(p_property, painted_value);
+ } else {
+ dummy_object->set(p_property, p_default_value);
+ }
+
+ // Create and setup the property editor.
+ property_editor = EditorInspectorDefaultPlugin::get_editor_for_property(dummy_object, p_type, p_property, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT);
+ property_editor->set_object_and_property(dummy_object, p_property);
+ if (p_label.is_empty()) {
+ property_editor->set_label(p_property);
+ } else {
+ property_editor->set_label(p_label);
+ }
+ property_editor->connect("property_changed", callable_mp(this, &TileDataDefaultEditor::_property_value_changed).unbind(1));
+ property_editor->update_property();
+ add_child(property_editor);
+}
+
+void TileDataDefaultEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
+ picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons"));
+ tile_bool_checked = get_theme_icon("TileChecked", "EditorIcons");
+ tile_bool_unchecked = get_theme_icon("TileUnchecked", "EditorIcons");
+ break;
+ default:
+ break;
+ }
+}
+
+TileDataDefaultEditor::TileDataDefaultEditor() {
+ label = memnew(Label);
+ label->set_text("Painting:");
+ add_child(label);
+
+ toolbar->add_child(memnew(VSeparator));
+
+ picker_button = memnew(Button);
+ picker_button->set_flat(true);
+ picker_button->set_toggle_mode(true);
+ picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", KEY_P));
+ toolbar->add_child(picker_button);
+}
+
+TileDataDefaultEditor::~TileDataDefaultEditor() {
+ toolbar->queue_delete();
+ memdelete(dummy_object);
+}
+
+void TileDataTextureOffsetEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
+ TileData *tile_data = _get_tile_data(p_cell);
+ ERR_FAIL_COND(!tile_data);
+
+ Vector2i tile_set_tile_size = tile_set->get_tile_size();
+ Rect2i rect = Rect2i(-tile_set_tile_size / 2, tile_set_tile_size);
+ Color color = Color(1.0, 0.0, 0.0);
+ if (p_selected) {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+ color = selection_color;
+ }
+ tile_set->draw_tile_shape(p_canvas_item, p_transform.xform(rect), color);
+}
+
+void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
+ TileData *tile_data = _get_tile_data(p_cell);
ERR_FAIL_COND(!tile_data);
bool valid;
- Variant value = tile_data->get(p_property, &valid);
+ Variant value = tile_data->get(property, &valid);
if (!valid) {
return;
}
ERR_FAIL_COND(value.get_type() != Variant::VECTOR2I && value.get_type() != Variant::VECTOR2);
+ Color color = Color(1.0, 1.0, 1.0);
+ if (p_selected) {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+ color = selection_color;
+ }
Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon("EditorPosition", "EditorIcons");
- p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(value)) - position_icon->get_size() / 2);
+ p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(value)) - position_icon->get_size() / 2, color);
}
-void TileDataYSortEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
- TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+void TileDataYSortEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
+ TileData *tile_data = _get_tile_data(p_cell);
ERR_FAIL_COND(!tile_data);
- bool valid;
- Variant value = tile_data->get(p_property, &valid);
- if (!valid) {
- return;
+ Color color = Color(1.0, 1.0, 1.0);
+ if (p_selected) {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+ color = selection_color;
}
- ERR_FAIL_COND(value.get_type() != Variant::INT);
-
Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon("EditorPosition", "EditorIcons");
- p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(0, value)) - position_icon->get_size() / 2);
+ p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(0, tile_data->get_y_sort_origin())) - position_icon->get_size() / 2, color);
}
-void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
- TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
+ TileData *tile_data = _get_tile_data(p_cell);
ERR_FAIL_COND(!tile_data);
- Vector<String> components = String(p_property).split("/", true);
- if (components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_integer()) {
- int occlusion_layer = components[0].trim_prefix("occlusion_layer_").to_int();
- if (occlusion_layer >= 0 && occlusion_layer < p_tile_set->get_occlusion_layers_count()) {
- // Draw all shapes.
- Vector<Color> debug_occlusion_color;
- debug_occlusion_color.push_back(Color(0.5, 0, 0, 0.6));
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+ Color color = grid_color.darkened(0.2);
+ if (p_selected) {
+ color = selection_color.darkened(0.2);
+ }
+ color.a *= 0.5;
- RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
- Ref<OccluderPolygon2D> occluder = tile_data->get_occluder(occlusion_layer);
- if (occluder.is_valid() && occluder->get_polygon().size() >= 3) {
- p_canvas_item->draw_polygon(Variant(occluder->get_polygon()), debug_occlusion_color);
- }
- RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
+ Vector<Color> debug_occlusion_color;
+ debug_occlusion_color.push_back(color);
+
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
+ Ref<OccluderPolygon2D> occluder = tile_data->get_occluder(occlusion_layer);
+ if (occluder.is_valid() && occluder->get_polygon().size() >= 3) {
+ p_canvas_item->draw_polygon(Variant(occluder->get_polygon()), debug_occlusion_color);
+ }
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
+}
+
+Variant TileDataOcclusionShapeEditor::_get_painted_value() {
+ Ref<OccluderPolygon2D> occluder_polygon;
+ occluder_polygon.instantiate();
+ if (polygon_editor->get_polygon_count() >= 1) {
+ occluder_polygon->set_polygon(polygon_editor->get_polygon(0));
+ }
+ return occluder_polygon;
+}
+
+void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ ERR_FAIL_COND(!tile_data);
+
+ Ref<OccluderPolygon2D> occluder_polygon = tile_data->get_occluder(occlusion_layer);
+ polygon_editor->clear_polygons();
+ if (occluder_polygon.is_valid()) {
+ polygon_editor->add_polygon(occluder_polygon->get_polygon());
+ }
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+}
+
+void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ ERR_FAIL_COND(!tile_data);
+ Ref<OccluderPolygon2D> occluder_polygon = p_value;
+ tile_data->set_occluder(occlusion_layer, occluder_polygon);
+
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+}
+
+Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ ERR_FAIL_COND_V(!tile_data, Variant());
+ return tile_data->get_occluder(occlusion_layer);
+}
+
+void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) {
+ for (Map<TileMapCell, Variant>::Element *E = p_previous_values.front(); E; E = E->next()) {
+ Vector2i coords = E->key().get_atlas_coords();
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/occlusion_layer_%d/polygon", coords.x, coords.y, E->key().alternative_tile, occlusion_layer), E->get());
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/occlusion_layer_%d/polygon", coords.x, coords.y, E->key().alternative_tile, occlusion_layer), p_new_value);
+ }
+}
+
+void TileDataOcclusionShapeEditor::_tile_set_changed() {
+ polygon_editor->set_tile_set(tile_set);
+}
+
+void TileDataOcclusionShapeEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ polygon_editor->set_polygons_color(get_tree()->get_debug_collisions_color());
+ break;
+ default:
+ break;
+ }
+}
+
+TileDataOcclusionShapeEditor::TileDataOcclusionShapeEditor() {
+ polygon_editor = memnew(GenericTilePolygonEditor);
+ add_child(polygon_editor);
+}
+
+void TileDataCollisionEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) {
+ dummy_object->set(p_property, p_value);
+}
+
+void TileDataCollisionEditor::_polygons_changed() {
+ // Update the dummy object properties and their editors.
+ for (int i = 0; i < polygon_editor->get_polygon_count(); i++) {
+ StringName one_way_property = vformat("polygon_%d_one_way", i);
+ StringName one_way_margin_property = vformat("polygon_%d_one_way_margin", i);
+
+ if (!dummy_object->has_dummy_property(one_way_property)) {
+ dummy_object->add_dummy_property(one_way_property);
+ dummy_object->set(one_way_property, false);
}
+
+ if (!dummy_object->has_dummy_property(one_way_margin_property)) {
+ dummy_object->add_dummy_property(one_way_margin_property);
+ dummy_object->set(one_way_margin_property, 1.0);
+ }
+
+ if (!property_editors.has(one_way_property)) {
+ EditorProperty *one_way_property_editor = EditorInspectorDefaultPlugin::get_editor_for_property(dummy_object, Variant::BOOL, one_way_property, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT);
+ one_way_property_editor->set_object_and_property(dummy_object, one_way_property);
+ one_way_property_editor->set_label(one_way_property);
+ one_way_property_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1));
+ one_way_property_editor->update_property();
+ add_child(one_way_property_editor);
+ property_editors[one_way_property] = one_way_property_editor;
+ }
+
+ if (!property_editors.has(one_way_margin_property)) {
+ EditorProperty *one_way_margin_property_editor = EditorInspectorDefaultPlugin::get_editor_for_property(dummy_object, Variant::FLOAT, one_way_margin_property, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT);
+ one_way_margin_property_editor->set_object_and_property(dummy_object, one_way_margin_property);
+ one_way_margin_property_editor->set_label(one_way_margin_property);
+ one_way_margin_property_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1));
+ one_way_margin_property_editor->update_property();
+ add_child(one_way_margin_property_editor);
+ property_editors[one_way_margin_property] = one_way_margin_property_editor;
+ }
+ }
+
+ // Remove uneeded properties and their editors.
+ for (int i = polygon_editor->get_polygon_count(); dummy_object->has_dummy_property(vformat("polygon_%d_one_way", i)); i++) {
+ dummy_object->remove_dummy_property(vformat("polygon_%d_one_way", i));
+ }
+ for (int i = polygon_editor->get_polygon_count(); dummy_object->has_dummy_property(vformat("polygon_%d_one_way_margin", i)); i++) {
+ dummy_object->remove_dummy_property(vformat("polygon_%d_one_way_margin", i));
+ }
+ for (int i = polygon_editor->get_polygon_count(); property_editors.has(vformat("polygon_%d_one_way", i)); i++) {
+ property_editors[vformat("polygon_%d_one_way", i)]->queue_delete();
+ property_editors.erase(vformat("polygon_%d_one_way", i));
}
+ for (int i = polygon_editor->get_polygon_count(); property_editors.has(vformat("polygon_%d_one_way_margin", i)); i++) {
+ property_editors[vformat("polygon_%d_one_way_margin", i)]->queue_delete();
+ property_editors.erase(vformat("polygon_%d_one_way_margin", i));
+ }
+}
+
+Variant TileDataCollisionEditor::_get_painted_value() {
+ Array array;
+ for (int i = 0; i < polygon_editor->get_polygon_count(); i++) {
+ ERR_FAIL_COND_V(polygon_editor->get_polygon(i).size() < 3, Variant());
+ Dictionary dict;
+ dict["points"] = polygon_editor->get_polygon(i);
+ dict["one_way"] = dummy_object->get(vformat("polygon_%d_one_way", i));
+ dict["one_way_margin"] = dummy_object->get(vformat("polygon_%d_one_way_margin", i));
+ array.push_back(dict);
+ }
+
+ return array;
}
-void TileDataCollisionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
- TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+void TileDataCollisionEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
ERR_FAIL_COND(!tile_data);
- Vector<String> components = String(p_property).split("/", true);
- if (components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_integer()) {
- int physics_layer = components[0].trim_prefix("physics_layer_").to_int();
- if (physics_layer >= 0 && physics_layer < p_tile_set->get_physics_layers_count()) {
- // Draw all shapes.
- Color debug_collision_color = p_canvas_item->get_tree()->get_debug_collisions_color();
- RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
- for (int i = 0; i < tile_data->get_collision_shapes_count(physics_layer); i++) {
- Ref<Shape2D> shape = tile_data->get_collision_shape_shape(physics_layer, i);
- if (shape.is_valid()) {
- shape->draw(p_canvas_item->get_canvas_item(), debug_collision_color);
- }
- }
- RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
+ polygon_editor->clear_polygons();
+ for (int i = 0; i < tile_data->get_collision_polygons_count(physics_layer); i++) {
+ Vector<Vector2> polygon = tile_data->get_collision_polygon_points(physics_layer, i);
+ if (polygon.size() >= 3) {
+ polygon_editor->add_polygon(polygon);
}
}
+
+ _polygons_changed();
+ for (int i = 0; i < tile_data->get_collision_polygons_count(physics_layer); i++) {
+ dummy_object->set(vformat("polygon_%d_one_way", i), tile_data->is_collision_polygon_one_way(physics_layer, i));
+ dummy_object->set(vformat("polygon_%d_one_way_margin", i), tile_data->get_collision_polygon_one_way_margin(physics_layer, i));
+ }
+ for (Map<StringName, EditorProperty *>::Element *E = property_editors.front(); E; E = E->next()) {
+ E->get()->update_property();
+ }
+
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
}
-void TileDataTerrainsEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
- TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
ERR_FAIL_COND(!tile_data);
- Vector<String> components = String(p_property).split("/", true);
- if (components[0] == "terrain_mode" || components[0] == "terrain" || components[0] == "terrains_peering_bit") {
- TileSetPluginAtlasTerrain::draw_terrains(p_canvas_item, p_transform, p_tile_set, tile_data);
+ Array array = p_value;
+ tile_data->set_collision_polygons_count(physics_layer, array.size());
+ for (int i = 0; i < array.size(); i++) {
+ Dictionary dict = array[i];
+ tile_data->set_collision_polygon_points(physics_layer, i, dict["points"]);
+ tile_data->set_collision_polygon_one_way(physics_layer, i, dict["one_way"]);
+ tile_data->set_collision_polygon_one_way_margin(physics_layer, i, dict["one_way_margin"]);
+ }
+
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+}
+
+Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ ERR_FAIL_COND_V(!tile_data, Variant());
+
+ Array array;
+ for (int i = 0; i < tile_data->get_collision_polygons_count(physics_layer); i++) {
+ Dictionary dict;
+ dict["points"] = tile_data->get_collision_polygon_points(physics_layer, i);
+ dict["one_way"] = tile_data->is_collision_polygon_one_way(physics_layer, i);
+ dict["one_way_margin"] = tile_data->get_collision_polygon_one_way_margin(physics_layer, i);
+ array.push_back(dict);
+ }
+ return array;
+}
+
+void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) {
+ Array new_array = p_new_value;
+ for (Map<TileMapCell, Variant>::Element *E = p_previous_values.front(); E; E = E->next()) {
+ Array old_array = E->get();
+
+ Vector2i coords = E->key().get_atlas_coords();
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E->key().alternative_tile, physics_layer), old_array.size());
+ for (int i = 0; i < old_array.size(); i++) {
+ Dictionary dict = old_array[i];
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["points"]);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["one_way"]);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["one_way_margin"]);
+ }
+
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E->key().alternative_tile, physics_layer), new_array.size());
+ for (int i = 0; i < new_array.size(); i++) {
+ Dictionary dict = new_array[i];
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["points"]);
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["one_way"]);
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["one_way_margin"]);
+ }
+ }
+}
+
+void TileDataCollisionEditor::_tile_set_changed() {
+ polygon_editor->set_tile_set(tile_set);
+ _polygons_changed();
+}
+
+void TileDataCollisionEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ polygon_editor->set_polygons_color(get_tree()->get_debug_collisions_color());
+ break;
+ default:
+ break;
}
}
-void TileDataNavigationPolygonEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
- TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+TileDataCollisionEditor::TileDataCollisionEditor() {
+ polygon_editor = memnew(GenericTilePolygonEditor);
+ polygon_editor->set_multiple_polygon_mode(true);
+ polygon_editor->connect("polygons_changed", callable_mp(this, &TileDataCollisionEditor::_polygons_changed));
+ add_child(polygon_editor);
+
+ _polygons_changed();
+}
+
+TileDataCollisionEditor::~TileDataCollisionEditor() {
+ memdelete(dummy_object);
+}
+
+void TileDataCollisionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
+ TileData *tile_data = _get_tile_data(p_cell);
ERR_FAIL_COND(!tile_data);
- Vector<String> components = String(p_property).split("/", true);
- if (components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_integer()) {
- int navigation_layer = components[0].trim_prefix("navigation_layer_").to_int();
- if (navigation_layer >= 0 && navigation_layer < p_tile_set->get_navigation_layers_count()) {
- // Draw all shapes.
- RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
+ // Draw all shapes.
+ Vector<Color> color;
+ if (p_selected) {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+ selection_color.a = 0.7;
+ color.push_back(selection_color);
+ } else {
+ Color debug_collision_color = p_canvas_item->get_tree()->get_debug_collisions_color();
+ color.push_back(debug_collision_color);
+ }
+
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
+ for (int i = 0; i < tile_data->get_collision_polygons_count(physics_layer); i++) {
+ Vector<Vector2> polygon = tile_data->get_collision_polygon_points(physics_layer, i);
+ if (polygon.size() >= 3) {
+ p_canvas_item->draw_polygon(polygon, color);
+ }
+ }
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
+}
+
+void TileDataTerrainsEditor::_update_terrain_selector() {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ // Update the terrain set selector.
+ Vector<String> options;
+ options.push_back(String(TTR("No terrains")) + String(":-1"));
+ for (int i = 0; i < tile_set->get_terrain_sets_count(); i++) {
+ options.push_back(vformat("Terrain Set %d", i));
+ }
+ terrain_set_property_editor->setup(options);
+ terrain_set_property_editor->update_property();
+
+ // Update the terrain selector.
+ int terrain_set = int(dummy_object->get("terrain_set"));
+ if (terrain_set == -1) {
+ terrain_property_editor->hide();
+ } else {
+ options.clear();
+ Vector<Vector<Ref<Texture2D>>> icons = tile_set->generate_terrains_icons(Size2(16, 16) * EDSCALE);
+ options.push_back(String(TTR("No terrain")) + String(":-1"));
+ for (int i = 0; i < tile_set->get_terrains_count(terrain_set); i++) {
+ String name = tile_set->get_terrain_name(terrain_set, i);
+ if (name.is_empty()) {
+ options.push_back(vformat("Terrain %d", i));
+ } else {
+ options.push_back(name);
+ }
+ }
+ terrain_property_editor->setup(options);
+ terrain_property_editor->update_property();
+
+ // Kind of a hack to set icons.
+ // We could provide a way to modify that in the EditorProperty.
+ OptionButton *option_button = Object::cast_to<OptionButton>(terrain_property_editor->get_child(0));
+ for (int terrain = 0; terrain < tile_set->get_terrains_count(terrain_set); terrain++) {
+ option_button->set_item_icon(terrain + 1, icons[terrain_set][terrain]);
+ }
+ terrain_property_editor->show();
+ }
+}
+
+void TileDataTerrainsEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) {
+ Variant old_value = dummy_object->get(p_property);
+ dummy_object->set(p_property, p_value);
+ if (p_property == "terrain_set") {
+ if (p_value != old_value) {
+ dummy_object->set("terrain", -1);
+ }
+ _update_terrain_selector();
+ }
+ emit_signal("needs_redraw");
+}
+
+void TileDataTerrainsEditor::_tile_set_changed() {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ // Fix if wrong values are selected.
+ if (int(dummy_object->get("terrain_set")) > tile_set->get_terrain_sets_count()) {
+ dummy_object->set("terrain_set", -1);
+ }
+ int terrain_set = int(dummy_object->get("terrain"));
+ if (terrain_set >= 0) {
+ if (int(dummy_object->get("terrain")) > tile_set->get_terrains_count(terrain_set)) {
+ dummy_object->set("terrain", -1);
+ }
+ }
+
+ _update_terrain_selector();
+}
+
+void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) {
+ ERR_FAIL_COND(!tile_set.is_valid());
- Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer);
- if (navigation_polygon.is_valid()) {
- Vector<Vector2> verts = navigation_polygon->get_vertices();
- if (verts.size() < 3) {
- return;
+ // Draw the hovered terrain bit, or the whole tile if it has the wrong terrain set.
+ Vector2i hovered_coords = TileSetSource::INVALID_ATLAS_COORDS;
+ if (drag_type == DRAG_TYPE_NONE) {
+ Vector2i mouse_pos = p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position());
+ hovered_coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_pos);
+ hovered_coords = p_tile_set_atlas_source->get_tile_at_coords(hovered_coords);
+ if (hovered_coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(hovered_coords, 0));
+ int terrain_set = tile_data->get_terrain_set();
+ Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(hovered_coords);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, 0);
+
+ if (terrain_set >= 0 && terrain_set == int(dummy_object->get("terrain_set"))) {
+ // Draw hovered bit.
+ Transform2D xform;
+ xform.set_origin(position);
+
+ Vector<Color> color;
+ color.push_back(Color(1.0, 1.0, 1.0, 0.5));
+
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) {
+ p_canvas_item->draw_set_transform_matrix(p_transform * xform);
+ p_canvas_item->draw_polygon(polygon, color);
+ }
+ }
}
+ } else {
+ // Draw hovered tile.
+ Vector2i tile_size = tile_set->get_tile_size();
+ Rect2i rect = p_transform.xform(Rect2i(position - tile_size / 2, tile_size));
+ tile_set->draw_tile_shape(p_canvas_item, rect, Color(1.0, 1.0, 1.0, 0.5), true);
+ }
+ }
+ }
+
+ // Dim terrains with wrong terrain set.
+ Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts");
+ for (int i = 0; i < p_tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i coords = p_tile_set_atlas_source->get_tile_id(i);
+ if (coords != hovered_coords) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ if (tile_data->get_terrain_set() != int(dummy_object->get("terrain_set"))) {
+ // Dimming
+ p_canvas_item->draw_set_transform_matrix(p_transform);
+ Rect2i rect = p_tile_set_atlas_source->get_tile_texture_region(coords);
+ p_canvas_item->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.3));
+
+ // Text
+ p_canvas_item->draw_set_transform_matrix(Transform2D());
+ Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+
+ Color color = Color(1, 1, 1);
+ String text;
+ if (tile_data->get_terrain_set() >= 0) {
+ text = vformat("%d", tile_data->get_terrain_set());
+ } else {
+ text = "-";
+ }
+ Vector2 string_size = font->get_string_size(text);
+ p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HALIGN_CENTER, string_size.x, -1, color, 1, Color(0, 0, 0, 1));
+ }
+ }
+ }
+ p_canvas_item->draw_set_transform_matrix(Transform2D());
+
+ if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET_RECT) {
+ // Draw selection rectangle.
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+
+ p_canvas_item->draw_set_transform_matrix(p_transform);
- Color color = p_canvas_item->get_tree()->get_debug_navigation_color();
+ Rect2i rect;
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position())));
+ rect = rect.abs();
- RandomPCG rand;
- for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) {
- // An array of vertices for this polygon.
- Vector<int> polygon = navigation_polygon->get_polygon(i);
- Vector<Vector2> vertices;
- vertices.resize(polygon.size());
+ Set<TileMapCell> edited;
+ for (int x = rect.get_position().x; x <= rect.get_end().x; x++) {
+ for (int y = rect.get_position().y; y <= rect.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+ edited.insert(cell);
+ }
+ }
+ }
+
+ for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) {
+ Vector2i coords = E->get().get_atlas_coords();
+ p_canvas_item->draw_rect(p_tile_set_atlas_source->get_tile_texture_region(coords), selection_color, false);
+ }
+ p_canvas_item->draw_set_transform_matrix(Transform2D());
+ } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS_RECT) {
+ // Highlight selected peering bits.
+ Dictionary painted = Dictionary(drag_painted_value);
+ int terrain_set = int(painted["terrain_set"]);
+
+ Rect2i rect;
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position())));
+ rect = rect.abs();
+
+ Set<TileMapCell> edited;
+ for (int x = rect.get_position().x; x <= rect.get_end().x; x++) {
+ for (int y = rect.get_position().y; y <= rect.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ if (tile_data->get_terrain_set() == terrain_set) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+ edited.insert(cell);
+ }
+ }
+ }
+ }
+
+ Vector2 end = p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position());
+ Vector<Point2> mouse_pos_rect_polygon;
+ mouse_pos_rect_polygon.push_back(drag_start_pos);
+ mouse_pos_rect_polygon.push_back(Vector2(end.x, drag_start_pos.y));
+ mouse_pos_rect_polygon.push_back(end);
+ mouse_pos_rect_polygon.push_back(Vector2(drag_start_pos.x, end.y));
+
+ Vector<Color> color;
+ color.push_back(Color(1.0, 1.0, 1.0, 0.5));
+
+ p_canvas_item->draw_set_transform_matrix(p_transform);
+
+ for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) {
+ Vector2i coords = E->get().get_atlas_coords();
+
+ Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
for (int j = 0; j < polygon.size(); j++) {
- ERR_FAIL_INDEX(polygon[j], verts.size());
- vertices.write[j] = verts[polygon[j]];
+ polygon.write[j] += position;
+ }
+ if (!Geometry2D::intersect_polygons(polygon, mouse_pos_rect_polygon).is_empty()) {
+ // Draw bit.
+ p_canvas_item->draw_polygon(polygon, color);
+ }
+ }
+ }
+ }
+
+ p_canvas_item->draw_set_transform_matrix(Transform2D());
+ }
+}
+
+void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ // Draw the hovered terrain bit, or the whole tile if it has the wrong terrain set.
+ Vector2i hovered_coords = TileSetSource::INVALID_ATLAS_COORDS;
+ int hovered_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ if (drag_type == DRAG_TYPE_NONE) {
+ Vector2i mouse_pos = p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position());
+ Vector3i hovered = p_tile_atlas_view->get_alternative_tile_at_pos(mouse_pos);
+ hovered_coords = Vector2i(hovered.x, hovered.y);
+ hovered_alternative = hovered.z;
+ if (hovered_coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(hovered_coords, hovered_alternative));
+ int terrain_set = tile_data->get_terrain_set();
+ Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(hovered_coords, hovered_alternative);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, hovered_alternative);
+
+ if (terrain_set == int(dummy_object->get("terrain_set"))) {
+ // Draw hovered bit.
+ Transform2D xform;
+ xform.set_origin(position);
+
+ Vector<Color> color;
+ color.push_back(Color(1.0, 1.0, 1.0, 0.5));
+
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) {
+ p_canvas_item->draw_set_transform_matrix(p_transform * xform);
+ p_canvas_item->draw_polygon(polygon, color);
+ }
+ }
+ }
+ } else {
+ // Draw hovered tile.
+ Vector2i tile_size = tile_set->get_tile_size();
+ Rect2i rect = p_transform.xform(Rect2i(position - tile_size / 2, tile_size));
+ tile_set->draw_tile_shape(p_canvas_item, rect, Color(1.0, 1.0, 1.0, 0.5), true);
+ }
+ }
+ }
+
+ // Dim terrains with wrong terrain set.
+ Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts");
+ for (int i = 0; i < p_tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i coords = p_tile_set_atlas_source->get_tile_id(i);
+ for (int j = 1; j < p_tile_set_atlas_source->get_alternative_tiles_count(coords); j++) {
+ int alternative_tile = p_tile_set_atlas_source->get_alternative_tile_id(coords, j);
+ if (coords != hovered_coords || alternative_tile != hovered_alternative) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
+ if (tile_data->get_terrain_set() != int(dummy_object->get("terrain_set"))) {
+ // Dimming
+ p_canvas_item->draw_set_transform_matrix(p_transform);
+ Rect2i rect = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
+ p_canvas_item->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.3));
+
+ // Text
+ p_canvas_item->draw_set_transform_matrix(Transform2D());
+ Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+
+ Color color = Color(1, 1, 1);
+ String text;
+ if (tile_data->get_terrain_set() >= 0) {
+ text = vformat("%d", tile_data->get_terrain_set());
+ } else {
+ text = "-";
+ }
+ Vector2 string_size = font->get_string_size(text);
+ p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HALIGN_CENTER, string_size.x, -1, color, 1, Color(0, 0, 0, 1));
+ }
+ }
+ }
+ }
+
+ p_canvas_item->draw_set_transform_matrix(Transform2D());
+}
+
+void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, const Ref<InputEvent> &p_event) {
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) {
+ Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position()));
+ for (int i = 0; i < line.size(); i++) {
+ Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ int terrain_set = drag_painted_value;
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+
+ // Save the old terrain_set and terrains bits.
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ if (!drag_modified.has(cell)) {
+ Dictionary dict;
+ dict["terrain_set"] = tile_data->get_terrain_set();
+ Array array;
+ for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
+ array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ }
+ dict["terrain_peering_bits"] = array;
+ drag_modified[cell] = dict;
+ }
+
+ // Set the terrain_set.
+ tile_data->set_terrain_set(terrain_set);
+ }
+ }
+ drag_last_pos = mm->get_position();
+ } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) {
+ int terrain_set = Dictionary(drag_painted_value)["terrain_set"];
+ int terrain = Dictionary(drag_painted_value)["terrain"];
+ Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position()));
+ for (int i = 0; i < line.size(); i++) {
+ Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ if (tile_data->get_terrain_set() == terrain_set) {
+ // Save the old terrain_set and terrains bits.
+ if (!drag_modified.has(cell)) {
+ Dictionary dict;
+ dict["terrain_set"] = tile_data->get_terrain_set();
+ Array array;
+ for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
+ array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ }
+ dict["terrain_peering_bits"] = array;
+ drag_modified[cell] = dict;
+ }
+
+ // Set the terrains bits.
+ Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
+ if (tile_data->is_valid_peering_bit_terrain(bit)) {
+ Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(tile_data->get_terrain_set(), bit);
+ if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
+ tile_data->set_peering_bit_terrain(bit, terrain);
+ }
+ }
+ }
+ }
+ }
+ }
+ drag_last_pos = mm->get_position();
+ }
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ if (picker_button->is_pressed()) {
+ Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
+ coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ int terrain_set = tile_data->get_terrain_set();
+ Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ dummy_object->set("terrain_set", terrain_set);
+ dummy_object->set("terrain", -1);
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
+ dummy_object->set("terrain", tile_data->get_peering_bit_terrain(bit));
+ }
+ }
+ }
+ terrain_set_property_editor->update_property();
+ _update_terrain_selector();
+ picker_button->set_pressed(false);
+ }
+ } else {
+ Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
+ coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
+ TileData *tile_data = nullptr;
+ if (coords != TileSetAtlasSource::INVALID_ATLAS_COORDS) {
+ tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ }
+ int terrain_set = int(dummy_object->get("terrain_set"));
+ int terrain = int(dummy_object->get("terrain"));
+ if (terrain_set == -1 || !tile_data || tile_data->get_terrain_set() != terrain_set) {
+ if (mb->is_ctrl_pressed()) {
+ // Paint terrain set with rect.
+ drag_type = DRAG_TYPE_PAINT_TERRAIN_SET_RECT;
+ drag_modified.clear();
+ drag_painted_value = terrain_set;
+ drag_start_pos = mb->get_position();
+ } else {
+ // Paint terrain set.
+ drag_type = DRAG_TYPE_PAINT_TERRAIN_SET;
+ drag_modified.clear();
+ drag_painted_value = terrain_set;
+
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+
+ // Save the old terrain_set and terrains bits.
+ Dictionary dict;
+ dict["terrain_set"] = tile_data->get_terrain_set();
+ Array array;
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ }
+ dict["terrain_peering_bits"] = array;
+ drag_modified[cell] = dict;
+
+ // Set the terrain_set.
+ tile_data->set_terrain_set(terrain_set);
+ }
+ drag_last_pos = mb->get_position();
+ }
+ } else if (tile_data && tile_data->get_terrain_set() == terrain_set) {
+ if (mb->is_ctrl_pressed()) {
+ // Paint terrain set with rect.
+ drag_type = DRAG_TYPE_PAINT_TERRAIN_BITS_RECT;
+ drag_modified.clear();
+ Dictionary painted_dict;
+ painted_dict["terrain_set"] = terrain_set;
+ painted_dict["terrain"] = terrain;
+ drag_painted_value = painted_dict;
+ drag_start_pos = mb->get_position();
+ } else {
+ // Paint terrain bits.
+ drag_type = DRAG_TYPE_PAINT_TERRAIN_BITS;
+ drag_modified.clear();
+ Dictionary painted_dict;
+ painted_dict["terrain_set"] = terrain_set;
+ painted_dict["terrain"] = terrain;
+ drag_painted_value = painted_dict;
+
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+
+ // Save the old terrain_set and terrains bits.
+ Dictionary dict;
+ dict["terrain_set"] = tile_data->get_terrain_set();
+ Array array;
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ }
+ dict["terrain_peering_bits"] = array;
+ drag_modified[cell] = dict;
+
+ // Set the terrain bit.
+ Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
+ tile_data->set_peering_bit_terrain(bit, terrain);
+ }
+ }
+ }
+ }
+ drag_last_pos = mb->get_position();
+ }
+ }
+ }
+ } else {
+ if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET_RECT) {
+ Rect2i rect;
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()));
+ rect = rect.abs();
+
+ Set<TileMapCell> edited;
+ for (int x = rect.get_position().x; x <= rect.get_end().x; x++) {
+ for (int y = rect.get_position().y; y <= rect.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+ edited.insert(cell);
+ }
+ }
+ }
+ undo_redo->create_action(TTR("Painting Terrain Set"));
+ for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) {
+ Vector2i coords = E->get().get_atlas_coords();
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->get().alternative_tile), tile_data->get_terrain_set());
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->get().alternative_tile), drag_painted_value);
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_data->is_valid_peering_bit_terrain(bit)) {
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->get().alternative_tile), tile_data->get_peering_bit_terrain(bit));
+ }
+ }
+ }
+ undo_redo->commit_action(true);
+ drag_type = DRAG_TYPE_NONE;
+ } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) {
+ undo_redo->create_action(TTR("Painting Terrain Set"));
+ for (Map<TileMapCell, Variant>::Element *E = drag_modified.front(); E; E = E->next()) {
+ Dictionary dict = E->get();
+ Vector2i coords = E->key().get_atlas_coords();
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->key().alternative_tile), drag_painted_value);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->key().alternative_tile), dict["terrain_set"]);
+ Array array = dict["terrain_peering_bits"];
+ for (int i = 0; i < array.size(); i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) {
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), array[i]);
+ }
+ }
+ }
+ undo_redo->commit_action(false);
+ drag_type = DRAG_TYPE_NONE;
+ } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) {
+ Dictionary painted = Dictionary(drag_painted_value);
+ int terrain_set = int(painted["terrain_set"]);
+ int terrain = int(painted["terrain"]);
+ undo_redo->create_action(TTR("Painting Terrain"));
+ for (Map<TileMapCell, Variant>::Element *E = drag_modified.front(); E; E = E->next()) {
+ Dictionary dict = E->get();
+ Vector2i coords = E->key().get_atlas_coords();
+ Array array = dict["terrain_peering_bits"];
+ for (int i = 0; i < array.size(); i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), terrain);
+ }
+ if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) {
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), array[i]);
+ }
+ }
+ }
+ undo_redo->commit_action(false);
+ drag_type = DRAG_TYPE_NONE;
+ } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS_RECT) {
+ Dictionary painted = Dictionary(drag_painted_value);
+ int terrain_set = int(painted["terrain_set"]);
+ int terrain = int(painted["terrain"]);
+
+ Rect2i rect;
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()));
+ rect = rect.abs();
+
+ Set<TileMapCell> edited;
+ for (int x = rect.get_position().x; x <= rect.get_end().x; x++) {
+ for (int y = rect.get_position().y; y <= rect.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ if (tile_data->get_terrain_set() == terrain_set) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+ edited.insert(cell);
+ }
+ }
+ }
+ }
+
+ Vector<Point2> mouse_pos_rect_polygon;
+ mouse_pos_rect_polygon.push_back(drag_start_pos);
+ mouse_pos_rect_polygon.push_back(Vector2(mb->get_position().x, drag_start_pos.y));
+ mouse_pos_rect_polygon.push_back(mb->get_position());
+ mouse_pos_rect_polygon.push_back(Vector2(drag_start_pos.x, mb->get_position().y));
+
+ undo_redo->create_action(TTR("Painting Terrain"));
+ for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) {
+ Vector2i coords = E->get().get_atlas_coords();
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+
+ Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ for (int j = 0; j < polygon.size(); j++) {
+ polygon.write[j] += position;
+ }
+ if (!Geometry2D::intersect_polygons(polygon, mouse_pos_rect_polygon).is_empty()) {
+ // Draw bit.
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->get().alternative_tile), terrain);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->get().alternative_tile), tile_data->get_peering_bit_terrain(bit));
+ }
+ }
+ }
+ }
+ undo_redo->commit_action(true);
+ drag_type = DRAG_TYPE_NONE;
+ }
+ }
+ }
+ }
+}
+
+void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, const Ref<InputEvent> &p_event) {
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) {
+ Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mm->get_position());
+ Vector2i coords = Vector2i(tile.x, tile.y);
+ int alternative_tile = tile.z;
+
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = alternative_tile;
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
+ if (!drag_modified.has(cell)) {
+ Dictionary dict;
+ dict["terrain_set"] = tile_data->get_terrain_set();
+ Array array;
+ for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
+ array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ }
+ dict["terrain_peering_bits"] = array;
+ drag_modified[cell] = dict;
+ }
+ tile_data->set_terrain_set(drag_painted_value);
+ }
+
+ drag_last_pos = mm->get_position();
+ } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) {
+ Dictionary painted = Dictionary(drag_painted_value);
+ int terrain_set = int(painted["terrain_set"]);
+ int terrain = int(painted["terrain"]);
+
+ Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mm->get_position());
+ Vector2i coords = Vector2i(tile.x, tile.y);
+ int alternative_tile = tile.z;
+
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = alternative_tile;
+
+ // Save the old terrain_set and terrains bits.
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
+ if (tile_data->get_terrain_set() == terrain_set) {
+ if (!drag_modified.has(cell)) {
+ Dictionary dict;
+ dict["terrain_set"] = tile_data->get_terrain_set();
+ Array array;
+ for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
+ array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ }
+ dict["terrain_peering_bits"] = array;
+ drag_modified[cell] = dict;
+ }
+
+ // Set the terrains bits.
+ Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+ for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
+ if (tile_data->is_valid_peering_bit_terrain(bit)) {
+ Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(tile_data->get_terrain_set(), bit);
+ if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
+ tile_data->set_peering_bit_terrain(bit, terrain);
+ }
+ }
+ }
+ }
+ }
+ drag_last_pos = mm->get_position();
+ }
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ if (picker_button->is_pressed()) {
+ Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mb->get_position());
+ Vector2i coords = Vector2i(tile.x, tile.y);
+ int alternative_tile = tile.z;
+
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
+ int terrain_set = tile_data->get_terrain_set();
+ Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+ dummy_object->set("terrain_set", terrain_set);
+ dummy_object->set("terrain", -1);
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
+ dummy_object->set("terrain", tile_data->get_peering_bit_terrain(bit));
+ }
+ }
+ }
+ terrain_set_property_editor->update_property();
+ _update_terrain_selector();
+ picker_button->set_pressed(false);
}
+ } else {
+ int terrain_set = int(dummy_object->get("terrain_set"));
+ int terrain = int(dummy_object->get("terrain"));
+
+ Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mb->get_position());
+ Vector2i coords = Vector2i(tile.x, tile.y);
+ int alternative_tile = tile.z;
- // Generate the polygon color, slightly randomly modified from the settings one.
- Color random_variation_color;
- random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1);
- random_variation_color.a = color.a;
- Vector<Color> colors;
- colors.push_back(random_variation_color);
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
- RenderingServer::get_singleton()->canvas_item_add_polygon(p_canvas_item->get_canvas_item(), vertices, colors);
+ if (terrain_set == -1 || !tile_data || tile_data->get_terrain_set() != terrain_set) {
+ drag_type = DRAG_TYPE_PAINT_TERRAIN_SET;
+ drag_modified.clear();
+ drag_painted_value = int(dummy_object->get("terrain_set"));
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = alternative_tile;
+ Dictionary dict;
+ dict["terrain_set"] = tile_data->get_terrain_set();
+ Array array;
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ }
+ dict["terrain_peering_bits"] = array;
+ drag_modified[cell] = dict;
+ tile_data->set_terrain_set(drag_painted_value);
+ }
+ drag_last_pos = mb->get_position();
+ } else if (tile_data && tile_data->get_terrain_set() == terrain_set) {
+ // Paint terrain bits.
+ drag_type = DRAG_TYPE_PAINT_TERRAIN_BITS;
+ drag_modified.clear();
+ Dictionary painted_dict;
+ painted_dict["terrain_set"] = terrain_set;
+ painted_dict["terrain"] = terrain;
+ drag_painted_value = painted_dict;
+
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ TileMapCell cell;
+ cell.source_id = 0;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = alternative_tile;
+
+ // Save the old terrain_set and terrains bits.
+ Dictionary dict;
+ dict["terrain_set"] = tile_data->get_terrain_set();
+ Array array;
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ }
+ dict["terrain_peering_bits"] = array;
+ drag_modified[cell] = dict;
+
+ // Set the terrain bit.
+ Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
+ tile_data->set_peering_bit_terrain(bit, terrain);
+ }
+ }
+ }
+ }
+ drag_last_pos = mb->get_position();
+ }
+ }
+ } else {
+ if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) {
+ undo_redo->create_action(TTR("Painting Tiles Property"));
+ for (Map<TileMapCell, Variant>::Element *E = drag_modified.front(); E; E = E->next()) {
+ Dictionary dict = E->get();
+ Vector2i coords = E->key().get_atlas_coords();
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->key().alternative_tile), dict["terrain_set"]);
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->key().alternative_tile), drag_painted_value);
+ Array array = dict["terrain_peering_bits"];
+ for (int i = 0; i < array.size(); i++) {
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), array[i]);
+ }
+ }
+ undo_redo->commit_action(false);
+ drag_type = DRAG_TYPE_NONE;
+ } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) {
+ Dictionary painted = Dictionary(drag_painted_value);
+ int terrain_set = int(painted["terrain_set"]);
+ int terrain = int(painted["terrain"]);
+ undo_redo->create_action(TTR("Painting Terrain"));
+ for (Map<TileMapCell, Variant>::Element *E = drag_modified.front(); E; E = E->next()) {
+ Dictionary dict = E->get();
+ Vector2i coords = E->key().get_atlas_coords();
+ Array array = dict["terrain_peering_bits"];
+ for (int i = 0; i < array.size(); i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), terrain);
+ }
+ if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) {
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), array[i]);
+ }
+ }
+ }
+ undo_redo->commit_action(false);
+ drag_type = DRAG_TYPE_NONE;
}
}
+ }
+ }
+}
+
+void TileDataTerrainsEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
+ TileData *tile_data = _get_tile_data(p_cell);
+ ERR_FAIL_COND(!tile_data);
- RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
+ tile_set->draw_terrains(p_canvas_item, p_transform, tile_data);
+}
+
+void TileDataTerrainsEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
+ picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons"));
+ break;
+ default:
+ break;
+ }
+}
+
+TileDataTerrainsEditor::TileDataTerrainsEditor() {
+ label = memnew(Label);
+ label->set_text("Painting:");
+ add_child(label);
+
+ // Toolbar
+ toolbar->add_child(memnew(VSeparator));
+
+ picker_button = memnew(Button);
+ picker_button->set_flat(true);
+ picker_button->set_toggle_mode(true);
+ picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", KEY_P));
+ toolbar->add_child(picker_button);
+
+ // Setup
+ dummy_object->add_dummy_property("terrain_set");
+ dummy_object->set("terrain_set", -1);
+ dummy_object->add_dummy_property("terrain");
+ dummy_object->set("terrain", -1);
+
+ // Get the default value for the type.
+ terrain_set_property_editor = memnew(EditorPropertyEnum);
+ terrain_set_property_editor->set_object_and_property(dummy_object, "terrain_set");
+ terrain_set_property_editor->set_label("Terrain Set");
+ terrain_set_property_editor->connect("property_changed", callable_mp(this, &TileDataTerrainsEditor::_property_value_changed).unbind(1));
+ add_child(terrain_set_property_editor);
+
+ terrain_property_editor = memnew(EditorPropertyEnum);
+ terrain_property_editor->set_object_and_property(dummy_object, "terrain");
+ terrain_property_editor->set_label("Terrain");
+ terrain_property_editor->connect("property_changed", callable_mp(this, &TileDataTerrainsEditor::_property_value_changed).unbind(1));
+ add_child(terrain_property_editor);
+}
+
+TileDataTerrainsEditor::~TileDataTerrainsEditor() {
+ toolbar->queue_delete();
+ memdelete(dummy_object);
+}
+
+Variant TileDataNavigationEditor::_get_painted_value() {
+ Ref<NavigationPolygon> navigation_polygon;
+ navigation_polygon.instantiate();
+
+ for (int i = 0; i < polygon_editor->get_polygon_count(); i++) {
+ Vector<Vector2> polygon = polygon_editor->get_polygon(i);
+ navigation_polygon->add_outline(polygon);
+ }
+
+ navigation_polygon->make_polygons_from_outlines();
+ return navigation_polygon;
+}
+
+void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ ERR_FAIL_COND(!tile_data);
+
+ Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer);
+ polygon_editor->clear_polygons();
+ if (navigation_polygon.is_valid()) {
+ for (int i = 0; i < navigation_polygon->get_outline_count(); i++) {
+ polygon_editor->add_polygon(navigation_polygon->get_outline(i));
+ }
+ }
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+}
+
+void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ ERR_FAIL_COND(!tile_data);
+ Ref<NavigationPolygon> navigation_polygon = p_value;
+ tile_data->set_navigation_polygon(navigation_layer, navigation_polygon);
+
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+}
+
+Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
+ TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ ERR_FAIL_COND_V(!tile_data, Variant());
+ return tile_data->get_navigation_polygon(navigation_layer);
+}
+
+void TileDataNavigationEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) {
+ for (Map<TileMapCell, Variant>::Element *E = p_previous_values.front(); E; E = E->next()) {
+ Vector2i coords = E->key().get_atlas_coords();
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/navigation_layer_%d/polygon", coords.x, coords.y, E->key().alternative_tile, navigation_layer), E->get());
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/navigation_layer_%d/polygon", coords.x, coords.y, E->key().alternative_tile, navigation_layer), p_new_value);
+ }
+}
+
+void TileDataNavigationEditor::_tile_set_changed() {
+ polygon_editor->set_tile_set(tile_set);
+}
+
+void TileDataNavigationEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ polygon_editor->set_polygons_color(get_tree()->get_debug_navigation_color());
+ break;
+ default:
+ break;
+ }
+}
+
+TileDataNavigationEditor::TileDataNavigationEditor() {
+ polygon_editor = memnew(GenericTilePolygonEditor);
+ polygon_editor->set_multiple_polygon_mode(true);
+ add_child(polygon_editor);
+}
+
+void TileDataNavigationEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
+ TileData *tile_data = _get_tile_data(p_cell);
+ ERR_FAIL_COND(!tile_data);
+
+ // Draw all shapes.
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
+
+ Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer);
+ if (navigation_polygon.is_valid()) {
+ Vector<Vector2> verts = navigation_polygon->get_vertices();
+ if (verts.size() < 3) {
+ return;
+ }
+
+ Color color = p_canvas_item->get_tree()->get_debug_navigation_color();
+ if (p_selected) {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+ selection_color.a = 0.7;
+ color = selection_color;
+ }
+
+ RandomPCG rand;
+ for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) {
+ // An array of vertices for this polygon.
+ Vector<int> polygon = navigation_polygon->get_polygon(i);
+ Vector<Vector2> vertices;
+ vertices.resize(polygon.size());
+ for (int j = 0; j < polygon.size(); j++) {
+ ERR_FAIL_INDEX(polygon[j], verts.size());
+ vertices.write[j] = verts[polygon[j]];
+ }
+
+ // Generate the polygon color, slightly randomly modified from the settings one.
+ Color random_variation_color;
+ random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1);
+ random_variation_color.a = color.a;
+ Vector<Color> colors;
+ colors.push_back(random_variation_color);
+
+ RenderingServer::get_singleton()->canvas_item_add_polygon(p_canvas_item->get_canvas_item(), vertices, colors);
}
}
+
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
}
diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h
index b82189e1ee..781f26cc02 100644
--- a/editor/plugins/tiles/tile_data_editors.h
+++ b/editor/plugins/tiles/tile_data_editors.h
@@ -31,87 +31,378 @@
#ifndef TILE_DATA_EDITORS_H
#define TILE_DATA_EDITORS_H
+#include "tile_atlas_view.h"
+
+#include "editor/editor_node.h"
+#include "editor/editor_properties.h"
+
+#include "scene/gui/box_container.h"
#include "scene/gui/control.h"
+#include "scene/gui/label.h"
#include "scene/resources/tile_set.h"
-class TileDataEditor : public Control {
- GDCLASS(TileDataEditor, Control);
+class TileDataEditor : public VBoxContainer {
+ GDCLASS(TileDataEditor, VBoxContainer);
+
+private:
+ void _call_tile_set_changed();
protected:
- TileData *tile_data;
- String property;
+ Ref<TileSet> tile_set;
+ TileData *_get_tile_data(TileMapCell p_cell);
+ virtual void _tile_set_changed(){};
- TileData *_get_tile_data(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile);
+ static void _bind_methods();
public:
- // Edits a TileData property.
- void edit(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property);
+ void set_tile_set(Ref<TileSet> p_tile_set);
+
+ // Input to handle painting.
+ virtual Control *get_toolbar() { return nullptr; };
+ virtual void forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform){};
+ virtual void forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform){};
+ virtual void forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event){};
+ virtual void forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event){};
- // Used to draw the value over a tile.
- virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property){};
+ // Used to draw the tile data property value over a tile.
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false){};
};
-class TileDataTextureOffsetEditor : public TileDataEditor {
- GDCLASS(TileDataTextureOffsetEditor, TileDataEditor);
+class DummyObject : public Object {
+ GDCLASS(DummyObject, Object)
+private:
+ Map<String, Variant> properties;
+
+protected:
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
public:
- virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+ bool has_dummy_property(StringName p_name);
+ void add_dummy_property(StringName p_name);
+ void remove_dummy_property(StringName p_name);
+ void clear_dummy_properties();
};
-class TileDataIntegerEditor : public TileDataEditor {
- GDCLASS(TileDataIntegerEditor, TileDataEditor);
+class GenericTilePolygonEditor : public VBoxContainer {
+ GDCLASS(GenericTilePolygonEditor, VBoxContainer);
+
+private:
+ Ref<TileSet> tile_set;
+ LocalVector<Vector<Point2>> polygons;
+ bool multiple_polygon_mode = false;
+
+ UndoRedo *undo_redo = EditorNode::get_undo_redo();
+
+ // UI
+ int hovered_polygon_index = -1;
+ int hovered_point_index = -1;
+ int hovered_segment_index = -1;
+ Vector2 hovered_segment_point;
+
+ enum DragType {
+ DRAG_TYPE_NONE,
+ DRAG_TYPE_DRAG_POINT,
+ DRAG_TYPE_CREATE_POINT,
+ DRAG_TYPE_PAN,
+ };
+ DragType drag_type;
+ int drag_polygon_index;
+ int drag_point_index;
+ Vector2 drag_last_pos;
+ PackedVector2Array drag_old_polygon;
+
+ HBoxContainer *toolbar;
+ Ref<ButtonGroup> tools_button_group;
+ Button *button_create;
+ Button *button_edit;
+ Button *button_delete;
+ Button *button_pixel_snap;
+ MenuButton *button_advanced_menu;
+
+ Vector<Point2> in_creation_polygon;
+
+ Panel *panel;
+ Control *base_control;
+ EditorZoomWidget *editor_zoom_widget;
+ Button *button_center_view;
+ Vector2 panning;
+
+ Ref<Texture2D> background_texture;
+ Rect2 background_region;
+ Vector2 background_offset;
+ bool background_h_flip;
+ bool background_v_flip;
+ bool background_transpose;
+ Color background_modulate;
+
+ Color polygon_color = Color(1.0, 0.0, 0.0);
+
+ enum AdvancedMenuOption {
+ RESET_TO_DEFAULT_TILE,
+ CLEAR_TILE,
+ };
+
+ void _base_control_draw();
+ void _zoom_changed();
+ void _advanced_menu_item_pressed(int p_item_pressed);
+ void _center_view();
+ void _base_control_gui_input(Ref<InputEvent> p_event);
+
+ void _snap_to_tile_shape(Point2 &r_point, float &r_current_snapped_dist, float p_snap_dist);
+ void _snap_to_half_pixel(Point2 &r_point);
+ void _grab_polygon_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_point_index);
+ void _grab_polygon_segment_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_segment_index, Vector2 &r_point);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
public:
- virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+ void set_tile_set(Ref<TileSet> p_tile_set);
+ void set_background(Ref<Texture2D> p_texture, Rect2 p_region = Rect2(), Vector2 p_offset = Vector2(), bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false, Color p_modulate = Color(1.0, 1.0, 1.0, 0.0));
+
+ int get_polygon_count();
+ int add_polygon(Vector<Point2> p_polygon, int p_index = -1);
+ void remove_polygon(int p_index);
+ void clear_polygons();
+ void set_polygon(int p_polygon_index, Vector<Point2> p_polygon);
+ Vector<Point2> get_polygon(int p_polygon_index);
+
+ void set_polygons_color(Color p_color);
+ void set_multiple_polygon_mode(bool p_multiple_polygon_mode);
+
+ GenericTilePolygonEditor();
};
-class TileDataFloatEditor : public TileDataEditor {
- GDCLASS(TileDataFloatEditor, TileDataEditor);
+class TileDataDefaultEditor : public TileDataEditor {
+ GDCLASS(TileDataDefaultEditor, TileDataEditor);
+
+private:
+ // Toolbar
+ HBoxContainer *toolbar = memnew(HBoxContainer);
+ Button *picker_button;
+
+ // UI
+ Ref<Texture2D> tile_bool_checked;
+ Ref<Texture2D> tile_bool_unchecked;
+ Label *label;
+
+ EditorProperty *property_editor = nullptr;
+
+ // Painting state.
+ enum DragType {
+ DRAG_TYPE_NONE = 0,
+ DRAG_TYPE_PAINT,
+ DRAG_TYPE_PAINT_RECT,
+ };
+ DragType drag_type = DRAG_TYPE_NONE;
+ Vector2 drag_start_pos;
+ Vector2 drag_last_pos;
+ Map<TileMapCell, Variant> drag_modified;
+ Variant drag_painted_value;
+
+ void _property_value_changed(StringName p_property, Variant p_value, StringName p_field);
+
+protected:
+ DummyObject *dummy_object = memnew(DummyObject);
+
+ UndoRedo *undo_redo = EditorNode::get_undo_redo();
+
+ StringName type;
+ String property;
+ void _notification(int p_what);
+
+ virtual Variant _get_painted_value();
+ virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile);
+ virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value);
+ virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile);
+ virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value);
public:
- virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+ virtual Control *get_toolbar() override { return toolbar; };
+ virtual void forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override;
+ virtual void forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override;
+ virtual void forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) override;
+ virtual void forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) override;
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override;
+
+ void setup_property_editor(Variant::Type p_type, String p_property, String p_label = "", Variant p_default_value = Variant());
+
+ TileDataDefaultEditor();
+ ~TileDataDefaultEditor();
};
-class TileDataPositionEditor : public TileDataEditor {
- GDCLASS(TileDataPositionEditor, TileDataEditor);
+class TileDataTextureOffsetEditor : public TileDataDefaultEditor {
+ GDCLASS(TileDataTextureOffsetEditor, TileDataDefaultEditor);
public:
- virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override;
};
-class TileDataYSortEditor : public TileDataEditor {
- GDCLASS(TileDataYSortEditor, TileDataEditor);
+class TileDataPositionEditor : public TileDataDefaultEditor {
+ GDCLASS(TileDataPositionEditor, TileDataDefaultEditor);
public:
- virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override;
};
-class TileDataOcclusionShapeEditor : public TileDataEditor {
- GDCLASS(TileDataOcclusionShapeEditor, TileDataEditor);
+class TileDataYSortEditor : public TileDataDefaultEditor {
+ GDCLASS(TileDataYSortEditor, TileDataDefaultEditor);
public:
- virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override;
};
-class TileDataCollisionShapeEditor : public TileDataEditor {
- GDCLASS(TileDataCollisionShapeEditor, TileDataEditor);
+class TileDataOcclusionShapeEditor : public TileDataDefaultEditor {
+ GDCLASS(TileDataOcclusionShapeEditor, TileDataDefaultEditor);
+
+private:
+ int occlusion_layer = -1;
+
+ // UI
+ GenericTilePolygonEditor *polygon_editor;
+
+ void _polygon_changed(PackedVector2Array p_polygon);
+
+ virtual Variant _get_painted_value() override;
+ virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
+ virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override;
+ virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
+ virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) override;
+
+protected:
+ UndoRedo *undo_redo = EditorNode::get_undo_redo();
+
+ virtual void _tile_set_changed() override;
+
+ void _notification(int p_what);
+
+public:
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override;
+
+ void set_occlusion_layer(int p_occlusion_layer) { occlusion_layer = p_occlusion_layer; }
+
+ TileDataOcclusionShapeEditor();
+};
+
+class TileDataCollisionEditor : public TileDataDefaultEditor {
+ GDCLASS(TileDataCollisionEditor, TileDataDefaultEditor);
+
+ int physics_layer = -1;
+
+ // UI
+ GenericTilePolygonEditor *polygon_editor;
+ DummyObject *dummy_object = memnew(DummyObject);
+ Map<StringName, EditorProperty *> property_editors;
+
+ void _property_value_changed(StringName p_property, Variant p_value, StringName p_field);
+ void _polygons_changed();
+
+ virtual Variant _get_painted_value() override;
+ virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
+ virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override;
+ virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
+ virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) override;
+
+protected:
+ UndoRedo *undo_redo = EditorNode::get_undo_redo();
+
+ virtual void _tile_set_changed() override;
+
+ void _notification(int p_what);
public:
- virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override;
+
+ void set_physics_layer(int p_physics_layer) { physics_layer = p_physics_layer; }
+
+ TileDataCollisionEditor();
+ ~TileDataCollisionEditor();
};
class TileDataTerrainsEditor : public TileDataEditor {
GDCLASS(TileDataTerrainsEditor, TileDataEditor);
+private:
+ // Toolbar
+ HBoxContainer *toolbar = memnew(HBoxContainer);
+ Button *picker_button;
+
+ // Painting state.
+ enum DragType {
+ DRAG_TYPE_NONE = 0,
+ DRAG_TYPE_PAINT_TERRAIN_SET,
+ DRAG_TYPE_PAINT_TERRAIN_SET_RECT,
+ DRAG_TYPE_PAINT_TERRAIN_BITS,
+ DRAG_TYPE_PAINT_TERRAIN_BITS_RECT,
+ };
+ DragType drag_type = DRAG_TYPE_NONE;
+ Vector2 drag_start_pos;
+ Vector2 drag_last_pos;
+ Map<TileMapCell, Variant> drag_modified;
+ Variant drag_painted_value;
+
+ // UI
+ Label *label;
+ DummyObject *dummy_object = memnew(DummyObject);
+ EditorPropertyEnum *terrain_set_property_editor = nullptr;
+ EditorPropertyEnum *terrain_property_editor = nullptr;
+
+ void _property_value_changed(StringName p_property, Variant p_value, StringName p_field);
+
+ void _update_terrain_selector();
+
+protected:
+ virtual void _tile_set_changed() override;
+
+ void _notification(int p_what);
+
+ UndoRedo *undo_redo = EditorNode::get_undo_redo();
+
public:
- virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+ virtual Control *get_toolbar() override { return toolbar; };
+ virtual void forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override;
+ virtual void forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override;
+ virtual void forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) override;
+ virtual void forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) override;
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override;
+
+ TileDataTerrainsEditor();
+ ~TileDataTerrainsEditor();
};
-class TileDataNavigationPolygonEditor : public TileDataEditor {
- GDCLASS(TileDataNavigationPolygonEditor, TileDataEditor);
+class TileDataNavigationEditor : public TileDataDefaultEditor {
+ GDCLASS(TileDataNavigationEditor, TileDataDefaultEditor);
+
+private:
+ int navigation_layer = -1;
+ PackedVector2Array navigation_polygon;
+
+ // UI
+ GenericTilePolygonEditor *polygon_editor;
+
+ void _polygon_changed(PackedVector2Array p_polygon);
+
+ virtual Variant _get_painted_value() override;
+ virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
+ virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override;
+ virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override;
+ virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) override;
+
+protected:
+ UndoRedo *undo_redo = EditorNode::get_undo_redo();
+
+ virtual void _tile_set_changed() override;
+
+ void _notification(int p_what);
public:
- virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override;
+
+ void set_navigation_layer(int p_navigation_layer) { navigation_layer = p_navigation_layer; }
+
+ TileDataNavigationEditor();
};
#endif // TILE_DATA_EDITORS_H
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index ef13d8ea12..86bd115ac2 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -1756,7 +1756,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
HBoxContainer *tilemap_tiles_tools_buttons = memnew(HBoxContainer);
- tool_buttons_group.instance();
+ tool_buttons_group.instantiate();
select_tool_button = memnew(Button);
select_tool_button->set_flat(true);
@@ -2989,6 +2989,7 @@ void TileMapEditorTerrainsPlugin::_update_terrains_tree() {
}
// Fill in the terrain list.
+ Vector<Vector<Ref<Texture2D>>> icons = tile_set->generate_terrains_icons(Size2(16, 16) * EDSCALE);
for (int terrain_set_index = 0; terrain_set_index < tile_set->get_terrain_sets_count(); terrain_set_index++) {
// Add an item for the terrain set.
TreeItem *terrain_set_tree_item = terrains_tree->create_item();
@@ -3007,58 +3008,12 @@ void TileMapEditorTerrainsPlugin::_update_terrains_tree() {
terrain_set_tree_item->set_selectable(0, false);
for (int terrain_index = 0; terrain_index < tile_set->get_terrains_count(terrain_set_index); terrain_index++) {
- // Compute the terrains_tile_pattern used for terrain preview (whenever possible).
- TerrainsTilePattern terrains_tile_pattern;
- int max_bit_count = -1;
- for (Set<TerrainsTilePattern>::Element *E = per_terrain_terrains_tile_patterns[terrain_set_index][terrain_index].front(); E; E = E->next()) {
- int count = 0;
- for (int i = 0; i < E->get().size(); i++) {
- if (int(E->get()[i]) == terrain_index) {
- count++;
- }
- }
- if (count > max_bit_count) {
- terrains_tile_pattern = E->get();
- max_bit_count = count;
- }
- }
-
- // Get the preview.
- Ref<Texture2D> icon;
- Rect2 region;
- if (max_bit_count >= 0) {
- double max_probability = -1.0;
- for (Set<TileMapCell>::Element *E = per_terrain_terrains_tile_patterns_tiles[terrain_set_index][terrains_tile_pattern].front(); E; E = E->next()) {
- Ref<TileSetSource> source = tile_set->get_source(E->get().source_id);
-
- Ref<TileSetAtlasSource> atlas_source = source;
- if (atlas_source.is_valid()) {
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile));
- if (tile_data->get_probability() > max_probability) {
- icon = atlas_source->get_texture();
- region = atlas_source->get_tile_texture_region(E->get().get_atlas_coords());
- max_probability = tile_data->get_probability();
- }
- }
- }
- } else {
- Ref<Image> image;
- image.instance();
- image->create(1, 1, false, Image::FORMAT_RGBA8);
- image->set_pixel(0, 0, tile_set->get_terrain_color(terrain_set_index, terrain_index));
- Ref<ImageTexture> image_texture;
- image_texture.instance();
- image_texture->create_from_image(image);
- image_texture->set_size_override(Size2(32, 32) * EDSCALE);
- icon = image_texture;
- }
-
// Add the item to the terrain list.
TreeItem *terrain_tree_item = terrains_tree->create_item(terrain_set_tree_item);
terrain_tree_item->set_text(0, tile_set->get_terrain_name(terrain_set_index, terrain_index));
terrain_tree_item->set_icon_max_width(0, 32 * EDSCALE);
- terrain_tree_item->set_icon(0, icon);
- terrain_tree_item->set_icon_region(0, region);
+ terrain_tree_item->set_icon(0, icons[terrain_set_index][terrain_index]);
+
Dictionary metadata_dict;
metadata_dict["terrain_set"] = terrain_set_index;
metadata_dict["terrain_id"] = terrain_index;
@@ -3188,7 +3143,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
HBoxContainer *tilemap_tiles_tools_buttons = memnew(HBoxContainer);
- tool_buttons_group.instance();
+ tool_buttons_group.instantiate();
paint_tool_button = memnew(Button);
paint_tool_button->set_flat(true);
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 8e7d613027..9d849a0df5 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -357,6 +357,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_bind_methods() {
void TileSetAtlasSourceEditor::_inspector_property_selected(String p_property) {
selected_property = p_property;
_update_atlas_view();
+ _update_current_tile_data_editor();
}
void TileSetAtlasSourceEditor::_update_tile_id_label() {
@@ -398,17 +399,315 @@ void TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles() {
}
}
+void TileSetAtlasSourceEditor::_update_atlas_source_inspector() {
+ // Update visibility.
+ bool visible = tools_button_group->get_pressed_button() == tool_setup_atlas_source_button;
+ atlas_source_inspector_label->set_visible(visible);
+ atlas_source_inspector->set_visible(visible);
+}
+
void TileSetAtlasSourceEditor::_update_tile_inspector() {
- bool has_atlas_tile_selected = (tools_button_group->get_pressed_button() == tool_select_button) && !selection.is_empty();
+ // Update visibility.
+ if (tools_button_group->get_pressed_button() == tool_select_button) {
+ if (!selection.is_empty()) {
+ tile_proxy_object->edit(tile_set_atlas_source, selection);
+ }
+ tile_inspector_label->show();
+ tile_inspector->set_visible(!selection.is_empty());
+ tile_inspector_no_tile_selected_label->set_visible(selection.is_empty());
+ } else {
+ tile_inspector_label->hide();
+ tile_inspector->hide();
+ tile_inspector_no_tile_selected_label->hide();
+ }
+}
- // Update the proxy object.
- if (has_atlas_tile_selected) {
- tile_proxy_object->edit(tile_set_atlas_source, selection);
+void TileSetAtlasSourceEditor::_update_tile_data_editors() {
+ String previously_selected;
+ if (tile_data_editors_tree && tile_data_editors_tree->get_selected()) {
+ previously_selected = tile_data_editors_tree->get_selected()->get_metadata(0);
+ }
+
+ tile_data_editors_tree->clear();
+
+ TreeItem *root = tile_data_editors_tree->create_item();
+
+ TreeItem *group;
+#define ADD_TILE_DATA_EDITOR_GROUP(text) \
+ group = tile_data_editors_tree->create_item(root); \
+ group->set_custom_bg_color(0, group_color); \
+ group->set_selectable(0, false); \
+ group->set_disable_folding(true); \
+ group->set_text(0, text);
+
+ TreeItem *item;
+#define ADD_TILE_DATA_EDITOR(parent, text, property) \
+ item = tile_data_editors_tree->create_item(parent); \
+ item->set_text(0, text); \
+ item->set_metadata(0, property); \
+ if (property == previously_selected) { \
+ item->select(0); \
+ }
+
+ // Theming.
+ tile_data_editors_tree->add_theme_constant_override("vseparation", 1);
+ tile_data_editors_tree->add_theme_constant_override("hseparation", 3);
+
+ Color group_color = get_theme_color("prop_category", "Editor");
+
+ // List of editors.
+ // --- Rendering ---
+ ADD_TILE_DATA_EDITOR_GROUP("Rendering");
+
+ ADD_TILE_DATA_EDITOR(group, "Texture Offset", "texture_offset");
+ if (!tile_data_editors.has("texture_offset")) {
+ TileDataTextureOffsetEditor *tile_data_texture_offset_editor = memnew(TileDataTextureOffsetEditor);
+ tile_data_texture_offset_editor->hide();
+ tile_data_texture_offset_editor->setup_property_editor(Variant::VECTOR2, "texture_offset");
+ tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
+ tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_editors["texture_offset"] = tile_data_texture_offset_editor;
+ }
+
+ ADD_TILE_DATA_EDITOR(group, "Modulate", "modulate");
+ if (!tile_data_editors.has("modulate")) {
+ TileDataDefaultEditor *tile_data_modulate_editor = memnew(TileDataDefaultEditor());
+ tile_data_modulate_editor->hide();
+ tile_data_modulate_editor->setup_property_editor(Variant::COLOR, "modulate", "", Color(1.0, 1.0, 1.0, 1.0));
+ tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
+ tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_editors["modulate"] = tile_data_modulate_editor;
+ }
+
+ ADD_TILE_DATA_EDITOR(group, "Z Index", "z_index");
+ if (!tile_data_editors.has("z_index")) {
+ TileDataDefaultEditor *tile_data_z_index_editor = memnew(TileDataDefaultEditor());
+ tile_data_z_index_editor->hide();
+ tile_data_z_index_editor->setup_property_editor(Variant::INT, "z_index");
+ tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
+ tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_editors["z_index"] = tile_data_z_index_editor;
+ }
+
+ ADD_TILE_DATA_EDITOR(group, "Y Sort Origin", "y_sort_origin");
+ if (!tile_data_editors.has("y_sort_origin")) {
+ TileDataYSortEditor *tile_data_y_sort_editor = memnew(TileDataYSortEditor);
+ tile_data_y_sort_editor->hide();
+ tile_data_y_sort_editor->setup_property_editor(Variant::INT, "y_sort_origin");
+ tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
+ tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_editors["y_sort_origin"] = tile_data_y_sort_editor;
+ }
+
+ for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
+ ADD_TILE_DATA_EDITOR(group, vformat("Occlusion Layer %d", i), vformat("occlusion_layer_%d", i));
+ if (!tile_data_editors.has(vformat("occlusion_layer_%d", i))) {
+ TileDataOcclusionShapeEditor *tile_data_occlusion_shape_editor = memnew(TileDataOcclusionShapeEditor());
+ tile_data_occlusion_shape_editor->hide();
+ tile_data_occlusion_shape_editor->set_occlusion_layer(i);
+ tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
+ tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_editors[vformat("occlusion_layer_%d", i)] = tile_data_occlusion_shape_editor;
+ }
+ }
+ for (int i = tile_set->get_occlusion_layers_count(); tile_data_editors.has(vformat("occlusion_layer_%d", i)); i++) {
+ tile_data_editors[vformat("occlusion_layer_%d", i)]->queue_delete();
+ tile_data_editors.erase(vformat("occlusion_layer_%d", i));
+ }
+
+ // --- Rendering ---
+ ADD_TILE_DATA_EDITOR(root, "Terrains", "terrain_set");
+ if (!tile_data_editors.has("terrain_set")) {
+ TileDataTerrainsEditor *tile_data_terrains_editor = memnew(TileDataTerrainsEditor);
+ tile_data_terrains_editor->hide();
+ tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
+ tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_editors["terrain_set"] = tile_data_terrains_editor;
+ }
+
+ // --- Miscellaneous ---
+ ADD_TILE_DATA_EDITOR(root, "Probability", "probability");
+ if (!tile_data_editors.has("probability")) {
+ TileDataDefaultEditor *tile_data_probability_editor = memnew(TileDataDefaultEditor());
+ tile_data_probability_editor->hide();
+ tile_data_probability_editor->setup_property_editor(Variant::FLOAT, "probability", "", 1.0);
+ tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
+ tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_editors["probability"] = tile_data_probability_editor;
+ }
+
+ // --- Physics ---
+ ADD_TILE_DATA_EDITOR_GROUP("Physics");
+ for (int i = 0; i < tile_set->get_physics_layers_count(); i++) {
+ ADD_TILE_DATA_EDITOR(group, vformat("Physics Layer %d", i), vformat("physics_layer_%d", i));
+ if (!tile_data_editors.has(vformat("physics_layer_%d", i))) {
+ TileDataCollisionEditor *tile_data_collision_editor = memnew(TileDataCollisionEditor());
+ tile_data_collision_editor->hide();
+ tile_data_collision_editor->set_physics_layer(i);
+ tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
+ tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_editors[vformat("physics_layer_%d", i)] = tile_data_collision_editor;
+ }
+ }
+ for (int i = tile_set->get_physics_layers_count(); tile_data_editors.has(vformat("physics_layer_%d", i)); i++) {
+ tile_data_editors[vformat("physics_layer_%d", i)]->queue_delete();
+ tile_data_editors.erase(vformat("physics_layer_%d", i));
+ }
+
+ // --- Navigation ---
+ ADD_TILE_DATA_EDITOR_GROUP("Navigation");
+ for (int i = 0; i < tile_set->get_navigation_layers_count(); i++) {
+ ADD_TILE_DATA_EDITOR(group, vformat("Navigation Layer %d", i), vformat("navigation_layer_%d", i));
+ if (!tile_data_editors.has(vformat("navigation_layer_%d", i))) {
+ TileDataNavigationEditor *tile_data_navigation_editor = memnew(TileDataNavigationEditor());
+ tile_data_navigation_editor->hide();
+ tile_data_navigation_editor->set_navigation_layer(i);
+ tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
+ tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_editors[vformat("navigation_layer_%d", i)] = tile_data_navigation_editor;
+ }
+ }
+ for (int i = tile_set->get_navigation_layers_count(); tile_data_editors.has(vformat("navigation_layer_%d", i)); i++) {
+ tile_data_editors[vformat("navigation_layer_%d", i)]->queue_delete();
+ tile_data_editors.erase(vformat("navigation_layer_%d", i));
+ }
+
+ // --- Custom Data ---
+ ADD_TILE_DATA_EDITOR_GROUP("Custom Data");
+ for (int i = 0; i < tile_set->get_custom_data_layers_count(); i++) {
+ if (tile_set->get_custom_data_name(i).is_empty()) {
+ ADD_TILE_DATA_EDITOR(group, vformat("Custom Data %d", i), vformat("custom_data_%d", i));
+ } else {
+ ADD_TILE_DATA_EDITOR(group, tile_set->get_custom_data_name(i), vformat("custom_data_%d", i));
+ }
+ if (!tile_data_editors.has(vformat("custom_data_%d", i))) {
+ TileDataDefaultEditor *tile_data_custom_data_editor = memnew(TileDataDefaultEditor());
+ tile_data_custom_data_editor->hide();
+ tile_data_custom_data_editor->setup_property_editor(tile_set->get_custom_data_type(i), vformat("custom_data_%d", i), tile_set->get_custom_data_name(i));
+ tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
+ tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_editors[vformat("custom_data_%d", i)] = tile_data_custom_data_editor;
+ }
+ }
+ for (int i = tile_set->get_custom_data_layers_count(); tile_data_editors.has(vformat("custom_data_%d", i)); i++) {
+ tile_data_editors[vformat("custom_data_%d", i)]->queue_delete();
+ tile_data_editors.erase(vformat("custom_data_%d", i));
+ }
+
+#undef ADD_TILE_DATA_EDITOR_GROUP
+#undef ADD_TILE_DATA_EDITOR
+
+ // Add tile data editors as children.
+ for (Map<String, TileDataEditor *>::Element *E = tile_data_editors.front(); E; E = E->next()) {
+ // Tile Data Editor.
+ TileDataEditor *tile_data_editor = E->get();
+ if (!tile_data_editor->is_inside_tree()) {
+ tile_data_painting_editor_container->add_child(tile_data_editor);
+ }
+ tile_data_editor->set_tile_set(tile_set);
+
+ // Toolbar.
+ Control *toolbar = tile_data_editor->get_toolbar();
+ if (!toolbar->is_inside_tree()) {
+ tool_settings_tile_data_toolbar_container->add_child(toolbar);
+ }
+ toolbar->hide();
}
// Update visibility.
- tile_inspector_label->set_visible(has_atlas_tile_selected);
- tile_inspector->set_visible(has_atlas_tile_selected);
+ bool is_visible = tools_button_group->get_pressed_button() == tool_paint_button;
+ tile_data_editor_dropdown_button->set_visible(is_visible);
+ tile_data_editor_dropdown_button->set_text(TTR("Select a property editor"));
+ tile_data_editors_label->set_visible(is_visible);
+}
+
+void TileSetAtlasSourceEditor::_update_current_tile_data_editor() {
+ // Find the property to use.
+ String property;
+ if (tools_button_group->get_pressed_button() == tool_select_button && tile_inspector->is_visible() && !tile_inspector->get_selected_path().is_empty()) {
+ Vector<String> components = tile_inspector->get_selected_path().split("/");
+ if (components.size() >= 1) {
+ property = components[0];
+
+ // Workaround for terrains as they don't have a common first component.
+ if (property.begins_with("terrains_")) {
+ property = "terrain_set";
+ }
+ }
+ } else if (tools_button_group->get_pressed_button() == tool_paint_button && tile_data_editors_tree->get_selected()) {
+ property = tile_data_editors_tree->get_selected()->get_metadata(0);
+ tile_data_editor_dropdown_button->set_text(tile_data_editors_tree->get_selected()->get_text(0));
+ }
+
+ // Hide all editors but the current one.
+ for (Map<String, TileDataEditor *>::Element *E = tile_data_editors.front(); E; E = E->next()) {
+ E->get()->hide();
+ E->get()->get_toolbar()->hide();
+ }
+ if (tile_data_editors.has(property)) {
+ current_tile_data_editor = tile_data_editors[property];
+ } else {
+ current_tile_data_editor = nullptr;
+ }
+
+ // Get the correct editor for the TileData's property.
+ if (current_tile_data_editor) {
+ current_tile_data_editor_toolbar = current_tile_data_editor->get_toolbar();
+ current_property = property;
+ current_tile_data_editor->set_visible(tools_button_group->get_pressed_button() == tool_paint_button);
+ current_tile_data_editor_toolbar->set_visible(tools_button_group->get_pressed_button() == tool_paint_button);
+ }
+}
+
+void TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_draw() {
+ if (!has_theme_icon("arrow", "OptionButton")) {
+ return;
+ }
+
+ RID ci = tile_data_editor_dropdown_button->get_canvas_item();
+ Ref<Texture2D> arrow = Control::get_theme_icon("arrow", "OptionButton");
+ Color clr = Color(1, 1, 1);
+ if (get_theme_constant("modulate_arrow")) {
+ switch (tile_data_editor_dropdown_button->get_draw_mode()) {
+ case BaseButton::DRAW_PRESSED:
+ clr = get_theme_color("font_pressed_color");
+ break;
+ case BaseButton::DRAW_HOVER:
+ clr = get_theme_color("font_hover_color");
+ break;
+ case BaseButton::DRAW_DISABLED:
+ clr = get_theme_color("font_disabled_color");
+ break;
+ default:
+ clr = get_theme_color("font_color");
+ }
+ }
+
+ Size2 size = tile_data_editor_dropdown_button->get_size();
+
+ Point2 ofs;
+ if (is_layout_rtl()) {
+ ofs = Point2(get_theme_constant("arrow_margin", "OptionButton"), int(Math::abs((size.height - arrow->get_height()) / 2)));
+ } else {
+ ofs = Point2(size.width - arrow->get_width() - get_theme_constant("arrow_margin", "OptionButton"), int(Math::abs((size.height - arrow->get_height()) / 2)));
+ }
+ arrow->draw(ci, ofs, clr);
+}
+
+void TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed() {
+ Size2 size = tile_data_editor_dropdown_button->get_size();
+ tile_data_editors_popup->set_position(tile_data_editor_dropdown_button->get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y));
+ tile_data_editors_popup->set_size(Size2(size.width, 0));
+ tile_data_editors_popup->popup();
+}
+
+void TileSetAtlasSourceEditor::_tile_data_editors_tree_selected() {
+ tile_data_editors_popup->call_deferred("hide");
+ _update_current_tile_data_editor();
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
}
void TileSetAtlasSourceEditor::_update_atlas_view() {
@@ -467,19 +766,28 @@ void TileSetAtlasSourceEditor::_update_atlas_view() {
}
void TileSetAtlasSourceEditor::_update_toolbar() {
- // Hide all settings.
- for (int i = 0; i < tool_settings->get_child_count(); i++) {
- Object::cast_to<CanvasItem>(tool_settings->get_child(i))->hide();
- }
-
- // SHow only the correct settings.
- if (tools_button_group->get_pressed_button() == tool_select_button) {
- } else if (tools_button_group->get_pressed_button() == tool_add_remove_button) {
- tool_settings_vsep->show();
- tools_settings_erase_button->show();
- } else if (tools_button_group->get_pressed_button() == tool_add_remove_rect_button) {
+ // Show the tools and settings.
+ if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) {
+ if (current_tile_data_editor_toolbar) {
+ current_tile_data_editor_toolbar->hide();
+ }
tool_settings_vsep->show();
tools_settings_erase_button->show();
+ tool_advanced_menu_buttom->show();
+ } else if (tools_button_group->get_pressed_button() == tool_select_button) {
+ if (current_tile_data_editor_toolbar) {
+ current_tile_data_editor_toolbar->hide();
+ }
+ tool_settings_vsep->hide();
+ tools_settings_erase_button->hide();
+ tool_advanced_menu_buttom->hide();
+ } else if (tools_button_group->get_pressed_button() == tool_paint_button) {
+ if (current_tile_data_editor_toolbar) {
+ current_tile_data_editor_toolbar->show();
+ }
+ tool_settings_vsep->hide();
+ tools_settings_erase_button->hide();
+ tool_advanced_menu_buttom->hide();
}
}
@@ -499,357 +807,336 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Update the hovered coords.
hovered_base_tile_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
- // Handle the event.
- Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid()) {
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ // Forward the event to the current tile data editor if we are in the painting mode.
+ if (tools_button_group->get_pressed_button() == tool_paint_button) {
+ if (current_tile_data_editor) {
+ current_tile_data_editor->forward_painting_atlas_gui_input(tile_atlas_view, tile_set_atlas_source, p_event);
+ }
+ // Update only what's needed.
+ tile_set_atlas_source_changed_needs_update = false;
- Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+ tile_atlas_view->update();
+ return;
+ } else {
+ // Handle the event.
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
- if (drag_type == DRAG_TYPE_NONE) {
- if (selection.size() == 1) {
- // Change the cursor depending on the hovered thing.
- TileSelection selected = selection.front()->get();
- if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
- Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
- Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
- Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
- Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
- Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
- const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
- const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
- CursorShape cursor_shape = CURSOR_ARROW;
- bool can_grow[4];
- for (int i = 0; i < 4; i++) {
- can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]);
- can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
- }
- for (int i = 0; i < 4; i++) {
- Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i];
- if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
- cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
+ Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
+
+ if (drag_type == DRAG_TYPE_NONE) {
+ if (selection.size() == 1) {
+ // Change the cursor depending on the hovered thing.
+ TileSelection selected = selection.front()->get();
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
+ Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
+ Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
+ Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
+ Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
+ Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
+ const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
+ const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
+ CursorShape cursor_shape = CURSOR_ARROW;
+ bool can_grow[4];
+ for (int i = 0; i < 4; i++) {
+ can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]);
+ can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
}
- Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4];
- if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
- cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
+ for (int i = 0; i < 4; i++) {
+ Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i];
+ if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
+ cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
+ }
+ Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4];
+ if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
+ cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
+ }
}
+ tile_atlas_control->set_default_cursor_shape(cursor_shape);
}
- tile_atlas_control->set_default_cursor_shape(cursor_shape);
}
- }
- } else if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) {
- // Create big tile.
- new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
-
- Rect2i new_rect = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
- new_rect.size += Vector2i(1, 1);
- // Check if the new tile can fit in the new rect.
- if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) {
- // Move and resize the tile.
- tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size);
- drag_current_tile = new_rect.position;
- }
- } else if (drag_type == DRAG_TYPE_CREATE_TILES) {
- // Create tiles.
- last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
- new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
-
- Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords);
- for (int i = 0; i < line.size(); i++) {
- if (tile_set_atlas_source->get_tile_at_coords(line[i]) == TileSetSource::INVALID_ATLAS_COORDS) {
- tile_set_atlas_source->create_tile(line[i]);
- drag_modified_tiles.insert(line[i]);
+ } else if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) {
+ // Create big tile.
+ new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+
+ Rect2i new_rect = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
+ new_rect.size += Vector2i(1, 1);
+ // Check if the new tile can fit in the new rect.
+ if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) {
+ // Move and resize the tile.
+ tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size);
+ drag_current_tile = new_rect.position;
+ }
+ } else if (drag_type == DRAG_TYPE_CREATE_TILES) {
+ // Create tiles.
+ last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+ new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+
+ Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords);
+ for (int i = 0; i < line.size(); i++) {
+ if (tile_set_atlas_source->get_tile_at_coords(line[i]) == TileSetSource::INVALID_ATLAS_COORDS) {
+ tile_set_atlas_source->create_tile(line[i]);
+ drag_modified_tiles.insert(line[i]);
+ }
}
- }
- drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position();
+ drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position();
- } else if (drag_type == DRAG_TYPE_REMOVE_TILES) {
- // Remove tiles.
- last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
- new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+ } else if (drag_type == DRAG_TYPE_REMOVE_TILES) {
+ // Remove tiles.
+ last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+ new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
- Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords);
- for (int i = 0; i < line.size(); i++) {
- Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(line[i]);
- if (base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
- drag_modified_tiles.insert(base_tile_coords);
+ Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords);
+ for (int i = 0; i < line.size(); i++) {
+ Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(line[i]);
+ if (base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ drag_modified_tiles.insert(base_tile_coords);
+ }
}
- }
- drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position();
- } else if (drag_type == DRAG_TYPE_MOVE_TILE) {
- // Move tile.
- Vector2 mouse_offset = (Vector2(tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
- Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() - mouse_offset);
- coords = coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
- if (drag_current_tile != coords && tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, coords)) {
- tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, coords);
- selection.clear();
- selection.insert({ coords, 0 });
- drag_current_tile = coords;
+ drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position();
+ } else if (drag_type == DRAG_TYPE_MOVE_TILE) {
+ // Move tile.
+ Vector2 mouse_offset = (Vector2(tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() - mouse_offset);
+ coords = coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+ if (drag_current_tile != coords && tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, coords)) {
+ tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, coords);
+ selection.clear();
+ selection.insert({ coords, 0 });
+ drag_current_tile = coords;
- // Update only what's needed.
- tile_set_atlas_source_changed_needs_update = false;
- _update_tile_inspector();
- _update_atlas_view();
- _update_tile_id_label();
- }
- } else if (drag_type >= DRAG_TYPE_RESIZE_TOP_LEFT && drag_type <= DRAG_TYPE_RESIZE_LEFT) {
- // Resizing a tile.
- new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(-1, -1)).min(grid_size);
+ // Update only what's needed.
+ tile_set_atlas_source_changed_needs_update = false;
+ _update_tile_inspector();
+ _update_atlas_view();
+ _update_tile_id_label();
+ _update_current_tile_data_editor();
+ }
+ } else if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) {
+ if (Vector2(drag_start_mouse_pos).distance_to(tile_atlas_control->get_local_mouse_position()) > 5.0 * EDSCALE) {
+ drag_type = DRAG_TYPE_NONE;
+ }
+ } else if (drag_type >= DRAG_TYPE_RESIZE_TOP_LEFT && drag_type <= DRAG_TYPE_RESIZE_LEFT) {
+ // Resizing a tile.
+ new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(-1, -1)).min(grid_size);
- Rect2i old_rect = Rect2i(drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile));
- Rect2i new_rect = old_rect;
+ Rect2i old_rect = Rect2i(drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile));
+ Rect2i new_rect = old_rect;
- if (drag_type == DRAG_TYPE_RESIZE_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT) {
- new_rect.position.x = MIN(new_base_tiles_coords.x + 1, old_rect.get_end().x - 1);
- new_rect.size.x = old_rect.get_end().x - new_rect.position.x;
- }
- if (drag_type == DRAG_TYPE_RESIZE_TOP || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT) {
- new_rect.position.y = MIN(new_base_tiles_coords.y + 1, old_rect.get_end().y - 1);
- new_rect.size.y = old_rect.get_end().y - new_rect.position.y;
- }
+ if (drag_type == DRAG_TYPE_RESIZE_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT) {
+ new_rect.position.x = MIN(new_base_tiles_coords.x + 1, old_rect.get_end().x - 1);
+ new_rect.size.x = old_rect.get_end().x - new_rect.position.x;
+ }
+ if (drag_type == DRAG_TYPE_RESIZE_TOP || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT) {
+ new_rect.position.y = MIN(new_base_tiles_coords.y + 1, old_rect.get_end().y - 1);
+ new_rect.size.y = old_rect.get_end().y - new_rect.position.y;
+ }
- if (drag_type == DRAG_TYPE_RESIZE_RIGHT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) {
- new_rect.set_end(Vector2i(MAX(new_base_tiles_coords.x, old_rect.position.x + 1), new_rect.get_end().y));
- }
- if (drag_type == DRAG_TYPE_RESIZE_BOTTOM || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) {
- new_rect.set_end(Vector2i(new_rect.get_end().x, MAX(new_base_tiles_coords.y, old_rect.position.y + 1)));
- }
+ if (drag_type == DRAG_TYPE_RESIZE_RIGHT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) {
+ new_rect.set_end(Vector2i(MAX(new_base_tiles_coords.x, old_rect.position.x + 1), new_rect.get_end().y));
+ }
+ if (drag_type == DRAG_TYPE_RESIZE_BOTTOM || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) {
+ new_rect.set_end(Vector2i(new_rect.get_end().x, MAX(new_base_tiles_coords.y, old_rect.position.y + 1)));
+ }
- if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) {
- tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size);
- selection.clear();
- selection.insert({ new_rect.position, 0 });
- drag_current_tile = new_rect.position;
+ if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) {
+ tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size);
+ selection.clear();
+ selection.insert({ new_rect.position, 0 });
+ drag_current_tile = new_rect.position;
- // Update only what's needed.
- tile_set_atlas_source_changed_needs_update = false;
- _update_tile_inspector();
- _update_atlas_view();
- _update_tile_id_label();
+ // Update only what's needed.
+ tile_set_atlas_source_changed_needs_update = false;
+ _update_tile_inspector();
+ _update_atlas_view();
+ _update_tile_id_label();
+ _update_current_tile_data_editor();
+ }
}
+
+ // Redraw for the hovered tile.
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+ tile_atlas_view->update();
+ return;
}
- // Redraw for the hovered tile.
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
- return;
- }
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ // Left click pressed.
+ if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) {
+ if (tools_settings_erase_button->is_pressed()) {
+ // Erasing
+ if (mb->is_ctrl_pressed() || mb->is_shift_pressed()) {
+ // Remove tiles using rect.
+
+ // Setup the dragging info.
+ drag_type = DRAG_TYPE_REMOVE_TILES_USING_RECT;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ } else {
+ // Remove tiles.
- Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid()) {
- Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (mb->is_pressed()) {
- // Left click pressed.
- if (tools_button_group->get_pressed_button() == tool_add_remove_button) {
- if (tools_settings_erase_button->is_pressed()) {
- // Remove tiles.
-
- // Setup the dragging info.
- drag_type = DRAG_TYPE_REMOVE_TILES;
- drag_start_mouse_pos = mouse_local_pos;
- drag_last_mouse_pos = drag_start_mouse_pos;
-
- // Remove a first tile.
- Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
- coords = tile_set_atlas_source->get_tile_at_coords(coords);
- }
- if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
- drag_modified_tiles.insert(coords);
- }
- } else {
- if (mb->is_shift_pressed()) {
- // Create a big tile.
- Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos);
- if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
- // Setup the dragging info, only if we start on an empty tile.
- drag_type = DRAG_TYPE_CREATE_BIG_TILE;
+ // Setup the dragging info.
+ drag_type = DRAG_TYPE_REMOVE_TILES;
drag_start_mouse_pos = mouse_local_pos;
drag_last_mouse_pos = drag_start_mouse_pos;
- drag_current_tile = coords;
- // Create a tile.
- tile_set_atlas_source->create_tile(coords);
+ // Remove a first tile.
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ coords = tile_set_atlas_source->get_tile_at_coords(coords);
+ }
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ drag_modified_tiles.insert(coords);
+ }
}
} else {
- // Create tiles.
-
- // Setup the dragging info.
- drag_type = DRAG_TYPE_CREATE_TILES;
- drag_start_mouse_pos = mouse_local_pos;
- drag_last_mouse_pos = drag_start_mouse_pos;
-
- // Create a first tile if needed.
- Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
- tile_set_atlas_source->create_tile(coords);
- drag_modified_tiles.insert(coords);
- }
- }
- }
- } else if (tools_button_group->get_pressed_button() == tool_add_remove_rect_button) {
- if (tools_settings_erase_button->is_pressed()) {
- // Remove tiles using rect.
-
- // Setup the dragging info.
- drag_type = DRAG_TYPE_REMOVE_TILES_USING_RECT;
- drag_start_mouse_pos = mouse_local_pos;
- drag_last_mouse_pos = drag_start_mouse_pos;
- } else {
- if (mb->is_shift_pressed()) {
- // Create a big tile.
- Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos);
- if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
- // Setup the dragging info, only if we start on an empty tile.
- drag_type = DRAG_TYPE_CREATE_BIG_TILE;
+ // Creating
+ if (mb->is_shift_pressed()) {
+ // Create a big tile.
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
+ // Setup the dragging info, only if we start on an empty tile.
+ drag_type = DRAG_TYPE_CREATE_BIG_TILE;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ drag_current_tile = coords;
+
+ // Create a tile.
+ tile_set_atlas_source->create_tile(coords);
+ }
+ } else if (mb->is_ctrl_pressed()) {
+ // Create tiles using rect.
+ drag_type = DRAG_TYPE_CREATE_TILES_USING_RECT;
drag_start_mouse_pos = mouse_local_pos;
drag_last_mouse_pos = drag_start_mouse_pos;
- drag_current_tile = coords;
+ } else {
+ // Create tiles.
- // Create a tile.
- tile_set_atlas_source->create_tile(coords);
+ // Setup the dragging info.
+ drag_type = DRAG_TYPE_CREATE_TILES;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+
+ // Create a first tile if needed.
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
+ tile_set_atlas_source->create_tile(coords);
+ drag_modified_tiles.insert(coords);
+ }
}
- } else {
- // Create tiles using rect.
- drag_type = DRAG_TYPE_CREATE_TILES_USING_RECT;
- drag_start_mouse_pos = mouse_local_pos;
- drag_last_mouse_pos = drag_start_mouse_pos;
}
- }
- } else if (tools_button_group->get_pressed_button() == tool_select_button) {
- // Dragging a handle.
- drag_type = DRAG_TYPE_NONE;
- if (selection.size() == 1) {
- TileSelection selected = selection.front()->get();
- if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
- Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
- Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
- Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
- Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
- const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
- const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
- CursorShape cursor_shape = CURSOR_ARROW;
- bool can_grow[4];
- for (int i = 0; i < 4; i++) {
- can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]);
- can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
- }
- for (int i = 0; i < 4; i++) {
- Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i];
- if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
- drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP_LEFT + i * 2);
- drag_start_mouse_pos = mouse_local_pos;
- drag_last_mouse_pos = drag_start_mouse_pos;
- drag_current_tile = selected.tile;
- drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
- cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
+ } else if (tools_button_group->get_pressed_button() == tool_select_button) {
+ // Dragging a handle.
+ drag_type = DRAG_TYPE_NONE;
+ if (selection.size() == 1) {
+ TileSelection selected = selection.front()->get();
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
+ Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
+ Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
+ Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
+ Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
+ const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
+ const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
+ CursorShape cursor_shape = CURSOR_ARROW;
+ bool can_grow[4];
+ for (int i = 0; i < 4; i++) {
+ can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]);
+ can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
}
- Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4];
- if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
- drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP + i * 2);
- drag_start_mouse_pos = mouse_local_pos;
- drag_last_mouse_pos = drag_start_mouse_pos;
- drag_current_tile = selected.tile;
- drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
- cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
+ for (int i = 0; i < 4; i++) {
+ Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i];
+ if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
+ drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP_LEFT + i * 2);
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ drag_current_tile = selected.tile;
+ drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
+ cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
+ }
+ Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4];
+ if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
+ drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP + i * 2);
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ drag_current_tile = selected.tile;
+ drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
+ cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
+ }
}
+ tile_atlas_control->set_default_cursor_shape(cursor_shape);
}
- tile_atlas_control->set_default_cursor_shape(cursor_shape);
}
- }
- // Selecting then dragging a tile.
- if (drag_type == DRAG_TYPE_NONE) {
- TileSelection selected = { TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE };
- Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos);
- if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
- coords = tile_set_atlas_source->get_tile_at_coords(coords);
+ // Selecting then dragging a tile.
+ if (drag_type == DRAG_TYPE_NONE) {
+ TileSelection selected = { TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE };
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
- selected = { coords, 0 };
+ coords = tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ selected = { coords, 0 };
+ }
}
- }
- bool shift = mb->is_shift_pressed();
- if (!shift && selection.size() == 1 && selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) {
- // Start move dragging.
- drag_type = DRAG_TYPE_MOVE_TILE;
- drag_start_mouse_pos = mouse_local_pos;
- drag_last_mouse_pos = drag_start_mouse_pos;
- drag_current_tile = selected.tile;
- drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
- tile_atlas_control->set_default_cursor_shape(CURSOR_MOVE);
- } else {
- // Start selection dragging.
- drag_type = DRAG_TYPE_RECT_SELECT;
- drag_start_mouse_pos = mouse_local_pos;
- drag_last_mouse_pos = drag_start_mouse_pos;
+ bool shift = mb->is_shift_pressed();
+ if (!shift && selection.size() == 1 && selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) {
+ // Start move dragging.
+ drag_type = DRAG_TYPE_MOVE_TILE;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ drag_current_tile = selected.tile;
+ drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
+ tile_atlas_control->set_default_cursor_shape(CURSOR_MOVE);
+ } else {
+ // Start selection dragging.
+ drag_type = DRAG_TYPE_RECT_SELECT;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ }
}
}
+ } else {
+ // Left click released.
+ _end_dragging();
}
- } else {
- // Left click released.
- _end_dragging();
- }
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
- return;
- } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
- if (mb->is_pressed()) {
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+ tile_atlas_view->update();
+ return;
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
// Right click pressed.
-
- TileSelection selected = { tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos), 0 };
- if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
- selected.tile = tile_set_atlas_source->get_tile_at_coords(selected.tile);
- }
-
- // Set the selection if needed.
- if (selection.size() <= 1) {
- if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
- undo_redo->create_action(TTR("Select tiles"));
- undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
- selection.clear();
- selection.insert(selected);
- undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array());
- undo_redo->commit_action(false);
- _update_tile_inspector();
- _update_tile_id_label();
- }
- }
-
- // Pops up the correct menu, depending on whether we have a tile or not.
- if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) {
- // We have a tile.
- menu_option_coords = selected.tile;
- menu_option_alternative = 0;
- base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
- } else if (hovered_base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
- // We don't have a tile, but can create one.
- menu_option_coords = hovered_base_tile_coords;
- menu_option_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE;
- empty_base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ if (mb->is_pressed()) {
+ drag_type = DRAG_TYPE_MAY_POPUP_MENU;
+ drag_start_mouse_pos = tile_atlas_control->get_local_mouse_position();
+ } else {
+ // Right click released.
+ _end_dragging();
}
- } else {
- // Right click released.
- _end_dragging();
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+ tile_atlas_view->update();
+ return;
}
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
- return;
}
}
}
@@ -1000,10 +1287,45 @@ void TileSetAtlasSourceEditor::_end_dragging() {
}
_update_tile_inspector();
_update_tile_id_label();
+ _update_current_tile_data_editor();
undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array());
undo_redo->commit_action(false);
- break;
- }
+ } break;
+ case DRAG_TYPE_MAY_POPUP_MENU: {
+ Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
+ TileSelection selected = { tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos), 0 };
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
+ selected.tile = tile_set_atlas_source->get_tile_at_coords(selected.tile);
+ }
+
+ // Set the selection if needed.
+ if (selection.size() <= 1) {
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
+ undo_redo->create_action(TTR("Select tiles"));
+ undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
+ selection.clear();
+ selection.insert(selected);
+ undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array());
+ undo_redo->commit_action(false);
+ _update_tile_inspector();
+ _update_tile_id_label();
+ _update_current_tile_data_editor();
+ }
+ }
+
+ // Pops up the correct menu, depending on whether we have a tile or not.
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) {
+ // We have a tile.
+ menu_option_coords = selected.tile;
+ menu_option_alternative = 0;
+ base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ } else if (hovered_base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ // We don't have a tile, but can create one.
+ menu_option_coords = hovered_base_tile_coords;
+ menu_option_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ empty_base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ }
+ } break;
case DRAG_TYPE_RESIZE_TOP_LEFT:
case DRAG_TYPE_RESIZE_TOP:
case DRAG_TYPE_RESIZE_TOP_RIGHT:
@@ -1040,7 +1362,7 @@ Map<Vector2i, List<const PropertyInfo *>> TileSetAtlasSourceEditor::_group_prope
Vector<String> components = String(E_property->get().name).split("/", true, 1);
if (components.size() >= 1) {
Vector<String> coord_arr = components[0].split(":");
- if (coord_arr.size() == 2 && coord_arr[0].is_valid_integer() && coord_arr[1].is_valid_integer()) {
+ if (coord_arr.size() == 2 && coord_arr[0].is_valid_int() && coord_arr[1].is_valid_int()) {
Vector2i coords = Vector2i(coord_arr[0].to_int(), coord_arr[1].to_int());
per_tile[coords].push_back(&(E_property->get()));
}
@@ -1088,7 +1410,7 @@ void TileSetAtlasSourceEditor::_menu_option(int p_option) {
if (per_tile.has(selected.tile)) {
for (List<const PropertyInfo *>::Element *E_property = per_tile[selected.tile].front(); E_property; E_property = E_property->next()) {
Vector<String> components = E_property->get()->name.split("/", true, 2);
- if (components.size() >= 2 && components[1].is_valid_integer() && components[1].to_int() == selected.alternative) {
+ if (components.size() >= 2 && components[1].is_valid_int() && components[1].to_int() == selected.alternative) {
String property = E_property->get()->name;
Variant value = tile_set_atlas_source->get(property);
if (value.get_type() != Variant::NIL) {
@@ -1166,6 +1488,7 @@ void TileSetAtlasSourceEditor::_set_selection_from_array(Array p_selection) {
_update_tile_inspector();
_update_tile_id_label();
_update_atlas_view();
+ _update_current_tile_data_editor();
}
Array TileSetAtlasSourceEditor::_get_selection_as_array() {
@@ -1297,7 +1620,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(hovered_tile), Color(1.0, 1.0, 1.0), false);
} else {
// Draw empty tile, only in add/remove tiles mode.
- if (tools_button_group->get_pressed_button() == tool_add_remove_button || tools_button_group->get_pressed_button() == tool_add_remove_rect_button) {
+ if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) {
Vector2i margins = tile_set_atlas_source->get_margins();
Vector2i separation = tile_set_atlas_source->get_separation();
Vector2i tile_size = tile_set_atlas_source->get_texture_region_size();
@@ -1310,9 +1633,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
}
void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() {
- // Draw the preview of the selected property.
- TileDataEditor *tile_data_editor = TileSetEditor::get_singleton()->get_tile_data_editor(selected_property);
- if (tile_data_editor && tile_inspector->is_visible_in_tree()) {
+ if (current_tile_data_editor) {
+ // Draw the preview of the selected property.
for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
Vector2i coords = tile_set_atlas_source->get_tile_id(i);
Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(coords);
@@ -1321,7 +1643,41 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() {
Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
xform.translate(position);
- tile_data_editor->draw_over_tile(tile_atlas_control_unscaled, xform, *tile_set, tile_set_atlas_source_id, coords, 0, selected_property);
+ if (tools_button_group->get_pressed_button() == tool_select_button && selection.has({ coords, 0 })) {
+ continue;
+ }
+
+ TileMapCell cell;
+ cell.source_id = tile_set_atlas_source_id;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = 0;
+ current_tile_data_editor->draw_over_tile(tile_atlas_control_unscaled, xform, cell);
+ }
+
+ // Draw the selection on top of other.
+ if (tools_button_group->get_pressed_button() == tool_select_button) {
+ for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) {
+ if (E->get().alternative != 0) {
+ continue;
+ }
+ Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(E->get().tile);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(E->get().tile, 0);
+
+ Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
+ xform.translate(position);
+
+ TileMapCell cell;
+ cell.source_id = tile_set_atlas_source_id;
+ cell.set_atlas_coords(E->get().tile);
+ cell.alternative_tile = 0;
+ current_tile_data_editor->draw_over_tile(tile_atlas_control_unscaled, xform, cell, true);
+ }
+ }
+
+ // Call the TileData's editor custom draw function.
+ if (tools_button_group->get_pressed_button() == tool_paint_button) {
+ Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
+ current_tile_data_editor->forward_draw_over_atlas(tile_atlas_view, tile_set_atlas_source, tile_atlas_control_unscaled, xform);
}
}
}
@@ -1330,6 +1686,19 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
// Update the hovered alternative tile.
hovered_alternative_tile_coords = tile_atlas_view->get_alternative_tile_at_pos(alternative_tiles_control->get_local_mouse_position());
+ // Forward the event to the current tile data editor if we are in the painting mode.
+ if (tools_button_group->get_pressed_button() == tool_paint_button) {
+ if (current_tile_data_editor) {
+ current_tile_data_editor->forward_painting_alternatives_gui_input(tile_atlas_view, tile_set_atlas_source, p_event);
+ }
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+ tile_atlas_view->update();
+ return;
+ }
+
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
tile_atlas_control->update();
@@ -1425,7 +1794,60 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() {
}
void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() {
- //TODO
+ // Draw the preview of the selected property.
+ if (current_tile_data_editor) {
+ // Draw the preview of the currently selected property.
+ for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i coords = tile_set_atlas_source->get_tile_id(i);
+ for (int j = 0; j < tile_set_atlas_source->get_alternative_tiles_count(coords); j++) {
+ int alternative_tile = tile_set_atlas_source->get_alternative_tile_id(coords, j);
+ if (alternative_tile == 0) {
+ continue;
+ }
+ Rect2i rect = tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
+ Vector2 position = (rect.get_position() + rect.get_end()) / 2;
+
+ Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform();
+ xform.translate(position);
+
+ if (tools_button_group->get_pressed_button() == tool_select_button && selection.has({ coords, alternative_tile })) {
+ continue;
+ }
+
+ TileMapCell cell;
+ cell.source_id = tile_set_atlas_source_id;
+ cell.set_atlas_coords(coords);
+ cell.alternative_tile = alternative_tile;
+ current_tile_data_editor->draw_over_tile(alternative_tiles_control_unscaled, xform, cell);
+ }
+ }
+
+ // Draw the selection on top of other.
+ if (tools_button_group->get_pressed_button() == tool_select_button) {
+ for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) {
+ if (E->get().alternative == 0) {
+ continue;
+ }
+ Rect2i rect = tile_atlas_view->get_alternative_tile_rect(E->get().tile, E->get().alternative);
+ Vector2 position = (rect.get_position() + rect.get_end()) / 2;
+
+ Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform();
+ xform.translate(position);
+
+ TileMapCell cell;
+ cell.source_id = tile_set_atlas_source_id;
+ cell.set_atlas_coords(E->get().tile);
+ cell.alternative_tile = E->get().alternative;
+ current_tile_data_editor->draw_over_tile(alternative_tiles_control_unscaled, xform, cell, true);
+ }
+ }
+
+ // Call the TileData's editor custom draw function.
+ if (tools_button_group->get_pressed_button() == tool_paint_button) {
+ Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
+ current_tile_data_editor->forward_draw_over_alternatives(tile_atlas_view, tile_set_atlas_source, alternative_tiles_control_unscaled, xform);
+ }
+ }
}
void TileSetAtlasSourceEditor::_tile_set_atlas_source_changed() {
@@ -1449,15 +1871,23 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
AtlasTileProxyObject *tile_data = Object::cast_to<AtlasTileProxyObject>(p_edited);
if (tile_data) {
Vector<String> components = String(p_property).split("/", true, 2);
- if (components.size() == 2 && components[1] == "shapes_count") {
+ if (components.size() == 2 && components[1] == "polygons_count") {
int layer_index = components[0].trim_prefix("physics_layer_").to_int();
- int new_shapes_count = p_new_value;
- int old_shapes_count = tile_data->get(vformat("physics_layer_%d/shapes_count", layer_index));
- if (new_shapes_count < old_shapes_count) {
- for (int i = new_shapes_count - 1; i < old_shapes_count; i++) {
- ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/shape", layer_index, i));
- ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way", layer_index, i));
- ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way_margin", layer_index, i));
+ int new_polygons_count = p_new_value;
+ int old_polygons_count = tile_data->get(vformat("physics_layer_%d/polygons_count", layer_index));
+ if (new_polygons_count < old_polygons_count) {
+ for (int i = new_polygons_count - 1; i < old_polygons_count; i++) {
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/points", layer_index, i));
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way", layer_index, i));
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way_margin", layer_index, i));
+ }
+ }
+ } else if (p_property == "terrain_set") {
+ int current_terrain_set = tile_data->get("terrain_set");
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(current_terrain_set, bit)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
}
}
}
@@ -1500,7 +1930,10 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource
_update_fix_selected_and_hovered_tiles();
_update_tile_id_label();
_update_atlas_view();
+ _update_atlas_source_inspector();
_update_tile_inspector();
+ _update_tile_data_editors();
+ _update_current_tile_data_editor();
}
void TileSetAtlasSourceEditor::init_source() {
@@ -1616,13 +2049,13 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED:
+ tool_setup_atlas_source_button->set_icon(get_theme_icon("Tools", "EditorIcons"));
tool_select_button->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
- tool_add_remove_button->set_icon(get_theme_icon("EditAddRemove", "EditorIcons"));
- tool_add_remove_rect_button->set_icon(get_theme_icon("RectangleAddRemove", "EditorIcons"));
+ tool_paint_button->set_icon(get_theme_icon("CanvasItem", "EditorIcons"));
tools_settings_erase_button->set_icon(get_theme_icon("Eraser", "EditorIcons"));
- tool_advanced_menu_buttom->set_icon(get_theme_icon("Tools", "EditorIcons"));
+ tool_advanced_menu_buttom->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons"));
resize_handle = get_theme_icon("EditorHandle", "EditorIcons");
resize_handle_disabled = get_theme_icon("EditorHandleDisabled", "EditorIcons");
@@ -1636,7 +2069,10 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
_update_fix_selected_and_hovered_tiles();
_update_tile_id_label();
_update_atlas_view();
+ _update_atlas_source_inspector();
_update_tile_inspector();
+ _update_tile_data_editors();
+ _update_current_tile_data_editor();
tile_set_atlas_source_changed_needs_update = false;
}
@@ -1675,7 +2111,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
// Tile inspector.
tile_inspector_label = memnew(Label);
tile_inspector_label->set_text(TTR("Tile Properties:"));
- tile_inspector_label->hide();
middle_vbox_container->add_child(tile_inspector_label);
tile_proxy_object = memnew(AtlasTileProxyObject(this));
@@ -1689,6 +2124,36 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_inspector->connect("property_selected", callable_mp(this, &TileSetAtlasSourceEditor::_inspector_property_selected));
middle_vbox_container->add_child(tile_inspector);
+ tile_inspector_no_tile_selected_label = memnew(Label);
+ tile_inspector_no_tile_selected_label->set_align(Label::ALIGN_CENTER);
+ tile_inspector_no_tile_selected_label->set_text(TTR("No tile selected."));
+ middle_vbox_container->add_child(tile_inspector_no_tile_selected_label);
+
+ // Property values palette.
+ tile_data_editors_popup = memnew(Popup);
+
+ tile_data_editors_label = memnew(Label);
+ tile_data_editors_label->set_text(TTR("Paint Properties:"));
+ middle_vbox_container->add_child(tile_data_editors_label);
+
+ tile_data_editor_dropdown_button = memnew(Button);
+ tile_data_editor_dropdown_button->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_draw));
+ tile_data_editor_dropdown_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed));
+ middle_vbox_container->add_child(tile_data_editor_dropdown_button);
+ tile_data_editor_dropdown_button->add_child(tile_data_editors_popup);
+
+ tile_data_editors_tree = memnew(Tree);
+ tile_data_editors_tree->set_hide_root(true);
+ tile_data_editors_tree->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ tile_data_editors_tree->set_h_scroll_enabled(false);
+ tile_data_editors_tree->set_v_scroll_enabled(false);
+ tile_data_editors_tree->connect("item_selected", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editors_tree_selected));
+ tile_data_editors_popup->add_child(tile_data_editors_tree);
+
+ tile_data_painting_editor_container = memnew(VBoxContainer);
+ tile_data_painting_editor_container->set_h_size_flags(SIZE_EXPAND_FILL);
+ middle_vbox_container->add_child(tile_data_painting_editor_container);
+
// Atlas source inspector.
atlas_source_inspector_label = memnew(Label);
atlas_source_inspector_label->set_text(TTR("Atlas Properties:"));
@@ -1719,47 +2184,41 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
add_child(confirm_auto_create_tiles);
// -- Toolbox --
- tools_button_group.instance();
+ tools_button_group.instantiate();
+ tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles).unbind(1));
+ tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label).unbind(1));
+ tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_source_inspector).unbind(1));
+ tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector).unbind(1));
+ tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_data_editors).unbind(1));
+ tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_current_tile_data_editor).unbind(1));
+ tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view).unbind(1));
+ tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar).unbind(1));
toolbox = memnew(HBoxContainer);
right_panel->add_child(toolbox);
+ tool_setup_atlas_source_button = memnew(Button);
+ tool_setup_atlas_source_button->set_flat(true);
+ tool_setup_atlas_source_button->set_toggle_mode(true);
+ tool_setup_atlas_source_button->set_pressed(true);
+ tool_setup_atlas_source_button->set_button_group(tools_button_group);
+ tool_setup_atlas_source_button->set_tooltip(TTR("Atlas Setup. Add/Remove tiles tool (use the shift key to create big tiles, control for rectangle editing)."));
+ toolbox->add_child(tool_setup_atlas_source_button);
+
tool_select_button = memnew(Button);
tool_select_button->set_flat(true);
tool_select_button->set_toggle_mode(true);
- tool_select_button->set_pressed(true);
+ tool_select_button->set_pressed(false);
tool_select_button->set_button_group(tools_button_group);
tool_select_button->set_tooltip(TTR("Select tiles."));
- tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles));
- tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label));
- tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector));
- tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view));
- tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar));
toolbox->add_child(tool_select_button);
- tool_add_remove_button = memnew(Button);
- tool_add_remove_button->set_flat(true);
- tool_add_remove_button->set_toggle_mode(true);
- tool_add_remove_button->set_button_group(tools_button_group);
- tool_add_remove_button->set_tooltip(TTR("Add/Remove tiles tool (use the shift key to create big tiles)."));
- tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles));
- tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label));
- tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector));
- tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view));
- tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar));
- toolbox->add_child(tool_add_remove_button);
-
- tool_add_remove_rect_button = memnew(Button);
- tool_add_remove_rect_button->set_flat(true);
- tool_add_remove_rect_button->set_toggle_mode(true);
- tool_add_remove_rect_button->set_button_group(tools_button_group);
- tool_add_remove_rect_button->set_tooltip(TTR("Add/Remove tiles rectangle tool (use the shift key to create big tiles)."));
- tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles));
- tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label));
- tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector));
- tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view));
- tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar));
- toolbox->add_child(tool_add_remove_rect_button);
+ tool_paint_button = memnew(Button);
+ tool_paint_button->set_flat(true);
+ tool_paint_button->set_toggle_mode(true);
+ tool_paint_button->set_button_group(tools_button_group);
+ tool_paint_button->set_tooltip(TTR("Paint properties."));
+ toolbox->add_child(tool_paint_button);
// Tool settings.
tool_settings = memnew(HBoxContainer);
@@ -1768,6 +2227,9 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tool_settings_vsep = memnew(VSeparator);
tool_settings->add_child(tool_settings_vsep);
+ tool_settings_tile_data_toolbar_container = memnew(HBoxContainer);
+ tool_settings->add_child(tool_settings_tile_data_toolbar_container);
+
tools_settings_erase_button = memnew(Button);
tools_settings_erase_button->set_flat(true);
tools_settings_erase_button->set_toggle_mode(true);
@@ -1775,9 +2237,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tools_settings_erase_button->set_shortcut_context(this);
tool_settings->add_child(tools_settings_erase_button);
- VSeparator *tool_advanced_vsep = memnew(VSeparator);
- toolbox->add_child(tool_advanced_vsep);
-
tool_advanced_menu_buttom = memnew(MenuButton);
tool_advanced_menu_buttom->set_flat(true);
tool_advanced_menu_buttom->get_popup()->add_item(TTR("Cleanup Tiles Outside Texture"), ADVANCED_CLEANUP_TILES_OUTSIDE_TEXTURE);
@@ -1844,7 +2303,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
alternative_tiles_control_unscaled = memnew(Control);
alternative_tiles_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
alternative_tiles_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw));
- tile_atlas_view->add_control_over_atlas_tiles(alternative_tiles_control_unscaled, false);
+ tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control_unscaled, false);
alternative_tiles_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
tile_atlas_view_missing_source_label = memnew(Label);
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
index 70f2cdbe01..dbb0756a16 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.h
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -32,6 +32,7 @@
#define TILE_SET_ATLAS_SOURCE_EDITOR_H
#include "tile_atlas_view.h"
+#include "tile_data_editors.h"
#include "editor/editor_node.h"
#include "scene/gui/split_container.h"
@@ -113,10 +114,27 @@ private:
bool tile_set_atlas_source_changed_needs_update = false;
+ // -- Properties painting --
+ VBoxContainer *tile_data_painting_editor_container;
+ Label *tile_data_editors_label;
+ Button *tile_data_editor_dropdown_button;
+ Popup *tile_data_editors_popup;
+ Tree *tile_data_editors_tree;
+ void _tile_data_editor_dropdown_button_draw();
+ void _tile_data_editor_dropdown_button_pressed();
+
+ // -- Tile data editors --
+ String current_property;
+ Control *current_tile_data_editor_toolbar = nullptr;
+ Map<String, TileDataEditor *> tile_data_editors;
+ TileDataEditor *current_tile_data_editor = nullptr;
+ void _tile_data_editors_tree_selected();
+
// -- Inspector --
AtlasTileProxyObject *tile_proxy_object;
Label *tile_inspector_label;
EditorInspector *tile_inspector;
+ Label *tile_inspector_no_tile_selected_label;
String selected_property;
void _inspector_property_selected(String p_property);
@@ -142,6 +160,8 @@ private:
DRAG_TYPE_RECT_SELECT,
+ DRAG_TYPE_MAY_POPUP_MENU,
+
// Warning: keep in this order.
DRAG_TYPE_RESIZE_TOP_LEFT,
DRAG_TYPE_RESIZE_TOP,
@@ -179,15 +199,16 @@ private:
// Tool buttons.
Ref<ButtonGroup> tools_button_group;
+ Button *tool_setup_atlas_source_button;
Button *tool_select_button;
- Button *tool_add_remove_button;
- Button *tool_add_remove_rect_button;
+ Button *tool_paint_button;
Label *tool_tile_id_label;
+ // Tool settings.
HBoxContainer *tool_settings;
VSeparator *tool_settings_vsep;
+ HBoxContainer *tool_settings_tile_data_toolbar_container;
Button *tools_settings_erase_button;
-
MenuButton *tool_advanced_menu_buttom;
// Selection.
@@ -226,7 +247,10 @@ private:
void _update_tile_id_label();
void _update_source_inspector();
void _update_fix_selected_and_hovered_tiles();
+ void _update_atlas_source_inspector();
void _update_tile_inspector();
+ void _update_tile_data_editors();
+ void _update_current_tile_data_editor();
void _update_manage_tile_properties_button();
void _update_atlas_view();
void _update_toolbar();
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 11842981f3..2c2ebd107f 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -347,65 +347,23 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
int old_layer_count = tile_set->get_physics_layers_count();
if (new_layer_count < old_layer_count) {
for (int physics_layer_index = new_layer_count - 1; physics_layer_index < old_layer_count; physics_layer_index++) {
- ADD_UNDO(tile_data, vformat("physics_layer_%d/shapes_count", physics_layer_index));
- for (int shape_index = 0; shape_index < tile_data->get_collision_shapes_count(physics_layer_index); shape_index++) {
- ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/shape", physics_layer_index, shape_index));
- ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way", physics_layer_index, shape_index));
- ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way_margin", physics_layer_index, shape_index));
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/polygons_count", physics_layer_index));
+ for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(physics_layer_index); polygon_index++) {
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/points", physics_layer_index, polygon_index));
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way", physics_layer_index, polygon_index));
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way_margin", physics_layer_index, polygon_index));
}
}
}
} else if ((p_property == "terrains_sets_count" && tile_data->get_terrain_set() >= (int)p_new_value) ||
- (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_integer() && components[1] == "mode") ||
- (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_integer() && components[1] == "terrains_count" && tile_data->get_terrain_set() == components[0].trim_prefix("terrain_set_").to_int() && (int)p_new_value < tile_set->get_terrains_count(tile_data->get_terrain_set()))) {
+ (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "mode") ||
+ (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrains_count" && tile_data->get_terrain_set() == components[0].trim_prefix("terrain_set_").to_int() && (int)p_new_value < tile_set->get_terrains_count(tile_data->get_terrain_set()))) {
ADD_UNDO(tile_data, "terrain_set");
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/right_side");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/right_corner");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/bottom_right_side");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/bottom_right_corner");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/bottom_side");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/bottom_corner");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/bottom_left_side");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/bottom_left_corner");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/left_side");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/left_corner");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/top_left_side");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/top_left_corner");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/top_side");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/top_corner");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/top_right_side");
- }
- if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER)) {
- ADD_UNDO(tile_data, "terrains_peering_bit/top_right_corner");
+ for (int l = 0; l < TileSet::CELL_NEIGHBOR_MAX; l++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(l);
+ if (tile_data->is_valid_peering_bit_terrain(bit)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[l]));
+ }
}
} else if (p_property == "navigation_layers_count") {
int new_layer_count = p_new_value;
@@ -423,8 +381,8 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
ADD_UNDO(tile_data, vformat("custom_data_%d", custom_data_layer_index));
}
}
- } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_integer() && components[1] == "type") {
- int custom_data_layer = components[0].trim_prefix("custom_data_layer_").is_valid_integer();
+ } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_int() && components[1] == "type") {
+ int custom_data_layer = components[0].trim_prefix("custom_data_layer_").is_valid_int();
ADD_UNDO(tile_data, vformat("custom_data_%d", custom_data_layer));
}
}
@@ -440,30 +398,6 @@ void TileSetEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetEditor::drop_data_fw);
}
-TileDataEditor *TileSetEditor::get_tile_data_editor(String p_property) {
- Vector<String> components = String(p_property).split("/", true);
-
- if (p_property == "z_index") {
- return tile_data_integer_editor;
- } else if (p_property == "probability") {
- return tile_data_float_editor;
- } else if (p_property == "y_sort_origin") {
- return tile_data_y_sort_editor;
- } else if (p_property == "texture_offset") {
- return tile_data_texture_offset_editor;
- } else if (components.size() >= 1 && components[0].begins_with("occlusion_layer_")) {
- return tile_data_occlusion_shape_editor;
- } else if (components.size() >= 1 && components[0].begins_with("physics_layer_")) {
- return tile_data_collision_shape_editor;
- } else if (p_property == "mode" || p_property == "terrain" || (components.size() >= 1 && components[0] == "terrains_peering_bit")) {
- return tile_data_terrains_editor;
- } else if (components.size() >= 1 && components[0].begins_with("navigation_layer_")) {
- return tile_data_navigation_polygon_editor;
- }
-
- return nullptr;
-}
-
void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
if (p_tile_set == tile_set) {
return;
@@ -575,14 +509,4 @@ TileSetEditor::~TileSetEditor() {
if (tile_set.is_valid()) {
tile_set->disconnect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed));
}
-
- // Delete tile data editors.
- memdelete(tile_data_texture_offset_editor);
- memdelete(tile_data_y_sort_editor);
- memdelete(tile_data_integer_editor);
- memdelete(tile_data_float_editor);
- memdelete(tile_data_occlusion_shape_editor);
- memdelete(tile_data_collision_shape_editor);
- memdelete(tile_data_terrains_editor);
- memdelete(tile_data_navigation_polygon_editor);
}
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index f584c043cc..9e50aca62f 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -33,7 +33,6 @@
#include "scene/gui/box_container.h"
#include "scene/resources/tile_set.h"
-#include "tile_data_editors.h"
#include "tile_set_atlas_source_editor.h"
#include "tile_set_scenes_collection_source_editor.h"
@@ -54,16 +53,6 @@ private:
void _update_atlas_sources_list(int force_selected_id = -1);
- // List of tile data editors.
- TileDataTextureOffsetEditor *tile_data_texture_offset_editor = memnew(TileDataTextureOffsetEditor);
- TileDataYSortEditor *tile_data_y_sort_editor = memnew(TileDataYSortEditor);
- TileDataIntegerEditor *tile_data_integer_editor = memnew(TileDataIntegerEditor);
- TileDataFloatEditor *tile_data_float_editor = memnew(TileDataFloatEditor);
- TileDataOcclusionShapeEditor *tile_data_occlusion_shape_editor = memnew(TileDataOcclusionShapeEditor);
- TileDataCollisionShapeEditor *tile_data_collision_shape_editor = memnew(TileDataCollisionShapeEditor);
- TileDataTerrainsEditor *tile_data_terrains_editor = memnew(TileDataTerrainsEditor);
- TileDataNavigationPolygonEditor *tile_data_navigation_polygon_editor = memnew(TileDataNavigationPolygonEditor);
-
// -- Sources management --
Button *sources_delete_button;
MenuButton *sources_add_button;
@@ -84,7 +73,6 @@ protected:
public:
_FORCE_INLINE_ static TileSetEditor *get_singleton() { return singleton; }
- TileDataEditor *get_tile_data_editor(String property);
void edit(Ref<TileSet> p_tile_set);
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index e393f960bd..16d36ad053 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -818,7 +818,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
if (is_expression) {
CodeEdit *expression_box = memnew(CodeEdit);
Ref<CodeHighlighter> expression_syntax_highlighter;
- expression_syntax_highlighter.instance();
+ expression_syntax_highlighter.instantiate();
expression_node->set_ctrl_pressed(expression_box, 0);
node->add_child(expression_box);
register_expression_edit(p_id, expression_box);
@@ -1053,7 +1053,7 @@ void VisualShaderEditor::update_custom_nodes() {
Ref<Script> script = Ref<Script>(res);
Ref<VisualShaderNodeCustom> ref;
- ref.instance();
+ ref.instantiate();
ref->set_script(script);
String name;
@@ -2209,7 +2209,7 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa
bool is_custom = add_options[p_idx].is_custom;
if (!is_custom && add_options[p_idx].type != String()) {
- VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type));
+ VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(add_options[p_idx].type));
ERR_FAIL_COND(!vsn);
VisualShaderNodeFloatConstant *constant = Object::cast_to<VisualShaderNodeFloatConstant>(vsn);
@@ -2234,7 +2234,7 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa
} else {
ERR_FAIL_COND(add_options[p_idx].script.is_null());
String base_type = add_options[p_idx].script->get_instance_base_type();
- VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(base_type));
+ VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(base_type));
ERR_FAIL_COND(!vsn);
vsnode = Ref<VisualShaderNode>(vsn);
vsnode->set_script(add_options[p_idx].script);
@@ -2315,6 +2315,13 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa
undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot);
undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot);
} else {
+ // Need to setting up Input node properly before committing since `is_port_types_compatible` (calling below) is using `mode` and `shader_type`.
+ VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsnode.ptr());
+ if (input) {
+ input->set_shader_mode(visual_shader->get_mode());
+ input->set_shader_type(visual_shader->get_shader_type());
+ }
+
// Attempting to connect to the first correct port.
for (int i = 0; i < vsnode->get_output_port_count(); i++) {
if (visual_shader->is_port_types_compatible(vsnode->get_output_port_type(i), input_port_type)) {
@@ -3835,7 +3842,7 @@ VisualShaderEditor::VisualShaderEditor() {
preview_vbox->add_theme_constant_override("separation", 0);
preview_text = memnew(CodeEdit);
- syntax_highlighter.instance();
+ syntax_highlighter.instantiate();
preview_vbox->add_child(preview_text);
preview_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);
preview_text->set_syntax_highlighter(syntax_highlighter);
@@ -4427,10 +4434,10 @@ VisualShaderEditor::VisualShaderEditor() {
undo_redo = EditorNode::get_singleton()->get_undo_redo();
Ref<VisualShaderNodePluginDefault> default_plugin;
- default_plugin.instance();
+ default_plugin.instantiate();
add_plugin(default_plugin);
- graph_plugin.instance();
+ graph_plugin.instantiate();
property_editor = memnew(CustomPropertyEditor);
add_child(property_editor);
@@ -4885,14 +4892,14 @@ void VisualShaderNodePortPreview::_shader_changed() {
String shader_code = shader->generate_preview_shader(type, node, port, default_textures);
Ref<Shader> preview_shader;
- preview_shader.instance();
+ preview_shader.instantiate();
preview_shader->set_code(shader_code);
for (int i = 0; i < default_textures.size(); i++) {
preview_shader->set_default_texture_param(default_textures[i].name, default_textures[i].param);
}
Ref<ShaderMaterial> material;
- material.instance();
+ material.instantiate();
material->set_shader(preview_shader);
//find if a material is also being edited and copy parameters to this one
@@ -4977,7 +4984,7 @@ Ref<Resource> VisualShaderConversionPlugin::convert(const Ref<Resource> &p_resou
ERR_FAIL_COND_V(!vshader.is_valid(), Ref<Resource>());
Ref<Shader> shader;
- shader.instance();
+ shader.instantiate();
String code = vshader->get_code();
shader->set_code(code);