Path: blob/master/editor/scene/scene_create_dialog.cpp
20844 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 "core/io/resource_saver.h"34#include "editor/editor_node.h"35#include "editor/editor_string_names.h"36#include "editor/gui/create_dialog.h"37#include "editor/gui/editor_validation_panel.h"38#include "editor/settings/editor_feature_profile.h"39#include "editor/themes/editor_scale.h"40#include "scene/2d/node_2d.h"41#include "scene/3d/node_3d.h"42#include "scene/gui/box_container.h"43#include "scene/gui/check_box.h"44#include "scene/gui/grid_container.h"45#include "scene/gui/line_edit.h"46#include "scene/gui/option_button.h"47#include "scene/resources/packed_scene.h"4849void SceneCreateDialog::_notification(int p_what) {50switch (p_what) {51case NOTIFICATION_THEME_CHANGED: {52select_node_button->set_button_icon(get_editor_theme_icon(SNAME("ClassList")));53node_type_2d->set_button_icon(get_editor_theme_icon(SNAME("Node2D")));54node_type_3d->set_button_icon(get_editor_theme_icon(SNAME("Node3D")));55node_type_gui->set_button_icon(get_editor_theme_icon(SNAME("Control")));56node_type_other->add_theme_icon_override(SNAME("icon"), get_editor_theme_icon(SNAME("Node")));57} break;5859case NOTIFICATION_READY: {60select_node_dialog->select_base();61} break;62}63}6465void SceneCreateDialog::config(const String &p_dir) {66directory = p_dir;67root_name_edit->set_text("");68scene_name_edit->set_text("");69callable_mp((Control *)scene_name_edit, &Control::grab_focus).call_deferred(false);70validation_panel->update();7172Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile();73node_type_3d->set_visible(profile.is_null() || !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D));74if (!node_type_3d->is_visible() && node_type_3d->is_pressed()) {75node_type_2d->set_pressed(true);76}77}7879void SceneCreateDialog::accept_create() {80if (!get_ok_button()->is_disabled()) {81hide();82emit_signal(SceneStringName(confirmed));83}84}8586void SceneCreateDialog::browse_types() {87select_node_dialog->popup_create(true);88select_node_dialog->set_title(TTR("Pick Root Node Type"));89select_node_dialog->set_ok_button_text(TTR("Pick"));90}9192void SceneCreateDialog::on_type_picked() {93other_type_display->set_text(select_node_dialog->get_selected_type());94if (node_type_other->is_pressed()) {95validation_panel->update();96} else {97node_type_other->set_pressed(true); // Calls validation_panel->update() via group.98}99}100101void SceneCreateDialog::update_dialog() {102scene_name = scene_name_edit->get_text().strip_edges();103104if (scene_name.is_empty()) {105validation_panel->set_message(MSG_ID_PATH, TTR("Scene name is empty."), EditorValidationPanel::MSG_ERROR);106}107108if (validation_panel->is_valid()) {109if (!scene_name.ends_with(".")) {110scene_name += ".";111}112scene_name += scene_extension_picker->get_selected_metadata().operator String();113}114115if (validation_panel->is_valid() && !scene_name.is_valid_filename()) {116validation_panel->set_message(MSG_ID_PATH, TTR("File name invalid."), EditorValidationPanel::MSG_ERROR);117} else if (validation_panel->is_valid() && scene_name[0] == '.') {118validation_panel->set_message(MSG_ID_PATH, TTR("File name begins with a dot."), EditorValidationPanel::MSG_ERROR);119}120121if (validation_panel->is_valid()) {122scene_name = directory.path_join(scene_name);123Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);124if (da->file_exists(scene_name)) {125validation_panel->set_message(MSG_ID_PATH, TTR("File already exists."), EditorValidationPanel::MSG_ERROR);126}127}128129const StringName root_type_name = StringName(other_type_display->get_text());130if (has_theme_icon(root_type_name, EditorStringName(EditorIcons))) {131node_type_other->set_button_icon(get_editor_theme_icon(root_type_name));132} else {133node_type_other->set_button_icon(nullptr);134}135136root_name = root_name_edit->get_text().strip_edges();137if (root_name.is_empty()) {138root_name = scene_name_edit->get_text().strip_edges();139140if (root_name.is_empty()) {141root_name_edit->set_placeholder(TTR("Leave empty to derive from scene name"));142} else {143// Respect the desired root node casing from ProjectSettings.144root_name = Node::adjust_name_casing(root_name);145root_name_edit->set_placeholder(root_name.validate_node_name());146}147}148149if (root_name.is_empty()) {150validation_panel->set_message(MSG_ID_ROOT, TTR("Invalid root node name."), EditorValidationPanel::MSG_ERROR);151} else if (root_name != root_name.validate_node_name()) {152validation_panel->set_message(MSG_ID_ROOT, TTR("Invalid root node name characters have been replaced."), EditorValidationPanel::MSG_WARNING);153}154}155156String SceneCreateDialog::get_scene_path() const {157return scene_name;158}159160Node *SceneCreateDialog::create_scene_root() {161ERR_FAIL_NULL_V(node_type_group->get_pressed_button(), nullptr);162RootType type = (RootType)node_type_group->get_pressed_button()->get_meta(type_meta).operator int();163164Node *root = nullptr;165switch (type) {166case ROOT_2D_SCENE:167root = memnew(Node2D);168break;169case ROOT_3D_SCENE:170root = memnew(Node3D);171break;172case ROOT_USER_INTERFACE: {173Control *gui_ctl = memnew(Control);174// Making the root control full rect by default is more useful for resizable UIs.175gui_ctl->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);176gui_ctl->set_grow_direction_preset(Control::PRESET_FULL_RECT);177root = gui_ctl;178} break;179case ROOT_OTHER:180root = Object::cast_to<Node>(select_node_dialog->instantiate_selected());181break;182}183184ERR_FAIL_NULL_V(root, nullptr);185root->set_name(root_name);186return root;187}188189SceneCreateDialog::SceneCreateDialog() {190select_node_dialog = memnew(CreateDialog);191add_child(select_node_dialog);192select_node_dialog->set_base_type("Node");193select_node_dialog->connect("create", callable_mp(this, &SceneCreateDialog::on_type_picked));194195VBoxContainer *main_vb = memnew(VBoxContainer);196add_child(main_vb);197198GridContainer *gc = memnew(GridContainer);199main_vb->add_child(gc);200gc->set_columns(2);201202{203Label *label = memnew(Label(TTR("Root Type:")));204gc->add_child(label);205label->set_v_size_flags(Control::SIZE_SHRINK_BEGIN);206207VBoxContainer *vb = memnew(VBoxContainer);208gc->add_child(vb);209210node_type_group.instantiate();211212node_type_2d = memnew(CheckBox);213vb->add_child(node_type_2d);214node_type_2d->set_text(TTR("2D Scene"));215node_type_2d->set_theme_type_variation("CheckBoxNoIconTint");216node_type_2d->set_button_group(node_type_group);217node_type_2d->set_meta(type_meta, ROOT_2D_SCENE);218node_type_2d->set_pressed(true);219220node_type_3d = memnew(CheckBox);221vb->add_child(node_type_3d);222node_type_3d->set_text(TTR("3D Scene"));223node_type_3d->set_theme_type_variation("CheckBoxNoIconTint");224node_type_3d->set_button_group(node_type_group);225node_type_3d->set_meta(type_meta, ROOT_3D_SCENE);226227node_type_gui = memnew(CheckBox);228vb->add_child(node_type_gui);229node_type_gui->set_text(TTR("User Interface"));230node_type_gui->set_theme_type_variation("CheckBoxNoIconTint");231node_type_gui->set_button_group(node_type_group);232node_type_gui->set_meta(type_meta, ROOT_USER_INTERFACE);233234HBoxContainer *hb = memnew(HBoxContainer);235vb->add_child(hb);236237node_type_other = memnew(CheckBox);238hb->add_child(node_type_other);239node_type_other->set_accessibility_name(TTRC("Other Type"));240node_type_other->set_theme_type_variation("CheckBoxNoIconTint");241node_type_other->set_button_group(node_type_group);242node_type_other->set_meta(type_meta, ROOT_OTHER);243244Control *spacing = memnew(Control);245hb->add_child(spacing);246spacing->set_custom_minimum_size(Size2(4 * EDSCALE, 0));247248other_type_display = memnew(LineEdit);249other_type_display->set_accessibility_name(TTRC("Other Type"));250hb->add_child(other_type_display);251other_type_display->set_h_size_flags(Control::SIZE_EXPAND_FILL);252other_type_display->set_editable(false);253other_type_display->set_text("Node");254255select_node_button = memnew(Button);256select_node_button->set_accessibility_name(TTRC("Select Node"));257hb->add_child(select_node_button);258select_node_button->connect(SceneStringName(pressed), callable_mp(this, &SceneCreateDialog::browse_types));259}260261{262Label *label = memnew(Label(TTR("Scene Name:")));263gc->add_child(label);264265HBoxContainer *hb = memnew(HBoxContainer);266gc->add_child(hb);267268scene_name_edit = memnew(LineEdit);269hb->add_child(scene_name_edit);270scene_name_edit->set_accessibility_name(TTRC("Scene Name:"));271scene_name_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);272scene_name_edit->connect(SceneStringName(text_submitted), callable_mp(this, &SceneCreateDialog::accept_create).unbind(1));273274List<String> extensions;275Ref<PackedScene> sd = memnew(PackedScene);276ResourceSaver::get_recognized_extensions(sd, &extensions);277278scene_extension_picker = memnew(OptionButton);279scene_extension_picker->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);280hb->add_child(scene_extension_picker);281for (const String &E : extensions) {282scene_extension_picker->add_item("." + E);283scene_extension_picker->set_item_metadata(-1, E);284}285}286287{288Label *label = memnew(Label(TTR("Root Name:")));289gc->add_child(label);290291root_name_edit = memnew(LineEdit);292gc->add_child(root_name_edit);293root_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."));294root_name_edit->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);295root_name_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);296root_name_edit->connect(SceneStringName(text_submitted), callable_mp(this, &SceneCreateDialog::accept_create).unbind(1));297}298299Control *spacing = memnew(Control);300main_vb->add_child(spacing);301spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));302303validation_panel = memnew(EditorValidationPanel);304main_vb->add_child(validation_panel);305validation_panel->add_line(MSG_ID_PATH, TTR("Scene name is valid."));306validation_panel->add_line(MSG_ID_ROOT, TTR("Root node valid."));307validation_panel->set_update_callback(callable_mp(this, &SceneCreateDialog::update_dialog));308validation_panel->set_accept_button(get_ok_button());309310node_type_group->connect(SceneStringName(pressed), callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));311scene_name_edit->connect(SceneStringName(text_changed), callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));312root_name_edit->connect(SceneStringName(text_changed), callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));313314set_title(TTR("Create New Scene"));315set_min_size(Size2i(400 * EDSCALE, 0));316}317318319