summaryrefslogtreecommitdiff
path: root/editor/plugins/tiles
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins/tiles')
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.cpp1
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp94
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h4
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp20
-rw-r--r--editor/plugins/tiles/tile_data_editors.h4
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp665
-rw-r--r--editor/plugins/tiles/tile_map_editor.h64
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp119
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h6
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp108
-rw-r--r--editor/plugins/tiles/tile_set_editor.h16
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp28
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.h1
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp311
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.h61
15 files changed, 977 insertions, 525 deletions
diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp
index 2a8a3216ed..efccac7b74 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.cpp
+++ b/editor/plugins/tiles/atlas_merging_dialog.cpp
@@ -118,6 +118,7 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla
output_image_texture.instantiate();
output_image_texture->create_from_image(output_image);
+ merged->set_name(p_atlas_sources[0]->get_name());
merged->set_texture(output_image_texture);
merged->set_texture_region_size(new_texture_region_size);
}
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index f21d5098d3..c064073b77 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -97,15 +97,6 @@ Size2i TileAtlasView::_compute_base_tiles_control_size() {
if (texture.is_valid()) {
size = texture->get_size();
}
-
- // Extend the size to all existing tiles.
- Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
- for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
- Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
- grid_size = grid_size.max(tile_id + Vector2i(1, 1));
- }
- size = size.max(grid_size * (tile_set_atlas_source->get_texture_region_size() + tile_set_atlas_source->get_separation()) + tile_set_atlas_source->get_margins());
-
return size;
}
@@ -213,43 +204,56 @@ void TileAtlasView::_draw_base_tiles() {
Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
if (texture.is_valid()) {
Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i separation = tile_set_atlas_source->get_separation();
Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
-
- // Draw the texture, square by square.
Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
+
+ // Draw the texture where there is no tile.
for (int x = 0; x < grid_size.x; x++) {
for (int y = 0; y < grid_size.y; y++) {
Vector2i coords = Vector2i(x, y);
if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
- Rect2i rect = Rect2i(texture_region_size * coords + margins, texture_region_size);
- base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ Rect2i rect = Rect2i((texture_region_size + separation) * coords + margins, texture_region_size + separation);
+ rect = rect.intersection(Rect2i(Vector2(), texture->get_size()));
+ if (rect.size.x > 0 && rect.size.y > 0) {
+ base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
+ }
}
}
}
// Draw the texture around the grid.
Rect2i rect;
+
// Top.
rect.position = Vector2i();
rect.set_end(Vector2i(texture->get_size().x, margins.y));
base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
+
// Bottom
- int bottom_border = margins.y + (grid_size.y * texture_region_size.y);
+ int bottom_border = margins.y + (grid_size.y * (texture_region_size.y + separation.y));
if (bottom_border < texture->get_size().y) {
rect.position = Vector2i(0, bottom_border);
rect.set_end(texture->get_size());
base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
}
+
// Left
rect.position = Vector2i(0, margins.y);
- rect.set_end(Vector2i(margins.x, margins.y + (grid_size.y * texture_region_size.y)));
+ rect.set_end(Vector2i(margins.x, margins.y + (grid_size.y * (texture_region_size.y + separation.y))));
base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
+
// Right.
- int right_border = margins.x + (grid_size.x * texture_region_size.x);
+ int right_border = margins.x + (grid_size.x * (texture_region_size.x + separation.x));
if (right_border < texture->get_size().x) {
rect.position = Vector2i(right_border, margins.y);
- rect.set_end(Vector2i(texture->get_size().x, margins.y + (grid_size.y * texture_region_size.y)));
+ rect.set_end(Vector2i(texture->get_size().x, margins.y + (grid_size.y * (texture_region_size.y + separation.y))));
base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
}
// Draw actual tiles, using their properties (modulation, etc...)
@@ -258,12 +262,30 @@ void TileAtlasView::_draw_base_tiles() {
for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(atlas_coords); frame++) {
// Update the y to max value.
- int animation_columns = tile_set_atlas_source->get_tile_animation_columns(atlas_coords);
- Vector2i frame_coords = atlas_coords + (tile_set_atlas_source->get_tile_size_in_atlas(atlas_coords) + tile_set_atlas_source->get_tile_animation_separation(atlas_coords)) * ((animation_columns > 0) ? Vector2i(frame % animation_columns, frame / animation_columns) : Vector2i(frame, 0));
- Vector2i offset_pos = (margins + (frame_coords * texture_region_size) + tile_set_atlas_source->get_tile_texture_region(atlas_coords, frame).size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0));
+ Rect2i base_frame_rect = tile_set_atlas_source->get_tile_texture_region(atlas_coords, frame);
+ Vector2i offset_pos = base_frame_rect.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0);
// Draw the tile.
TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0, frame);
+
+ // Draw, the texture in the separation areas
+ if (separation.x > 0) {
+ Rect2i right_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(base_frame_rect.size.x, 0), Vector2i(separation.x, base_frame_rect.size.y));
+ right_sep_rect = right_sep_rect.intersection(Rect2i(Vector2(), texture->get_size()));
+ if (right_sep_rect.size.x > 0 && right_sep_rect.size.y > 0) {
+ base_tiles_draw->draw_texture_rect_region(texture, right_sep_rect, right_sep_rect);
+ base_tiles_draw->draw_rect(right_sep_rect, Color(0.0, 0.0, 0.0, 0.5));
+ }
+ }
+
+ if (separation.y > 0) {
+ Rect2i bottom_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(0, base_frame_rect.size.y), Vector2i(base_frame_rect.size.x + separation.x, separation.y));
+ bottom_sep_rect = bottom_sep_rect.intersection(Rect2i(Vector2(), texture->get_size()));
+ if (bottom_sep_rect.size.x > 0 && bottom_sep_rect.size.y > 0) {
+ base_tiles_draw->draw_texture_rect_region(texture, bottom_sep_rect, bottom_sep_rect);
+ base_tiles_draw->draw_rect(bottom_sep_rect, Color(0.0, 0.0, 0.0, 0.5));
+ }
+ }
}
}
}
@@ -299,30 +321,6 @@ void TileAtlasView::_draw_base_tiles_texture_grid() {
}
}
-void TileAtlasView::_draw_base_tiles_dark() {
- Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
- if (texture.is_valid()) {
- Vector2i margins = tile_set_atlas_source->get_margins();
- Vector2i separation = tile_set_atlas_source->get_separation();
- Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
-
- Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
-
- // Draw each tile texture region.
- for (int x = 0; x < grid_size.x; x++) {
- for (int y = 0; y < grid_size.y; y++) {
- Vector2i origin = margins + (Vector2i(x, y) * (texture_region_size + separation));
- Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(Vector2i(x, y));
-
- if (base_tile_coords == TileSetSource::INVALID_ATLAS_COORDS) {
- // Draw the grid.
- base_tiles_dark->draw_rect(Rect2i(origin, texture_region_size), Color(0.0, 0.0, 0.0, 0.5), true);
- }
- }
- }
- }
-}
-
void TileAtlasView::_draw_base_tiles_shape_grid() {
// Draw the shapes.
Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
@@ -453,7 +451,6 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_
base_tiles_draw->update();
base_tiles_texture_grid->update();
base_tiles_shape_grid->update();
- base_tiles_dark->update();
alternatives_draw->update();
background_left->update();
background_right->update();
@@ -544,7 +541,6 @@ void TileAtlasView::update() {
base_tiles_draw->update();
base_tiles_texture_grid->update();
base_tiles_shape_grid->update();
- base_tiles_dark->update();
alternatives_draw->update();
background_left->update();
background_right->update();
@@ -660,12 +656,6 @@ TileAtlasView::TileAtlasView() {
base_tiles_shape_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_shape_grid));
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_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);
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
index 5b0df366ae..e1ca3eebee 100644
--- a/editor/plugins/tiles/tile_atlas_view.h
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -93,9 +93,6 @@ private:
Control *base_tiles_shape_grid;
void _draw_base_tiles_shape_grid();
- Control *base_tiles_dark;
- void _draw_base_tiles_dark();
-
Size2i _compute_base_tiles_control_size();
// Right side.
@@ -124,7 +121,6 @@ public:
// Left side.
void set_texture_grid_visible(bool p_visible) { base_tiles_texture_grid->set_visible(p_visible); };
- void set_dark_visible(bool p_visible) { base_tiles_dark->set_visible(p_visible); };
void set_tile_shape_grid_visible(bool p_visible) { base_tiles_shape_grid->set_visible(p_visible); };
Vector2i get_atlas_tile_coords_at_pos(const Vector2 p_pos) const;
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index 1a69d19d3c..104f46f773 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -38,8 +38,16 @@
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
-void TileDataEditor::_call_tile_set_changed() {
- _tile_set_changed();
+void TileDataEditor::_tile_set_changed_plan_update() {
+ _tile_set_changed_update_needed = true;
+ call_deferred("_tile_set_changed_deferred_update");
+}
+
+void TileDataEditor::_tile_set_changed_deferred_update() {
+ if (_tile_set_changed_update_needed) {
+ _tile_set_changed();
+ _tile_set_changed_update_needed = false;
+ }
}
TileData *TileDataEditor::_get_tile_data(TileMapCell p_cell) {
@@ -59,18 +67,20 @@ TileData *TileDataEditor::_get_tile_data(TileMapCell p_cell) {
}
void TileDataEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_tile_set_changed_deferred_update"), &TileDataEditor::_tile_set_changed_deferred_update);
+
ADD_SIGNAL(MethodInfo("needs_redraw"));
}
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->disconnect("changed", callable_mp(this, &TileDataEditor::_tile_set_changed_plan_update));
}
tile_set = p_tile_set;
if (tile_set.is_valid()) {
- tile_set->connect("changed", callable_mp(this, &TileDataEditor::_call_tile_set_changed));
+ tile_set->connect("changed", callable_mp(this, &TileDataEditor::_tile_set_changed_plan_update));
}
- _call_tile_set_changed();
+ _tile_set_changed_plan_update();
}
bool DummyObject::_set(const StringName &p_name, const Variant &p_value) {
diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h
index 99998dc779..acb4c5882d 100644
--- a/editor/plugins/tiles/tile_data_editors.h
+++ b/editor/plugins/tiles/tile_data_editors.h
@@ -45,7 +45,9 @@ class TileDataEditor : public VBoxContainer {
GDCLASS(TileDataEditor, VBoxContainer);
private:
- void _call_tile_set_changed();
+ bool _tile_set_changed_update_needed = false;
+ void _tile_set_changed_plan_update();
+ void _tile_set_changed_deferred_update();
protected:
Ref<TileSet> tile_set;
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index c2e86f8b43..5dfa44a353 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_scale.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
+#include "scene/2d/camera_2d.h"
#include "scene/gui/center_container.h"
#include "scene/gui/split_container.h"
@@ -43,31 +44,11 @@
#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
-void TileMapEditorTilesPlugin::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED:
- select_tool_button->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
- paint_tool_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
- line_tool_button->set_icon(get_theme_icon(SNAME("CurveLinear"), SNAME("EditorIcons")));
- rect_tool_button->set_icon(get_theme_icon(SNAME("Rectangle"), SNAME("EditorIcons")));
- bucket_tool_button->set_icon(get_theme_icon(SNAME("Bucket"), SNAME("EditorIcons")));
-
- picker_button->set_icon(get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
- erase_button->set_icon(get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
-
- missing_atlas_texture_icon = get_theme_icon(SNAME("TileSet"), SNAME("EditorIcons"));
- break;
- case NOTIFICATION_VISIBILITY_CHANGED:
- _stop_dragging();
- break;
- }
-}
-
void TileMapEditorTilesPlugin::tile_set_changed() {
_update_fix_selected_and_hovered();
_update_tile_set_sources_list();
- _update_bottom_panel();
+ _update_source_display();
+ _update_patterns_list();
}
void TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled(bool p_pressed) {
@@ -125,8 +106,19 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
}
}
-Control *TileMapEditorTilesPlugin::get_toolbar() const {
- return toolbar;
+Vector<TileMapEditorPlugin::TabData> TileMapEditorTilesPlugin::get_tabs() const {
+ Vector<TileMapEditorPlugin::TabData> tabs;
+ tabs.push_back({ toolbar, tiles_bottom_panel });
+ tabs.push_back({ toolbar, patterns_bottom_panel });
+ return tabs;
+}
+
+void TileMapEditorTilesPlugin::_tab_changed() {
+ if (tiles_bottom_panel->is_visible_in_tree()) {
+ _update_selection_pattern_from_tileset_tiles_selection();
+ } else if (patterns_bottom_panel->is_visible_in_tree()) {
+ _update_selection_pattern_from_tileset_pattern_selection();
+ }
}
void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
@@ -152,22 +144,31 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
Ref<Texture2D> texture;
String item_text;
+ // Common to all type of sources.
+ if (!source->get_name().is_empty()) {
+ item_text = vformat(TTR("%s (id:%d)"), source->get_name(), source_id);
+ }
+
// Atlas source.
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
texture = atlas_source->get_texture();
- if (texture.is_valid()) {
- item_text = vformat("%s (ID: %d)", texture->get_path().get_file(), source_id);
- } else {
- item_text = vformat("No Texture Atlas Source (ID: %d)", source_id);
+ if (item_text.is_empty()) {
+ if (texture.is_valid()) {
+ item_text = vformat("%s (ID: %d)", texture->get_path().get_file(), source_id);
+ } else {
+ item_text = vformat("No Texture Atlas Source (ID: %d)", source_id);
+ }
}
}
// Scene collection source.
TileSetScenesCollectionSource *scene_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
if (scene_collection_source) {
- texture = get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons"));
- item_text = vformat(TTR("Scene Collection Source (ID: %d)"), source_id);
+ texture = tiles_bottom_panel->get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons"));
+ if (item_text.is_empty()) {
+ item_text = vformat(TTR("Scene Collection Source (ID: %d)"), source_id);
+ }
}
// Use default if not valid.
@@ -193,10 +194,10 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
}
// Synchronize
- TilesEditor::get_singleton()->set_sources_lists_current(sources_list->get_current());
+ TilesEditorPlugin::get_singleton()->set_sources_lists_current(sources_list->get_current());
}
-void TileMapEditorTilesPlugin::_update_bottom_panel() {
+void TileMapEditorTilesPlugin::_update_source_display() {
// Update the atlas display.
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
@@ -243,6 +244,81 @@ void TileMapEditorTilesPlugin::_update_bottom_panel() {
}
}
+void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEvent> &p_event) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ if (ED_IS_SHORTCUT("tiles_editor/paste", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
+ select_last_pattern = true;
+ int new_pattern_index = tile_set->get_patterns_count();
+ undo_redo->create_action(TTR("Add TileSet pattern"));
+ undo_redo->add_do_method(*tile_set, "add_pattern", tile_map_clipboard, new_pattern_index);
+ undo_redo->add_undo_method(*tile_set, "remove_pattern", new_pattern_index);
+ undo_redo->commit_action();
+ patterns_item_list->accept_event();
+ }
+
+ if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
+ Vector<int> selected = patterns_item_list->get_selected_items();
+ undo_redo->create_action(TTR("Remove TileSet patterns"));
+ for (int i = 0; i < selected.size(); i++) {
+ int pattern_index = selected[i];
+ undo_redo->add_do_method(*tile_set, "remove_pattern", pattern_index);
+ undo_redo->add_undo_method(*tile_set, "add_pattern", tile_set->get_pattern(pattern_index), pattern_index);
+ }
+ undo_redo->commit_action();
+ patterns_item_list->accept_event();
+ }
+}
+
+void TileMapEditorTilesPlugin::_pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture) {
+ // TODO optimize ?
+ for (int i = 0; i < patterns_item_list->get_item_count(); i++) {
+ if (patterns_item_list->get_item_metadata(i) == p_pattern) {
+ patterns_item_list->set_item_icon(i, p_texture);
+ break;
+ }
+ }
+}
+
+void TileMapEditorTilesPlugin::_update_patterns_list() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ // Recreate the items.
+ patterns_item_list->clear();
+ for (int i = 0; i < tile_set->get_patterns_count(); i++) {
+ int id = patterns_item_list->add_item("");
+ patterns_item_list->set_item_metadata(id, tile_set->get_pattern(i));
+ TilesEditorPlugin::get_singleton()->queue_pattern_preview(tile_set, tile_set->get_pattern(i), callable_mp(this, &TileMapEditorTilesPlugin::_pattern_preview_done));
+ }
+
+ // Update the label visibility.
+ patterns_help_label->set_visible(patterns_item_list->get_item_count() == 0);
+
+ // Added a new pattern, thus select the last one.
+ if (select_last_pattern) {
+ patterns_item_list->select(tile_set->get_patterns_count() - 1);
+ patterns_item_list->grab_focus();
+ _update_selection_pattern_from_tileset_pattern_selection();
+ }
+ select_last_pattern = false;
+}
+
void TileMapEditorTilesPlugin::_update_atlas_view() {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
@@ -260,7 +336,7 @@ void TileMapEditorTilesPlugin::_update_atlas_view() {
ERR_FAIL_COND(!atlas_source);
tile_atlas_view->set_atlas_source(*tile_map->get_tileset(), atlas_source, source_id);
- TilesEditor::get_singleton()->synchronize_atlas_view(tile_atlas_view);
+ TilesEditorPlugin::get_singleton()->synchronize_atlas_view(tile_atlas_view);
tile_atlas_control->update();
}
@@ -295,7 +371,7 @@ void TileMapEditorTilesPlugin::_update_scenes_collection_view() {
Variant udata = i;
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(scene, this, "_scene_thumbnail_done", udata);
} else {
- item_index = scene_tiles_list->add_item(TTR("Tile with Invalid Scene"), get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")));
+ item_index = scene_tiles_list->add_item(TTR("Tile with Invalid Scene"), tiles_bottom_panel->get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")));
}
scene_tiles_list->set_item_metadata(item_index, scene_id);
@@ -351,19 +427,32 @@ void TileMapEditorTilesPlugin::_scenes_list_multi_selected(int p_index, bool p_s
}
}
- _update_selection_pattern_from_tileset_selection();
+ _update_selection_pattern_from_tileset_tiles_selection();
}
void TileMapEditorTilesPlugin::_scenes_list_nothing_selected() {
scene_tiles_list->deselect_all();
tile_set_selection.clear();
tile_map_selection.clear();
- selection_pattern->clear();
- _update_selection_pattern_from_tileset_selection();
+ selection_pattern.instantiate();
+ _update_selection_pattern_from_tileset_tiles_selection();
+}
+
+void TileMapEditorTilesPlugin::_update_theme() {
+ select_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
+ paint_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ line_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("CurveLinear"), SNAME("EditorIcons")));
+ rect_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Rectangle"), SNAME("EditorIcons")));
+ bucket_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Bucket"), SNAME("EditorIcons")));
+
+ picker_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
+ erase_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
+
+ missing_atlas_texture_icon = tiles_bottom_panel->get_theme_icon(SNAME("TileSet"), SNAME("EditorIcons"));
}
bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
- if (!is_visible_in_tree()) {
+ if (!(tiles_bottom_panel->is_visible_in_tree() || patterns_bottom_panel->is_visible_in_tree())) {
// If the bottom editor is not visible, we ignore inputs.
return false;
}
@@ -391,7 +480,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (ED_IS_SHORTCUT("tiles_editor/cut", p_event) || ED_IS_SHORTCUT("tiles_editor/copy", p_event)) {
// Fill in the clipboard.
if (!tile_map_selection.is_empty()) {
- memdelete(tile_map_clipboard);
+ tile_map_clipboard.instantiate();
TypedArray<Vector2i> coords_array;
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
coords_array.push_back(E->get());
@@ -456,7 +545,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
case DRAG_TYPE_PAINT: {
Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, drag_last_mouse_pos, mpos);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!erase_button->is_pressed() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
Vector2i coords = E.key;
@@ -473,7 +562,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (!drag_modified.has(line[i])) {
Map<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_continuous_checkbox->is_pressed());
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!erase_button->is_pressed() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
Vector2i coords = E.key;
@@ -501,8 +590,12 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
Vector2 mpos = xform.affine_inverse().xform(mb->get_position());
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT || mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
if (mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ rmb_erasing = true;
+ }
+
// Pressed
if (drag_type == DRAG_TYPE_CLIPBOARD_PASTE) {
// Do nothing.
@@ -524,18 +617,18 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
}
} else {
// Check if we are picking a tile.
- if (picker_button->is_pressed()) {
+ if (picker_button->is_pressed() || (Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
drag_type = DRAG_TYPE_PICK;
drag_start_mouse_pos = mpos;
} else {
// Paint otherwise.
- if (tool_buttons_group->get_pressed_button() == paint_tool_button) {
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
drag_type = DRAG_TYPE_PAINT;
drag_start_mouse_pos = mpos;
drag_modified.clear();
Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, mpos, mpos);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!erase_button->is_pressed() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
Vector2i coords = E.key;
@@ -545,11 +638,11 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
_fix_invalid_tiles_in_tile_map_selection();
- } else if (tool_buttons_group->get_pressed_button() == line_tool_button) {
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(KEY_SHIFT) && !Input::get_singleton()->is_key_pressed(KEY_CTRL))) {
drag_type = DRAG_TYPE_LINE;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- } else if (tool_buttons_group->get_pressed_button() == rect_tool_button) {
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(KEY_SHIFT) && Input::get_singleton()->is_key_pressed(KEY_CTRL))) {
drag_type = DRAG_TYPE_RECT;
drag_start_mouse_pos = mpos;
drag_modified.clear();
@@ -562,7 +655,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (!drag_modified.has(line[i])) {
Map<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_continuous_checkbox->is_pressed());
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!erase_button->is_pressed() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
Vector2i coords = E.key;
@@ -581,6 +674,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
} else {
// Released
_stop_dragging();
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ rmb_erasing = false;
+ }
}
CanvasItemEditor::get_singleton()->update_viewport();
@@ -617,7 +713,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Vector2i tile_shape_size = tile_set->get_tile_size();
// Draw the selection.
- if (is_visible_in_tree() && tool_buttons_group->get_pressed_button() == select_tool_button) {
+ if ((tiles_bottom_panel->is_visible_in_tree() || patterns_bottom_panel->is_visible_in_tree()) && tool_buttons_group->get_pressed_button() == select_tool_button) {
// In select mode, we only draw the current selection if we are modifying it (pressing control or shift).
if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
// Do nothing
@@ -629,7 +725,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
}
// Handle the preview of the tiles to be placed.
- if (is_visible_in_tree() && has_mouse) { // Only if the tilemap editor is opened and the viewport is hovered.
+ if ((tiles_bottom_panel->is_visible_in_tree() || patterns_bottom_panel->is_visible_in_tree()) && has_mouse) { // Only if the tilemap editor is opened and the viewport is hovered.
Map<Vector2i, TileMapCell> preview;
Rect2i drawn_grid_rect;
@@ -663,21 +759,23 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
}
tile_map->draw_cells_outline(p_overlay, to_draw, Color(1.0, 1.0, 1.0), xform);
} else if (drag_type == DRAG_TYPE_MOVE) {
- // Preview when moving.
- Vector2i top_left;
- if (!tile_map_selection.is_empty()) {
- top_left = tile_map_selection.front()->get();
- }
- for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
- top_left = top_left.min(E->get());
- }
- Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
- offset = tile_map->world_to_map(drag_last_mouse_pos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
+ if (!(patterns_item_list->is_visible_in_tree() && patterns_item_list->has_point(patterns_item_list->get_local_mouse_position()))) {
+ // Preview when moving.
+ Vector2i top_left;
+ if (!tile_map_selection.is_empty()) {
+ top_left = tile_map_selection.front()->get();
+ }
+ for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
+ top_left = top_left.min(E->get());
+ }
+ Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
+ offset = tile_map->world_to_map(drag_last_mouse_pos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
- TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
- for (int i = 0; i < selection_used_cells.size(); i++) {
- Vector2i coords = tile_map->map_pattern(offset + top_left, selection_used_cells[i], selection_pattern);
- preview[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i]));
+ TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
+ for (int i = 0; i < selection_used_cells.size(); i++) {
+ Vector2i coords = tile_map->map_pattern(offset + top_left, selection_used_cells[i], selection_pattern);
+ preview[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i]));
+ }
}
} else if (drag_type == DRAG_TYPE_CLIPBOARD_PASTE) {
// Preview when pasting.
@@ -687,13 +785,13 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Vector2i coords = tile_map->map_pattern(tile_map->world_to_map(drag_last_mouse_pos - mouse_offset), clipboard_used_cells[i], tile_map_clipboard);
preview[coords] = TileMapCell(tile_map_clipboard->get_cell_source_id(clipboard_used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(clipboard_used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(clipboard_used_cells[i]));
}
- } else if (!picker_button->is_pressed()) {
+ } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
bool expand_grid = false;
if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a single pattern.
preview = _draw_line(drag_last_mouse_pos, drag_last_mouse_pos, drag_last_mouse_pos);
expand_grid = true;
- } else if (tool_buttons_group->get_pressed_button() == line_tool_button) {
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button || drag_type == DRAG_TYPE_LINE) {
if (drag_type == DRAG_TYPE_NONE) {
// Preview for a single pattern.
preview = _draw_line(drag_last_mouse_pos, drag_last_mouse_pos, drag_last_mouse_pos);
@@ -703,12 +801,12 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
preview = _draw_line(drag_start_mouse_pos, drag_start_mouse_pos, drag_last_mouse_pos);
expand_grid = true;
}
- } else if (tool_buttons_group->get_pressed_button() == rect_tool_button && drag_type == DRAG_TYPE_RECT) {
- // Preview for a line pattern.
+ } else if (drag_type == DRAG_TYPE_RECT) {
+ // Preview for a rect pattern.
preview = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos));
expand_grid = true;
} else if (tool_buttons_group->get_pressed_button() == bucket_tool_button && drag_type == DRAG_TYPE_NONE) {
- // Preview for a line pattern.
+ // Preview for a fill pattern.
preview = _draw_bucket_fill(tile_map->world_to_map(drag_last_mouse_pos), bucket_continuous_checkbox->is_pressed());
}
@@ -757,7 +855,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Transform2D tile_xform;
tile_xform.set_origin(tile_map->map_to_world(E.key));
tile_xform.set_scale(tile_set->get_tile_size());
- if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
+ if (!_is_erasing() && random_tile_checkbox->is_pressed()) {
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
} else {
if (tile_set->has_source(E.value.source_id)) {
@@ -816,7 +914,7 @@ void TileMapEditorTilesPlugin::_mouse_exited_viewport() {
CanvasItemEditor::get_singleton()->update_viewport();
}
-TileMapCell TileMapEditorTilesPlugin::_pick_random_tile(const TileMapPattern *p_pattern) {
+TileMapCell TileMapEditorTilesPlugin::_pick_random_tile(Ref<TileMapPattern> p_pattern) {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
return TileMapCell();
@@ -880,14 +978,15 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_start_
}
// Get or create the pattern.
- TileMapPattern erase_pattern;
- erase_pattern.set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
- TileMapPattern *pattern = erase_button->is_pressed() ? &erase_pattern : selection_pattern;
+ Ref<TileMapPattern> erase_pattern;
+ erase_pattern.instantiate();
+ erase_pattern->set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ Ref<TileMapPattern> pattern = _is_erasing() ? erase_pattern : selection_pattern;
Map<Vector2i, TileMapCell> output;
if (!pattern->is_empty()) {
// Paint the tiles on the tile map.
- if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
+ if (!_is_erasing() && random_tile_checkbox->is_pressed()) {
// Paint a random tile.
Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(p_from_mouse_pos), tile_map->world_to_map(p_to_mouse_pos));
for (int i = 0; i < line.size(); i++) {
@@ -932,9 +1031,11 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start
rect.size += Vector2i(1, 1);
// Get or create the pattern.
- TileMapPattern erase_pattern;
- erase_pattern.set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
- TileMapPattern *pattern = erase_button->is_pressed() ? &erase_pattern : selection_pattern;
+ Ref<TileMapPattern> erase_pattern;
+ erase_pattern.instantiate();
+ erase_pattern->set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ Ref<TileMapPattern> pattern = _is_erasing() ? erase_pattern : selection_pattern;
+
Map<Vector2i, TileMapCell> err_output;
ERR_FAIL_COND_V(pattern->is_empty(), err_output);
@@ -945,7 +1046,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start
Map<Vector2i, TileMapCell> output;
if (!pattern->is_empty()) {
- if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
+ if (!_is_erasing() && random_tile_checkbox->is_pressed()) {
// Paint a random tile.
for (int x = 0; x < rect.size.x; x++) {
for (int y = 0; y < rect.size.y; y++) {
@@ -991,9 +1092,10 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
}
// Get or create the pattern.
- TileMapPattern erase_pattern;
- erase_pattern.set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
- TileMapPattern *pattern = erase_button->is_pressed() ? &erase_pattern : selection_pattern;
+ Ref<TileMapPattern> erase_pattern;
+ erase_pattern.instantiate();
+ erase_pattern->set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ Ref<TileMapPattern> pattern = _is_erasing() ? erase_pattern : selection_pattern;
if (!pattern->is_empty()) {
TileMapCell source = tile_map->get_cell(tile_map_layer, p_coords);
@@ -1017,7 +1119,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
source.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) &&
source.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) &&
(source.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) {
- if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
+ if (!_is_erasing() && random_tile_checkbox->is_pressed()) {
// Paint a random tile.
output.insert(coords, _pick_random_tile(pattern));
} else {
@@ -1063,7 +1165,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
source.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) &&
source.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) &&
(source.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) {
- if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
+ if (!_is_erasing() && random_tile_checkbox->is_pressed()) {
// Paint a random tile.
output.insert(coords, _pick_random_tile(pattern));
} else {
@@ -1137,60 +1239,80 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
_update_tileset_selection_from_selection_pattern();
} break;
case DRAG_TYPE_MOVE: {
- Vector2i top_left;
- if (!tile_map_selection.is_empty()) {
- top_left = tile_map_selection.front()->get();
- }
- for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
- top_left = top_left.min(E->get());
- }
+ if (patterns_item_list->is_visible_in_tree() && patterns_item_list->has_point(patterns_item_list->get_local_mouse_position())) {
+ // Restore the cells.
+ for (KeyValue<Vector2i, TileMapCell> kv : drag_modified) {
+ tile_map->set_cell(tile_map_layer, kv.key, kv.value.source_id, kv.value.get_atlas_coords(), kv.value.alternative_tile);
+ }
+
+ // Creating a pattern in the pattern list.
+ select_last_pattern = true;
+ int new_pattern_index = tile_set->get_patterns_count();
+ undo_redo->create_action(TTR("Add TileSet pattern"));
+ undo_redo->add_do_method(*tile_set, "add_pattern", selection_pattern, new_pattern_index);
+ undo_redo->add_undo_method(*tile_set, "remove_pattern", new_pattern_index);
+ undo_redo->commit_action();
+ } else {
+ // Get the top-left cell.
+ Vector2i top_left;
+ if (!tile_map_selection.is_empty()) {
+ top_left = tile_map_selection.front()->get();
+ }
+ for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
+ top_left = top_left.min(E->get());
+ }
- Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
- offset = tile_map->world_to_map(mpos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
+ // Get the offset from the mouse.
+ Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
+ offset = tile_map->world_to_map(mpos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
- TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
+ TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
- Vector2i coords;
- Map<Vector2i, TileMapCell> cells_undo;
- for (int i = 0; i < selection_used_cells.size(); i++) {
- coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern);
- cells_undo[coords] = TileMapCell(drag_modified[coords].source_id, drag_modified[coords].get_atlas_coords(), drag_modified[coords].alternative_tile);
- coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
- cells_undo[coords] = TileMapCell(tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords));
- }
+ // Build the list of cells to undo.
+ Vector2i coords;
+ Map<Vector2i, TileMapCell> cells_undo;
+ for (int i = 0; i < selection_used_cells.size(); i++) {
+ coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern);
+ cells_undo[coords] = TileMapCell(drag_modified[coords].source_id, drag_modified[coords].get_atlas_coords(), drag_modified[coords].alternative_tile);
+ coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
+ cells_undo[coords] = TileMapCell(tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords));
+ }
- Map<Vector2i, TileMapCell> cells_do;
- for (int i = 0; i < selection_used_cells.size(); i++) {
- coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern);
- cells_do[coords] = TileMapCell();
- }
- for (int i = 0; i < selection_used_cells.size(); i++) {
- coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
- cells_do[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i]));
- }
- undo_redo->create_action(TTR("Move tiles"));
- // Move the tiles.
- for (const KeyValue<Vector2i, TileMapCell> &E : cells_do) {
- undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
- }
- for (const KeyValue<Vector2i, TileMapCell> &E : cells_undo) {
- undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
- }
+ // Build the list of cells to do.
+ Map<Vector2i, TileMapCell> cells_do;
+ for (int i = 0; i < selection_used_cells.size(); i++) {
+ coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern);
+ cells_do[coords] = TileMapCell();
+ }
+ for (int i = 0; i < selection_used_cells.size(); i++) {
+ coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
+ cells_do[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i]));
+ }
- // Update the selection.
- undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
- tile_map_selection.clear();
- for (int i = 0; i < selection_used_cells.size(); i++) {
- coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
- tile_map_selection.insert(coords);
+ // Move the tiles.
+ undo_redo->create_action(TTR("Move tiles"));
+ for (Map<Vector2i, TileMapCell>::Element *E = cells_do.front(); E; E = E->next()) {
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ for (Map<Vector2i, TileMapCell>::Element *E = cells_undo.front(); E; E = E->next()) {
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+
+ // Update the selection.
+ undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
+ tile_map_selection.clear();
+ for (int i = 0; i < selection_used_cells.size(); i++) {
+ coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
+ tile_map_selection.insert(coords);
+ }
+ undo_redo->add_do_method(this, "_set_tile_map_selection", _get_tile_map_selection());
+ undo_redo->commit_action();
}
- undo_redo->add_do_method(this, "_set_tile_map_selection", _get_tile_map_selection());
- undo_redo->commit_action();
} break;
case DRAG_TYPE_PICK: {
Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
rect.size += Vector2i(1, 1);
- memdelete(selection_pattern);
+
TypedArray<Vector2i> coords_array;
for (int x = rect.position.x; x < rect.get_end().x; x++) {
for (int y = rect.position.y; y < rect.get_end().y; y++) {
@@ -1200,11 +1322,10 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
}
}
}
- selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
- if (!selection_pattern->is_empty()) {
+ Ref<TileMapPattern> new_selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
+ if (!new_selection_pattern->is_empty()) {
+ selection_pattern = new_selection_pattern;
_update_tileset_selection_from_selection_pattern();
- } else {
- _update_selection_pattern_from_tileset_selection();
}
picker_button->set_pressed(false);
} break;
@@ -1220,7 +1341,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, drag_start_mouse_pos, mpos);
undo_redo->create_action(TTR("Paint tiles"));
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!erase_button->is_pressed() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
@@ -1232,7 +1353,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
Map<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos));
undo_redo->create_action(TTR("Paint tiles"));
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!erase_button->is_pressed() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
@@ -1272,8 +1393,9 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() {
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
tile_set_selection.clear();
+ patterns_item_list->deselect_all();
tile_map_selection.clear();
- selection_pattern->clear();
+ selection_pattern.instantiate();
return;
}
@@ -1283,8 +1405,9 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() {
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
tile_set_selection.clear();
+ patterns_item_list->deselect_all();
tile_map_selection.clear();
- selection_pattern->clear();
+ selection_pattern.instantiate();
return;
}
@@ -1294,8 +1417,9 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() {
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
tile_set_selection.clear();
+ patterns_item_list->deselect_all();
tile_map_selection.clear();
- selection_pattern->clear();
+ selection_pattern.instantiate();
return;
}
@@ -1323,8 +1447,10 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() {
if (!tile_map_selection.is_empty()) {
_update_selection_pattern_from_tilemap_selection();
+ } else if (tiles_bottom_panel->is_visible_in_tree()) {
+ _update_selection_pattern_from_tileset_tiles_selection();
} else {
- _update_selection_pattern_from_tileset_selection();
+ _update_selection_pattern_from_tileset_pattern_selection();
}
}
@@ -1347,15 +1473,24 @@ void TileMapEditorTilesPlugin::_fix_invalid_tiles_in_tile_map_selection() {
}
}
+bool TileMapEditorTilesPlugin::_is_erasing() const {
+ return erase_button->is_pressed() || rmb_erasing;
+}
+
void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection() {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
return;
}
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count());
- memdelete(selection_pattern);
+ selection_pattern.instantiate();
TypedArray<Vector2i> coords_array;
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
@@ -1364,7 +1499,7 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection(
selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
}
-void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection() {
+void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_tiles_selection() {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
return;
@@ -1379,7 +1514,7 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection(
tile_map_selection.clear();
// Clear the selected pattern.
- selection_pattern->clear();
+ selection_pattern.instantiate();
// Group per source.
Map<int, List<const TileMapCell *>> per_source;
@@ -1437,6 +1572,30 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection(
CanvasItemEditor::get_singleton()->update_viewport();
}
+void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ // Clear the tilemap selection.
+ tile_map_selection.clear();
+
+ // Clear the selected pattern.
+ selection_pattern.instantiate();
+
+ if (patterns_item_list->get_selected_items().size() >= 1) {
+ selection_pattern = patterns_item_list->get_item_metadata(patterns_item_list->get_selected_items()[0]);
+ }
+
+ CanvasItemEditor::get_singleton()->update_viewport();
+}
+
void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern() {
tile_set_selection.clear();
TypedArray<Vector2i> used_cells = selection_pattern->get_used_cells();
@@ -1446,7 +1605,7 @@ void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern(
tile_set_selection.insert(TileMapCell(selection_pattern->get_cell_source_id(coords), selection_pattern->get_cell_atlas_coords(coords), selection_pattern->get_cell_alternative_tile(coords)));
}
}
- _update_bottom_panel();
+ _update_source_display();
tile_atlas_control->update();
alternative_tiles_control->update();
}
@@ -1596,7 +1755,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
tile_set_selection.insert(TileMapCell(source_id, hovered_tile.get_atlas_coords(), 0));
}
}
- _update_selection_pattern_from_tileset_selection();
+ _update_selection_pattern_from_tileset_tiles_selection();
} else { // Released
if (tile_set_dragging_selection) {
if (!mb->is_shift_pressed()) {
@@ -1633,7 +1792,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
}
}
}
- _update_selection_pattern_from_tileset_selection();
+ _update_selection_pattern_from_tileset_tiles_selection();
}
tile_set_dragging_selection = false;
}
@@ -1753,7 +1912,7 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<In
tile_set_selection.insert(TileMapCell(source_id, hovered_tile.get_atlas_coords(), hovered_tile.alternative_tile));
}
}
- _update_selection_pattern_from_tileset_selection();
+ _update_selection_pattern_from_tileset_tiles_selection();
}
tile_atlas_control->update();
alternative_tiles_control->update();
@@ -1786,8 +1945,9 @@ void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer
// Clear the selection.
tile_set_selection.clear();
+ patterns_item_list->deselect_all();
tile_map_selection.clear();
- selection_pattern->clear();
+ selection_pattern.instantiate();
}
tile_map_layer = p_tile_map_layer;
@@ -1809,9 +1969,13 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
ED_SHORTCUT("tiles_editor/cancel", TTR("Cancel"), KEY_ESCAPE);
ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), KEY_DELETE);
+ // --- Initialize references ---
+ tile_map_clipboard.instantiate();
+ selection_pattern.instantiate();
+
// --- Toolbar ---
toolbar = memnew(HBoxContainer);
- toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
+ toolbar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
HBoxContainer *tilemap_tiles_tools_buttons = memnew(HBoxContainer);
@@ -1830,6 +1994,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
paint_tool_button->set_toggle_mode(true);
paint_tool_button->set_button_group(tool_buttons_group);
paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", KEY_D));
+ paint_tool_button->set_tooltip(TTR("Shift: Draw line.") + "\n" + TTR("Shift+Ctrl: Draw rectangle."));
paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
@@ -1870,6 +2035,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
picker_button->set_flat(true);
picker_button->set_toggle_mode(true);
picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", KEY_P));
+ picker_button->set_tooltip(TTR("Alternatively hold Ctrl with other tools to pick tile."));
picker_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(picker_button);
@@ -1878,6 +2044,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
erase_button->set_flat(true);
erase_button->set_toggle_mode(true);
erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", KEY_E));
+ erase_button->set_tooltip(TTR("Alternatively use RMB to erase tiles."));
erase_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(erase_button);
@@ -1919,42 +2086,47 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
paint_tool_button->set_pressed(true);
_update_toolbar();
- // --- Bottom panel ---
- set_name("Tiles");
+ // --- Bottom panel tiles ---
+ tiles_bottom_panel = memnew(VBoxContainer);
+ tiles_bottom_panel->connect("tree_entered", callable_mp(this, &TileMapEditorTilesPlugin::_update_theme));
+ tiles_bottom_panel->connect("theme_changed", callable_mp(this, &TileMapEditorTilesPlugin::_update_theme));
+ tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_stop_dragging));
+ tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_tab_changed));
+ tiles_bottom_panel->set_name(TTR("Tiles"));
missing_source_label = memnew(Label);
missing_source_label->set_text(TTR("This TileMap's TileSet has no source configured. Edit the TileSet resource to add one."));
- missing_source_label->set_h_size_flags(SIZE_EXPAND_FILL);
- missing_source_label->set_v_size_flags(SIZE_EXPAND_FILL);
+ missing_source_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ missing_source_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
missing_source_label->set_align(Label::ALIGN_CENTER);
missing_source_label->set_valign(Label::VALIGN_CENTER);
missing_source_label->hide();
- add_child(missing_source_label);
+ tiles_bottom_panel->add_child(missing_source_label);
atlas_sources_split_container = memnew(HSplitContainer);
- atlas_sources_split_container->set_h_size_flags(SIZE_EXPAND_FILL);
- atlas_sources_split_container->set_v_size_flags(SIZE_EXPAND_FILL);
- add_child(atlas_sources_split_container);
+ atlas_sources_split_container->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ atlas_sources_split_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ tiles_bottom_panel->add_child(atlas_sources_split_container);
sources_list = memnew(ItemList);
sources_list->set_fixed_icon_size(Size2i(60, 60) * EDSCALE);
- sources_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ sources_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
sources_list->set_stretch_ratio(0.25);
sources_list->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_fix_selected_and_hovered).unbind(1));
- sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_bottom_panel).unbind(1));
- sources_list->connect("item_selected", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_sources_lists_current));
- sources_list->connect("visibility_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::synchronize_sources_list), varray(sources_list));
+ sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_source_display).unbind(1));
+ sources_list->connect("item_selected", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_sources_lists_current));
+ sources_list->connect("visibility_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::synchronize_sources_list), varray(sources_list));
atlas_sources_split_container->add_child(sources_list);
// Tile atlas source.
tile_atlas_view = memnew(TileAtlasView);
- tile_atlas_view->set_h_size_flags(SIZE_EXPAND_FILL);
- tile_atlas_view->set_v_size_flags(SIZE_EXPAND_FILL);
+ tile_atlas_view->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ tile_atlas_view->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tile_atlas_view->set_texture_grid_visible(false);
tile_atlas_view->set_tile_shape_grid_visible(false);
- tile_atlas_view->connect("transform_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_atlas_view_transform));
+ tile_atlas_view->connect("transform_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_atlas_view_transform));
atlas_sources_split_container->add_child(tile_atlas_view);
tile_atlas_control = memnew(Control);
@@ -1971,8 +2143,8 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
// Scenes collection source.
scene_tiles_list = memnew(ItemList);
- scene_tiles_list->set_h_size_flags(SIZE_EXPAND_FILL);
- scene_tiles_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ scene_tiles_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ scene_tiles_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
scene_tiles_list->set_drag_forwarding(this);
scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI);
scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_multi_selected));
@@ -1983,30 +2155,42 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
// Invalid source label.
invalid_source_label = memnew(Label);
invalid_source_label->set_text(TTR("Invalid source selected."));
- invalid_source_label->set_h_size_flags(SIZE_EXPAND_FILL);
- invalid_source_label->set_v_size_flags(SIZE_EXPAND_FILL);
+ invalid_source_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ invalid_source_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
invalid_source_label->set_align(Label::ALIGN_CENTER);
invalid_source_label->set_valign(Label::VALIGN_CENTER);
invalid_source_label->hide();
atlas_sources_split_container->add_child(invalid_source_label);
- _update_bottom_panel();
+ // --- Bottom panel patterns ---
+ patterns_bottom_panel = memnew(VBoxContainer);
+ patterns_bottom_panel->set_name(TTR("Patterns"));
+ patterns_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_tab_changed));
+
+ int thumbnail_size = 64;
+ patterns_item_list = memnew(ItemList);
+ patterns_item_list->set_max_columns(0);
+ patterns_item_list->set_icon_mode(ItemList::ICON_MODE_TOP);
+ patterns_item_list->set_fixed_column_width(thumbnail_size * 3 / 2);
+ patterns_item_list->set_max_text_lines(2);
+ patterns_item_list->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
+ patterns_item_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ patterns_item_list->connect("gui_input", callable_mp(this, &TileMapEditorTilesPlugin::_patterns_item_list_gui_input));
+ patterns_item_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection).unbind(1));
+ patterns_item_list->connect("item_activated", callable_mp(this, &TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection));
+ patterns_item_list->connect("nothing_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection));
+ patterns_bottom_panel->add_child(patterns_item_list);
+
+ patterns_help_label = memnew(Label);
+ patterns_help_label->set_text(TTR("Drag and drop or paste a TileMap selection here to store a pattern."));
+ patterns_help_label->set_anchors_and_offsets_preset(Control::PRESET_CENTER);
+ patterns_item_list->add_child(patterns_help_label);
+
+ // Update.
+ _update_source_display();
}
TileMapEditorTilesPlugin::~TileMapEditorTilesPlugin() {
- memdelete(selection_pattern);
- memdelete(tile_map_clipboard);
-}
-
-void TileMapEditorTerrainsPlugin::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED:
- paint_tool_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
- picker_button->set_icon(get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
- erase_button->set_icon(get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
- break;
- }
}
void TileMapEditorTerrainsPlugin::tile_set_changed() {
@@ -2029,8 +2213,10 @@ void TileMapEditorTerrainsPlugin::_update_toolbar() {
}
}
-Control *TileMapEditorTerrainsPlugin::get_toolbar() const {
- return toolbar;
+Vector<TileMapEditorPlugin::TabData> TileMapEditorTerrainsPlugin::get_tabs() const {
+ Vector<TileMapEditorPlugin::TabData> tabs;
+ tabs.push_back({ toolbar, main_vbox_container });
+ return tabs;
}
Map<Vector2i, TileSet::CellNeighbor> TileMapEditorTerrainsPlugin::Constraint::get_overlapping_coords_and_peering_bits() const {
@@ -2788,7 +2974,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
}
bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
- if (!is_visible_in_tree()) {
+ if (!main_vbox_container->is_visible_in_tree()) {
// If the bottom editor is not visible, we ignore inputs.
return false;
}
@@ -3060,13 +3246,13 @@ void TileMapEditorTerrainsPlugin::_update_terrains_tree() {
TreeItem *terrain_set_tree_item = terrains_tree->create_item();
String matches;
if (tile_set->get_terrain_set_mode(terrain_set_index) == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- terrain_set_tree_item->set_icon(0, get_theme_icon(SNAME("TerrainMatchCornersAndSides"), SNAME("EditorIcons")));
+ terrain_set_tree_item->set_icon(0, main_vbox_container->get_theme_icon(SNAME("TerrainMatchCornersAndSides"), SNAME("EditorIcons")));
matches = String(TTR("Matches Corners and Sides"));
} else if (tile_set->get_terrain_set_mode(terrain_set_index) == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- terrain_set_tree_item->set_icon(0, get_theme_icon(SNAME("TerrainMatchCorners"), SNAME("EditorIcons")));
+ terrain_set_tree_item->set_icon(0, main_vbox_container->get_theme_icon(SNAME("TerrainMatchCorners"), SNAME("EditorIcons")));
matches = String(TTR("Matches Corners Only"));
} else {
- terrain_set_tree_item->set_icon(0, get_theme_icon(SNAME("TerrainMatchSides"), SNAME("EditorIcons")));
+ terrain_set_tree_item->set_icon(0, main_vbox_container->get_theme_icon(SNAME("TerrainMatchSides"), SNAME("EditorIcons")));
matches = String(TTR("Matches Sides Only"));
}
terrain_set_tree_item->set_text(0, vformat("Terrain Set %d (%s)", terrain_set_index, matches));
@@ -3171,6 +3357,12 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
}
}
+void TileMapEditorTerrainsPlugin::_update_theme() {
+ paint_tool_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ picker_button->set_icon(main_vbox_container->get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
+ erase_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
+}
+
void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) {
_stop_dragging(); // Avoids staying in a wrong drag state.
@@ -3183,15 +3375,18 @@ void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_la
}
TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
- set_name("Terrains");
+ main_vbox_container = memnew(VBoxContainer);
+ main_vbox_container->connect("tree_entered", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
+ main_vbox_container->connect("theme_changed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
+ main_vbox_container->set_name("Terrains");
HSplitContainer *tilemap_tab_terrains = memnew(HSplitContainer);
- tilemap_tab_terrains->set_h_size_flags(SIZE_EXPAND_FILL);
- tilemap_tab_terrains->set_v_size_flags(SIZE_EXPAND_FILL);
- add_child(tilemap_tab_terrains);
+ tilemap_tab_terrains->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ tilemap_tab_terrains->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ main_vbox_container->add_child(tilemap_tab_terrains);
terrains_tree = memnew(Tree);
- terrains_tree->set_h_size_flags(SIZE_EXPAND_FILL);
+ terrains_tree->set_h_size_flags(Control::SIZE_EXPAND_FILL);
terrains_tree->set_stretch_ratio(0.25);
terrains_tree->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
terrains_tree->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
@@ -3200,7 +3395,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
tilemap_tab_terrains->add_child(terrains_tree);
terrains_tile_list = memnew(ItemList);
- terrains_tile_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ terrains_tile_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
terrains_tile_list->set_max_columns(0);
terrains_tile_list->set_same_column_width(true);
terrains_tile_list->set_fixed_icon_size(Size2(30, 30) * EDSCALE);
@@ -3267,7 +3462,7 @@ void TileMapEditor::_notification(int p_what) {
if (is_visible_in_tree() && tileset_changed_needs_update) {
_update_bottom_panel();
_update_layers_selection();
- tile_map_editor_plugins[tabs->get_current_tab()]->tile_set_changed();
+ tabs_plugins[tabs_bar->get_current_tab()]->tile_set_changed();
CanvasItemEditor::get_singleton()->update_viewport();
tileset_changed_needs_update = false;
}
@@ -3391,14 +3586,11 @@ void TileMapEditor::_update_bottom_panel() {
// Update the visibility of controls.
missing_tileset_label->set_visible(!tile_set.is_valid());
- if (!tile_set.is_valid()) {
- for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
- tile_map_editor_plugins[i]->hide();
- }
- } else {
- for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
- tile_map_editor_plugins[i]->set_visible(i == tabs->get_current_tab());
- }
+ for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) {
+ tabs_data[tab_index].panel->hide();
+ }
+ if (tile_set.is_valid()) {
+ tabs_data[tabs_bar->get_current_tab()].panel->show();
}
}
@@ -3481,27 +3673,25 @@ void TileMapEditor::_tile_map_changed() {
void TileMapEditor::_tab_changed(int p_tab_id) {
// Make the plugin edit the correct tilemap.
- tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer);
+ tabs_plugins[tabs_bar->get_current_tab()]->edit(tile_map_id, tile_map_layer);
// Update toolbar.
- for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
- tile_map_editor_plugins[i]->get_toolbar()->set_visible(i == p_tab_id);
+ for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) {
+ tabs_data[tab_index].toolbar->hide();
}
+ tabs_data[p_tab_id].toolbar->show();
// Update visible panel.
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
- if (!tile_map || !tile_map->get_tileset().is_valid()) {
- for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
- tile_map_editor_plugins[i]->hide();
- }
- } else {
- for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
- tile_map_editor_plugins[i]->set_visible(i == tabs->get_current_tab());
- }
+ for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) {
+ tabs_data[tab_index].panel->hide();
+ }
+ if (tile_map && tile_map->get_tileset().is_valid()) {
+ tabs_data[tabs_bar->get_current_tab()].panel->show();
}
// Graphical update.
- tile_map_editor_plugins[tabs->get_current_tab()]->update();
+ tabs_data[tabs_bar->get_current_tab()].panel->update();
CanvasItemEditor::get_singleton()->update_viewport();
}
@@ -3588,7 +3778,7 @@ void TileMapEditor::_update_layers_selection() {
layers_selection_button->set_custom_minimum_size(min_button_size);
layers_selection_button->update();
- tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer);
+ tabs_plugins[tabs_bar->get_current_tab()]->edit(tile_map_id, tile_map_layer);
}
void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
@@ -3674,7 +3864,7 @@ bool TileMapEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
return true;
}
- return tile_map_editor_plugins[tabs->get_current_tab()]->forward_canvas_gui_input(p_event);
+ return tabs_plugins[tabs_bar->get_current_tab()]->forward_canvas_gui_input(p_event);
}
void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
@@ -3809,7 +3999,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
}*/
// Draw the plugins.
- tile_map_editor_plugins[tabs->get_current_tab()]->forward_canvas_draw_over_viewport(p_overlay);
+ tabs_plugins[tabs_bar->get_current_tab()]->forward_canvas_draw_over_viewport(p_overlay);
}
void TileMapEditor::edit(TileMap *p_tile_map) {
@@ -3843,7 +4033,7 @@ void TileMapEditor::edit(TileMap *p_tile_map) {
_update_layers_selection();
// Call the plugins.
- tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer);
+ tabs_plugins[tabs_bar->get_current_tab()]->edit(tile_map_id, tile_map_layer);
_tile_map_changed();
}
@@ -3859,25 +4049,33 @@ TileMapEditor::TileMapEditor() {
tile_map_editor_plugins.push_back(memnew(TileMapEditorTilesPlugin));
tile_map_editor_plugins.push_back(memnew(TileMapEditorTerrainsPlugin));
- // Tabs.
- tabs = memnew(Tabs);
- tabs->set_clip_tabs(false);
- for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
- tabs->add_tab(tile_map_editor_plugins[i]->get_name());
+ // TabBar.
+ tabs_bar = memnew(TabBar);
+ tabs_bar->set_clip_tabs(false);
+ for (int plugin_index = 0; plugin_index < tile_map_editor_plugins.size(); plugin_index++) {
+ Vector<TileMapEditorPlugin::TabData> tabs_vector = tile_map_editor_plugins[plugin_index]->get_tabs();
+ for (int tab_index = 0; tab_index < tabs_vector.size(); tab_index++) {
+ tabs_bar->add_tab(tabs_vector[tab_index].panel->get_name());
+ tabs_data.push_back(tabs_vector[tab_index]);
+ tabs_plugins.push_back(tile_map_editor_plugins[plugin_index]);
+ }
}
- tabs->connect("tab_changed", callable_mp(this, &TileMapEditor::_tab_changed));
+ tabs_bar->connect("tab_changed", callable_mp(this, &TileMapEditor::_tab_changed));
// --- TileMap toolbar ---
tile_map_toolbar = memnew(HBoxContainer);
tile_map_toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_child(tile_map_toolbar);
// Tabs.
- tile_map_toolbar->add_child(tabs);
+ tile_map_toolbar->add_child(tabs_bar);
// Tabs toolbars.
- for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
- tile_map_editor_plugins[i]->get_toolbar()->hide();
- tile_map_toolbar->add_child(tile_map_editor_plugins[i]->get_toolbar());
+ for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) {
+ tabs_data[tab_index].toolbar->hide();
+ if (!tabs_data[tab_index].toolbar->get_parent()) {
+ tile_map_toolbar->add_child(tabs_data[tab_index].toolbar);
+ }
}
// Wide empty separation control.
@@ -3933,11 +4131,11 @@ TileMapEditor::TileMapEditor() {
missing_tileset_label->hide();
add_child(missing_tileset_label);
- for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
- add_child(tile_map_editor_plugins[i]);
- tile_map_editor_plugins[i]->set_h_size_flags(SIZE_EXPAND_FILL);
- tile_map_editor_plugins[i]->set_v_size_flags(SIZE_EXPAND_FILL);
- tile_map_editor_plugins[i]->set_visible(i == 0);
+ for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) {
+ add_child(tabs_data[tab_index].panel);
+ tabs_data[tab_index].panel->set_v_size_flags(SIZE_EXPAND_FILL);
+ tabs_data[tab_index].panel->set_visible(tab_index == 0);
+ tabs_data[tab_index].panel->set_h_size_flags(SIZE_EXPAND_FILL);
}
_tab_changed(0);
@@ -3947,4 +4145,7 @@ TileMapEditor::TileMapEditor() {
}
TileMapEditor::~TileMapEditor() {
+ for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
+ memdelete(tile_map_editor_plugins[i]);
+ }
}
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
index a1ab3db318..1f1a560113 100644
--- a/editor/plugins/tiles/tile_map_editor.h
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -33,17 +33,24 @@
#include "tile_atlas_view.h"
+#include "core/os/thread.h"
#include "core/typedefs.h"
#include "editor/editor_node.h"
#include "scene/2d/tile_map.h"
#include "scene/gui/box_container.h"
-#include "scene/gui/tabs.h"
+#include "scene/gui/tab_bar.h"
-class TileMapEditorPlugin : public VBoxContainer {
+class TileMapEditorPlugin : public Object {
public:
- virtual Control *get_toolbar() const {
- return memnew(Control);
+ struct TabData {
+ Control *toolbar;
+ Control *panel;
};
+
+ virtual Vector<TabData> get_tabs() const {
+ return Vector<TabData>();
+ };
+
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; };
virtual void forward_canvas_draw_over_viewport(Control *p_overlay){};
virtual void tile_set_changed(){};
@@ -104,29 +111,36 @@ private:
Vector2 drag_start_mouse_pos;
Vector2 drag_last_mouse_pos;
Map<Vector2i, TileMapCell> drag_modified;
+ bool rmb_erasing = false;
- TileMapCell _pick_random_tile(const TileMapPattern *p_pattern);
+ TileMapCell _pick_random_tile(Ref<TileMapPattern> p_pattern);
Map<Vector2i, TileMapCell> _draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos);
Map<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell);
Map<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous);
void _stop_dragging();
+ bool _is_erasing() const;
///// Selection system. /////
Set<Vector2i> tile_map_selection;
- TileMapPattern *tile_map_clipboard = memnew(TileMapPattern);
- TileMapPattern *selection_pattern = memnew(TileMapPattern);
+ Ref<TileMapPattern> tile_map_clipboard;
+ Ref<TileMapPattern> selection_pattern;
void _set_tile_map_selection(const TypedArray<Vector2i> &p_selection);
TypedArray<Vector2i> _get_tile_map_selection() const;
Set<TileMapCell> tile_set_selection;
void _update_selection_pattern_from_tilemap_selection();
- void _update_selection_pattern_from_tileset_selection();
+ void _update_selection_pattern_from_tileset_tiles_selection();
+ void _update_selection_pattern_from_tileset_pattern_selection();
void _update_tileset_selection_from_selection_pattern();
void _update_fix_selected_and_hovered();
void _fix_invalid_tiles_in_tile_map_selection();
- ///// Bottom panel. ////.
+ ///// Bottom panel common ////
+ void _tab_changed();
+
+ ///// Bottom panel tiles ////
+ VBoxContainer *tiles_bottom_panel;
Label *missing_source_label;
Label *invalid_source_label;
@@ -135,7 +149,7 @@ private:
Ref<Texture2D> missing_atlas_texture_icon;
void _update_tile_set_sources_list();
- void _update_bottom_panel();
+ void _update_source_display();
// Atlas sources.
TileMapCell hovered_tile;
@@ -165,15 +179,26 @@ private:
void _scenes_list_multi_selected(int p_index, bool p_selected);
void _scenes_list_nothing_selected();
+ ///// Bottom panel patterns ////
+ VBoxContainer *patterns_bottom_panel;
+ ItemList *patterns_item_list;
+ Label *patterns_help_label;
+ void _patterns_item_list_gui_input(const Ref<InputEvent> &p_event);
+ void _pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture);
+ bool select_last_pattern = false;
+ void _update_patterns_list();
+
+ // General
+ void _update_theme();
+
// Update callback
virtual void tile_set_changed() override;
protected:
- void _notification(int p_what);
static void _bind_methods();
public:
- virtual Control *get_toolbar() const override;
+ virtual Vector<TabData> get_tabs() const override;
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override;
virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
@@ -203,6 +228,9 @@ private:
void _update_toolbar();
+ // Main vbox.
+ VBoxContainer *main_vbox_container;
+
// TileMap editing.
enum DragType {
DRAG_TYPE_NONE = 0,
@@ -279,16 +307,13 @@ private:
void _update_terrains_cache();
void _update_terrains_tree();
void _update_tiles_list();
+ void _update_theme();
// Update callback
virtual void tile_set_changed() override;
-protected:
- void _notification(int p_what);
- // static void _bind_methods();
-
public:
- virtual Control *get_toolbar() const override;
+ virtual Vector<TabData> get_tabs() const override;
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override;
//virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
@@ -326,7 +351,9 @@ private:
// Bottom panel.
Label *missing_tileset_label;
- Tabs *tabs;
+ TabBar *tabs_bar;
+ LocalVector<TileMapEditorPlugin::TabData> tabs_data;
+ LocalVector<TileMapEditorPlugin *> tabs_plugins;
void _update_bottom_panel();
// TileMap.
@@ -353,7 +380,6 @@ public:
void forward_canvas_draw_over_viewport(Control *p_overlay);
void edit(TileMap *p_tile_map);
- Control *get_toolbar() { return tile_map_toolbar; };
TileMapEditor();
~TileMapEditor();
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 3fbd315aec..c8892bceaa 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -66,10 +66,15 @@ int TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::get_id() {
}
bool TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_set(const StringName &p_name, const Variant &p_value) {
+ String name = p_name;
+ if (name == "name") {
+ // Use the resource_name property to store the source's name.
+ name = "resource_name";
+ }
bool valid = false;
- tile_set_atlas_source->set(p_name, p_value, &valid);
+ tile_set_atlas_source->set(name, p_value, &valid);
if (valid) {
- emit_signal(SNAME("changed"), String(p_name).utf8().get_data());
+ emit_signal(SNAME("changed"), String(name).utf8().get_data());
}
return valid;
}
@@ -78,12 +83,18 @@ bool TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get(const StringN
if (!tile_set_atlas_source) {
return false;
}
+ String name = p_name;
+ if (name == "name") {
+ // Use the resource_name property to store the source's name.
+ name = "resource_name";
+ }
bool valid = false;
- r_ret = tile_set_atlas_source->get(p_name, &valid);
+ r_ret = tile_set_atlas_source->get(name, &valid);
return valid;
}
void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, ""));
@@ -106,6 +117,10 @@ void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::edit(Ref<TileSet>
ERR_FAIL_COND(p_source_id < 0);
ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
+ if (p_tile_set == tile_set && p_tile_set_atlas_source == tile_set_atlas_source && p_source_id == source_id) {
+ return;
+ }
+
// Disconnect to changes.
if (tile_set_atlas_source) {
tile_set_atlas_source->disconnect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
@@ -157,7 +172,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
} else if (p_name == "size_in_atlas") {
Vector2i as_vector2i = Vector2i(p_value);
bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, as_vector2i, tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords);
- ERR_FAIL_COND_V(!has_room_for_tile, false);
+ ERR_FAIL_COND_V_EDMSG(!has_room_for_tile, false, "Invalid size or not enough room in the atlas for the tile.");
tile_set_atlas_source->move_tile_in_atlas(coords, TileSetSource::INVALID_ATLAS_COORDS, as_vector2i);
emit_signal(SNAME("changed"), "size_in_atlas");
return true;
@@ -520,9 +535,6 @@ void TileSetAtlasSourceEditor::_update_tile_id_label() {
void TileSetAtlasSourceEditor::_update_source_inspector() {
// Update the proxy object.
atlas_source_proxy_object->edit(tile_set, tile_set_atlas_source, tile_set_atlas_source_id);
-
- // Update the "clear outside texture" button.
- tool_advanced_menu_buttom->get_popup()->set_item_disabled(0, !tile_set_atlas_source->has_tiles_outside_texture());
}
void TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles() {
@@ -763,7 +775,11 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
// Update visibility.
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"));
+ if (tile_data_editors_tree->get_selected()) {
+ tile_data_editor_dropdown_button->set_text(tile_data_editors_tree->get_selected()->get_text(0));
+ } else {
+ tile_data_editor_dropdown_button->set_text(TTR("Select a property editor"));
+ }
tile_data_editors_label->set_visible(is_visible);
}
@@ -908,7 +924,7 @@ void TileSetAtlasSourceEditor::_update_atlas_view() {
tile_atlas_view->update();
// Synchronize atlas view.
- TilesEditor::get_singleton()->synchronize_atlas_view(tile_atlas_view);
+ TilesEditorPlugin::get_singleton()->synchronize_atlas_view(tile_atlas_view);
}
void TileSetAtlasSourceEditor::_update_toolbar() {
@@ -959,7 +975,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
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;
+ tile_set_changed_needs_update = false;
tile_atlas_control->update();
tile_atlas_control_unscaled->update();
@@ -1061,7 +1077,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
drag_current_tile = coords;
// Update only what's needed.
- tile_set_atlas_source_changed_needs_update = false;
+ tile_set_changed_needs_update = false;
_update_tile_inspector();
_update_atlas_view();
_update_tile_id_label();
@@ -1101,7 +1117,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
drag_current_tile = new_rect.position;
// Update only what's needed.
- tile_set_atlas_source_changed_needs_update = false;
+ tile_set_changed_needs_update = false;
_update_tile_inspector();
_update_atlas_view();
_update_tile_id_label();
@@ -1600,9 +1616,6 @@ void TileSetAtlasSourceEditor::_menu_option(int p_option) {
undo_redo->commit_action();
_update_tile_id_label();
} break;
- case ADVANCED_CLEANUP_TILES_OUTSIDE_TEXTURE: {
- tile_set_atlas_source->clear_tiles_outside_texture();
- } break;
case ADVANCED_AUTO_CREATE_TILES: {
_auto_create_tiles();
} break;
@@ -2012,12 +2025,12 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() {
}
}
-void TileSetAtlasSourceEditor::_tile_set_atlas_source_changed() {
- tile_set_atlas_source_changed_needs_update = true;
+void TileSetAtlasSourceEditor::_tile_set_changed() {
+ tile_set_changed_needs_update = true;
}
void TileSetAtlasSourceEditor::_tile_proxy_object_changed(String p_what) {
- tile_set_atlas_source_changed_needs_update = false; // Avoid updating too many things.
+ tile_set_changed_needs_update = false; // Avoid updating too many things.
_update_atlas_view();
}
@@ -2035,30 +2048,66 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
- AtlasTileProxyObject *tile_data = Object::cast_to<AtlasTileProxyObject>(p_edited);
- if (tile_data) {
+ undo_redo->start_force_keep_in_merge_ends();
+ AtlasTileProxyObject *tile_data_proxy = Object::cast_to<AtlasTileProxyObject>(p_edited);
+ if (tile_data_proxy) {
Vector<String> components = String(p_property).split("/", true, 2);
if (components.size() == 2 && components[1] == "polygons_count") {
int layer_index = components[0].trim_prefix("physics_layer_").to_int();
int new_polygons_count = p_new_value;
- int old_polygons_count = tile_data->get(vformat("physics_layer_%d/polygons_count", layer_index));
+ int old_polygons_count = tile_data_proxy->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));
+ ADD_UNDO(tile_data_proxy, vformat("physics_layer_%d/polygon_%d/points", layer_index, i));
+ ADD_UNDO(tile_data_proxy, vformat("physics_layer_%d/polygon_%d/one_way", layer_index, i));
+ ADD_UNDO(tile_data_proxy, 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");
+ int current_terrain_set = tile_data_proxy->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]));
+ ADD_UNDO(tile_data_proxy, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
}
}
}
}
+
+ TileSetAtlasSourceProxyObject *atlas_source_proxy = Object::cast_to<TileSetAtlasSourceProxyObject>(p_edited);
+ if (atlas_source_proxy) {
+ TileSetAtlasSource *atlas_source = atlas_source_proxy->get_edited();
+ ERR_FAIL_COND(!atlas_source);
+
+ PackedVector2Array arr;
+ if (p_property == "texture") {
+ arr = atlas_source->get_tiles_to_be_removed_on_change(p_new_value, atlas_source->get_margins(), atlas_source->get_separation(), atlas_source->get_texture_region_size());
+ } else if (p_property == "margins") {
+ arr = atlas_source->get_tiles_to_be_removed_on_change(atlas_source->get_texture(), p_new_value, atlas_source->get_separation(), atlas_source->get_texture_region_size());
+ } else if (p_property == "separation") {
+ arr = atlas_source->get_tiles_to_be_removed_on_change(atlas_source->get_texture(), atlas_source->get_margins(), p_new_value, atlas_source->get_texture_region_size());
+ } else if (p_property == "texture_region_size") {
+ arr = atlas_source->get_tiles_to_be_removed_on_change(atlas_source->get_texture(), atlas_source->get_margins(), atlas_source->get_separation(), p_new_value);
+ }
+
+ if (!arr.is_empty()) {
+ // Get all properties assigned to a tile.
+ List<PropertyInfo> properties;
+ atlas_source->get_property_list(&properties);
+
+ for (int i = 0; i < arr.size(); i++) {
+ Vector2i coords = arr[i];
+ String prefix = vformat("%d:%d/", coords.x, coords.y);
+ for (PropertyInfo pi : properties) {
+ if (pi.name.begins_with(prefix)) {
+ ADD_UNDO(atlas_source, pi.name);
+ }
+ }
+ }
+ }
+ }
+ undo_redo->end_force_keep_in_merge_ends();
+
#undef ADD_UNDO
}
@@ -2073,8 +2122,8 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource
}
// Remove listener for old objects.
- if (tile_set_atlas_source) {
- tile_set_atlas_source->disconnect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_atlas_source_changed));
+ if (tile_set.is_valid()) {
+ tile_set->disconnect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
}
// Clear the selection.
@@ -2086,8 +2135,8 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource
tile_set_atlas_source_id = p_source_id;
// Add the listener again.
- if (tile_set_atlas_source) {
- tile_set_atlas_source->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_atlas_source_changed));
+ if (tile_set.is_valid()) {
+ tile_set->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
}
// Update everything.
@@ -2228,7 +2277,7 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
resize_handle_disabled = get_theme_icon(SNAME("EditorHandleDisabled"), SNAME("EditorIcons"));
break;
case NOTIFICATION_INTERNAL_PROCESS:
- if (tile_set_atlas_source_changed_needs_update) {
+ if (tile_set_changed_needs_update) {
// Update everything.
_update_source_inspector();
@@ -2241,7 +2290,7 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
_update_tile_data_editors();
_update_current_tile_data_editor();
- tile_set_atlas_source_changed_needs_update = false;
+ tile_set_changed_needs_update = false;
}
break;
default:
@@ -2406,8 +2455,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
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);
- tool_advanced_menu_buttom->get_popup()->set_item_disabled(0, true);
tool_advanced_menu_buttom->get_popup()->add_item(TTR("Create Tiles in Non-Transparent Texture Regions"), ADVANCED_AUTO_CREATE_TILES);
tool_advanced_menu_buttom->get_popup()->add_item(TTR("Remove Tiles in Fully Transparent Texture Regions"), ADVANCED_AUTO_REMOVE_TILES);
tool_advanced_menu_buttom->get_popup()->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
@@ -2429,7 +2476,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_atlas_view = memnew(TileAtlasView);
tile_atlas_view->set_h_size_flags(SIZE_EXPAND_FILL);
tile_atlas_view->set_v_size_flags(SIZE_EXPAND_FILL);
- tile_atlas_view->connect("transform_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_atlas_view_transform));
+ tile_atlas_view->connect("transform_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_atlas_view_transform));
tile_atlas_view->connect("transform_changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_view_transform_changed).unbind(2));
right_panel->add_child(tile_atlas_view);
@@ -2481,6 +2528,8 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_atlas_view_missing_source_label->set_v_size_flags(SIZE_EXPAND_FILL);
tile_atlas_view_missing_source_label->hide();
right_panel->add_child(tile_atlas_view_missing_source_label);
+
+ EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetAtlasSourceEditor::_undo_redo_inspector_callback));
}
TileSetAtlasSourceEditor::~TileSetAtlasSourceEditor() {
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
index 6448b55feb..ea6f2847ae 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.h
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -78,6 +78,7 @@ private:
int get_id();
void edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id);
+ TileSetAtlasSource *get_edited() { return tile_set_atlas_source; };
};
// -- Proxy object for a tile, needed by the inspector --
@@ -112,7 +113,7 @@ private:
UndoRedo *undo_redo = EditorNode::get_undo_redo();
- bool tile_set_atlas_source_changed_needs_update = false;
+ bool tile_set_changed_needs_update = false;
// -- Properties painting --
VBoxContainer *tile_data_painting_editor_container;
@@ -189,7 +190,6 @@ private:
TILE_CREATE_ALTERNATIVE,
TILE_DELETE,
- ADVANCED_CLEANUP_TILES_OUTSIDE_TEXTURE,
ADVANCED_AUTO_CREATE_TILES,
ADVANCED_AUTO_REMOVE_TILES,
};
@@ -263,7 +263,7 @@ private:
void _auto_remove_tiles();
AcceptDialog *confirm_auto_create_tiles;
- void _tile_set_atlas_source_changed();
+ void _tile_set_changed();
void _tile_proxy_object_changed(String p_what);
void _atlas_source_proxy_object_changed(String p_what);
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 48d0d9b333..0fbb9a98c7 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -145,14 +145,21 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
Ref<Texture2D> texture;
String item_text;
+ // Common to all type of sources.
+ if (!source->get_name().is_empty()) {
+ item_text = vformat(TTR("%s (id:%d)"), source->get_name(), source_id);
+ }
+
// Atlas source.
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
texture = atlas_source->get_texture();
- if (texture.is_valid()) {
- item_text = vformat("%s (id:%d)", texture->get_path().get_file(), source_id);
- } else {
- item_text = vformat(TTR("No Texture Atlas Source (id:%d)"), source_id);
+ if (item_text.is_empty()) {
+ if (texture.is_valid()) {
+ item_text = vformat("%s (ID:%d)", texture->get_path().get_file(), source_id);
+ } else {
+ item_text = vformat(TTR("No Texture Atlas Source (ID:%d)"), source_id);
+ }
}
}
@@ -160,12 +167,14 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
TileSetScenesCollectionSource *scene_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
if (scene_collection_source) {
texture = get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons"));
- item_text = vformat(TTR("Scene Collection Source (id:%d)"), source_id);
+ if (item_text.is_empty()) {
+ item_text = vformat(TTR("Scene Collection Source (ID:%d)"), source_id);
+ }
}
// Use default if not valid.
if (item_text.is_empty()) {
- item_text = vformat(TTR("Unknown Type Source (id:%d)"), source_id);
+ item_text = vformat(TTR("Unknown Type Source (ID:%d)"), source_id);
}
if (!texture.is_valid()) {
texture = missing_texture_texture;
@@ -200,7 +209,7 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
_source_selected(sources_list->get_current());
// Synchronize the lists.
- TilesEditor::get_singleton()->set_sources_lists_current(sources_list->get_current());
+ TilesEditorPlugin::get_singleton()->set_sources_lists_current(sources_list->get_current());
}
void TileSetEditor::_source_selected(int p_source_index) {
@@ -318,6 +327,7 @@ void TileSetEditor::_notification(int p_what) {
tile_set->set_edited(true);
}
_update_sources_list();
+ _update_patterns_list();
tile_set_changed_needs_update = false;
}
break;
@@ -326,10 +336,56 @@ void TileSetEditor::_notification(int p_what) {
}
}
+void TileSetEditor::_patterns_item_list_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
+ Vector<int> selected = patterns_item_list->get_selected_items();
+ undo_redo->create_action(TTR("Remove TileSet patterns"));
+ for (int i = 0; i < selected.size(); i++) {
+ int pattern_index = selected[i];
+ undo_redo->add_do_method(*tile_set, "remove_pattern", pattern_index);
+ undo_redo->add_undo_method(*tile_set, "add_pattern", tile_set->get_pattern(pattern_index), pattern_index);
+ }
+ undo_redo->commit_action();
+ patterns_item_list->accept_event();
+ }
+}
+
+void TileSetEditor::_pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture) {
+ // TODO optimize ?
+ for (int i = 0; i < patterns_item_list->get_item_count(); i++) {
+ if (patterns_item_list->get_item_metadata(i) == p_pattern) {
+ patterns_item_list->set_item_icon(i, p_texture);
+ break;
+ }
+ }
+}
+
+void TileSetEditor::_update_patterns_list() {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ // Recreate the items.
+ patterns_item_list->clear();
+ for (int i = 0; i < tile_set->get_patterns_count(); i++) {
+ int id = patterns_item_list->add_item("");
+ patterns_item_list->set_item_metadata(id, tile_set->get_pattern(i));
+ TilesEditorPlugin::get_singleton()->queue_pattern_preview(tile_set, tile_set->get_pattern(i), callable_mp(this, &TileSetEditor::_pattern_preview_done));
+ }
+
+ // Update the label visibility.
+ patterns_help_label->set_visible(patterns_item_list->get_item_count() == 0);
+}
+
void TileSetEditor::_tile_set_changed() {
tile_set_changed_needs_update = true;
}
+void TileSetEditor::_tab_changed(int p_tab_changed) {
+ split_container->set_visible(p_tab_changed == 0);
+ patterns_item_list->set_visible(p_tab_changed == 1);
+}
+
void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
ERR_FAIL_COND(!undo_redo);
@@ -573,6 +629,7 @@ void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
if (tile_set.is_valid()) {
tile_set->connect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed));
_update_sources_list();
+ _update_patterns_list();
}
tile_set_atlas_source_editor->hide();
@@ -585,8 +642,21 @@ TileSetEditor::TileSetEditor() {
set_process_internal(true);
+ // TabBar.
+ tabs_bar = memnew(TabBar);
+ tabs_bar->set_clip_tabs(false);
+ tabs_bar->add_tab(TTR("Tiles"));
+ tabs_bar->add_tab(TTR("Patterns"));
+ tabs_bar->connect("tab_changed", callable_mp(this, &TileSetEditor::_tab_changed));
+
+ tile_set_toolbar = memnew(HBoxContainer);
+ tile_set_toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
+ tile_set_toolbar->add_child(tabs_bar);
+ add_child(tile_set_toolbar);
+
+ //// Tiles ////
// Split container.
- HSplitContainer *split_container = memnew(HSplitContainer);
+ split_container = memnew(HSplitContainer);
split_container->set_name(TTR("Tiles"));
split_container->set_h_size_flags(SIZE_EXPAND_FILL);
split_container->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -605,8 +675,8 @@ TileSetEditor::TileSetEditor() {
sources_list->set_h_size_flags(SIZE_EXPAND_FILL);
sources_list->set_v_size_flags(SIZE_EXPAND_FILL);
sources_list->connect("item_selected", callable_mp(this, &TileSetEditor::_source_selected));
- sources_list->connect("item_selected", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_sources_lists_current));
- sources_list->connect("visibility_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::synchronize_sources_list), varray(sources_list));
+ sources_list->connect("item_selected", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_sources_lists_current));
+ sources_list->connect("visibility_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::synchronize_sources_list), varray(sources_list));
sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
sources_list->set_drag_forwarding(this);
split_container_left_side->add_child(sources_list);
@@ -672,6 +742,24 @@ TileSetEditor::TileSetEditor() {
split_container_right_side->add_child(tile_set_scenes_collection_source_editor);
tile_set_scenes_collection_source_editor->hide();
+ //// Patterns ////
+ int thumbnail_size = 64;
+ patterns_item_list = memnew(ItemList);
+ patterns_item_list->set_max_columns(0);
+ patterns_item_list->set_icon_mode(ItemList::ICON_MODE_TOP);
+ patterns_item_list->set_fixed_column_width(thumbnail_size * 3 / 2);
+ patterns_item_list->set_max_text_lines(2);
+ patterns_item_list->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
+ patterns_item_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ patterns_item_list->connect("gui_input", callable_mp(this, &TileSetEditor::_patterns_item_list_gui_input));
+ add_child(patterns_item_list);
+ patterns_item_list->hide();
+
+ patterns_help_label = memnew(Label);
+ patterns_help_label->set_text(TTR("Add new patterns in the TileMap editing mode."));
+ patterns_help_label->set_anchors_and_offsets_preset(Control::PRESET_CENTER);
+ patterns_item_list->add_child(patterns_help_label);
+
// Registers UndoRedo inspector callback.
EditorNode::get_singleton()->get_editor_data().add_move_array_element_function(SNAME("TileSet"), callable_mp(this, &TileSetEditor::_move_tile_set_array_element));
EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetEditor::_undo_redo_inspector_callback));
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index fe854b2281..cda38760cf 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -46,7 +46,13 @@ class TileSetEditor : public VBoxContainer {
private:
Ref<TileSet> tile_set;
bool tile_set_changed_needs_update = false;
+ HSplitContainer *split_container;
+ // TabBar.
+ HBoxContainer *tile_set_toolbar;
+ TabBar *tabs_bar;
+
+ // Tiles.
Label *no_source_selected_label;
TileSetAtlasSourceEditor *tile_set_atlas_source_editor;
TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor;
@@ -69,7 +75,16 @@ private:
AtlasMergingDialog *atlas_merging_dialog;
TileProxiesManagerDialog *tile_proxies_manager_dialog;
+ // Patterns.
+ ItemList *patterns_item_list;
+ Label *patterns_help_label;
+ void _patterns_item_list_gui_input(const Ref<InputEvent> &p_event);
+ void _pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture);
+ bool select_last_pattern = false;
+ void _update_patterns_list();
+
void _tile_set_changed();
+ void _tab_changed(int p_tab_changed);
void _move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos);
void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value);
@@ -82,6 +97,7 @@ public:
_FORCE_INLINE_ static TileSetEditor *get_singleton() { return singleton; }
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/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
index f74b3bf9c2..dc26d380b8 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -56,10 +56,15 @@ int TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::get
}
bool TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::_set(const StringName &p_name, const Variant &p_value) {
+ String name = p_name;
+ if (name == "name") {
+ // Use the resource_name property to store the source's name.
+ name = "resource_name";
+ }
bool valid = false;
- tile_set_scenes_collection_source->set(p_name, p_value, &valid);
+ tile_set_scenes_collection_source->set(name, p_value, &valid);
if (valid) {
- emit_signal(SNAME("changed"), String(p_name).utf8().get_data());
+ emit_signal(SNAME("changed"), String(name).utf8().get_data());
}
return valid;
}
@@ -68,11 +73,20 @@ bool TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::_g
if (!tile_set_scenes_collection_source) {
return false;
}
+ String name = p_name;
+ if (name == "name") {
+ // Use the resource_name property to store the source's name.
+ name = "resource_name";
+ }
bool valid = false;
- r_ret = tile_set_scenes_collection_source->get(p_name, &valid);
+ r_ret = tile_set_scenes_collection_source->get(name, &valid);
return valid;
}
+void TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, ""));
+}
+
void TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::_bind_methods() {
// -- Shape and layout --
ClassDB::bind_method(D_METHOD("set_id", "id"), &TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::set_id);
@@ -89,6 +103,10 @@ void TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::ed
ERR_FAIL_COND(p_source_id < 0);
ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_scenes_collection_source);
+ if (tile_set == p_tile_set && tile_set_scenes_collection_source == p_tile_set_scenes_collection_source && source_id == p_source_id) {
+ return;
+ }
+
// Disconnect to changes.
if (tile_set_scenes_collection_source) {
tile_set_scenes_collection_source->disconnect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
@@ -174,6 +192,10 @@ void TileSetScenesCollectionSourceEditor::SceneTileProxyObject::edit(TileSetScen
ERR_FAIL_COND(!p_tile_set_scenes_collection_source);
ERR_FAIL_COND(!p_tile_set_scenes_collection_source->has_scene_tile_id(p_scene_id));
+ if (tile_set_scenes_collection_source == p_tile_set_scenes_collection_source && scene_id == p_scene_id) {
+ return;
+ }
+
tile_set_scenes_collection_source = p_tile_set_scenes_collection_source;
scene_id = p_scene_id;
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
index 195aa79bc4..3be7bee714 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
@@ -51,6 +51,7 @@ private:
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
public:
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index d0d01a8d49..f1918073fb 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -30,99 +30,183 @@
#include "tiles_editor_plugin.h"
+#include "core/os/mutex.h"
+
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/2d/tile_map.h"
-#include "scene/resources/tile_set.h"
-
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/control.h"
#include "scene/gui/separator.h"
+#include "scene/resources/tile_set.h"
#include "tile_set_editor.h"
-TilesEditor *TilesEditor::singleton = nullptr;
+TilesEditorPlugin *TilesEditorPlugin::singleton = nullptr;
+
+void TilesEditorPlugin::_pattern_preview_done(const Variant &p_udata) {
+ pattern_preview_done.set();
+}
+
+void TilesEditorPlugin::_thread_func(void *ud) {
+ TilesEditorPlugin *te = (TilesEditorPlugin *)ud;
+ te->_thread();
+}
+
+void TilesEditorPlugin::_thread() {
+ pattern_thread_exited.clear();
+ while (!pattern_thread_exit.is_set()) {
+ pattern_preview_sem.wait();
+
+ pattern_preview_mutex.lock();
+ if (pattern_preview_queue.size()) {
+ QueueItem item = pattern_preview_queue.front()->get();
+ pattern_preview_queue.pop_front();
+ pattern_preview_mutex.unlock();
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ thumbnail_size *= EDSCALE;
+ Vector2 thumbnail_size2 = Vector2(thumbnail_size, thumbnail_size);
+
+ if (item.pattern.is_valid() && !item.pattern->is_empty()) {
+ // Generate the pattern preview
+ SubViewport *viewport = memnew(SubViewport);
+ viewport->set_size(thumbnail_size2);
+ viewport->set_disable_input(true);
+ viewport->set_transparent_background(true);
+ viewport->set_update_mode(SubViewport::UPDATE_ONCE);
+
+ TileMap *tile_map = memnew(TileMap);
+ tile_map->set_tileset(item.tile_set);
+ tile_map->set_pattern(0, Vector2(), item.pattern);
+ viewport->add_child(tile_map);
+
+ TypedArray<Vector2i> used_cells = tile_map->get_used_cells(0);
+
+ Rect2 encompassing_rect = Rect2();
+ encompassing_rect.set_position(tile_map->map_to_world(used_cells[0]));
+ for (int i = 0; i < used_cells.size(); i++) {
+ Vector2i cell = used_cells[i];
+ Vector2 world_pos = tile_map->map_to_world(cell);
+ encompassing_rect.expand_to(world_pos);
+
+ // Texture.
+ Ref<TileSetAtlasSource> atlas_source = tile_set->get_source(tile_map->get_cell_source_id(0, cell));
+ if (atlas_source.is_valid()) {
+ Vector2i coords = tile_map->get_cell_atlas_coords(0, cell);
+ int alternative = tile_map->get_cell_alternative_tile(0, cell);
+
+ Vector2 center = world_pos - atlas_source->get_tile_effective_texture_offset(coords, alternative);
+ encompassing_rect.expand_to(center - atlas_source->get_tile_texture_region(coords).size / 2);
+ encompassing_rect.expand_to(center + atlas_source->get_tile_texture_region(coords).size / 2);
+ }
+ }
+
+ Vector2 scale = thumbnail_size2 / MAX(encompassing_rect.size.x, encompassing_rect.size.y);
+ tile_map->set_scale(scale);
+ tile_map->set_position(-(scale * encompassing_rect.get_center()) + thumbnail_size2 / 2);
-void TilesEditor::_notification(int p_what) {
+ // Add the viewport at the lasst moment to avoid rendering too early.
+ EditorNode::get_singleton()->add_child(viewport);
+
+ pattern_preview_done.clear();
+ RS::get_singleton()->request_frame_drawn_callback(const_cast<TilesEditorPlugin *>(this), "_pattern_preview_done", Variant());
+
+ while (!pattern_preview_done.is_set()) {
+ OS::get_singleton()->delay_usec(10);
+ }
+
+ Ref<Image> image = viewport->get_texture()->get_image();
+ Ref<ImageTexture> image_texture;
+ image_texture.instantiate();
+ image_texture->create_from_image(image);
+
+ // Find the index for the given pattern. TODO: optimize.
+ Variant args[] = { item.pattern, image_texture };
+ const Variant *args_ptr[] = { &args[0], &args[1] };
+ Variant r;
+ Callable::CallError error;
+ item.callback.call(args_ptr, 2, r, error);
+
+ viewport->queue_delete();
+ } else {
+ pattern_preview_mutex.unlock();
+ }
+ }
+ }
+ pattern_thread_exited.set();
+}
+
+void TilesEditorPlugin::_tile_map_changed() {
+ tile_map_changed_needs_update = true;
+}
+
+void TilesEditorPlugin::_update_editors() {
+ // If tile_map is not edited, we change the edited only if we are not editing a tile_set.
+ tileset_editor->edit(tile_set);
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (tile_map) {
+ tilemap_editor->edit(tile_map);
+ } else {
+ tilemap_editor->edit(nullptr);
+ }
+
+ // Update the viewport.
+ CanvasItemEditor::get_singleton()->update_viewport();
+}
+
+void TilesEditorPlugin::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED: {
- tileset_tilemap_switch_button->set_icon(get_theme_icon(SNAME("TileSet"), SNAME("EditorIcons")));
- } break;
case NOTIFICATION_INTERNAL_PROCESS: {
if (tile_map_changed_needs_update) {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (tile_map) {
tile_set = tile_map->get_tileset();
}
- _update_switch_button();
_update_editors();
+ tile_map_changed_needs_update = false;
}
} break;
}
}
-void TilesEditor::_tile_map_changed() {
- tile_map_changed_needs_update = true;
-}
-
-void TilesEditor::_update_switch_button() {
- // Force the buttons status if needed.
- TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
- if (tile_map && !tile_set.is_valid()) {
- tileset_tilemap_switch_button->set_pressed(false);
- } else if (!tile_map && tile_set.is_valid()) {
- tileset_tilemap_switch_button->set_pressed(true);
- }
-}
-
-void TilesEditor::_update_editors() {
- // Set editors visibility.
- tilemap_toolbar->set_visible(!tileset_tilemap_switch_button->is_pressed());
- tilemap_editor->set_visible(!tileset_tilemap_switch_button->is_pressed());
- tileset_editor->set_visible(tileset_tilemap_switch_button->is_pressed());
-
- // Enable/disable the switch button.
- if (!tileset_tilemap_switch_button->is_pressed()) {
- if (!tile_set.is_valid()) {
- tileset_tilemap_switch_button->set_disabled(true);
- tileset_tilemap_switch_button->set_tooltip(TTR("This TileMap has no assigned TileSet, assign a TileSet to this TileMap to edit it."));
- } else {
- tileset_tilemap_switch_button->set_disabled(false);
- tileset_tilemap_switch_button->set_tooltip(TTR("Switch between TileSet/TileMap editor."));
- }
- } else {
+void TilesEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ // Disable and hide invalid editors.
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
- if (!tile_map) {
- tileset_tilemap_switch_button->set_disabled(true);
- tileset_tilemap_switch_button->set_tooltip(TTR("You are editing a TileSet resource. Select a TileMap node to paint."));
+ tileset_editor_button->set_visible(tile_set.is_valid());
+ tilemap_editor_button->set_visible(tile_map);
+ if (tile_map) {
+ editor_node->make_bottom_panel_item_visible(tilemap_editor);
} else {
- tileset_tilemap_switch_button->set_disabled(false);
- tileset_tilemap_switch_button->set_tooltip(TTR("Switch between TileSet/TileMap editor."));
+ editor_node->make_bottom_panel_item_visible(tileset_editor);
}
- }
- // If tile_map is not edited, we change the edited only if we are not editing a tile_set.
- TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
- if (tile_map) {
- tilemap_editor->edit(tile_map);
} else {
- tilemap_editor->edit(nullptr);
+ tileset_editor_button->hide();
+ tilemap_editor_button->hide();
+ editor_node->hide_bottom_panel();
}
- tileset_editor->edit(tile_set);
+}
- // Update the viewport
- CanvasItemEditor::get_singleton()->update_viewport();
+void TilesEditorPlugin::queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileMapPattern> p_pattern, Callable p_callback) {
+ ERR_FAIL_COND(!p_tile_set.is_valid());
+ ERR_FAIL_COND(!p_pattern.is_valid());
+ {
+ MutexLock lock(pattern_preview_mutex);
+ pattern_preview_queue.push_back({ p_tile_set, p_pattern, p_callback });
+ }
+ pattern_preview_sem.post();
}
-void TilesEditor::set_sources_lists_current(int p_current) {
+void TilesEditorPlugin::set_sources_lists_current(int p_current) {
atlas_sources_lists_current = p_current;
}
-void TilesEditor::synchronize_sources_list(Object *p_current) {
+void TilesEditorPlugin::synchronize_sources_list(Object *p_current) {
ItemList *item_list = Object::cast_to<ItemList>(p_current);
ERR_FAIL_COND(!item_list);
@@ -136,12 +220,12 @@ void TilesEditor::synchronize_sources_list(Object *p_current) {
}
}
-void TilesEditor::set_atlas_view_transform(float p_zoom, Vector2 p_scroll) {
+void TilesEditorPlugin::set_atlas_view_transform(float p_zoom, Vector2 p_scroll) {
atlas_view_zoom = p_zoom;
atlas_view_scroll = p_scroll;
}
-void TilesEditor::synchronize_atlas_view(Object *p_current) {
+void TilesEditorPlugin::synchronize_atlas_view(Object *p_current) {
TileAtlasView *tile_atlas_view = Object::cast_to<TileAtlasView>(p_current);
ERR_FAIL_COND(!tile_atlas_view);
@@ -150,11 +234,11 @@ void TilesEditor::synchronize_atlas_view(Object *p_current) {
}
}
-void TilesEditor::edit(Object *p_object) {
+void TilesEditorPlugin::edit(Object *p_object) {
// Disconnect to changes.
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (tile_map) {
- tile_map->disconnect("changed", callable_mp(this, &TilesEditor::_tile_map_changed));
+ tile_map->disconnect("changed", callable_mp(this, &TilesEditorPlugin::_tile_map_changed));
}
// Update edited objects.
@@ -164,112 +248,79 @@ void TilesEditor::edit(Object *p_object) {
tile_map_id = p_object->get_instance_id();
tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
tile_set = tile_map->get_tileset();
+ editor_node->make_bottom_panel_item_visible(tilemap_editor);
} else if (p_object->is_class("TileSet")) {
tile_set = Ref<TileSet>(p_object);
if (tile_map) {
- if (tile_map->get_tileset() != tile_set) {
+ if (tile_map->get_tileset() != tile_set || !tile_map->is_inside_tree()) {
tile_map = nullptr;
+ tile_map_id = ObjectID();
}
}
- }
-
- // Update pressed status button.
- if (p_object->is_class("TileMap")) {
- tileset_tilemap_switch_button->set_pressed(false);
- } else if (p_object->is_class("TileSet")) {
- tileset_tilemap_switch_button->set_pressed(true);
+ editor_node->make_bottom_panel_item_visible(tileset_editor);
}
}
// Update the editors.
- _update_switch_button();
_update_editors();
// Add change listener.
if (tile_map) {
- tile_map->connect("changed", callable_mp(this, &TilesEditor::_tile_map_changed));
+ tile_map->connect("changed", callable_mp(this, &TilesEditorPlugin::_tile_map_changed));
}
}
-void TilesEditor::_bind_methods() {
+bool TilesEditorPlugin::handles(Object *p_object) const {
+ return p_object->is_class("TileMap") || p_object->is_class("TileSet");
+}
+
+void TilesEditorPlugin::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_pattern_preview_done", "pattern"), &TilesEditorPlugin::_pattern_preview_done);
}
-TilesEditor::TilesEditor(EditorNode *p_editor) {
+TilesEditorPlugin::TilesEditorPlugin(EditorNode *p_node) {
set_process_internal(true);
// Update the singleton.
singleton = this;
- // Toolbar.
- HBoxContainer *toolbar = memnew(HBoxContainer);
- toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
- add_child(toolbar);
+ editor_node = p_node;
- // Switch button.
- tileset_tilemap_switch_button = memnew(Button);
- tileset_tilemap_switch_button->set_flat(true);
- tileset_tilemap_switch_button->set_toggle_mode(true);
- tileset_tilemap_switch_button->connect("toggled", callable_mp(this, &TilesEditor::_update_editors).unbind(1));
- toolbar->add_child(tileset_tilemap_switch_button);
+ // Tileset editor.
+ tileset_editor = memnew(TileSetEditor);
+ tileset_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ tileset_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ tileset_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
+ tileset_editor->hide();
// Tilemap editor.
tilemap_editor = memnew(TileMapEditor);
- tilemap_editor->set_h_size_flags(SIZE_EXPAND_FILL);
- tilemap_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ tilemap_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ tilemap_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ tilemap_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
tilemap_editor->hide();
- add_child(tilemap_editor);
- tilemap_toolbar = tilemap_editor->get_toolbar();
- toolbar->add_child(tilemap_toolbar);
+ // Pattern preview generation thread.
+ pattern_preview_thread.start(_thread_func, this);
- // Tileset editor.
- tileset_editor = memnew(TileSetEditor);
- tileset_editor->set_h_size_flags(SIZE_EXPAND_FILL);
- tileset_editor->set_v_size_flags(SIZE_EXPAND_FILL);
- tileset_editor->hide();
- add_child(tileset_editor);
+ // Bottom buttons.
+ tileset_editor_button = p_node->add_bottom_panel_item(TTR("TileSet"), tileset_editor);
+ tileset_editor_button->hide();
+ tilemap_editor_button = p_node->add_bottom_panel_item(TTR("TileMap"), tilemap_editor);
+ tilemap_editor_button->hide();
// Initialization.
- _update_switch_button();
_update_editors();
}
-TilesEditor::~TilesEditor() {
-}
-
-///////////////////////////////////////////////////////////////
-
-void TilesEditorPlugin::_notification(int p_what) {
-}
-
-void TilesEditorPlugin::make_visible(bool p_visible) {
- if (p_visible) {
- tiles_editor_button->show();
- editor_node->make_bottom_panel_item_visible(tiles_editor);
- } else {
- editor_node->hide_bottom_panel();
- tiles_editor_button->hide();
- }
-}
-
-void TilesEditorPlugin::edit(Object *p_object) {
- tiles_editor->edit(p_object);
-}
-
-bool TilesEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("TileMap") || p_object->is_class("TileSet");
-}
-
-TilesEditorPlugin::TilesEditorPlugin(EditorNode *p_node) {
- editor_node = p_node;
-
- tiles_editor = memnew(TilesEditor(p_node));
- tiles_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
- tiles_editor->hide();
-
- tiles_editor_button = p_node->add_bottom_panel_item(TTR("Tiles"), tiles_editor);
- tiles_editor_button->hide();
-}
-
TilesEditorPlugin::~TilesEditorPlugin() {
+ if (pattern_preview_thread.is_started()) {
+ pattern_thread_exit.set();
+ pattern_preview_sem.post();
+ while (!pattern_thread_exited.is_set()) {
+ OS::get_singleton()->delay_usec(10000);
+ RenderingServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server
+ }
+ pattern_preview_thread.wait_to_finish();
+ }
}
diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h
index f976d68938..dd52bdc31a 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.h
+++ b/editor/plugins/tiles/tiles_editor_plugin.h
@@ -38,24 +38,24 @@
#include "tile_map_editor.h"
#include "tile_set_editor.h"
-class TilesEditor : public VBoxContainer {
- GDCLASS(TilesEditor, VBoxContainer);
+class TilesEditorPlugin : public EditorPlugin {
+ GDCLASS(TilesEditorPlugin, EditorPlugin);
- static TilesEditor *singleton;
+ static TilesEditorPlugin *singleton;
private:
+ EditorNode *editor_node;
+
bool tile_map_changed_needs_update = false;
ObjectID tile_map_id;
Ref<TileSet> tile_set;
- Button *tileset_tilemap_switch_button;
-
- Control *tilemap_toolbar;
+ Button *tilemap_editor_button;
TileMapEditor *tilemap_editor;
+ Button *tileset_editor_button;
TileSetEditor *tileset_editor;
- void _update_switch_button();
void _update_editors();
// For synchronization.
@@ -65,15 +65,35 @@ private:
void _tile_map_changed();
+ // Patterns preview generation.
+ struct QueueItem {
+ Ref<TileSet> tile_set;
+ Ref<TileMapPattern> pattern;
+ Callable callback;
+ };
+ List<QueueItem> pattern_preview_queue;
+ Mutex pattern_preview_mutex;
+ Semaphore pattern_preview_sem;
+ Thread pattern_preview_thread;
+ SafeFlag pattern_thread_exit;
+ SafeFlag pattern_thread_exited;
+ mutable SafeFlag pattern_preview_done;
+ void _pattern_preview_done(const Variant &p_udata);
+ static void _thread_func(void *ud);
+ void _thread();
+
protected:
void _notification(int p_what);
static void _bind_methods();
public:
- _FORCE_INLINE_ static TilesEditor *get_singleton() { return singleton; }
+ _FORCE_INLINE_ static TilesEditorPlugin *get_singleton() { return singleton; }
- bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return tilemap_editor->forward_canvas_gui_input(p_event); }
- void forward_canvas_draw_over_viewport(Control *p_overlay) { tilemap_editor->forward_canvas_draw_over_viewport(p_overlay); }
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return tilemap_editor->forward_canvas_gui_input(p_event); }
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { tilemap_editor->forward_canvas_draw_over_viewport(p_overlay); }
+
+ // Pattern preview API.
+ void queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileMapPattern> p_pattern, Callable p_callback);
// To synchronize the atlas sources lists.
void set_sources_lists_current(int p_current);
@@ -82,27 +102,6 @@ public:
void set_atlas_view_transform(float p_zoom, Vector2 p_scroll);
void synchronize_atlas_view(Object *p_current);
- void edit(Object *p_object);
-
- TilesEditor(EditorNode *p_editor);
- ~TilesEditor();
-};
-
-class TilesEditorPlugin : public EditorPlugin {
- GDCLASS(TilesEditorPlugin, EditorPlugin);
-
-private:
- EditorNode *editor_node;
- TilesEditor *tiles_editor;
- Button *tiles_editor_button;
-
-protected:
- void _notification(int p_what);
-
-public:
- virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return tiles_editor->forward_canvas_gui_input(p_event); }
- virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { tiles_editor->forward_canvas_draw_over_viewport(p_overlay); }
-
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;