Path: blob/master/editor/scene/scene_create_dialog.cpp
9898 views
/**************************************************************************/1/* scene_create_dialog.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "scene_create_dialog.h"3132#include "core/io/dir_access.h"33#include "editor/editor_node.h"34#include "editor/editor_string_names.h"35#include "editor/gui/create_dialog.h"36#include "editor/gui/editor_validation_panel.h"37#include "editor/settings/editor_feature_profile.h"38#include "editor/themes/editor_scale.h"39#include "scene/2d/node_2d.h"40#include "scene/3d/node_3d.h"41#include "scene/gui/box_container.h"42#include "scene/gui/check_box.h"43#include "scene/gui/grid_container.h"44#include "scene/gui/line_edit.h"45#include "scene/gui/option_button.h"46#include "scene/resources/packed_scene.h"4748void SceneCreateDialog::_notification(int p_what) {49switch (p_what) {50case NOTIFICATION_THEME_CHANGED: {51select_node_button->set_button_icon(get_editor_theme_icon(SNAME("ClassList")));52node_type_2d->set_button_icon(get_editor_theme_icon(SNAME("Node2D")));53node_type_3d->set_button_icon(get_editor_theme_icon(SNAME("Node3D")));54node_type_gui->set_button_icon(get_editor_theme_icon(SNAME("Control")));55node_type_other->add_theme_icon_override(SNAME("icon"), get_editor_theme_icon(SNAME("Node")));56} break;5758case NOTIFICATION_READY: {59select_node_dialog->select_base();60} break;61}62}6364void SceneCreateDialog::config(const String &p_dir) {65directory = p_dir;66root_name_edit->set_text("");67scene_name_edit->set_text("");68callable_mp((Control *)scene_name_edit, &Control::grab_focus).call_deferred();69validation_panel->update();7071Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile();72node_type_3d->set_visible(profile.is_null() || !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D));73if (!node_type_3d->is_visible() && node_type_3d->is_pressed()) {74node_type_2d->set_pressed(true);75}76}7778void SceneCreateDialog::accept_create() {79if (!get_ok_button()->is_disabled()) {80hide();81emit_signal(SceneStringName(confirmed));82}83}8485void SceneCreateDialog::browse_types() {86select_node_dialog->popup_create(true);87select_node_dialog->set_title(TTR("Pick Root Node Type"));88select_node_dialog->set_ok_button_text(TTR("Pick"));89}9091void SceneCreateDialog::on_type_picked() {92other_type_display->set_text(select_node_dialog->get_selected_type().get_slicec(' ', 0));93if (node_type_other->is_pressed()) {94validation_panel->update();95} else {96node_type_other->set_pressed(true); // Calls validation_panel->update() via group.97}98}99100void SceneCreateDialog::update_dialog() {101scene_name = scene_name_edit->get_text().strip_edges();102103if (scene_name.is_empty()) {104validation_panel->set_message(MSG_ID_PATH, TTR("Scene name is empty."), EditorValidationPanel::MSG_ERROR);105}106107if (validation_panel->is_valid()) {108if (!scene_name.ends_with(".")) {109scene_name += ".";110}111scene_name += scene_extension_picker->get_selected_metadata().operator String();112}113114if (validation_panel->is_valid() && !scene_name.is_valid_filename()) {115validation_panel->set_message(MSG_ID_PATH, TTR("File name invalid."), EditorValidationPanel::MSG_ERROR);116} else if (validation_panel->is_valid() && scene_name[0] == '.') {117validation_panel->set_message(MSG_ID_PATH, TTR("File name begins with a dot."), EditorValidationPanel::MSG_ERROR);118}119120if (validation_panel->is_valid()) {121scene_name = directory.path_join(scene_name);122Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);123if (da->file_exists(scene_name)) {124validation_panel->set_message(MSG_ID_PATH, TTR("File already exists."), EditorValidationPanel::MSG_ERROR);125}126}127128const StringName root_type_name = StringName(other_type_display->get_text());129if (has_theme_icon(root_type_name, EditorStringName(EditorIcons))) {130node_type_other->set_button_icon(get_editor_theme_icon(root_type_name));131} else {132node_type_other->set_button_icon(nullptr);133}134135root_name = root_name_edit->get_text().strip_edges();136if (root_name.is_empty()) {137root_name = scene_name_edit->get_text().strip_edges();138139if (root_name.is_empty()) {140root_name_edit->set_placeholder(TTR("Leave empty to derive from scene name"));141} else {142// Respect the desired root node casing from ProjectSettings.143root_name = Node::adjust_name_casing(root_name);144root_name_edit->set_placeholder(root_name.validate_node_name());145}146}147148if (root_name.is_empty()) {149validation_panel->set_message(MSG_ID_ROOT, TTR("Invalid root node name."), EditorValidationPanel::MSG_ERROR);150} else if (root_name != root_name.validate_node_name()) {151validation_panel->set_message(MSG_ID_ROOT, TTR("Invalid root node name characters have been replaced."), EditorValidationPanel::MSG_WARNING);152}153}154155String SceneCreateDialog::get_scene_path() const {156return scene_name;157}158159Node *SceneCreateDialog::create_scene_root() {160ERR_FAIL_NULL_V(node_type_group->get_pressed_button(), nullptr);161RootType type = (RootType)node_type_group->get_pressed_button()->get_meta(type_meta).operator int();162163Node *root = nullptr;164switch (type) {165case ROOT_2D_SCENE:166root = memnew(Node2D);167break;168case ROOT_3D_SCENE:169root = memnew(Node3D);170break;171case ROOT_USER_INTERFACE: {172Control *gui_ctl = memnew(Control);173// Making the root control full rect by default is more useful for resizable UIs.174gui_ctl->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);175gui_ctl->set_grow_direction_preset(Control::PRESET_FULL_RECT);176root = gui_ctl;177} break;178case ROOT_OTHER:179root = Object::cast_to<Node>(select_node_dialog->instantiate_selected());180break;181}182183ERR_FAIL_NULL_V(root, nullptr);184root->set_name(root_name);185return root;186}187188SceneCreateDialog::SceneCreateDialog() {189select_node_dialog = memnew(CreateDialog);190add_child(select_node_dialog);191select_node_dialog->set_base_type("Node");192select_node_dialog->connect("create", callable_mp(this, &SceneCreateDialog::on_type_picked));193194VBoxContainer *main_vb = memnew(VBoxContainer);195add_child(main_vb);196197GridContainer *gc = memnew(GridContainer);198main_vb->add_child(gc);199gc->set_columns(2);200201{202Label *label = memnew(Label(TTR("Root Type:")));203gc->add_child(label);204label->set_v_size_flags(Control::SIZE_SHRINK_BEGIN);205206VBoxContainer *vb = memnew(VBoxContainer);207gc->add_child(vb);208209node_type_group.instantiate();210211node_type_2d = memnew(CheckBox);212vb->add_child(node_type_2d);213node_type_2d->set_text(TTR("2D Scene"));214node_type_2d->set_button_group(node_type_group);215node_type_2d->set_meta(type_meta, ROOT_2D_SCENE);216node_type_2d->set_pressed(true);217218node_type_3d = memnew(CheckBox);219vb->add_child(node_type_3d);220node_type_3d->set_text(TTR("3D Scene"));221node_type_3d->set_button_group(node_type_group);222node_type_3d->set_meta(type_meta, ROOT_3D_SCENE);223224node_type_gui = memnew(CheckBox);225vb->add_child(node_type_gui);226node_type_gui->set_text(TTR("User Interface"));227node_type_gui->set_button_group(node_type_group);228node_type_gui->set_meta(type_meta, ROOT_USER_INTERFACE);229230HBoxContainer *hb = memnew(HBoxContainer);231vb->add_child(hb);232233node_type_other = memnew(CheckBox);234hb->add_child(node_type_other);235node_type_other->set_accessibility_name(TTRC("Other Type"));236node_type_other->set_button_group(node_type_group);237node_type_other->set_meta(type_meta, ROOT_OTHER);238239Control *spacing = memnew(Control);240hb->add_child(spacing);241spacing->set_custom_minimum_size(Size2(4 * EDSCALE, 0));242243other_type_display = memnew(LineEdit);244other_type_display->set_accessibility_name(TTRC("Other Type"));245hb->add_child(other_type_display);246other_type_display->set_h_size_flags(Control::SIZE_EXPAND_FILL);247other_type_display->set_editable(false);248other_type_display->set_text("Node");249250select_node_button = memnew(Button);251select_node_button->set_accessibility_name(TTRC("Select Node"));252hb->add_child(select_node_button);253select_node_button->connect(SceneStringName(pressed), callable_mp(this, &SceneCreateDialog::browse_types));254}255256{257Label *label = memnew(Label(TTR("Scene Name:")));258gc->add_child(label);259260HBoxContainer *hb = memnew(HBoxContainer);261gc->add_child(hb);262263scene_name_edit = memnew(LineEdit);264hb->add_child(scene_name_edit);265scene_name_edit->set_accessibility_name(TTRC("Scene Name:"));266scene_name_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);267scene_name_edit->connect(SceneStringName(text_submitted), callable_mp(this, &SceneCreateDialog::accept_create).unbind(1));268269List<String> extensions;270Ref<PackedScene> sd = memnew(PackedScene);271ResourceSaver::get_recognized_extensions(sd, &extensions);272273scene_extension_picker = memnew(OptionButton);274scene_extension_picker->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);275hb->add_child(scene_extension_picker);276for (const String &E : extensions) {277scene_extension_picker->add_item("." + E);278scene_extension_picker->set_item_metadata(-1, E);279}280}281282{283Label *label = memnew(Label(TTR("Root Name:")));284gc->add_child(label);285286root_name_edit = memnew(LineEdit);287gc->add_child(root_name_edit);288root_name_edit->set_tooltip_text(TTR("When empty, the root node name is derived from the scene name based on the \"editor/naming/node_name_casing\" project setting."));289root_name_edit->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);290root_name_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);291root_name_edit->connect(SceneStringName(text_submitted), callable_mp(this, &SceneCreateDialog::accept_create).unbind(1));292}293294Control *spacing = memnew(Control);295main_vb->add_child(spacing);296spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));297298validation_panel = memnew(EditorValidationPanel);299main_vb->add_child(validation_panel);300validation_panel->add_line(MSG_ID_PATH, TTR("Scene name is valid."));301validation_panel->add_line(MSG_ID_ROOT, TTR("Root node valid."));302validation_panel->set_update_callback(callable_mp(this, &SceneCreateDialog::update_dialog));303validation_panel->set_accept_button(get_ok_button());304305node_type_group->connect(SceneStringName(pressed), callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));306scene_name_edit->connect(SceneStringName(text_changed), callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));307root_name_edit->connect(SceneStringName(text_changed), callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));308309set_title(TTR("Create New Scene"));310set_min_size(Size2i(400 * EDSCALE, 0));311}312313314