Standardize dialog input validation as a new class
This commit is contained in:
parent
eca6f0eb54
commit
7f41403a6f
|
@ -33,10 +33,10 @@
|
||||||
#include "core/io/dir_access.h"
|
#include "core/io/dir_access.h"
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
#include "editor/editor_scale.h"
|
#include "editor/editor_scale.h"
|
||||||
|
#include "editor/gui/editor_validation_panel.h"
|
||||||
#include "scene/gui/box_container.h"
|
#include "scene/gui/box_container.h"
|
||||||
#include "scene/gui/label.h"
|
#include "scene/gui/label.h"
|
||||||
#include "scene/gui/line_edit.h"
|
#include "scene/gui/line_edit.h"
|
||||||
#include "scene/gui/panel_container.h"
|
|
||||||
|
|
||||||
static String sanitize_input(const String &p_path) {
|
static String sanitize_input(const String &p_path) {
|
||||||
String path = p_path.strip_edges();
|
String path = p_path.strip_edges();
|
||||||
|
@ -73,24 +73,17 @@ String DirectoryCreateDialog::_validate_path(const String &p_path) const {
|
||||||
return String();
|
return String();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectoryCreateDialog::_on_dir_path_changed(const String &p_text) {
|
void DirectoryCreateDialog::_on_dir_path_changed() {
|
||||||
const String path = sanitize_input(p_text);
|
const String path = sanitize_input(dir_path->get_text());
|
||||||
const String error = _validate_path(path);
|
const String error = _validate_path(path);
|
||||||
|
|
||||||
if (error.is_empty()) {
|
if (error.is_empty()) {
|
||||||
status_label->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
|
|
||||||
|
|
||||||
if (path.contains("/")) {
|
if (path.contains("/")) {
|
||||||
status_label->set_text(TTR("Using slashes in folder names will create subfolders recursively."));
|
validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Using slashes in folder names will create subfolders recursively."), EditorValidationPanel::MSG_OK);
|
||||||
} else {
|
|
||||||
status_label->set_text(TTR("Folder name is valid."));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
status_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
|
validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, error, EditorValidationPanel::MSG_ERROR);
|
||||||
status_label->set_text(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_ok_button()->set_disabled(!error.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectoryCreateDialog::ok_pressed() {
|
void DirectoryCreateDialog::ok_pressed() {
|
||||||
|
@ -127,21 +120,13 @@ void DirectoryCreateDialog::config(const String &p_base_dir) {
|
||||||
label->set_text(vformat(TTR("Create new folder in %s:"), base_dir));
|
label->set_text(vformat(TTR("Create new folder in %s:"), base_dir));
|
||||||
dir_path->set_text("new folder");
|
dir_path->set_text("new folder");
|
||||||
dir_path->select_all();
|
dir_path->select_all();
|
||||||
_on_dir_path_changed(dir_path->get_text());
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectoryCreateDialog::_bind_methods() {
|
void DirectoryCreateDialog::_bind_methods() {
|
||||||
ADD_SIGNAL(MethodInfo("dir_created"));
|
ADD_SIGNAL(MethodInfo("dir_created"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectoryCreateDialog::_notification(int p_what) {
|
|
||||||
switch (p_what) {
|
|
||||||
case NOTIFICATION_THEME_CHANGED: {
|
|
||||||
status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectoryCreateDialog::DirectoryCreateDialog() {
|
DirectoryCreateDialog::DirectoryCreateDialog() {
|
||||||
set_title(TTR("Create Folder"));
|
set_title(TTR("Create Folder"));
|
||||||
set_min_size(Size2i(480, 0) * EDSCALE);
|
set_min_size(Size2i(480, 0) * EDSCALE);
|
||||||
|
@ -154,7 +139,6 @@ DirectoryCreateDialog::DirectoryCreateDialog() {
|
||||||
vb->add_child(label);
|
vb->add_child(label);
|
||||||
|
|
||||||
dir_path = memnew(LineEdit);
|
dir_path = memnew(LineEdit);
|
||||||
dir_path->connect("text_changed", callable_mp(this, &DirectoryCreateDialog::_on_dir_path_changed));
|
|
||||||
vb->add_child(dir_path);
|
vb->add_child(dir_path);
|
||||||
register_text_enter(dir_path);
|
register_text_enter(dir_path);
|
||||||
|
|
||||||
|
@ -162,11 +146,11 @@ DirectoryCreateDialog::DirectoryCreateDialog() {
|
||||||
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
|
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
|
||||||
vb->add_child(spacing);
|
vb->add_child(spacing);
|
||||||
|
|
||||||
status_panel = memnew(PanelContainer);
|
validation_panel = memnew(EditorValidationPanel);
|
||||||
status_panel->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
vb->add_child(validation_panel);
|
||||||
vb->add_child(status_panel);
|
validation_panel->add_line(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Folder name is valid."));
|
||||||
|
validation_panel->set_update_callback(callable_mp(this, &DirectoryCreateDialog::_on_dir_path_changed));
|
||||||
|
validation_panel->set_accept_button(get_ok_button());
|
||||||
|
|
||||||
status_label = memnew(Label);
|
dir_path->connect("text_changed", callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
|
||||||
status_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
|
||||||
status_panel->add_child(status_label);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@
|
||||||
|
|
||||||
#include "scene/gui/dialogs.h"
|
#include "scene/gui/dialogs.h"
|
||||||
|
|
||||||
|
class EditorValidationPanel;
|
||||||
class Label;
|
class Label;
|
||||||
class LineEdit;
|
class LineEdit;
|
||||||
class PanelContainer;
|
|
||||||
|
|
||||||
class DirectoryCreateDialog : public ConfirmationDialog {
|
class DirectoryCreateDialog : public ConfirmationDialog {
|
||||||
GDCLASS(DirectoryCreateDialog, ConfirmationDialog);
|
GDCLASS(DirectoryCreateDialog, ConfirmationDialog);
|
||||||
|
@ -44,17 +44,13 @@ class DirectoryCreateDialog : public ConfirmationDialog {
|
||||||
|
|
||||||
Label *label = nullptr;
|
Label *label = nullptr;
|
||||||
LineEdit *dir_path = nullptr;
|
LineEdit *dir_path = nullptr;
|
||||||
|
EditorValidationPanel *validation_panel = nullptr;
|
||||||
PanelContainer *status_panel = nullptr;
|
|
||||||
Label *status_label = nullptr;
|
|
||||||
|
|
||||||
String _validate_path(const String &p_path) const;
|
String _validate_path(const String &p_path) const;
|
||||||
|
void _on_dir_path_changed();
|
||||||
void _on_dir_path_changed(const String &p_text);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
void _notification(int p_what);
|
|
||||||
|
|
||||||
virtual void ok_pressed() override;
|
virtual void ok_pressed() override;
|
||||||
virtual void _post_popup() override;
|
virtual void _post_popup() override;
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "editor/editor_scale.h"
|
#include "editor/editor_scale.h"
|
||||||
#include "editor/editor_settings.h"
|
#include "editor/editor_settings.h"
|
||||||
#include "editor/editor_undo_redo_manager.h"
|
#include "editor/editor_undo_redo_manager.h"
|
||||||
|
#include "editor/gui/editor_validation_panel.h"
|
||||||
#include "editor/inspector_dock.h"
|
#include "editor/inspector_dock.h"
|
||||||
#include "editor/plugins/script_editor_plugin.h"
|
#include "editor/plugins/script_editor_plugin.h"
|
||||||
#include "multi_node_edit.h"
|
#include "multi_node_edit.h"
|
||||||
|
@ -3927,12 +3928,6 @@ void EditorInspector::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_THEME_CHANGED: {
|
|
||||||
if (add_meta_error_panel) {
|
|
||||||
add_meta_error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NOTIFICATION_PREDELETE: {
|
case NOTIFICATION_PREDELETE: {
|
||||||
edit(nullptr); //just in case
|
edit(nullptr); //just in case
|
||||||
} break;
|
} break;
|
||||||
|
@ -4083,27 +4078,17 @@ void EditorInspector::_add_meta_confirm() {
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorInspector::_check_meta_name(const String &p_name) {
|
void EditorInspector::_check_meta_name() {
|
||||||
String error;
|
const String meta_name = add_meta_name->get_text();
|
||||||
|
|
||||||
if (p_name == "") {
|
if (meta_name.is_empty()) {
|
||||||
error = TTR("Metadata name can't be empty.");
|
validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Metadata name can't be empty."), EditorValidationPanel::MSG_ERROR);
|
||||||
} else if (!p_name.is_valid_identifier()) {
|
} else if (!meta_name.is_valid_identifier()) {
|
||||||
error = TTR("Metadata name must be a valid identifier.");
|
validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Metadata name must be a valid identifier."), EditorValidationPanel::MSG_ERROR);
|
||||||
} else if (object->has_meta(p_name)) {
|
} else if (object->has_meta(meta_name)) {
|
||||||
error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name);
|
validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, vformat(TTR("Metadata with name \"%s\" already exists."), meta_name), EditorValidationPanel::MSG_ERROR);
|
||||||
} else if (p_name[0] == '_') {
|
} else if (meta_name[0] == '_') {
|
||||||
error = TTR("Names starting with _ are reserved for editor-only metadata.");
|
validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Names starting with _ are reserved for editor-only metadata."), EditorValidationPanel::MSG_ERROR);
|
||||||
}
|
|
||||||
|
|
||||||
if (error != "") {
|
|
||||||
add_meta_error->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
|
|
||||||
add_meta_error->set_text(error);
|
|
||||||
add_meta_dialog->get_ok_button()->set_disabled(true);
|
|
||||||
} else {
|
|
||||||
add_meta_error->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
|
|
||||||
add_meta_error->set_text(TTR("Metadata name is valid."));
|
|
||||||
add_meta_dialog->get_ok_button()->set_disabled(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4143,16 +4128,13 @@ void EditorInspector::_show_add_meta_dialog() {
|
||||||
add_meta_dialog->register_text_enter(add_meta_name);
|
add_meta_dialog->register_text_enter(add_meta_name);
|
||||||
add_meta_dialog->connect("confirmed", callable_mp(this, &EditorInspector::_add_meta_confirm));
|
add_meta_dialog->connect("confirmed", callable_mp(this, &EditorInspector::_add_meta_confirm));
|
||||||
|
|
||||||
add_meta_error_panel = memnew(PanelContainer);
|
validation_panel = memnew(EditorValidationPanel);
|
||||||
vbc->add_child(add_meta_error_panel);
|
vbc->add_child(validation_panel);
|
||||||
if (is_inside_tree()) {
|
validation_panel->add_line(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Metadata name is valid."));
|
||||||
add_meta_error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
|
validation_panel->set_update_callback(callable_mp(this, &EditorInspector::_check_meta_name));
|
||||||
}
|
validation_panel->set_accept_button(add_meta_dialog->get_ok_button());
|
||||||
|
|
||||||
add_meta_error = memnew(Label);
|
add_meta_name->connect("text_changed", callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
|
||||||
add_meta_error_panel->add_child(add_meta_error);
|
|
||||||
|
|
||||||
add_meta_name->connect("text_changed", callable_mp(this, &EditorInspector::_check_meta_name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *node = Object::cast_to<Node>(object);
|
Node *node = Object::cast_to<Node>(object);
|
||||||
|
@ -4164,9 +4146,9 @@ void EditorInspector::_show_add_meta_dialog() {
|
||||||
}
|
}
|
||||||
|
|
||||||
add_meta_dialog->popup_centered();
|
add_meta_dialog->popup_centered();
|
||||||
add_meta_name->set_text("");
|
|
||||||
_check_meta_name("");
|
|
||||||
add_meta_name->grab_focus();
|
add_meta_name->grab_focus();
|
||||||
|
add_meta_name->set_text("");
|
||||||
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorInspector::_bind_methods() {
|
void EditorInspector::_bind_methods() {
|
||||||
|
|
|
@ -39,6 +39,7 @@ class AcceptDialog;
|
||||||
class Button;
|
class Button;
|
||||||
class ConfirmationDialog;
|
class ConfirmationDialog;
|
||||||
class EditorInspector;
|
class EditorInspector;
|
||||||
|
class EditorValidationPanel;
|
||||||
class LineEdit;
|
class LineEdit;
|
||||||
class OptionButton;
|
class OptionButton;
|
||||||
class PanelContainer;
|
class PanelContainer;
|
||||||
|
@ -543,12 +544,11 @@ class EditorInspector : public ScrollContainer {
|
||||||
ConfirmationDialog *add_meta_dialog = nullptr;
|
ConfirmationDialog *add_meta_dialog = nullptr;
|
||||||
LineEdit *add_meta_name = nullptr;
|
LineEdit *add_meta_name = nullptr;
|
||||||
OptionButton *add_meta_type = nullptr;
|
OptionButton *add_meta_type = nullptr;
|
||||||
PanelContainer *add_meta_error_panel = nullptr;
|
EditorValidationPanel *validation_panel = nullptr;
|
||||||
Label *add_meta_error = nullptr;
|
|
||||||
|
|
||||||
void _add_meta_confirm();
|
void _add_meta_confirm();
|
||||||
void _show_add_meta_dialog();
|
void _show_add_meta_dialog();
|
||||||
void _check_meta_name(const String &p_name);
|
void _check_meta_name();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
|
@ -1280,6 +1280,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||||
}
|
}
|
||||||
|
|
||||||
theme->set_stylebox("panel", "Tree", style_tree_bg);
|
theme->set_stylebox("panel", "Tree", style_tree_bg);
|
||||||
|
theme->set_stylebox("panel", "EditorValidationPanel", style_tree_bg);
|
||||||
|
|
||||||
// Tree
|
// Tree
|
||||||
theme->set_icon("checked", "Tree", theme->get_icon(SNAME("GuiChecked"), SNAME("EditorIcons")));
|
theme->set_icon("checked", "Tree", theme->get_icon(SNAME("GuiChecked"), SNAME("EditorIcons")));
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
/**************************************************************************/
|
||||||
|
/* editor_validation_panel.cpp */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* 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 "editor_validation_panel.h"
|
||||||
|
|
||||||
|
#include "editor/editor_scale.h"
|
||||||
|
#include "scene/gui/box_container.h"
|
||||||
|
#include "scene/gui/button.h"
|
||||||
|
#include "scene/gui/label.h"
|
||||||
|
|
||||||
|
void EditorValidationPanel::_update() {
|
||||||
|
for (const KeyValue<int, String> &E : valid_messages) {
|
||||||
|
set_message(E.key, E.value, MSG_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
valid = true;
|
||||||
|
update_callback.callv(Array());
|
||||||
|
|
||||||
|
if (accept_button) {
|
||||||
|
accept_button->set_disabled(!valid);
|
||||||
|
}
|
||||||
|
pending_update = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorValidationPanel::_notification(int p_what) {
|
||||||
|
switch (p_what) {
|
||||||
|
case NOTIFICATION_THEME_CHANGED: {
|
||||||
|
theme_cache.valid_color = get_theme_color(SNAME("success_color"), SNAME("Editor"));
|
||||||
|
theme_cache.warning_color = get_theme_color(SNAME("warning_color"), SNAME("Editor"));
|
||||||
|
theme_cache.error_color = get_theme_color(SNAME("error_color"), SNAME("Editor"));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorValidationPanel::add_line(int p_id, const String &p_valid_message) {
|
||||||
|
ERR_FAIL_COND(valid_messages.has(p_id));
|
||||||
|
|
||||||
|
Label *label = memnew(Label);
|
||||||
|
message_container->add_child(label);
|
||||||
|
label->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
|
||||||
|
label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
|
||||||
|
|
||||||
|
valid_messages[p_id] = p_valid_message;
|
||||||
|
labels[p_id] = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorValidationPanel::set_accept_button(Button *p_button) {
|
||||||
|
accept_button = p_button;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorValidationPanel::set_update_callback(const Callable &p_callback) {
|
||||||
|
update_callback = p_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorValidationPanel::update() {
|
||||||
|
ERR_FAIL_COND(update_callback.is_null());
|
||||||
|
|
||||||
|
if (pending_update) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pending_update = true;
|
||||||
|
callable_mp(this, &EditorValidationPanel::_update).call_deferred();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorValidationPanel::set_message(int p_id, const String &p_text, MessageType p_type, bool p_auto_prefix) {
|
||||||
|
ERR_FAIL_COND(!valid_messages.has(p_id));
|
||||||
|
|
||||||
|
Label *label = labels[p_id];
|
||||||
|
if (p_text.is_empty()) {
|
||||||
|
label->hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
label->show();
|
||||||
|
|
||||||
|
if (p_auto_prefix) {
|
||||||
|
label->set_text(String(U"• ") + p_text);
|
||||||
|
} else {
|
||||||
|
label->set_text(p_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (p_type) {
|
||||||
|
case MSG_OK:
|
||||||
|
label->add_theme_color_override(SNAME("font_color"), theme_cache.valid_color);
|
||||||
|
break;
|
||||||
|
case MSG_WARNING:
|
||||||
|
label->add_theme_color_override(SNAME("font_color"), theme_cache.warning_color);
|
||||||
|
break;
|
||||||
|
case MSG_ERROR:
|
||||||
|
label->add_theme_color_override(SNAME("font_color"), theme_cache.error_color);
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
case MSG_INFO:
|
||||||
|
label->remove_theme_color_override(SNAME("font_color"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditorValidationPanel::is_valid() const {
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorValidationPanel::EditorValidationPanel() {
|
||||||
|
set_v_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
|
||||||
|
message_container = memnew(VBoxContainer);
|
||||||
|
add_child(message_container);
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/**************************************************************************/
|
||||||
|
/* editor_validation_panel.h */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* 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. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef EDITOR_VALIDATION_PANEL_H
|
||||||
|
#define EDITOR_VALIDATION_PANEL_H
|
||||||
|
|
||||||
|
#include "scene/gui/panel_container.h"
|
||||||
|
|
||||||
|
class Button;
|
||||||
|
class Label;
|
||||||
|
class VBoxContainer;
|
||||||
|
|
||||||
|
class EditorValidationPanel : public PanelContainer {
|
||||||
|
GDCLASS(EditorValidationPanel, PanelContainer);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum MessageType {
|
||||||
|
MSG_OK,
|
||||||
|
MSG_WARNING,
|
||||||
|
MSG_ERROR,
|
||||||
|
MSG_INFO,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int MSG_ID_DEFAULT = 0; // Avoids hard-coding ID in dialogs with single-line validation.
|
||||||
|
|
||||||
|
private:
|
||||||
|
VBoxContainer *message_container = nullptr;
|
||||||
|
|
||||||
|
HashMap<int, String> valid_messages;
|
||||||
|
HashMap<int, Label *> labels;
|
||||||
|
|
||||||
|
bool valid = false;
|
||||||
|
bool pending_update = false;
|
||||||
|
|
||||||
|
struct ThemeCache {
|
||||||
|
Color valid_color;
|
||||||
|
Color warning_color;
|
||||||
|
Color error_color;
|
||||||
|
} theme_cache;
|
||||||
|
|
||||||
|
void _update();
|
||||||
|
|
||||||
|
Callable update_callback;
|
||||||
|
Button *accept_button = nullptr;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _notification(int p_what);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void add_line(int p_id, const String &p_valid_message = "");
|
||||||
|
void set_accept_button(Button *p_button);
|
||||||
|
void set_update_callback(const Callable &p_callback);
|
||||||
|
|
||||||
|
void update();
|
||||||
|
void set_message(int p_id, const String &p_text, MessageType p_type, bool p_auto_prefix = true);
|
||||||
|
bool is_valid() const;
|
||||||
|
|
||||||
|
EditorValidationPanel();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EDITOR_VALIDATION_PANEL_H
|
|
@ -34,6 +34,7 @@
|
||||||
#include "editor/create_dialog.h"
|
#include "editor/create_dialog.h"
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
#include "editor/editor_scale.h"
|
#include "editor/editor_scale.h"
|
||||||
|
#include "editor/gui/editor_validation_panel.h"
|
||||||
#include "scene/2d/node_2d.h"
|
#include "scene/2d/node_2d.h"
|
||||||
#include "scene/3d/node_3d.h"
|
#include "scene/3d/node_3d.h"
|
||||||
#include "scene/gui/box_container.h"
|
#include "scene/gui/box_container.h"
|
||||||
|
@ -41,7 +42,6 @@
|
||||||
#include "scene/gui/grid_container.h"
|
#include "scene/gui/grid_container.h"
|
||||||
#include "scene/gui/line_edit.h"
|
#include "scene/gui/line_edit.h"
|
||||||
#include "scene/gui/option_button.h"
|
#include "scene/gui/option_button.h"
|
||||||
#include "scene/gui/panel_container.h"
|
|
||||||
#include "scene/resources/packed_scene.h"
|
#include "scene/resources/packed_scene.h"
|
||||||
|
|
||||||
void SceneCreateDialog::_notification(int p_what) {
|
void SceneCreateDialog::_notification(int p_what) {
|
||||||
|
@ -53,7 +53,6 @@ void SceneCreateDialog::_notification(int p_what) {
|
||||||
node_type_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons")));
|
node_type_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons")));
|
||||||
node_type_gui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons")));
|
node_type_gui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons")));
|
||||||
node_type_other->add_theme_icon_override(SNAME("icon"), get_theme_icon(SNAME("Node"), SNAME("EditorIcons")));
|
node_type_other->add_theme_icon_override(SNAME("icon"), get_theme_icon(SNAME("Node"), SNAME("EditorIcons")));
|
||||||
status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
|
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +62,7 @@ void SceneCreateDialog::config(const String &p_dir) {
|
||||||
root_name_edit->set_text("");
|
root_name_edit->set_text("");
|
||||||
scene_name_edit->set_text("");
|
scene_name_edit->set_text("");
|
||||||
scene_name_edit->call_deferred(SNAME("grab_focus"));
|
scene_name_edit->call_deferred(SNAME("grab_focus"));
|
||||||
update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneCreateDialog::accept_create() {
|
void SceneCreateDialog::accept_create() {
|
||||||
|
@ -82,40 +81,35 @@ void SceneCreateDialog::browse_types() {
|
||||||
void SceneCreateDialog::on_type_picked() {
|
void SceneCreateDialog::on_type_picked() {
|
||||||
other_type_display->set_text(select_node_dialog->get_selected_type().get_slice(" ", 0));
|
other_type_display->set_text(select_node_dialog->get_selected_type().get_slice(" ", 0));
|
||||||
if (node_type_other->is_pressed()) {
|
if (node_type_other->is_pressed()) {
|
||||||
update_dialog();
|
validation_panel->update();
|
||||||
} else {
|
} else {
|
||||||
node_type_other->set_pressed(true); // Calls update_dialog() via group.
|
node_type_other->set_pressed(true); // Calls validation_panel->update() via group.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneCreateDialog::update_dialog() {
|
void SceneCreateDialog::update_dialog() {
|
||||||
scene_name = scene_name_edit->get_text().strip_edges();
|
scene_name = scene_name_edit->get_text().strip_edges();
|
||||||
update_error(file_error_label, MSG_OK, TTR("Scene name is valid."));
|
|
||||||
|
|
||||||
bool is_valid = true;
|
|
||||||
if (scene_name.is_empty()) {
|
if (scene_name.is_empty()) {
|
||||||
update_error(file_error_label, MSG_ERROR, TTR("Scene name is empty."));
|
validation_panel->set_message(MSG_ID_PATH, TTR("Scene name is empty."), EditorValidationPanel::MSG_ERROR);
|
||||||
is_valid = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_valid) {
|
if (validation_panel->is_valid()) {
|
||||||
if (!scene_name.ends_with(".")) {
|
if (!scene_name.ends_with(".")) {
|
||||||
scene_name += ".";
|
scene_name += ".";
|
||||||
}
|
}
|
||||||
scene_name += scene_extension_picker->get_selected_metadata().operator String();
|
scene_name += scene_extension_picker->get_selected_metadata().operator String();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_valid && !scene_name.is_valid_filename()) {
|
if (validation_panel->is_valid() && !scene_name.is_valid_filename()) {
|
||||||
update_error(file_error_label, MSG_ERROR, TTR("File name invalid."));
|
validation_panel->set_message(MSG_ID_PATH, TTR("File name invalid."), EditorValidationPanel::MSG_ERROR);
|
||||||
is_valid = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_valid) {
|
if (validation_panel->is_valid()) {
|
||||||
scene_name = directory.path_join(scene_name);
|
scene_name = directory.path_join(scene_name);
|
||||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||||
if (da->file_exists(scene_name)) {
|
if (da->file_exists(scene_name)) {
|
||||||
update_error(file_error_label, MSG_ERROR, TTR("File already exists."));
|
validation_panel->set_message(MSG_ID_PATH, TTR("File already exists."), EditorValidationPanel::MSG_ERROR);
|
||||||
is_valid = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,8 +120,6 @@ void SceneCreateDialog::update_dialog() {
|
||||||
node_type_other->set_icon(nullptr);
|
node_type_other->set_icon(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
update_error(node_error_label, MSG_OK, TTR("Root node valid."));
|
|
||||||
|
|
||||||
root_name = root_name_edit->get_text().strip_edges();
|
root_name = root_name_edit->get_text().strip_edges();
|
||||||
if (root_name.is_empty()) {
|
if (root_name.is_empty()) {
|
||||||
root_name = scene_name_edit->get_text().strip_edges();
|
root_name = scene_name_edit->get_text().strip_edges();
|
||||||
|
@ -135,39 +127,16 @@ void SceneCreateDialog::update_dialog() {
|
||||||
if (root_name.is_empty()) {
|
if (root_name.is_empty()) {
|
||||||
root_name_edit->set_placeholder(TTR("Leave empty to derive from scene name"));
|
root_name_edit->set_placeholder(TTR("Leave empty to derive from scene name"));
|
||||||
} else {
|
} else {
|
||||||
// Respect the desired root node casing from ProjectSettings and ensure it's a valid node name.
|
// Respect the desired root node casing from ProjectSettings.
|
||||||
String adjusted_root_name = Node::adjust_name_casing(root_name);
|
root_name = Node::adjust_name_casing(root_name);
|
||||||
root_name = adjusted_root_name.validate_node_name();
|
root_name_edit->set_placeholder(root_name.validate_node_name());
|
||||||
|
|
||||||
bool has_invalid_characters = root_name != adjusted_root_name;
|
|
||||||
if (has_invalid_characters) {
|
|
||||||
update_error(node_error_label, MSG_WARNING, TTR("Invalid root node name characters have been replaced."));
|
|
||||||
}
|
|
||||||
|
|
||||||
root_name_edit->set_placeholder(root_name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root_name.is_empty() || root_name.validate_node_name() != root_name) {
|
if (root_name.is_empty()) {
|
||||||
update_error(node_error_label, MSG_ERROR, TTR("Invalid root node name."));
|
validation_panel->set_message(MSG_ID_ROOT, TTR("Invalid root node name."), EditorValidationPanel::MSG_ERROR);
|
||||||
is_valid = false;
|
} else if (root_name != root_name.validate_node_name()) {
|
||||||
}
|
validation_panel->set_message(MSG_ID_ROOT, TTR("Invalid root node name characters have been replaced."), EditorValidationPanel::MSG_WARNING);
|
||||||
|
|
||||||
get_ok_button()->set_disabled(!is_valid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneCreateDialog::update_error(Label *p_label, MsgType p_type, const String &p_msg) {
|
|
||||||
p_label->set_text(String::utf8("• ") + p_msg);
|
|
||||||
switch (p_type) {
|
|
||||||
case MSG_OK:
|
|
||||||
p_label->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
|
|
||||||
break;
|
|
||||||
case MSG_ERROR:
|
|
||||||
p_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
|
|
||||||
break;
|
|
||||||
case MSG_WARNING:
|
|
||||||
p_label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,8 +237,6 @@ SceneCreateDialog::SceneCreateDialog() {
|
||||||
select_node_button = memnew(Button);
|
select_node_button = memnew(Button);
|
||||||
hb->add_child(select_node_button);
|
hb->add_child(select_node_button);
|
||||||
select_node_button->connect("pressed", callable_mp(this, &SceneCreateDialog::browse_types));
|
select_node_button->connect("pressed", callable_mp(this, &SceneCreateDialog::browse_types));
|
||||||
|
|
||||||
node_type_group->connect("pressed", callable_mp(this, &SceneCreateDialog::update_dialog).unbind(1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -282,7 +249,6 @@ SceneCreateDialog::SceneCreateDialog() {
|
||||||
scene_name_edit = memnew(LineEdit);
|
scene_name_edit = memnew(LineEdit);
|
||||||
hb->add_child(scene_name_edit);
|
hb->add_child(scene_name_edit);
|
||||||
scene_name_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
scene_name_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
scene_name_edit->connect("text_changed", callable_mp(this, &SceneCreateDialog::update_dialog).unbind(1));
|
|
||||||
scene_name_edit->connect("text_submitted", callable_mp(this, &SceneCreateDialog::accept_create).unbind(1));
|
scene_name_edit->connect("text_submitted", callable_mp(this, &SceneCreateDialog::accept_create).unbind(1));
|
||||||
|
|
||||||
List<String> extensions;
|
List<String> extensions;
|
||||||
|
@ -305,7 +271,6 @@ SceneCreateDialog::SceneCreateDialog() {
|
||||||
gc->add_child(root_name_edit);
|
gc->add_child(root_name_edit);
|
||||||
root_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."));
|
root_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."));
|
||||||
root_name_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
root_name_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
root_name_edit->connect("text_changed", callable_mp(this, &SceneCreateDialog::update_dialog).unbind(1));
|
|
||||||
root_name_edit->connect("text_submitted", callable_mp(this, &SceneCreateDialog::accept_create).unbind(1));
|
root_name_edit->connect("text_submitted", callable_mp(this, &SceneCreateDialog::accept_create).unbind(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,19 +278,16 @@ SceneCreateDialog::SceneCreateDialog() {
|
||||||
main_vb->add_child(spacing);
|
main_vb->add_child(spacing);
|
||||||
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
|
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
|
||||||
|
|
||||||
status_panel = memnew(PanelContainer);
|
validation_panel = memnew(EditorValidationPanel);
|
||||||
main_vb->add_child(status_panel);
|
main_vb->add_child(validation_panel);
|
||||||
status_panel->set_h_size_flags(Control::SIZE_FILL);
|
validation_panel->add_line(MSG_ID_PATH, TTR("Scene name is valid."));
|
||||||
status_panel->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
validation_panel->add_line(MSG_ID_ROOT, TTR("Root node valid."));
|
||||||
|
validation_panel->set_update_callback(callable_mp(this, &SceneCreateDialog::update_dialog));
|
||||||
|
validation_panel->set_accept_button(get_ok_button());
|
||||||
|
|
||||||
VBoxContainer *status_vb = memnew(VBoxContainer);
|
node_type_group->connect("pressed", callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
|
||||||
status_panel->add_child(status_vb);
|
scene_name_edit->connect("text_changed", callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
|
||||||
|
root_name_edit->connect("text_changed", callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
|
||||||
file_error_label = memnew(Label);
|
|
||||||
status_vb->add_child(file_error_label);
|
|
||||||
|
|
||||||
node_error_label = memnew(Label);
|
|
||||||
status_vb->add_child(node_error_label);
|
|
||||||
|
|
||||||
set_title(TTR("Create New Scene"));
|
set_title(TTR("Create New Scene"));
|
||||||
set_min_size(Size2i(400 * EDSCALE, 0));
|
set_min_size(Size2i(400 * EDSCALE, 0));
|
||||||
|
|
|
@ -37,18 +37,17 @@ class ButtonGroup;
|
||||||
class CheckBox;
|
class CheckBox;
|
||||||
class CreateDialog;
|
class CreateDialog;
|
||||||
class EditorFileDialog;
|
class EditorFileDialog;
|
||||||
|
class EditorValidationPanel;
|
||||||
class Label;
|
class Label;
|
||||||
class LineEdit;
|
class LineEdit;
|
||||||
class OptionButton;
|
class OptionButton;
|
||||||
class PanelContainer;
|
|
||||||
|
|
||||||
class SceneCreateDialog : public ConfirmationDialog {
|
class SceneCreateDialog : public ConfirmationDialog {
|
||||||
GDCLASS(SceneCreateDialog, ConfirmationDialog);
|
GDCLASS(SceneCreateDialog, ConfirmationDialog);
|
||||||
|
|
||||||
enum MsgType {
|
enum {
|
||||||
MSG_OK,
|
MSG_ID_PATH,
|
||||||
MSG_ERROR,
|
MSG_ID_ROOT,
|
||||||
MSG_WARNING,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const StringName type_meta = StringName("type");
|
const StringName type_meta = StringName("type");
|
||||||
|
@ -80,15 +79,12 @@ private:
|
||||||
OptionButton *scene_extension_picker = nullptr;
|
OptionButton *scene_extension_picker = nullptr;
|
||||||
LineEdit *root_name_edit = nullptr;
|
LineEdit *root_name_edit = nullptr;
|
||||||
|
|
||||||
PanelContainer *status_panel = nullptr;
|
EditorValidationPanel *validation_panel = nullptr;
|
||||||
Label *file_error_label = nullptr;
|
|
||||||
Label *node_error_label = nullptr;
|
|
||||||
|
|
||||||
void accept_create();
|
void accept_create();
|
||||||
void browse_types();
|
void browse_types();
|
||||||
void on_type_picked();
|
void on_type_picked();
|
||||||
void update_dialog();
|
void update_dialog();
|
||||||
void update_error(Label *p_label, MsgType p_type, const String &p_msg);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "editor/editor_scale.h"
|
#include "editor/editor_scale.h"
|
||||||
#include "editor/editor_settings.h"
|
#include "editor/editor_settings.h"
|
||||||
#include "editor/gui/editor_file_dialog.h"
|
#include "editor/gui/editor_file_dialog.h"
|
||||||
|
#include "editor/gui/editor_validation_panel.h"
|
||||||
|
|
||||||
static String _get_parent_class_of_script(String p_path) {
|
static String _get_parent_class_of_script(String p_path) {
|
||||||
if (!ResourceLoader::exists(p_path, "Script")) {
|
if (!ResourceLoader::exists(p_path, "Script")) {
|
||||||
|
@ -136,7 +137,6 @@ void ScriptCreateDialog::_notification(int p_what) {
|
||||||
path_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
|
path_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
|
||||||
parent_browse_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
|
parent_browse_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
|
||||||
parent_search_button->set_icon(get_theme_icon(SNAME("ClassList"), SNAME("EditorIcons")));
|
parent_search_button->set_icon(get_theme_icon(SNAME("ClassList"), SNAME("EditorIcons")));
|
||||||
status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
|
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -295,13 +295,7 @@ String ScriptCreateDialog::_validate_path(const String &p_path, bool p_file_must
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let ScriptLanguage do custom validation.
|
// Let ScriptLanguage do custom validation.
|
||||||
String path_error = ScriptServer::get_language(language_menu->get_selected())->validate_path(p);
|
return ScriptServer::get_language(language_menu->get_selected())->validate_path(p);
|
||||||
if (!path_error.is_empty()) {
|
|
||||||
return path_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All checks passed.
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String ScriptCreateDialog::_get_class_name() const {
|
String ScriptCreateDialog::_get_class_name() const {
|
||||||
|
@ -314,12 +308,12 @@ String ScriptCreateDialog::_get_class_name() const {
|
||||||
|
|
||||||
void ScriptCreateDialog::_class_name_changed(const String &p_name) {
|
void ScriptCreateDialog::_class_name_changed(const String &p_name) {
|
||||||
is_class_name_valid = _validate_class(class_name->get_text());
|
is_class_name_valid = _validate_class(class_name->get_text());
|
||||||
_update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptCreateDialog::_parent_name_changed(const String &p_parent) {
|
void ScriptCreateDialog::_parent_name_changed(const String &p_parent) {
|
||||||
is_parent_name_valid = _validate_parent(parent_name->get_text());
|
is_parent_name_valid = _validate_parent(parent_name->get_text());
|
||||||
_update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptCreateDialog::_template_changed(int p_template) {
|
void ScriptCreateDialog::_template_changed(int p_template) {
|
||||||
|
@ -347,6 +341,7 @@ void ScriptCreateDialog::_template_changed(int p_template) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update template label information.
|
// Update template label information.
|
||||||
String template_info = U"• ";
|
String template_info = U"• ";
|
||||||
template_info += TTR("Template:");
|
template_info += TTR("Template:");
|
||||||
|
@ -354,8 +349,7 @@ void ScriptCreateDialog::_template_changed(int p_template) {
|
||||||
if (!sinfo.description.is_empty()) {
|
if (!sinfo.description.is_empty()) {
|
||||||
template_info += " - " + sinfo.description;
|
template_info += " - " + sinfo.description;
|
||||||
}
|
}
|
||||||
template_info_label->set_text(template_info);
|
validation_panel->set_message(MSG_ID_TEMPLATE, template_info, EditorValidationPanel::MSG_INFO, false);
|
||||||
template_info_label->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptCreateDialog::ok_pressed() {
|
void ScriptCreateDialog::ok_pressed() {
|
||||||
|
@ -367,7 +361,7 @@ void ScriptCreateDialog::ok_pressed() {
|
||||||
|
|
||||||
EditorSettings::get_singleton()->save();
|
EditorSettings::get_singleton()->save();
|
||||||
is_new_script_created = true;
|
is_new_script_created = true;
|
||||||
_update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptCreateDialog::_create_new() {
|
void ScriptCreateDialog::_create_new() {
|
||||||
|
@ -471,7 +465,7 @@ void ScriptCreateDialog::_language_changed(int l) {
|
||||||
EditorSettings::get_singleton()->set_project_metadata("script_setup", "last_selected_language", language_menu->get_item_text(language_menu->get_selected()));
|
EditorSettings::get_singleton()->set_project_metadata("script_setup", "last_selected_language", language_menu->get_item_text(language_menu->get_selected()));
|
||||||
|
|
||||||
_parent_name_changed(parent_name->get_text());
|
_parent_name_changed(parent_name->get_text());
|
||||||
_update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptCreateDialog::_built_in_pressed() {
|
void ScriptCreateDialog::_built_in_pressed() {
|
||||||
|
@ -482,13 +476,13 @@ void ScriptCreateDialog::_built_in_pressed() {
|
||||||
is_built_in = false;
|
is_built_in = false;
|
||||||
_path_changed(file_path->get_text());
|
_path_changed(file_path->get_text());
|
||||||
}
|
}
|
||||||
_update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptCreateDialog::_use_template_pressed() {
|
void ScriptCreateDialog::_use_template_pressed() {
|
||||||
is_using_templates = use_templates->is_pressed();
|
is_using_templates = use_templates->is_pressed();
|
||||||
EditorSettings::get_singleton()->set_meta("script_setup_use_script_templates", is_using_templates);
|
EditorSettings::get_singleton()->set_meta("script_setup_use_script_templates", is_using_templates);
|
||||||
_update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptCreateDialog::_browse_path(bool browse_parent, bool p_save) {
|
void ScriptCreateDialog::_browse_path(bool browse_parent, bool p_save) {
|
||||||
|
@ -555,10 +549,9 @@ void ScriptCreateDialog::_path_changed(const String &p_path) {
|
||||||
is_path_valid = false;
|
is_path_valid = false;
|
||||||
is_new_script_created = true;
|
is_new_script_created = true;
|
||||||
|
|
||||||
String path_error = _validate_path(p_path, false);
|
path_error = _validate_path(p_path, false);
|
||||||
if (!path_error.is_empty()) {
|
if (!path_error.is_empty()) {
|
||||||
_msg_path_valid(false, path_error);
|
validation_panel->update();
|
||||||
_update_dialog();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,32 +560,15 @@ void ScriptCreateDialog::_path_changed(const String &p_path) {
|
||||||
String p = ProjectSettings::get_singleton()->localize_path(p_path.strip_edges());
|
String p = ProjectSettings::get_singleton()->localize_path(p_path.strip_edges());
|
||||||
if (da->file_exists(p)) {
|
if (da->file_exists(p)) {
|
||||||
is_new_script_created = false;
|
is_new_script_created = false;
|
||||||
_msg_path_valid(true, TTR("File exists, it will be reused."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is_path_valid = true;
|
is_path_valid = true;
|
||||||
_update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptCreateDialog::_path_submitted(const String &p_path) {
|
void ScriptCreateDialog::_path_submitted(const String &p_path) {
|
||||||
ok_pressed();
|
if (!get_ok_button()->is_disabled()) {
|
||||||
}
|
ok_pressed();
|
||||||
|
|
||||||
void ScriptCreateDialog::_msg_script_valid(bool valid, const String &p_msg) {
|
|
||||||
error_label->set_text(String::utf8("• ") + p_msg);
|
|
||||||
if (valid) {
|
|
||||||
error_label->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
|
|
||||||
} else {
|
|
||||||
error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScriptCreateDialog::_msg_path_valid(bool valid, const String &p_msg) {
|
|
||||||
path_error_label->set_text(String::utf8("• ") + p_msg);
|
|
||||||
if (valid) {
|
|
||||||
path_error_label->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
|
|
||||||
} else {
|
|
||||||
path_error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,25 +664,25 @@ void ScriptCreateDialog::_update_template_menu() {
|
||||||
void ScriptCreateDialog::_update_dialog() {
|
void ScriptCreateDialog::_update_dialog() {
|
||||||
// "Add Script Dialog" GUI logic and script checks.
|
// "Add Script Dialog" GUI logic and script checks.
|
||||||
_update_template_menu();
|
_update_template_menu();
|
||||||
bool script_ok = true;
|
|
||||||
|
|
||||||
// Is script path/name valid (order from top to bottom)?
|
// Is script path/name valid (order from top to bottom)?
|
||||||
|
|
||||||
if (!is_built_in && !is_path_valid) {
|
if (!is_built_in && !is_path_valid) {
|
||||||
_msg_script_valid(false, TTR("Invalid path."));
|
validation_panel->set_message(MSG_ID_SCRIPT, TTR("Invalid path."), EditorValidationPanel::MSG_ERROR);
|
||||||
script_ok = false;
|
|
||||||
}
|
}
|
||||||
if (has_named_classes && (is_new_script_created && !is_class_name_valid)) {
|
if (has_named_classes && (is_new_script_created && !is_class_name_valid)) {
|
||||||
_msg_script_valid(false, TTR("Invalid class name."));
|
validation_panel->set_message(MSG_ID_SCRIPT, TTR("Invalid class name."), EditorValidationPanel::MSG_ERROR);
|
||||||
script_ok = false;
|
|
||||||
}
|
}
|
||||||
if (!is_parent_name_valid && is_new_script_created) {
|
if (!is_parent_name_valid && is_new_script_created) {
|
||||||
_msg_script_valid(false, TTR("Invalid inherited parent name or path."));
|
validation_panel->set_message(MSG_ID_SCRIPT, TTR("Invalid inherited parent name or path."), EditorValidationPanel::MSG_ERROR);
|
||||||
script_ok = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (script_ok) {
|
if (validation_panel->is_valid() && !is_new_script_created) {
|
||||||
_msg_script_valid(true, TTR("Script path/name is valid."));
|
validation_panel->set_message(MSG_ID_SCRIPT, TTR("File exists, it will be reused."), EditorValidationPanel::MSG_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path_error.is_empty()) {
|
||||||
|
validation_panel->set_message(MSG_ID_PATH, path_error, EditorValidationPanel::MSG_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does script have named classes?
|
// Does script have named classes?
|
||||||
|
@ -752,7 +728,11 @@ void ScriptCreateDialog::_update_dialog() {
|
||||||
|
|
||||||
// Is Script created or loaded from existing file?
|
// Is Script created or loaded from existing file?
|
||||||
|
|
||||||
builtin_warning_label->set_visible(is_built_in);
|
if (is_built_in) {
|
||||||
|
validation_panel->set_message(MSG_ID_BUILT_IN, TTR("Note: Built-in scripts have some limitations and can't be edited using an external editor."), EditorValidationPanel::MSG_INFO, false);
|
||||||
|
} else if (_get_class_name() == parent_name->get_text()) {
|
||||||
|
validation_panel->set_message(MSG_ID_BUILT_IN, TTR("Warning: Having the script name be the same as a built-in type is usually not desired."), EditorValidationPanel::MSG_WARNING, false);
|
||||||
|
}
|
||||||
|
|
||||||
path_controls[0]->set_visible(!is_built_in);
|
path_controls[0]->set_visible(!is_built_in);
|
||||||
path_controls[1]->set_visible(!is_built_in);
|
path_controls[1]->set_visible(!is_built_in);
|
||||||
|
@ -761,7 +741,6 @@ void ScriptCreateDialog::_update_dialog() {
|
||||||
|
|
||||||
// Check if the script name is the same as the parent class.
|
// Check if the script name is the same as the parent class.
|
||||||
// This warning isn't relevant if the script is built-in.
|
// This warning isn't relevant if the script is built-in.
|
||||||
script_name_warning_label->set_visible(!is_built_in && _get_class_name() == parent_name->get_text());
|
|
||||||
|
|
||||||
bool is_new_file = is_built_in || is_new_script_created;
|
bool is_new_file = is_built_in || is_new_script_created;
|
||||||
|
|
||||||
|
@ -774,21 +753,16 @@ void ScriptCreateDialog::_update_dialog() {
|
||||||
|
|
||||||
if (is_new_file) {
|
if (is_new_file) {
|
||||||
if (is_built_in) {
|
if (is_built_in) {
|
||||||
_msg_path_valid(true, TTR("Built-in script (into scene file)."));
|
validation_panel->set_message(MSG_ID_PATH, TTR("Built-in script (into scene file)."), EditorValidationPanel::MSG_OK);
|
||||||
}
|
|
||||||
if (is_new_script_created && is_path_valid) {
|
|
||||||
_msg_path_valid(true, TTR("Will create a new script file."));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
template_inactive_message = TTR("Using existing script file.");
|
||||||
if (load_enabled) {
|
if (load_enabled) {
|
||||||
template_inactive_message = TTR("Using existing script file.");
|
|
||||||
if (is_path_valid) {
|
if (is_path_valid) {
|
||||||
_msg_path_valid(true, TTR("Will load an existing script file."));
|
validation_panel->set_message(MSG_ID_PATH, TTR("Will load an existing script file."), EditorValidationPanel::MSG_OK);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
template_inactive_message = TTR("Using existing script file.");
|
validation_panel->set_message(MSG_ID_PATH, TTR("Script file already exists."), EditorValidationPanel::MSG_ERROR);
|
||||||
_msg_path_valid(false, TTR("Script file already exists."));
|
|
||||||
script_ok = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -806,18 +780,7 @@ void ScriptCreateDialog::_update_dialog() {
|
||||||
template_menu->set_disabled(true);
|
template_menu->set_disabled(true);
|
||||||
template_menu->clear();
|
template_menu->clear();
|
||||||
template_menu->add_item(template_inactive_message);
|
template_menu->add_item(template_inactive_message);
|
||||||
}
|
validation_panel->set_message(MSG_ID_TEMPLATE, "", EditorValidationPanel::MSG_INFO);
|
||||||
template_info_label->set_visible(!template_menu->is_disabled());
|
|
||||||
|
|
||||||
get_ok_button()->set_disabled(!script_ok);
|
|
||||||
|
|
||||||
Callable entered_call = callable_mp(this, &ScriptCreateDialog::_path_submitted);
|
|
||||||
if (script_ok) {
|
|
||||||
if (!file_path->is_connected("text_submitted", entered_call)) {
|
|
||||||
file_path->connect("text_submitted", entered_call);
|
|
||||||
}
|
|
||||||
} else if (file_path->is_connected("text_submitted", entered_call)) {
|
|
||||||
file_path->disconnect("text_submitted", entered_call);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -967,47 +930,23 @@ ScriptCreateDialog::ScriptCreateDialog() {
|
||||||
|
|
||||||
/* Information Messages Field */
|
/* Information Messages Field */
|
||||||
|
|
||||||
VBoxContainer *vb = memnew(VBoxContainer);
|
validation_panel = memnew(EditorValidationPanel);
|
||||||
|
validation_panel->add_line(MSG_ID_SCRIPT, TTR("Script path/name is valid."));
|
||||||
error_label = memnew(Label);
|
validation_panel->add_line(MSG_ID_PATH, TTR("Will create a new script file."));
|
||||||
vb->add_child(error_label);
|
validation_panel->add_line(MSG_ID_BUILT_IN);
|
||||||
|
validation_panel->add_line(MSG_ID_TEMPLATE);
|
||||||
path_error_label = memnew(Label);
|
validation_panel->set_update_callback(callable_mp(this, &ScriptCreateDialog::_update_dialog));
|
||||||
vb->add_child(path_error_label);
|
validation_panel->set_accept_button(get_ok_button());
|
||||||
|
|
||||||
builtin_warning_label = memnew(Label);
|
|
||||||
builtin_warning_label->set_text(
|
|
||||||
TTR("Note: Built-in scripts have some limitations and can't be edited using an external editor."));
|
|
||||||
vb->add_child(builtin_warning_label);
|
|
||||||
builtin_warning_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
|
|
||||||
builtin_warning_label->hide();
|
|
||||||
|
|
||||||
script_name_warning_label = memnew(Label);
|
|
||||||
script_name_warning_label->set_text(
|
|
||||||
TTR("Warning: Having the script name be the same as a built-in type is usually not desired."));
|
|
||||||
vb->add_child(script_name_warning_label);
|
|
||||||
script_name_warning_label->add_theme_color_override("font_color", Color(1, 0.85, 0.4));
|
|
||||||
script_name_warning_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
|
|
||||||
script_name_warning_label->hide();
|
|
||||||
|
|
||||||
template_info_label = memnew(Label);
|
|
||||||
vb->add_child(template_info_label);
|
|
||||||
template_info_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
|
|
||||||
|
|
||||||
status_panel = memnew(PanelContainer);
|
|
||||||
status_panel->set_h_size_flags(Control::SIZE_FILL);
|
|
||||||
status_panel->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
|
||||||
status_panel->add_child(vb);
|
|
||||||
|
|
||||||
/* Spacing */
|
/* Spacing */
|
||||||
|
|
||||||
Control *spacing = memnew(Control);
|
Control *spacing = memnew(Control);
|
||||||
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
|
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
|
||||||
|
|
||||||
vb = memnew(VBoxContainer);
|
VBoxContainer *vb = memnew(VBoxContainer);
|
||||||
vb->add_child(gc);
|
vb->add_child(gc);
|
||||||
vb->add_child(spacing);
|
vb->add_child(spacing);
|
||||||
vb->add_child(status_panel);
|
vb->add_child(validation_panel);
|
||||||
add_child(vb);
|
add_child(vb);
|
||||||
|
|
||||||
/* Language */
|
/* Language */
|
||||||
|
|
|
@ -41,17 +41,20 @@
|
||||||
|
|
||||||
class CreateDialog;
|
class CreateDialog;
|
||||||
class EditorFileDialog;
|
class EditorFileDialog;
|
||||||
|
class EditorValidationPanel;
|
||||||
|
|
||||||
class ScriptCreateDialog : public ConfirmationDialog {
|
class ScriptCreateDialog : public ConfirmationDialog {
|
||||||
GDCLASS(ScriptCreateDialog, ConfirmationDialog);
|
GDCLASS(ScriptCreateDialog, ConfirmationDialog);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MSG_ID_SCRIPT,
|
||||||
|
MSG_ID_PATH,
|
||||||
|
MSG_ID_BUILT_IN,
|
||||||
|
MSG_ID_TEMPLATE,
|
||||||
|
};
|
||||||
|
|
||||||
LineEdit *class_name = nullptr;
|
LineEdit *class_name = nullptr;
|
||||||
Label *error_label = nullptr;
|
EditorValidationPanel *validation_panel = nullptr;
|
||||||
Label *path_error_label = nullptr;
|
|
||||||
Label *builtin_warning_label = nullptr;
|
|
||||||
Label *script_name_warning_label = nullptr;
|
|
||||||
Label *template_info_label = nullptr;
|
|
||||||
PanelContainer *status_panel = nullptr;
|
|
||||||
LineEdit *parent_name = nullptr;
|
LineEdit *parent_name = nullptr;
|
||||||
Button *parent_browse_button = nullptr;
|
Button *parent_browse_button = nullptr;
|
||||||
Button *parent_search_button = nullptr;
|
Button *parent_search_button = nullptr;
|
||||||
|
@ -67,6 +70,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
|
||||||
AcceptDialog *alert = nullptr;
|
AcceptDialog *alert = nullptr;
|
||||||
CreateDialog *select_class = nullptr;
|
CreateDialog *select_class = nullptr;
|
||||||
bool is_browsing_parent = false;
|
bool is_browsing_parent = false;
|
||||||
|
String path_error;
|
||||||
String template_inactive_message;
|
String template_inactive_message;
|
||||||
String initial_bp;
|
String initial_bp;
|
||||||
bool is_new_script_created = true;
|
bool is_new_script_created = true;
|
||||||
|
@ -113,8 +117,6 @@ class ScriptCreateDialog : public ConfirmationDialog {
|
||||||
virtual void ok_pressed() override;
|
virtual void ok_pressed() override;
|
||||||
void _create_new();
|
void _create_new();
|
||||||
void _load_exist();
|
void _load_exist();
|
||||||
void _msg_script_valid(bool valid, const String &p_msg = String());
|
|
||||||
void _msg_path_valid(bool valid, const String &p_msg = String());
|
|
||||||
void _update_template_menu();
|
void _update_template_menu();
|
||||||
void _update_dialog();
|
void _update_dialog();
|
||||||
ScriptLanguage::ScriptTemplate _get_current_template() const;
|
ScriptLanguage::ScriptTemplate _get_current_template() const;
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "core/config/project_settings.h"
|
#include "core/config/project_settings.h"
|
||||||
#include "editor/editor_scale.h"
|
#include "editor/editor_scale.h"
|
||||||
#include "editor/gui/editor_file_dialog.h"
|
#include "editor/gui/editor_file_dialog.h"
|
||||||
|
#include "editor/gui/editor_validation_panel.h"
|
||||||
#include "scene/resources/shader_include.h"
|
#include "scene/resources/shader_include.h"
|
||||||
#include "scene/resources/visual_shader.h"
|
#include "scene/resources/visual_shader.h"
|
||||||
#include "servers/rendering/shader_types.h"
|
#include "servers/rendering/shader_types.h"
|
||||||
|
@ -89,7 +90,6 @@ void ShaderCreateDialog::_update_theme() {
|
||||||
}
|
}
|
||||||
|
|
||||||
path_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
|
path_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
|
||||||
status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCreateDialog::_update_language_info() {
|
void ShaderCreateDialog::_update_language_info() {
|
||||||
|
@ -147,7 +147,7 @@ void ShaderCreateDialog::ok_pressed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
is_new_shader_created = true;
|
is_new_shader_created = true;
|
||||||
_update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCreateDialog::_create_new() {
|
void ShaderCreateDialog::_create_new() {
|
||||||
|
@ -327,7 +327,7 @@ void ShaderCreateDialog::_type_changed(int p_language) {
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorSettings::get_singleton()->set_project_metadata("shader_setup", "last_selected_language", type_menu->get_item_text(type_menu->get_selected()));
|
EditorSettings::get_singleton()->set_project_metadata("shader_setup", "last_selected_language", type_menu->get_item_text(type_menu->get_selected()));
|
||||||
_update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCreateDialog::_built_in_toggled(bool p_enabled) {
|
void ShaderCreateDialog::_built_in_toggled(bool p_enabled) {
|
||||||
|
@ -337,7 +337,7 @@ void ShaderCreateDialog::_built_in_toggled(bool p_enabled) {
|
||||||
} else {
|
} else {
|
||||||
_path_changed(file_path->get_text());
|
_path_changed(file_path->get_text());
|
||||||
}
|
}
|
||||||
_update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCreateDialog::_browse_path() {
|
void ShaderCreateDialog::_browse_path() {
|
||||||
|
@ -378,10 +378,9 @@ void ShaderCreateDialog::_path_changed(const String &p_path) {
|
||||||
is_path_valid = false;
|
is_path_valid = false;
|
||||||
is_new_shader_created = true;
|
is_new_shader_created = true;
|
||||||
|
|
||||||
String path_error = _validate_path(p_path);
|
path_error = _validate_path(p_path);
|
||||||
if (!path_error.is_empty()) {
|
if (!path_error.is_empty()) {
|
||||||
_msg_path_valid(false, path_error);
|
validation_panel->update();
|
||||||
_update_dialog();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,15 +388,16 @@ void ShaderCreateDialog::_path_changed(const String &p_path) {
|
||||||
String p = ProjectSettings::get_singleton()->localize_path(p_path.strip_edges());
|
String p = ProjectSettings::get_singleton()->localize_path(p_path.strip_edges());
|
||||||
if (f->file_exists(p)) {
|
if (f->file_exists(p)) {
|
||||||
is_new_shader_created = false;
|
is_new_shader_created = false;
|
||||||
_msg_path_valid(true, TTR("File exists, it will be reused."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is_path_valid = true;
|
is_path_valid = true;
|
||||||
_update_dialog();
|
validation_panel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCreateDialog::_path_submitted(const String &p_path) {
|
void ShaderCreateDialog::_path_submitted(const String &p_path) {
|
||||||
ok_pressed();
|
if (!get_ok_button()->is_disabled()) {
|
||||||
|
ok_pressed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCreateDialog::config(const String &p_base_path, bool p_built_in_enabled, bool p_load_enabled, int p_preferred_type, int p_preferred_mode) {
|
void ShaderCreateDialog::config(const String &p_base_path, bool p_built_in_enabled, bool p_load_enabled, int p_preferred_type, int p_preferred_mode) {
|
||||||
|
@ -490,33 +490,14 @@ String ShaderCreateDialog::_validate_path(const String &p_path) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCreateDialog::_msg_script_valid(bool valid, const String &p_msg) {
|
|
||||||
error_label->set_text(String::utf8("• ") + p_msg);
|
|
||||||
if (valid) {
|
|
||||||
error_label->add_theme_color_override("font_color", gc->get_theme_color(SNAME("success_color"), SNAME("Editor")));
|
|
||||||
} else {
|
|
||||||
error_label->add_theme_color_override("font_color", gc->get_theme_color(SNAME("error_color"), SNAME("Editor")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShaderCreateDialog::_msg_path_valid(bool valid, const String &p_msg) {
|
|
||||||
path_error_label->set_text(String::utf8("• ") + p_msg);
|
|
||||||
if (valid) {
|
|
||||||
path_error_label->add_theme_color_override("font_color", gc->get_theme_color(SNAME("success_color"), SNAME("Editor")));
|
|
||||||
} else {
|
|
||||||
path_error_label->add_theme_color_override("font_color", gc->get_theme_color(SNAME("error_color"), SNAME("Editor")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShaderCreateDialog::_update_dialog() {
|
void ShaderCreateDialog::_update_dialog() {
|
||||||
bool shader_ok = true;
|
|
||||||
|
|
||||||
if (!is_built_in && !is_path_valid) {
|
if (!is_built_in && !is_path_valid) {
|
||||||
_msg_script_valid(false, TTR("Invalid path."));
|
validation_panel->set_message(MSG_ID_SHADER, TTR("Invalid path."), EditorValidationPanel::MSG_ERROR);
|
||||||
shader_ok = false;
|
|
||||||
}
|
}
|
||||||
if (shader_ok) {
|
if (!path_error.is_empty()) {
|
||||||
_msg_script_valid(true, TTR("Shader path/name is valid."));
|
validation_panel->set_message(MSG_ID_PATH, path_error, EditorValidationPanel::MSG_ERROR);
|
||||||
|
} else if (validation_panel->is_valid() && !is_new_shader_created) {
|
||||||
|
validation_panel->set_message(MSG_ID_SHADER, TTR("File exists, it will be reused."), EditorValidationPanel::MSG_OK);
|
||||||
}
|
}
|
||||||
if (!built_in_enabled) {
|
if (!built_in_enabled) {
|
||||||
internal->set_pressed(false);
|
internal->set_pressed(false);
|
||||||
|
@ -537,37 +518,23 @@ void ShaderCreateDialog::_update_dialog() {
|
||||||
|
|
||||||
internal->set_disabled(!built_in_enabled);
|
internal->set_disabled(!built_in_enabled);
|
||||||
|
|
||||||
builtin_warning_label->set_visible(is_built_in);
|
if (is_built_in) {
|
||||||
|
validation_panel->set_message(MSG_ID_BUILT_IN, TTR("Note: Built-in shaders can't be edited using an external editor."), EditorValidationPanel::MSG_INFO, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_built_in) {
|
if (is_built_in) {
|
||||||
set_ok_button_text(TTR("Create"));
|
set_ok_button_text(TTR("Create"));
|
||||||
_msg_path_valid(true, TTR("Built-in shader (into scene file)."));
|
validation_panel->set_message(MSG_ID_PATH, TTR("Built-in shader (into scene file)."), EditorValidationPanel::MSG_OK);
|
||||||
} else if (is_new_shader_created) {
|
} else if (is_new_shader_created) {
|
||||||
set_ok_button_text(TTR("Create"));
|
set_ok_button_text(TTR("Create"));
|
||||||
if (is_path_valid) {
|
|
||||||
_msg_path_valid(true, TTR("Will create a new shader file."));
|
|
||||||
}
|
|
||||||
} else if (load_enabled) {
|
} else if (load_enabled) {
|
||||||
set_ok_button_text(TTR("Load"));
|
set_ok_button_text(TTR("Load"));
|
||||||
if (is_path_valid) {
|
if (is_path_valid) {
|
||||||
_msg_path_valid(true, TTR("Will load an existing shader file."));
|
validation_panel->set_message(MSG_ID_PATH, TTR("Will load an existing shader file."), EditorValidationPanel::MSG_OK);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
set_ok_button_text(TTR("Create"));
|
set_ok_button_text(TTR("Create"));
|
||||||
_msg_path_valid(false, TTR("Shader file already exists."));
|
validation_panel->set_message(MSG_ID_PATH, TTR("Shader file already exists."), EditorValidationPanel::MSG_ERROR);
|
||||||
|
|
||||||
shader_ok = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_ok_button()->set_disabled(!shader_ok);
|
|
||||||
|
|
||||||
Callable entered_call = callable_mp(this, &ShaderCreateDialog::_path_submitted);
|
|
||||||
if (shader_ok) {
|
|
||||||
if (!file_path->is_connected("text_submitted", entered_call)) {
|
|
||||||
file_path->connect("text_submitted", entered_call);
|
|
||||||
}
|
|
||||||
} else if (file_path->is_connected("text_submitted", entered_call)) {
|
|
||||||
file_path->disconnect("text_submitted", entered_call);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,35 +555,22 @@ ShaderCreateDialog::ShaderCreateDialog() {
|
||||||
|
|
||||||
// Error Fields.
|
// Error Fields.
|
||||||
|
|
||||||
VBoxContainer *vb = memnew(VBoxContainer);
|
validation_panel = memnew(EditorValidationPanel);
|
||||||
|
validation_panel->add_line(MSG_ID_SHADER, TTR("Shader path/name is valid."));
|
||||||
error_label = memnew(Label);
|
validation_panel->add_line(MSG_ID_PATH, TTR("Will create a new shader file."));
|
||||||
vb->add_child(error_label);
|
validation_panel->add_line(MSG_ID_BUILT_IN);
|
||||||
|
validation_panel->set_update_callback(callable_mp(this, &ShaderCreateDialog::_update_dialog));
|
||||||
path_error_label = memnew(Label);
|
validation_panel->set_accept_button(get_ok_button());
|
||||||
vb->add_child(path_error_label);
|
|
||||||
|
|
||||||
builtin_warning_label = memnew(Label);
|
|
||||||
builtin_warning_label->set_text(
|
|
||||||
TTR("Note: Built-in shaders can't be edited using an external editor."));
|
|
||||||
vb->add_child(builtin_warning_label);
|
|
||||||
builtin_warning_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
|
|
||||||
builtin_warning_label->hide();
|
|
||||||
|
|
||||||
status_panel = memnew(PanelContainer);
|
|
||||||
status_panel->set_h_size_flags(Control::SIZE_FILL);
|
|
||||||
status_panel->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
|
||||||
status_panel->add_child(vb);
|
|
||||||
|
|
||||||
// Spacing.
|
// Spacing.
|
||||||
|
|
||||||
Control *spacing = memnew(Control);
|
Control *spacing = memnew(Control);
|
||||||
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
|
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
|
||||||
|
|
||||||
vb = memnew(VBoxContainer);
|
VBoxContainer *vb = memnew(VBoxContainer);
|
||||||
vb->add_child(gc);
|
vb->add_child(gc);
|
||||||
vb->add_child(spacing);
|
vb->add_child(spacing);
|
||||||
vb->add_child(status_panel);
|
vb->add_child(validation_panel);
|
||||||
add_child(vb);
|
add_child(vb);
|
||||||
|
|
||||||
// Type.
|
// Type.
|
||||||
|
|
|
@ -40,10 +40,17 @@
|
||||||
#include "scene/gui/panel_container.h"
|
#include "scene/gui/panel_container.h"
|
||||||
|
|
||||||
class EditorFileDialog;
|
class EditorFileDialog;
|
||||||
|
class EditorValidationPanel;
|
||||||
|
|
||||||
class ShaderCreateDialog : public ConfirmationDialog {
|
class ShaderCreateDialog : public ConfirmationDialog {
|
||||||
GDCLASS(ShaderCreateDialog, ConfirmationDialog);
|
GDCLASS(ShaderCreateDialog, ConfirmationDialog);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MSG_ID_SHADER,
|
||||||
|
MSG_ID_PATH,
|
||||||
|
MSG_ID_BUILT_IN,
|
||||||
|
};
|
||||||
|
|
||||||
struct ShaderTypeData {
|
struct ShaderTypeData {
|
||||||
List<String> extensions;
|
List<String> extensions;
|
||||||
String default_extension;
|
String default_extension;
|
||||||
|
@ -53,10 +60,7 @@ class ShaderCreateDialog : public ConfirmationDialog {
|
||||||
List<ShaderTypeData> type_data;
|
List<ShaderTypeData> type_data;
|
||||||
|
|
||||||
GridContainer *gc = nullptr;
|
GridContainer *gc = nullptr;
|
||||||
Label *error_label = nullptr;
|
EditorValidationPanel *validation_panel = nullptr;
|
||||||
Label *path_error_label = nullptr;
|
|
||||||
Label *builtin_warning_label = nullptr;
|
|
||||||
PanelContainer *status_panel = nullptr;
|
|
||||||
OptionButton *type_menu = nullptr;
|
OptionButton *type_menu = nullptr;
|
||||||
OptionButton *mode_menu = nullptr;
|
OptionButton *mode_menu = nullptr;
|
||||||
OptionButton *template_menu = nullptr;
|
OptionButton *template_menu = nullptr;
|
||||||
|
@ -67,6 +71,7 @@ class ShaderCreateDialog : public ConfirmationDialog {
|
||||||
AcceptDialog *alert = nullptr;
|
AcceptDialog *alert = nullptr;
|
||||||
|
|
||||||
String initial_base_path;
|
String initial_base_path;
|
||||||
|
String path_error;
|
||||||
bool is_new_shader_created = true;
|
bool is_new_shader_created = true;
|
||||||
bool is_path_valid = false;
|
bool is_path_valid = false;
|
||||||
bool is_built_in = false;
|
bool is_built_in = false;
|
||||||
|
@ -93,8 +98,6 @@ class ShaderCreateDialog : public ConfirmationDialog {
|
||||||
virtual void ok_pressed() override;
|
virtual void ok_pressed() override;
|
||||||
void _create_new();
|
void _create_new();
|
||||||
void _load_exist();
|
void _load_exist();
|
||||||
void _msg_script_valid(bool valid, const String &p_msg = String());
|
|
||||||
void _msg_path_valid(bool valid, const String &p_msg = String());
|
|
||||||
void _update_dialog();
|
void _update_dialog();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
Loading…
Reference in New Issue