godot/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
reduz 6631f66c2a Optimize StringName usage
* Added a new macro SNAME() that constructs and caches a local stringname.
* Subsequent usages use the cached version.
* Since these use a global static variable, a second refcounter of static usages need to be kept for cleanup time.
* Replaced all theme usages by this new macro.
* Replace all signal emission usages by this new macro.
* Replace all call_deferred usages by this new macro.

This is part of ongoing work to optimize GUI and the editor.
2021-07-18 21:20:02 -03:00

512 lines
21 KiB
C++

/*************************************************************************/
/* tile_set_scenes_collection_source_editor.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "tile_set_scenes_collection_source_editor.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "scene/gui/item_list.h"
#include "core/core_string_names.h"
void TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::set_id(int p_id) {
ERR_FAIL_COND(p_id < 0);
if (source_id == p_id) {
return;
}
ERR_FAIL_COND_MSG(tile_set->has_source(p_id), vformat("Cannot change TileSet Scenes Collection source ID. Another TileSet source exists with id %d.", p_id));
int previous_source = source_id;
source_id = p_id; // source_id must be updated before, because it's used by the source list update.
tile_set->set_source_id(previous_source, p_id);
emit_signal(SNAME("changed"), "id");
}
int TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::get_id() {
return source_id;
}
bool TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::_set(const StringName &p_name, const Variant &p_value) {
bool valid = false;
tile_set_scenes_collection_source->set(p_name, p_value, &valid);
if (valid) {
emit_signal(SNAME("changed"), String(p_name).utf8().get_data());
}
return valid;
}
bool TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::_get(const StringName &p_name, Variant &r_ret) const {
if (!tile_set_scenes_collection_source) {
return false;
}
bool valid = false;
r_ret = tile_set_scenes_collection_source->get(p_name, &valid);
return valid;
}
void TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::_bind_methods() {
// -- Shape and layout --
ClassDB::bind_method(D_METHOD("set_id", "id"), &TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::set_id);
ClassDB::bind_method(D_METHOD("get_id"), &TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::get_id);
ADD_PROPERTY(PropertyInfo(Variant::INT, "id"), "set_id", "get_id");
ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what")));
}
void TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::edit(Ref<TileSet> p_tile_set, TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_source_id) {
ERR_FAIL_COND(!p_tile_set.is_valid());
ERR_FAIL_COND(!p_tile_set_scenes_collection_source);
ERR_FAIL_COND(p_source_id < 0);
ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_scenes_collection_source);
// 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));
}
tile_set = p_tile_set;
tile_set_scenes_collection_source = p_tile_set_scenes_collection_source;
source_id = p_source_id;
// Connect to changes.
if (tile_set_scenes_collection_source) {
if (!tile_set_scenes_collection_source->is_connected(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed))) {
tile_set_scenes_collection_source->connect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
}
}
notify_property_list_changed();
}
// -- Proxy object used by the tile inspector --
bool TileSetScenesCollectionSourceEditor::SceneTileProxyObject::_set(const StringName &p_name, const Variant &p_value) {
if (!tile_set_scenes_collection_source) {
return false;
}
if (p_name == "id") {
int as_int = int(p_value);
ERR_FAIL_COND_V(as_int < 0, false);
ERR_FAIL_COND_V(tile_set_scenes_collection_source->has_scene_tile_id(as_int), false);
tile_set_scenes_collection_source->set_scene_tile_id(scene_id, as_int);
scene_id = as_int;
emit_signal(SNAME("changed"), "id");
for (int i = 0; i < tile_set_scenes_collection_source_editor->scene_tiles_list->get_item_count(); i++) {
if (int(tile_set_scenes_collection_source_editor->scene_tiles_list->get_item_metadata(i)) == scene_id) {
tile_set_scenes_collection_source_editor->scene_tiles_list->select(i);
break;
}
}
return true;
} else if (p_name == "scene") {
tile_set_scenes_collection_source->set_scene_tile_scene(scene_id, p_value);
emit_signal(SNAME("changed"), "scene");
return true;
} else if (p_name == "display_placeholder") {
tile_set_scenes_collection_source->set_scene_tile_display_placeholder(scene_id, p_value);
emit_signal(SNAME("changed"), "display_placeholder");
return true;
}
return false;
}
bool TileSetScenesCollectionSourceEditor::SceneTileProxyObject::_get(const StringName &p_name, Variant &r_ret) const {
if (!tile_set_scenes_collection_source) {
return false;
}
if (p_name == "id") {
r_ret = scene_id;
return true;
} else if (p_name == "scene") {
r_ret = tile_set_scenes_collection_source->get_scene_tile_scene(scene_id);
return true;
} else if (p_name == "display_placeholder") {
r_ret = tile_set_scenes_collection_source->get_scene_tile_display_placeholder(scene_id);
return true;
}
return false;
}
void TileSetScenesCollectionSourceEditor::SceneTileProxyObject::_get_property_list(List<PropertyInfo> *p_list) const {
if (!tile_set_scenes_collection_source) {
return;
}
p_list->push_back(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::OBJECT, "scene", PROPERTY_HINT_RESOURCE_TYPE, "PackedScene"));
p_list->push_back(PropertyInfo(Variant::BOOL, "display_placeholder", PROPERTY_HINT_NONE, ""));
}
void TileSetScenesCollectionSourceEditor::SceneTileProxyObject::edit(TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_scene_id) {
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));
tile_set_scenes_collection_source = p_tile_set_scenes_collection_source;
scene_id = p_scene_id;
notify_property_list_changed();
}
void TileSetScenesCollectionSourceEditor::SceneTileProxyObject::_bind_methods() {
ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what")));
}
void TileSetScenesCollectionSourceEditor::_scenes_collection_source_proxy_object_changed(String p_what) {
if (p_what == "id") {
emit_signal(SNAME("source_id_changed"), scenes_collection_source_proxy_object->get_id());
}
}
void TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed() {
tile_set_scenes_collection_source_changed_needs_update = true;
}
void TileSetScenesCollectionSourceEditor::_scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud) {
int index = p_ud;
if (index >= 0 && index < scene_tiles_list->get_item_count()) {
scene_tiles_list->set_item_icon(index, p_preview);
}
}
void TileSetScenesCollectionSourceEditor::_scenes_list_item_activated(int p_index) {
Ref<PackedScene> packed_scene = tile_set_scenes_collection_source->get_scene_tile_scene(scene_tiles_list->get_item_metadata(p_index));
if (packed_scene.is_valid()) {
EditorNode::get_singleton()->open_request(packed_scene->get_path());
}
}
void TileSetScenesCollectionSourceEditor::_source_add_pressed() {
int scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id();
undo_redo->create_action(TTR("Add a Scene Tile"));
undo_redo->add_do_method(tile_set_scenes_collection_source, "create_scene_tile", Ref<PackedScene>(), scene_id);
undo_redo->add_undo_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
undo_redo->commit_action();
_update_scenes_list();
_update_action_buttons();
_update_tile_inspector();
}
void TileSetScenesCollectionSourceEditor::_source_delete_pressed() {
Vector<int> selected_indices = scene_tiles_list->get_selected_items();
ERR_FAIL_COND(selected_indices.size() <= 0);
int scene_id = scene_tiles_list->get_item_metadata(selected_indices[0]);
undo_redo->create_action(TTR("Remove a Scene Tile"));
undo_redo->add_do_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
undo_redo->add_undo_method(tile_set_scenes_collection_source, "create_scene_tile", tile_set_scenes_collection_source->get_scene_tile_scene(scene_id), scene_id);
undo_redo->commit_action();
_update_scenes_list();
_update_action_buttons();
_update_tile_inspector();
}
void TileSetScenesCollectionSourceEditor::_update_source_inspector() {
// Update the proxy object.
scenes_collection_source_proxy_object->edit(tile_set, tile_set_scenes_collection_source, tile_set_source_id);
}
void TileSetScenesCollectionSourceEditor::_update_tile_inspector() {
Vector<int> selected_indices = scene_tiles_list->get_selected_items();
bool has_atlas_tile_selected = (selected_indices.size() > 0);
// Update the proxy object.
if (has_atlas_tile_selected) {
int scene_id = scene_tiles_list->get_item_metadata(selected_indices[0]);
tile_proxy_object->edit(tile_set_scenes_collection_source, scene_id);
}
// Update visibility.
tile_inspector_label->set_visible(has_atlas_tile_selected);
tile_inspector->set_visible(has_atlas_tile_selected);
}
void TileSetScenesCollectionSourceEditor::_update_action_buttons() {
Vector<int> selected_indices = scene_tiles_list->get_selected_items();
scene_tile_delete_button->set_disabled(selected_indices.size() <= 0);
}
void TileSetScenesCollectionSourceEditor::_update_scenes_list() {
if (!tile_set_scenes_collection_source) {
return;
}
// Get the previously selected id.
Vector<int> selected_indices = scene_tiles_list->get_selected_items();
int old_selected_scene_id = (selected_indices.size() > 0) ? int(scene_tiles_list->get_item_metadata(selected_indices[0])) : -1;
// Clear the list.
scene_tiles_list->clear();
// Rebuild the list.
int to_reselect = -1;
for (int i = 0; i < tile_set_scenes_collection_source->get_scene_tiles_count(); i++) {
int scene_id = tile_set_scenes_collection_source->get_scene_tile_id(i);
Ref<PackedScene> scene = tile_set_scenes_collection_source->get_scene_tile_scene(scene_id);
int item_index = 0;
if (scene.is_valid()) {
item_index = scene_tiles_list->add_item(vformat("%s (path:%s id:%d)", scene->get_path().get_file().get_basename(), scene->get_path(), scene_id));
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")));
}
scene_tiles_list->set_item_metadata(item_index, scene_id);
if (old_selected_scene_id >= 0 && scene_id == old_selected_scene_id) {
to_reselect = i;
}
}
// Reselect if needed.
if (to_reselect >= 0) {
scene_tiles_list->select(to_reselect);
}
// Icon size update.
int int_size = int(EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size")) * EDSCALE;
scene_tiles_list->set_fixed_icon_size(Vector2(int_size, int_size));
}
void TileSetScenesCollectionSourceEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED:
scene_tile_add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
scene_tile_delete_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
_update_scenes_list();
break;
case NOTIFICATION_INTERNAL_PROCESS:
if (tile_set_scenes_collection_source_changed_needs_update) {
// Update everything.
_update_source_inspector();
_update_scenes_list();
_update_action_buttons();
_update_tile_inspector();
tile_set_scenes_collection_source_changed_needs_update = false;
}
break;
case NOTIFICATION_VISIBILITY_CHANGED:
// Update things just in case.
_update_scenes_list();
_update_action_buttons();
break;
default:
break;
}
}
void TileSetScenesCollectionSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_source_id) {
ERR_FAIL_COND(!p_tile_set.is_valid());
ERR_FAIL_COND(!p_tile_set_scenes_collection_source);
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 (p_tile_set == tile_set && p_tile_set_scenes_collection_source == tile_set_scenes_collection_source && p_source_id == tile_set_source_id) {
return;
}
// Remove listener for old objects.
if (tile_set_scenes_collection_source) {
tile_set_scenes_collection_source->disconnect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed));
}
// Change the edited object.
tile_set = p_tile_set;
tile_set_scenes_collection_source = p_tile_set_scenes_collection_source;
tile_set_source_id = p_source_id;
// Add the listener again.
if (tile_set_scenes_collection_source) {
tile_set_scenes_collection_source->connect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed));
}
// Update everything.
_update_source_inspector();
_update_scenes_list();
_update_action_buttons();
_update_tile_inspector();
}
void TileSetScenesCollectionSourceEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
if (!can_drop_data_fw(p_point, p_data, p_from)) {
return;
}
if (p_from == scene_tiles_list) {
// Handle dropping a texture in the list of atlas resources.
int scene_id = -1;
Dictionary d = p_data;
Vector<String> files = d["files"];
for (int i = 0; i < files.size(); i++) {
Ref<PackedScene> resource = ResourceLoader::load(files[i]);
if (resource.is_valid()) {
scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id();
undo_redo->create_action(TTR("Add a Scene Tile"));
undo_redo->add_do_method(tile_set_scenes_collection_source, "create_scene_tile", resource, scene_id);
undo_redo->add_undo_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
undo_redo->commit_action();
}
}
_update_scenes_list();
_update_action_buttons();
_update_tile_inspector();
}
}
bool TileSetScenesCollectionSourceEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
if (p_from == scene_tiles_list) {
Dictionary d = p_data;
if (!d.has("type")) {
return false;
}
// Check if we have a Texture2D.
if (String(d["type"]) == "files") {
Vector<String> files = d["files"];
if (files.size() == 0) {
return false;
}
for (int i = 0; i < files.size(); i++) {
String file = files[i];
String ftype = EditorFileSystem::get_singleton()->get_file_type(file);
if (!ClassDB::is_parent_class(ftype, "PackedScene")) {
return false;
}
}
return true;
}
}
return false;
}
void TileSetScenesCollectionSourceEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("source_id_changed", PropertyInfo(Variant::INT, "source_id")));
ClassDB::bind_method(D_METHOD("_scene_thumbnail_done"), &TileSetScenesCollectionSourceEditor::_scene_thumbnail_done);
ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &TileSetScenesCollectionSourceEditor::can_drop_data_fw);
ClassDB::bind_method(D_METHOD("drop_data_fw"), &TileSetScenesCollectionSourceEditor::drop_data_fw);
}
TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
// -- Right side --
HSplitContainer *split_container_right_side = memnew(HSplitContainer);
split_container_right_side->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(split_container_right_side);
// Middle panel.
ScrollContainer *middle_panel = memnew(ScrollContainer);
middle_panel->set_enable_h_scroll(false);
middle_panel->set_custom_minimum_size(Size2i(200, 0) * EDSCALE);
split_container_right_side->add_child(middle_panel);
VBoxContainer *middle_vbox_container = memnew(VBoxContainer);
middle_vbox_container->set_h_size_flags(SIZE_EXPAND_FILL);
middle_panel->add_child(middle_vbox_container);
// Scenes collection source inspector.
scenes_collection_source_inspector_label = memnew(Label);
scenes_collection_source_inspector_label->set_text(TTR("Scenes collection properties:"));
middle_vbox_container->add_child(scenes_collection_source_inspector_label);
scenes_collection_source_proxy_object = memnew(TileSetScenesCollectionProxyObject());
scenes_collection_source_proxy_object->connect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_scenes_collection_source_proxy_object_changed));
scenes_collection_source_inspector = memnew(EditorInspector);
scenes_collection_source_inspector->set_undo_redo(undo_redo);
scenes_collection_source_inspector->set_enable_v_scroll(false);
scenes_collection_source_inspector->edit(scenes_collection_source_proxy_object);
middle_vbox_container->add_child(scenes_collection_source_inspector);
// Tile inspector.
tile_inspector_label = memnew(Label);
tile_inspector_label->set_text(TTR("Tile properties:"));
tile_inspector_label->hide();
middle_vbox_container->add_child(tile_inspector_label);
tile_proxy_object = memnew(SceneTileProxyObject(this));
tile_proxy_object->connect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_scenes_list).unbind(1));
tile_proxy_object->connect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_action_buttons).unbind(1));
tile_inspector = memnew(EditorInspector);
tile_inspector->set_undo_redo(undo_redo);
tile_inspector->set_enable_v_scroll(false);
tile_inspector->edit(tile_proxy_object);
tile_inspector->set_use_folding(true);
middle_vbox_container->add_child(tile_inspector);
// Scenes list.
VBoxContainer *right_vbox_container = memnew(VBoxContainer);
split_container_right_side->add_child(right_vbox_container);
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_drag_forwarding(this);
scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_tile_inspector).unbind(1));
scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_action_buttons).unbind(1));
scene_tiles_list->connect("item_activated", callable_mp(this, &TileSetScenesCollectionSourceEditor::_scenes_list_item_activated));
scene_tiles_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
right_vbox_container->add_child(scene_tiles_list);
HBoxContainer *scenes_bottom_actions = memnew(HBoxContainer);
right_vbox_container->add_child(scenes_bottom_actions);
scene_tile_add_button = memnew(Button);
scene_tile_add_button->set_flat(true);
scene_tile_add_button->connect("pressed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_source_add_pressed));
scenes_bottom_actions->add_child(scene_tile_add_button);
scene_tile_delete_button = memnew(Button);
scene_tile_delete_button->set_flat(true);
scene_tile_delete_button->set_disabled(true);
scene_tile_delete_button->connect("pressed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_source_delete_pressed));
scenes_bottom_actions->add_child(scene_tile_delete_button);
}
TileSetScenesCollectionSourceEditor::~TileSetScenesCollectionSourceEditor() {
memdelete(scenes_collection_source_proxy_object);
memdelete(tile_proxy_object);
}