summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--editor/directory_create_dialog.cpp40
-rw-r--r--editor/directory_create_dialog.h10
-rw-r--r--editor/editor_inspector.cpp56
-rw-r--r--editor/editor_inspector.h6
-rw-r--r--editor/editor_themes.cpp1
-rw-r--r--editor/gui/editor_validation_panel.cpp134
-rw-r--r--editor/gui/editor_validation_panel.h88
-rw-r--r--editor/scene_create_dialog.cpp90
-rw-r--r--editor/scene_create_dialog.h14
-rw-r--r--editor/script_create_dialog.cpp147
-rw-r--r--editor/script_create_dialog.h18
-rw-r--r--editor/shader_create_dialog.cpp104
-rw-r--r--editor/shader_create_dialog.h15
13 files changed, 382 insertions, 341 deletions
diff --git a/editor/directory_create_dialog.cpp b/editor/directory_create_dialog.cpp
index df860bab2c..fed7cb82c9 100644
--- a/editor/directory_create_dialog.cpp
+++ b/editor/directory_create_dialog.cpp
@@ -33,10 +33,10 @@
#include "core/io/dir_access.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/gui/editor_validation_panel.h"
#include "scene/gui/box_container.h"
#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
-#include "scene/gui/panel_container.h"
static String sanitize_input(const String &p_path) {
String path = p_path.strip_edges();
@@ -73,24 +73,17 @@ String DirectoryCreateDialog::_validate_path(const String &p_path) const {
return String();
}
-void DirectoryCreateDialog::_on_dir_path_changed(const String &p_text) {
- const String path = sanitize_input(p_text);
+void DirectoryCreateDialog::_on_dir_path_changed() {
+ const String path = sanitize_input(dir_path->get_text());
const String error = _validate_path(path);
if (error.is_empty()) {
- status_label->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
-
if (path.contains("/")) {
- status_label->set_text(TTR("Using slashes in folder names will create subfolders recursively."));
- } else {
- status_label->set_text(TTR("Folder name is valid."));
+ validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Using slashes in folder names will create subfolders recursively."), EditorValidationPanel::MSG_OK);
}
} else {
- status_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
- status_label->set_text(error);
+ validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, error, EditorValidationPanel::MSG_ERROR);
}
-
- get_ok_button()->set_disabled(!error.is_empty());
}
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));
dir_path->set_text("new folder");
dir_path->select_all();
- _on_dir_path_changed(dir_path->get_text());
+ validation_panel->update();
}
void DirectoryCreateDialog::_bind_methods() {
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() {
set_title(TTR("Create Folder"));
set_min_size(Size2i(480, 0) * EDSCALE);
@@ -154,7 +139,6 @@ DirectoryCreateDialog::DirectoryCreateDialog() {
vb->add_child(label);
dir_path = memnew(LineEdit);
- dir_path->connect("text_changed", callable_mp(this, &DirectoryCreateDialog::_on_dir_path_changed));
vb->add_child(dir_path);
register_text_enter(dir_path);
@@ -162,11 +146,11 @@ DirectoryCreateDialog::DirectoryCreateDialog() {
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
vb->add_child(spacing);
- status_panel = memnew(PanelContainer);
- status_panel->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- vb->add_child(status_panel);
+ validation_panel = memnew(EditorValidationPanel);
+ vb->add_child(validation_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);
- status_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- status_panel->add_child(status_label);
+ dir_path->connect("text_changed", callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
}
diff --git a/editor/directory_create_dialog.h b/editor/directory_create_dialog.h
index e2601181da..82e2e98ae5 100644
--- a/editor/directory_create_dialog.h
+++ b/editor/directory_create_dialog.h
@@ -33,9 +33,9 @@
#include "scene/gui/dialogs.h"
+class EditorValidationPanel;
class Label;
class LineEdit;
-class PanelContainer;
class DirectoryCreateDialog : public ConfirmationDialog {
GDCLASS(DirectoryCreateDialog, ConfirmationDialog);
@@ -44,17 +44,13 @@ class DirectoryCreateDialog : public ConfirmationDialog {
Label *label = nullptr;
LineEdit *dir_path = nullptr;
-
- PanelContainer *status_panel = nullptr;
- Label *status_label = nullptr;
+ EditorValidationPanel *validation_panel = nullptr;
String _validate_path(const String &p_path) const;
-
- void _on_dir_path_changed(const String &p_text);
+ void _on_dir_path_changed();
protected:
static void _bind_methods();
- void _notification(int p_what);
virtual void ok_pressed() override;
virtual void _post_popup() override;
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index d95b1de365..7ac812101a 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -38,6 +38,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/gui/editor_validation_panel.h"
#include "editor/inspector_dock.h"
#include "editor/plugins/script_editor_plugin.h"
#include "multi_node_edit.h"
@@ -3927,12 +3928,6 @@ void EditorInspector::_notification(int p_what) {
}
} 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: {
edit(nullptr); //just in case
} break;
@@ -4083,27 +4078,17 @@ void EditorInspector::_add_meta_confirm() {
undo_redo->commit_action();
}
-void EditorInspector::_check_meta_name(const String &p_name) {
- String error;
-
- if (p_name == "") {
- error = TTR("Metadata name can't be empty.");
- } else if (!p_name.is_valid_identifier()) {
- error = TTR("Metadata name must be a valid identifier.");
- } else if (object->has_meta(p_name)) {
- error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name);
- } else if (p_name[0] == '_') {
- error = TTR("Names starting with _ are reserved for editor-only metadata.");
- }
+void EditorInspector::_check_meta_name() {
+ const String meta_name = add_meta_name->get_text();
- 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);
+ if (meta_name.is_empty()) {
+ validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Metadata name can't be empty."), EditorValidationPanel::MSG_ERROR);
+ } else if (!meta_name.is_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(meta_name)) {
+ validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, vformat(TTR("Metadata with name \"%s\" already exists."), meta_name), EditorValidationPanel::MSG_ERROR);
+ } else if (meta_name[0] == '_') {
+ validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Names starting with _ are reserved for editor-only metadata."), EditorValidationPanel::MSG_ERROR);
}
}
@@ -4143,16 +4128,13 @@ void EditorInspector::_show_add_meta_dialog() {
add_meta_dialog->register_text_enter(add_meta_name);
add_meta_dialog->connect("confirmed", callable_mp(this, &EditorInspector::_add_meta_confirm));
- add_meta_error_panel = memnew(PanelContainer);
- vbc->add_child(add_meta_error_panel);
- if (is_inside_tree()) {
- add_meta_error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
- }
-
- add_meta_error = memnew(Label);
- add_meta_error_panel->add_child(add_meta_error);
+ validation_panel = memnew(EditorValidationPanel);
+ vbc->add_child(validation_panel);
+ validation_panel->add_line(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Metadata name is valid."));
+ 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_name->connect("text_changed", callable_mp(this, &EditorInspector::_check_meta_name));
+ add_meta_name->connect("text_changed", callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
}
Node *node = Object::cast_to<Node>(object);
@@ -4164,9 +4146,9 @@ void EditorInspector::_show_add_meta_dialog() {
}
add_meta_dialog->popup_centered();
- add_meta_name->set_text("");
- _check_meta_name("");
add_meta_name->grab_focus();
+ add_meta_name->set_text("");
+ validation_panel->update();
}
void EditorInspector::_bind_methods() {
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 9a4c4f7f99..ed0d0ec373 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -39,6 +39,7 @@ class AcceptDialog;
class Button;
class ConfirmationDialog;
class EditorInspector;
+class EditorValidationPanel;
class LineEdit;
class OptionButton;
class PanelContainer;
@@ -543,12 +544,11 @@ class EditorInspector : public ScrollContainer {
ConfirmationDialog *add_meta_dialog = nullptr;
LineEdit *add_meta_name = nullptr;
OptionButton *add_meta_type = nullptr;
- PanelContainer *add_meta_error_panel = nullptr;
- Label *add_meta_error = nullptr;
+ EditorValidationPanel *validation_panel = nullptr;
void _add_meta_confirm();
void _show_add_meta_dialog();
- void _check_meta_name(const String &p_name);
+ void _check_meta_name();
protected:
static void _bind_methods();
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 80cefecee2..628976ac57 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -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", "EditorValidationPanel", style_tree_bg);
// Tree
theme->set_icon("checked", "Tree", theme->get_icon(SNAME("GuiChecked"), SNAME("EditorIcons")));
diff --git a/editor/gui/editor_validation_panel.cpp b/editor/gui/editor_validation_panel.cpp
new file mode 100644
index 0000000000..af15010b78
--- /dev/null
+++ b/editor/gui/editor_validation_panel.cpp
@@ -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);
+}
diff --git a/editor/gui/editor_validation_panel.h b/editor/gui/editor_validation_panel.h
new file mode 100644
index 0000000000..c371795e15
--- /dev/null
+++ b/editor/gui/editor_validation_panel.h
@@ -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
diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp
index 986f6bb87a..8f56267123 100644
--- a/editor/scene_create_dialog.cpp
+++ b/editor/scene_create_dialog.cpp
@@ -34,6 +34,7 @@
#include "editor/create_dialog.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/gui/editor_validation_panel.h"
#include "scene/2d/node_2d.h"
#include "scene/3d/node_3d.h"
#include "scene/gui/box_container.h"
@@ -41,7 +42,6 @@
#include "scene/gui/grid_container.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/option_button.h"
-#include "scene/gui/panel_container.h"
#include "scene/resources/packed_scene.h"
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_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")));
- status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
}
}
@@ -63,7 +62,7 @@ void SceneCreateDialog::config(const String &p_dir) {
root_name_edit->set_text("");
scene_name_edit->set_text("");
scene_name_edit->call_deferred(SNAME("grab_focus"));
- update_dialog();
+ validation_panel->update();
}
void SceneCreateDialog::accept_create() {
@@ -82,40 +81,35 @@ void SceneCreateDialog::browse_types() {
void SceneCreateDialog::on_type_picked() {
other_type_display->set_text(select_node_dialog->get_selected_type().get_slice(" ", 0));
if (node_type_other->is_pressed()) {
- update_dialog();
+ validation_panel->update();
} 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() {
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()) {
- update_error(file_error_label, MSG_ERROR, TTR("Scene name is empty."));
- is_valid = false;
+ validation_panel->set_message(MSG_ID_PATH, TTR("Scene name is empty."), EditorValidationPanel::MSG_ERROR);
}
- if (is_valid) {
+ if (validation_panel->is_valid()) {
if (!scene_name.ends_with(".")) {
scene_name += ".";
}
scene_name += scene_extension_picker->get_selected_metadata().operator String();
}
- if (is_valid && !scene_name.is_valid_filename()) {
- update_error(file_error_label, MSG_ERROR, TTR("File name invalid."));
- is_valid = false;
+ if (validation_panel->is_valid() && !scene_name.is_valid_filename()) {
+ validation_panel->set_message(MSG_ID_PATH, TTR("File name invalid."), EditorValidationPanel::MSG_ERROR);
}
- if (is_valid) {
+ if (validation_panel->is_valid()) {
scene_name = directory.path_join(scene_name);
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
if (da->file_exists(scene_name)) {
- update_error(file_error_label, MSG_ERROR, TTR("File already exists."));
- is_valid = false;
+ validation_panel->set_message(MSG_ID_PATH, TTR("File already exists."), EditorValidationPanel::MSG_ERROR);
}
}
@@ -126,8 +120,6 @@ void SceneCreateDialog::update_dialog() {
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();
if (root_name.is_empty()) {
root_name = scene_name_edit->get_text().strip_edges();
@@ -135,39 +127,16 @@ void SceneCreateDialog::update_dialog() {
if (root_name.is_empty()) {
root_name_edit->set_placeholder(TTR("Leave empty to derive from scene name"));
} else {
- // Respect the desired root node casing from ProjectSettings and ensure it's a valid node name.
- String adjusted_root_name = Node::adjust_name_casing(root_name);
- root_name = adjusted_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);
+ // Respect the desired root node casing from ProjectSettings.
+ root_name = Node::adjust_name_casing(root_name);
+ root_name_edit->set_placeholder(root_name.validate_node_name());
}
}
- if (root_name.is_empty() || root_name.validate_node_name() != root_name) {
- update_error(node_error_label, MSG_ERROR, TTR("Invalid root node name."));
- is_valid = false;
- }
-
- 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;
+ if (root_name.is_empty()) {
+ validation_panel->set_message(MSG_ID_ROOT, TTR("Invalid root node name."), EditorValidationPanel::MSG_ERROR);
+ } 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);
}
}
@@ -268,8 +237,6 @@ SceneCreateDialog::SceneCreateDialog() {
select_node_button = memnew(Button);
hb->add_child(select_node_button);
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);
hb->add_child(scene_name_edit);
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));
List<String> extensions;
@@ -305,7 +271,6 @@ SceneCreateDialog::SceneCreateDialog() {
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_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));
}
@@ -313,19 +278,16 @@ SceneCreateDialog::SceneCreateDialog() {
main_vb->add_child(spacing);
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
- status_panel = memnew(PanelContainer);
- main_vb->add_child(status_panel);
- status_panel->set_h_size_flags(Control::SIZE_FILL);
- status_panel->set_v_size_flags(Control::SIZE_EXPAND_FILL);
-
- VBoxContainer *status_vb = memnew(VBoxContainer);
- status_panel->add_child(status_vb);
-
- file_error_label = memnew(Label);
- status_vb->add_child(file_error_label);
+ validation_panel = memnew(EditorValidationPanel);
+ main_vb->add_child(validation_panel);
+ validation_panel->add_line(MSG_ID_PATH, TTR("Scene name is valid."));
+ 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());
- node_error_label = memnew(Label);
- status_vb->add_child(node_error_label);
+ node_type_group->connect("pressed", callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
+ 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));
set_title(TTR("Create New Scene"));
set_min_size(Size2i(400 * EDSCALE, 0));
diff --git a/editor/scene_create_dialog.h b/editor/scene_create_dialog.h
index c6f40b928e..c7a4a09850 100644
--- a/editor/scene_create_dialog.h
+++ b/editor/scene_create_dialog.h
@@ -37,18 +37,17 @@ class ButtonGroup;
class CheckBox;
class CreateDialog;
class EditorFileDialog;
+class EditorValidationPanel;
class Label;
class LineEdit;
class OptionButton;
-class PanelContainer;
class SceneCreateDialog : public ConfirmationDialog {
GDCLASS(SceneCreateDialog, ConfirmationDialog);
- enum MsgType {
- MSG_OK,
- MSG_ERROR,
- MSG_WARNING,
+ enum {
+ MSG_ID_PATH,
+ MSG_ID_ROOT,
};
const StringName type_meta = StringName("type");
@@ -80,15 +79,12 @@ private:
OptionButton *scene_extension_picker = nullptr;
LineEdit *root_name_edit = nullptr;
- PanelContainer *status_panel = nullptr;
- Label *file_error_label = nullptr;
- Label *node_error_label = nullptr;
+ EditorValidationPanel *validation_panel = nullptr;
void accept_create();
void browse_types();
void on_type_picked();
void update_dialog();
- void update_error(Label *p_label, MsgType p_type, const String &p_msg);
protected:
void _notification(int p_what);
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 058f4c8d91..daac755529 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -41,6 +41,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.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) {
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")));
parent_browse_button->set_icon(get_theme_icon(SNAME("Folder"), 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;
}
}
@@ -295,13 +295,7 @@ String ScriptCreateDialog::_validate_path(const String &p_path, bool p_file_must
}
// Let ScriptLanguage do custom validation.
- String path_error = ScriptServer::get_language(language_menu->get_selected())->validate_path(p);
- if (!path_error.is_empty()) {
- return path_error;
- }
-
- // All checks passed.
- return "";
+ return ScriptServer::get_language(language_menu->get_selected())->validate_path(p);
}
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) {
is_class_name_valid = _validate_class(class_name->get_text());
- _update_dialog();
+ validation_panel->update();
}
void ScriptCreateDialog::_parent_name_changed(const String &p_parent) {
is_parent_name_valid = _validate_parent(parent_name->get_text());
- _update_dialog();
+ validation_panel->update();
}
void ScriptCreateDialog::_template_changed(int p_template) {
@@ -347,6 +341,7 @@ void ScriptCreateDialog::_template_changed(int p_template) {
}
}
}
+
// Update template label information.
String template_info = U"• ";
template_info += TTR("Template:");
@@ -354,8 +349,7 @@ void ScriptCreateDialog::_template_changed(int p_template) {
if (!sinfo.description.is_empty()) {
template_info += " - " + sinfo.description;
}
- template_info_label->set_text(template_info);
- template_info_label->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
+ validation_panel->set_message(MSG_ID_TEMPLATE, template_info, EditorValidationPanel::MSG_INFO, false);
}
void ScriptCreateDialog::ok_pressed() {
@@ -367,7 +361,7 @@ void ScriptCreateDialog::ok_pressed() {
EditorSettings::get_singleton()->save();
is_new_script_created = true;
- _update_dialog();
+ validation_panel->update();
}
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()));
_parent_name_changed(parent_name->get_text());
- _update_dialog();
+ validation_panel->update();
}
void ScriptCreateDialog::_built_in_pressed() {
@@ -482,13 +476,13 @@ void ScriptCreateDialog::_built_in_pressed() {
is_built_in = false;
_path_changed(file_path->get_text());
}
- _update_dialog();
+ validation_panel->update();
}
void ScriptCreateDialog::_use_template_pressed() {
is_using_templates = use_templates->is_pressed();
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) {
@@ -555,10 +549,9 @@ void ScriptCreateDialog::_path_changed(const String &p_path) {
is_path_valid = false;
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()) {
- _msg_path_valid(false, path_error);
- _update_dialog();
+ validation_panel->update();
return;
}
@@ -567,32 +560,15 @@ void ScriptCreateDialog::_path_changed(const String &p_path) {
String p = ProjectSettings::get_singleton()->localize_path(p_path.strip_edges());
if (da->file_exists(p)) {
is_new_script_created = false;
- _msg_path_valid(true, TTR("File exists, it will be reused."));
}
is_path_valid = true;
- _update_dialog();
+ validation_panel->update();
}
void ScriptCreateDialog::_path_submitted(const String &p_path) {
- 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")));
+ if (!get_ok_button()->is_disabled()) {
+ ok_pressed();
}
}
@@ -688,25 +664,25 @@ void ScriptCreateDialog::_update_template_menu() {
void ScriptCreateDialog::_update_dialog() {
// "Add Script Dialog" GUI logic and script checks.
_update_template_menu();
- bool script_ok = true;
// Is script path/name valid (order from top to bottom)?
if (!is_built_in && !is_path_valid) {
- _msg_script_valid(false, TTR("Invalid path."));
- script_ok = false;
+ validation_panel->set_message(MSG_ID_SCRIPT, TTR("Invalid path."), EditorValidationPanel::MSG_ERROR);
}
if (has_named_classes && (is_new_script_created && !is_class_name_valid)) {
- _msg_script_valid(false, TTR("Invalid class name."));
- script_ok = false;
+ validation_panel->set_message(MSG_ID_SCRIPT, TTR("Invalid class name."), EditorValidationPanel::MSG_ERROR);
}
if (!is_parent_name_valid && is_new_script_created) {
- _msg_script_valid(false, TTR("Invalid inherited parent name or path."));
- script_ok = false;
+ validation_panel->set_message(MSG_ID_SCRIPT, TTR("Invalid inherited parent name or path."), EditorValidationPanel::MSG_ERROR);
}
- if (script_ok) {
- _msg_script_valid(true, TTR("Script path/name is valid."));
+ if (validation_panel->is_valid() && !is_new_script_created) {
+ 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?
@@ -752,7 +728,11 @@ void ScriptCreateDialog::_update_dialog() {
// 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[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.
// 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;
@@ -774,21 +753,16 @@ void ScriptCreateDialog::_update_dialog() {
if (is_new_file) {
if (is_built_in) {
- _msg_path_valid(true, TTR("Built-in script (into scene file)."));
- }
- if (is_new_script_created && is_path_valid) {
- _msg_path_valid(true, TTR("Will create a new script file."));
+ validation_panel->set_message(MSG_ID_PATH, TTR("Built-in script (into scene file)."), EditorValidationPanel::MSG_OK);
}
} else {
+ template_inactive_message = TTR("Using existing script file.");
if (load_enabled) {
- template_inactive_message = TTR("Using existing script file.");
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 {
- template_inactive_message = TTR("Using existing script file.");
- _msg_path_valid(false, TTR("Script file already exists."));
- script_ok = false;
+ validation_panel->set_message(MSG_ID_PATH, TTR("Script file already exists."), EditorValidationPanel::MSG_ERROR);
}
}
@@ -806,18 +780,7 @@ void ScriptCreateDialog::_update_dialog() {
template_menu->set_disabled(true);
template_menu->clear();
template_menu->add_item(template_inactive_message);
- }
- 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);
+ validation_panel->set_message(MSG_ID_TEMPLATE, "", EditorValidationPanel::MSG_INFO);
}
}
@@ -967,47 +930,23 @@ ScriptCreateDialog::ScriptCreateDialog() {
/* Information Messages Field */
- VBoxContainer *vb = memnew(VBoxContainer);
-
- error_label = memnew(Label);
- vb->add_child(error_label);
-
- path_error_label = memnew(Label);
- vb->add_child(path_error_label);
-
- 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);
+ validation_panel = memnew(EditorValidationPanel);
+ validation_panel->add_line(MSG_ID_SCRIPT, TTR("Script path/name is valid."));
+ validation_panel->add_line(MSG_ID_PATH, TTR("Will create a new script file."));
+ validation_panel->add_line(MSG_ID_BUILT_IN);
+ validation_panel->add_line(MSG_ID_TEMPLATE);
+ validation_panel->set_update_callback(callable_mp(this, &ScriptCreateDialog::_update_dialog));
+ validation_panel->set_accept_button(get_ok_button());
/* Spacing */
Control *spacing = memnew(Control);
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
- vb = memnew(VBoxContainer);
+ VBoxContainer *vb = memnew(VBoxContainer);
vb->add_child(gc);
vb->add_child(spacing);
- vb->add_child(status_panel);
+ vb->add_child(validation_panel);
add_child(vb);
/* Language */
diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h
index fa42b96746..ea2f480c57 100644
--- a/editor/script_create_dialog.h
+++ b/editor/script_create_dialog.h
@@ -41,17 +41,20 @@
class CreateDialog;
class EditorFileDialog;
+class EditorValidationPanel;
class ScriptCreateDialog : public ConfirmationDialog {
GDCLASS(ScriptCreateDialog, ConfirmationDialog);
+ enum {
+ MSG_ID_SCRIPT,
+ MSG_ID_PATH,
+ MSG_ID_BUILT_IN,
+ MSG_ID_TEMPLATE,
+ };
+
LineEdit *class_name = nullptr;
- Label *error_label = 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;
+ EditorValidationPanel *validation_panel = nullptr;
LineEdit *parent_name = nullptr;
Button *parent_browse_button = nullptr;
Button *parent_search_button = nullptr;
@@ -67,6 +70,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
AcceptDialog *alert = nullptr;
CreateDialog *select_class = nullptr;
bool is_browsing_parent = false;
+ String path_error;
String template_inactive_message;
String initial_bp;
bool is_new_script_created = true;
@@ -113,8 +117,6 @@ class ScriptCreateDialog : public ConfirmationDialog {
virtual void ok_pressed() override;
void _create_new();
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_dialog();
ScriptLanguage::ScriptTemplate _get_current_template() const;
diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp
index 607b53718b..9a7b9bc84d 100644
--- a/editor/shader_create_dialog.cpp
+++ b/editor/shader_create_dialog.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_scale.h"
#include "editor/gui/editor_file_dialog.h"
+#include "editor/gui/editor_validation_panel.h"
#include "scene/resources/shader_include.h"
#include "scene/resources/visual_shader.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")));
- status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
}
void ShaderCreateDialog::_update_language_info() {
@@ -147,7 +147,7 @@ void ShaderCreateDialog::ok_pressed() {
}
is_new_shader_created = true;
- _update_dialog();
+ validation_panel->update();
}
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()));
- _update_dialog();
+ validation_panel->update();
}
void ShaderCreateDialog::_built_in_toggled(bool p_enabled) {
@@ -337,7 +337,7 @@ void ShaderCreateDialog::_built_in_toggled(bool p_enabled) {
} else {
_path_changed(file_path->get_text());
}
- _update_dialog();
+ validation_panel->update();
}
void ShaderCreateDialog::_browse_path() {
@@ -378,10 +378,9 @@ void ShaderCreateDialog::_path_changed(const String &p_path) {
is_path_valid = false;
is_new_shader_created = true;
- String path_error = _validate_path(p_path);
+ path_error = _validate_path(p_path);
if (!path_error.is_empty()) {
- _msg_path_valid(false, path_error);
- _update_dialog();
+ validation_panel->update();
return;
}
@@ -389,15 +388,16 @@ void ShaderCreateDialog::_path_changed(const String &p_path) {
String p = ProjectSettings::get_singleton()->localize_path(p_path.strip_edges());
if (f->file_exists(p)) {
is_new_shader_created = false;
- _msg_path_valid(true, TTR("File exists, it will be reused."));
}
is_path_valid = true;
- _update_dialog();
+ validation_panel->update();
}
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) {
@@ -490,33 +490,14 @@ String ShaderCreateDialog::_validate_path(const String &p_path) {
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() {
- bool shader_ok = true;
-
if (!is_built_in && !is_path_valid) {
- _msg_script_valid(false, TTR("Invalid path."));
- shader_ok = false;
+ validation_panel->set_message(MSG_ID_SHADER, TTR("Invalid path."), EditorValidationPanel::MSG_ERROR);
}
- if (shader_ok) {
- _msg_script_valid(true, TTR("Shader path/name is valid."));
+ if (!path_error.is_empty()) {
+ 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) {
internal->set_pressed(false);
@@ -537,37 +518,23 @@ void ShaderCreateDialog::_update_dialog() {
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) {
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) {
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) {
set_ok_button_text(TTR("Load"));
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 {
set_ok_button_text(TTR("Create"));
- _msg_path_valid(false, TTR("Shader file already exists."));
-
- 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);
+ validation_panel->set_message(MSG_ID_PATH, TTR("Shader file already exists."), EditorValidationPanel::MSG_ERROR);
}
}
@@ -588,35 +555,22 @@ ShaderCreateDialog::ShaderCreateDialog() {
// Error Fields.
- VBoxContainer *vb = memnew(VBoxContainer);
-
- error_label = memnew(Label);
- vb->add_child(error_label);
-
- path_error_label = memnew(Label);
- 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);
+ validation_panel = memnew(EditorValidationPanel);
+ validation_panel->add_line(MSG_ID_SHADER, TTR("Shader path/name is valid."));
+ validation_panel->add_line(MSG_ID_PATH, TTR("Will create a new shader file."));
+ validation_panel->add_line(MSG_ID_BUILT_IN);
+ validation_panel->set_update_callback(callable_mp(this, &ShaderCreateDialog::_update_dialog));
+ validation_panel->set_accept_button(get_ok_button());
// Spacing.
Control *spacing = memnew(Control);
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
- vb = memnew(VBoxContainer);
+ VBoxContainer *vb = memnew(VBoxContainer);
vb->add_child(gc);
vb->add_child(spacing);
- vb->add_child(status_panel);
+ vb->add_child(validation_panel);
add_child(vb);
// Type.
diff --git a/editor/shader_create_dialog.h b/editor/shader_create_dialog.h
index 729a7b5bd4..d6d9f10020 100644
--- a/editor/shader_create_dialog.h
+++ b/editor/shader_create_dialog.h
@@ -40,10 +40,17 @@
#include "scene/gui/panel_container.h"
class EditorFileDialog;
+class EditorValidationPanel;
class ShaderCreateDialog : public ConfirmationDialog {
GDCLASS(ShaderCreateDialog, ConfirmationDialog);
+ enum {
+ MSG_ID_SHADER,
+ MSG_ID_PATH,
+ MSG_ID_BUILT_IN,
+ };
+
struct ShaderTypeData {
List<String> extensions;
String default_extension;
@@ -53,10 +60,7 @@ class ShaderCreateDialog : public ConfirmationDialog {
List<ShaderTypeData> type_data;
GridContainer *gc = nullptr;
- Label *error_label = nullptr;
- Label *path_error_label = nullptr;
- Label *builtin_warning_label = nullptr;
- PanelContainer *status_panel = nullptr;
+ EditorValidationPanel *validation_panel = nullptr;
OptionButton *type_menu = nullptr;
OptionButton *mode_menu = nullptr;
OptionButton *template_menu = nullptr;
@@ -67,6 +71,7 @@ class ShaderCreateDialog : public ConfirmationDialog {
AcceptDialog *alert = nullptr;
String initial_base_path;
+ String path_error;
bool is_new_shader_created = true;
bool is_path_valid = false;
bool is_built_in = false;
@@ -93,8 +98,6 @@ class ShaderCreateDialog : public ConfirmationDialog {
virtual void ok_pressed() override;
void _create_new();
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();
protected: