summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/config/project_settings.cpp2
-rw-r--r--core/object/script_language.h1
-rw-r--r--doc/classes/ButtonGroup.xml9
-rw-r--r--doc/classes/OS.xml2
-rw-r--r--doc/classes/ProjectSettings.xml8
-rw-r--r--editor/action_map_editor.cpp46
-rw-r--r--editor/action_map_editor.h10
-rw-r--r--editor/editor_log.cpp61
-rw-r--r--editor/editor_log.h18
-rw-r--r--editor/editor_node.cpp4
-rw-r--r--editor/editor_run.cpp45
-rw-r--r--editor/editor_settings.cpp1
-rw-r--r--editor/editor_themes.cpp2
-rw-r--r--editor/plugins/editor_preview_plugins.cpp20
-rw-r--r--editor/plugins/script_editor_plugin.cpp7
-rw-r--r--editor/plugins/shader_editor_plugin.cpp7
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp14
-rw-r--r--editor/project_settings_editor.cpp2
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp4
-rw-r--r--modules/gdnative/nativescript/nativescript.h1
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.cpp4
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.h1
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp7
-rw-r--r--modules/gdscript/gdscript.cpp13
-rw-r--r--modules/gdscript/gdscript.h1
-rw-r--r--modules/mono/csharp_script.cpp20
-rw-r--r--modules/mono/csharp_script.h1
-rw-r--r--modules/visual_script/visual_script.cpp4
-rw-r--r--modules/visual_script/visual_script.h1
-rw-r--r--scene/gui/base_button.cpp7
-rw-r--r--scene/gui/color_picker.cpp53
-rw-r--r--scene/gui/color_picker.h7
-rw-r--r--scene/resources/surface_tool.cpp8
-rw-r--r--servers/rendering/shader_language.cpp14
-rw-r--r--servers/rendering/shader_language.h1
35 files changed, 337 insertions, 69 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 25dd408dce..0d699cdacb 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1104,6 +1104,8 @@ ProjectSettings::ProjectSettings() {
}
extensions.push_back("shader");
+ GLOBAL_DEF("editor/run/main_run_args", "");
+
GLOBAL_DEF("editor/script/search_in_file_extensions", extensions);
custom_prop_info["editor/script/search_in_file_extensions"] = PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions");
diff --git a/core/object/script_language.h b/core/object/script_language.h
index f9898ccd0c..bb46c718b2 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -303,6 +303,7 @@ public:
void get_core_type_words(List<String> *p_core_type_words) const;
virtual void get_reserved_words(List<String> *p_words) const = 0;
+ virtual bool is_control_flow_keyword(String p_string) const = 0;
virtual void get_comment_delimiters(List<String> *p_delimiters) const = 0;
virtual void get_string_delimiters(List<String> *p_delimiters) const = 0;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0;
diff --git a/doc/classes/ButtonGroup.xml b/doc/classes/ButtonGroup.xml
index 5aa2d699a8..0b31352611 100644
--- a/doc/classes/ButtonGroup.xml
+++ b/doc/classes/ButtonGroup.xml
@@ -28,6 +28,15 @@
<members>
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" override="true" default="true" />
</members>
+ <signals>
+ <signal name="pressed">
+ <argument index="0" name="button" type="Object">
+ </argument>
+ <description>
+ Emitted when one of the buttons of the group is pressed.
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 8c90108aef..d997073849 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -143,7 +143,7 @@
Returns the command-line arguments passed to the engine.
Command-line arguments can be written in any form, including both [code]--key value[/code] and [code]--key=value[/code] forms so they can be properly parsed, as long as custom command-line arguments do not conflict with engine arguments.
You can also incorporate environment variables using the [method get_environment] method.
- You can set [code]editor/main_run_args[/code] in the Project Settings to define command-line arguments to be passed by the editor when running the project.
+ You can set [member ProjectSettings.editor/run/main_run_args] to define command-line arguments to be passed by the editor when running the project.
Here's a minimal example on how to parse command-line arguments into a dictionary using the [code]--key=value[/code] form for arguments:
[codeblocks]
[gdscript]
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 005873c2ff..3200f789b8 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -542,6 +542,14 @@
<member name="editor/node_naming/name_num_separator" type="int" setter="" getter="" default="0">
What to use to separate node name from number. This is mostly an editor setting.
</member>
+ <member name="editor/run/main_run_args" type="String" setter="" getter="" default="&quot;&quot;">
+ The command-line arguments to append to Godot's own command line when running the project. This doesn't affect the editor itself.
+ It is possible to make another executable run Godot by using the [code]%command%[/code] placeholder. The placeholder will be replaced with Godot's own command line. Program-specific arguments should be placed [i]before[/i] the placeholder, whereas Godot-specific arguments should be placed [i]after[/i] the placeholder.
+ For example, this can be used to force the project to run on the dedicated GPU in a NVIDIA Optimus system on Linux:
+ [codeblock]
+ prime-run %command%
+ [/codeblock]
+ </member>
<member name="editor/script/search_in_file_extensions" type="PackedStringArray" setter="" getter="" default="PackedStringArray( &quot;gd&quot;, &quot;shader&quot; )">
Text-based file extensions to include in the script editor's "Find in Files" feature. You can add e.g. [code]tscn[/code] if you wish to also parse your scene files, especially if you use built-in scripts which are serialized in the scene files.
</member>
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 9949fd8199..c0d5716c4e 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -730,10 +730,6 @@ void ActionMapEditor::_add_action_pressed() {
}
void ActionMapEditor::_add_action(const String &p_name) {
- if (!allow_editing_actions) {
- return;
- }
-
if (p_name == "" || !_is_action_name_valid(p_name)) {
show_message(TTR("Invalid action name. it cannot be.is_empty()() nor contain '/', ':', '=', '\\' or '\"'"));
return;
@@ -744,10 +740,6 @@ void ActionMapEditor::_add_action(const String &p_name) {
}
void ActionMapEditor::_action_edited() {
- if (!allow_editing_actions) {
- return;
- }
-
TreeItem *ti = action_tree->get_edited();
if (!ti) {
return;
@@ -812,10 +804,6 @@ void ActionMapEditor::_tree_button_pressed(Object *p_item, int p_column, int p_i
} break;
case ActionMapEditor::BUTTON_REMOVE_ACTION: {
- if (!allow_editing_actions) {
- break;
- }
-
// Send removed action name
String name = item->get_meta("__name");
emit_signal("action_removed", name);
@@ -848,11 +836,11 @@ void ActionMapEditor::_tree_item_activated() {
_tree_button_pressed(item, 2, BUTTON_EDIT_EVENT);
}
-void ActionMapEditor::set_show_uneditable(bool p_show) {
- show_uneditable = p_show;
- show_uneditable_actions_checkbox->set_pressed(p_show);
+void ActionMapEditor::set_show_builtin_actions(bool p_show) {
+ show_builtin_actions = p_show;
+ show_builtin_actions_checkbutton->set_pressed(p_show);
- // Prevent unnecessary updates of action list when cache is.is_empty()().
+ // Prevent unnecessary updates of action list when cache is empty.
if (!actions_cache.is_empty()) {
update_action_list();
}
@@ -1022,7 +1010,7 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info
continue;
}
- if (!action_info.editable && !show_uneditable) {
+ if (!action_info.editable && !show_builtin_actions) {
continue;
}
@@ -1080,15 +1068,6 @@ void ActionMapEditor::show_message(const String &p_message) {
message->popup_centered(Size2(300, 100) * EDSCALE);
}
-void ActionMapEditor::set_allow_editing_actions(bool p_allow) {
- allow_editing_actions = p_allow;
- add_hbox->set_visible(p_allow);
-}
-
-void ActionMapEditor::set_toggle_editable_label(const String &p_label) {
- show_uneditable_actions_checkbox->set_text(p_label);
-}
-
void ActionMapEditor::use_external_search_box(LineEdit *p_searchbox) {
memdelete(action_list_search);
action_list_search = p_searchbox;
@@ -1096,8 +1075,7 @@ void ActionMapEditor::use_external_search_box(LineEdit *p_searchbox) {
}
ActionMapEditor::ActionMapEditor() {
- allow_editing_actions = true;
- show_uneditable = true;
+ show_builtin_actions = false;
// Main Vbox Container
VBoxContainer *main_vbox = memnew(VBoxContainer);
@@ -1114,11 +1092,11 @@ ActionMapEditor::ActionMapEditor() {
action_list_search->connect("text_changed", callable_mp(this, &ActionMapEditor::_search_term_updated));
top_hbox->add_child(action_list_search);
- show_uneditable_actions_checkbox = memnew(CheckBox);
- show_uneditable_actions_checkbox->set_pressed(false);
- show_uneditable_actions_checkbox->set_text(TTR("Show Uneditable Actions"));
- show_uneditable_actions_checkbox->connect("toggled", callable_mp(this, &ActionMapEditor::set_show_uneditable));
- top_hbox->add_child(show_uneditable_actions_checkbox);
+ show_builtin_actions_checkbutton = memnew(CheckButton);
+ show_builtin_actions_checkbutton->set_pressed(false);
+ show_builtin_actions_checkbutton->set_text(TTR("Show Built-in Actions"));
+ show_builtin_actions_checkbutton->connect("toggled", callable_mp(this, &ActionMapEditor::set_show_builtin_actions));
+ top_hbox->add_child(show_builtin_actions_checkbutton);
// Adding Action line edit + button
add_hbox = memnew(HBoxContainer);
@@ -1132,7 +1110,7 @@ ActionMapEditor::ActionMapEditor() {
add_hbox->add_child(add_edit);
Button *add_button = memnew(Button);
- add_button->set_text("Add");
+ add_button->set_text(TTR("Add"));
add_button->connect("pressed", callable_mp(this, &ActionMapEditor::_add_action_pressed));
add_hbox->add_child(add_button);
diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h
index f1f7bffef4..fb097ddfdd 100644
--- a/editor/action_map_editor.h
+++ b/editor/action_map_editor.h
@@ -156,11 +156,10 @@ private:
// Filtering and Adding actions
- bool show_uneditable;
- CheckBox *show_uneditable_actions_checkbox;
+ bool show_builtin_actions;
+ CheckButton *show_builtin_actions_checkbutton;
LineEdit *action_list_search;
- bool allow_editing_actions;
HBoxContainer *add_hbox;
LineEdit *add_edit;
@@ -190,10 +189,7 @@ public:
void update_action_list(const Vector<ActionInfo> &p_action_infos = Vector<ActionInfo>());
void show_message(const String &p_message);
- void set_show_uneditable(bool p_show);
- void set_allow_editing_actions(bool p_allow);
-
- void set_toggle_editable_label(const String &p_label);
+ void set_show_builtin_actions(bool p_show);
void use_external_search_box(LineEdit *p_searchbox);
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 602035634a..7c485d53c5 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -75,6 +75,8 @@ void EditorLog::_notification(int p_what) {
collapse_button->set_icon(get_theme_icon("CombineLines", "EditorIcons"));
show_search_button->set_icon(get_theme_icon("Search", "EditorIcons"));
+ _load_state();
+
} else if (p_what == NOTIFICATION_THEME_CHANGED) {
Ref<Font> df_output_code = get_theme_font("output_source", "EditorFonts");
if (df_output_code.is_valid()) {
@@ -89,9 +91,56 @@ void EditorLog::_notification(int p_what) {
void EditorLog::_set_collapse(bool p_collapse) {
collapse = p_collapse;
+ _start_state_save_timer();
_rebuild_log();
}
+void EditorLog::_start_state_save_timer() {
+ if (!is_loading_state) {
+ save_state_timer->start();
+ }
+}
+
+void EditorLog::_save_state() {
+ Ref<ConfigFile> config;
+ config.instance();
+ // Load and amend existing config if it exists.
+ config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+
+ const String section = "editor_log";
+ for (Map<MessageType, LogFilter *>::Element *E = type_filter_map.front(); E; E = E->next()) {
+ config->set_value(section, "log_filter_" + itos(E->key()), E->get()->is_active());
+ }
+
+ config->set_value(section, "collapse", collapse);
+ config->set_value(section, "show_search", search_box->is_visible());
+
+ config->save(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+}
+
+void EditorLog::_load_state() {
+ is_loading_state = true;
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+
+ if (err == OK) {
+ const String section = "editor_log";
+ for (Map<MessageType, LogFilter *>::Element *E = type_filter_map.front(); E; E = E->next()) {
+ E->get()->set_active(config->get_value(section, "log_filter_" + itos(E->key()), false));
+ }
+
+ collapse = config->get_value(section, "collapse", false);
+ collapse_button->set_pressed(collapse);
+ bool show_search = config->get_value(section, "show_search", true);
+ search_box->set_visible(show_search);
+ show_search_button->set_pressed(show_search);
+ }
+
+ is_loading_state = false;
+}
+
void EditorLog::_clear_request() {
log->clear();
messages.clear();
@@ -175,7 +224,7 @@ void EditorLog::_rebuild_log() {
void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
// Only add the message to the log if it passes the filters.
- bool filter_active = type_filter_map[p_message.type]->active;
+ bool filter_active = type_filter_map[p_message.type]->is_active();
String search_text = search_box->get_text();
bool search_match = search_text == String() || p_message.text.findn(search_text) > -1;
@@ -230,7 +279,8 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
}
void EditorLog::_set_filter_active(bool p_active, MessageType p_message_type) {
- type_filter_map[p_message_type]->active = p_active;
+ type_filter_map[p_message_type]->set_active(p_active);
+ _start_state_save_timer();
_rebuild_log();
}
@@ -239,6 +289,7 @@ void EditorLog::_set_search_visible(bool p_visible) {
if (p_visible) {
search_box->grab_focus();
}
+ _start_state_save_timer();
}
void EditorLog::_search_changed(const String &p_text) {
@@ -257,6 +308,12 @@ void EditorLog::_bind_methods() {
}
EditorLog::EditorLog() {
+ save_state_timer = memnew(Timer);
+ save_state_timer->set_wait_time(2);
+ save_state_timer->set_one_shot(true);
+ save_state_timer->connect("timeout", callable_mp(this, &EditorLog::_save_state));
+ add_child(save_state_timer);
+
HBoxContainer *hb = this;
VBoxContainer *vb_left = memnew(VBoxContainer);
diff --git a/editor/editor_log.h b/editor/editor_log.h
index 89d00d0fa0..3b6476634a 100644
--- a/editor/editor_log.h
+++ b/editor/editor_log.h
@@ -72,11 +72,11 @@ private:
private:
// Force usage of set method since it has functionality built-in.
int message_count = 0;
+ bool active = true;
public:
MessageType type;
Button *toggle_button = nullptr;
- bool active = true;
void initialize_button(const String &p_tooltip, Callable p_toggled_callback) {
toggle_button = memnew(Button);
@@ -100,6 +100,15 @@ private:
toggle_button->set_text(itos(message_count));
}
+ bool is_active() {
+ return active;
+ }
+
+ void set_active(bool p_active) {
+ toggle_button->set_pressed(p_active);
+ active = p_active;
+ }
+
LogFilter(MessageType p_type) :
type(p_type) {
}
@@ -124,6 +133,9 @@ private:
// Warnings or Errors are encounetered.
Button *tool_button;
+ bool is_loading_state = false; // Used to disable saving requests while loading (some signals from buttons will try trigger a save, which happens during loading).
+ Timer *save_state_timer;
+
static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, ErrorHandlerType p_type);
ErrorHandlerList eh;
@@ -147,6 +159,10 @@ private:
void _set_collapse(bool p_collapse);
+ void _start_state_save_timer();
+ void _save_state();
+ void _load_state();
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index ed670b1296..6390755656 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -4362,6 +4362,8 @@ void EditorNode::_save_docks() {
}
Ref<ConfigFile> config;
config.instance();
+ // Load and amend existing config if it exists.
+ config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
_save_docks_to_config(config, "docks");
_save_open_scenes_to_config(config, "EditorNode");
@@ -5877,8 +5879,6 @@ EditorNode::EditorNode() {
register_exporters();
- GLOBAL_DEF("editor/run/main_run_args", "");
-
ClassDB::set_class_enabled("RootMotionView", true);
//defs here, use EDITOR_GET in logic
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index e46f4eb65a..5e6d2ab69c 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -183,15 +183,50 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
args.push_back(p_scene);
}
+ String exec = OS::get_singleton()->get_executable_path();
+
if (p_custom_args != "") {
- Vector<String> cargs = p_custom_args.split(" ", false);
- for (int i = 0; i < cargs.size(); i++) {
- args.push_back(cargs[i].replace(" ", "%20"));
+ // Allow the user to specify a command to run, similar to Steam's launch options.
+ // In this case, Godot will no longer be run directly; it's up to the underlying command
+ // to run it. For instance, this can be used on Linux to force a running project
+ // to use Optimus using `prime-run` or similar.
+ // Example: `prime-run %command% --time-scale 0.5`
+ const int placeholder_pos = p_custom_args.find("%command%");
+
+ Vector<String> custom_args;
+
+ if (placeholder_pos != -1) {
+ // Prepend executable-specific custom arguments.
+ // If nothing is placed before `%command%`, behave as if no placeholder was specified.
+ Vector<String> exec_args = p_custom_args.substr(0, placeholder_pos).split(" ", false);
+ if (exec_args.size() >= 1) {
+ exec = exec_args[0];
+ exec_args.remove(0);
+
+ // Append the Godot executable name before we append executable arguments
+ // (since the order is reversed when using `push_front()`).
+ args.push_front(OS::get_singleton()->get_executable_path());
+ }
+
+ for (int i = exec_args.size() - 1; i >= 0; i--) {
+ // Iterate backwards as we're pushing items in the reverse order.
+ args.push_front(exec_args[i].replace(" ", "%20"));
+ }
+
+ // Append Godot-specific custom arguments.
+ custom_args = p_custom_args.substr(placeholder_pos + String("%command%").size()).split(" ", false);
+ for (int i = 0; i < custom_args.size(); i++) {
+ args.push_back(custom_args[i].replace(" ", "%20"));
+ }
+ } else {
+ // Append Godot-specific custom arguments.
+ custom_args = p_custom_args.split(" ", false);
+ for (int i = 0; i < custom_args.size(); i++) {
+ args.push_back(custom_args[i].replace(" ", "%20"));
+ }
}
}
- String exec = OS::get_singleton()->get_executable_path();
-
printf("Running: %s", exec.utf8().get_data());
for (List<String>::Element *E = args.front(); E; E = E->next()) {
printf(" %s", E->get().utf8().get_data());
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 7e450ed5fc..1bb40c50b8 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -787,6 +787,7 @@ void EditorSettings::_load_default_text_editor_theme() {
_initial_set("text_editor/highlighting/symbol_color", Color(0.73, 0.87, 1.0));
_initial_set("text_editor/highlighting/keyword_color", Color(1.0, 1.0, 0.7));
+ _initial_set("text_editor/highlighting/control_flow_keyword_color", Color(1.0, 0.85, 0.7));
_initial_set("text_editor/highlighting/base_type_color", Color(0.64, 1.0, 0.83));
_initial_set("text_editor/highlighting/engine_type_color", Color(0.51, 0.83, 1.0));
_initial_set("text_editor/highlighting/user_type_color", Color(0.42, 0.67, 0.93));
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 44b4a9f688..d5ad638436 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -1322,6 +1322,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color symbol_color = Color(0.34, 0.57, 1.0).lerp(mono_color, dark_theme ? 0.5 : 0.3);
const Color keyword_color = Color(1.0, 0.44, 0.52);
+ const Color control_flow_keyword_color = dark_theme ? Color(1.0, 0.55, 0.8) : Color(0.8, 0.4, 0.6);
const Color basetype_color = dark_theme ? Color(0.26, 1.0, 0.76) : Color(0.0, 0.76, 0.38);
const Color type_color = basetype_color.lerp(mono_color, dark_theme ? 0.4 : 0.3);
const Color usertype_color = basetype_color.lerp(mono_color, dark_theme ? 0.7 : 0.5);
@@ -1360,6 +1361,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
if (text_editor_color_theme == "Adaptive") {
setting->set_initial_value("text_editor/highlighting/symbol_color", symbol_color, true);
setting->set_initial_value("text_editor/highlighting/keyword_color", keyword_color, true);
+ setting->set_initial_value("text_editor/highlighting/control_flow_keyword_color", control_flow_keyword_color, true);
setting->set_initial_value("text_editor/highlighting/base_type_color", basetype_color, true);
setting->set_initial_value("text_editor/highlighting/engine_type_color", type_color, true);
setting->set_initial_value("text_editor/highlighting/user_type_color", usertype_color, true);
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index a319a595c7..18cc5d43fb 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -487,10 +487,15 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
List<String> kwors;
scr->get_language()->get_reserved_words(&kwors);
+ Set<String> control_flow_keywords;
Set<String> keywords;
for (List<String>::Element *E = kwors.front(); E; E = E->next()) {
- keywords.insert(E->get());
+ if (scr->get_language()->is_control_flow_keyword(E->get())) {
+ control_flow_keywords.insert(E->get());
+ } else {
+ keywords.insert(E->get());
+ }
}
int line = 0;
@@ -502,6 +507,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
Color bg_color = EditorSettings::get_singleton()->get("text_editor/highlighting/background_color");
Color keyword_color = EditorSettings::get_singleton()->get("text_editor/highlighting/keyword_color");
+ Color control_flow_keyword_color = EditorSettings::get_singleton()->get("text_editor/highlighting/control_flow_keyword_color");
Color text_color = EditorSettings::get_singleton()->get("text_editor/highlighting/text_color");
Color symbol_color = EditorSettings::get_singleton()->get("text_editor/highlighting/symbol_color");
Color comment_color = EditorSettings::get_singleton()->get("text_editor/highlighting/comment_color");
@@ -523,6 +529,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
col = x0;
bool prev_is_text = false;
+ bool in_control_flow_keyword = false;
bool in_keyword = false;
bool in_comment = false;
for (int i = 0; i < code.length(); i++) {
@@ -541,6 +548,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
if (c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t')) {
//make symbol a little visible
color = symbol_color;
+ in_control_flow_keyword = false;
in_keyword = false;
} else if (!prev_is_text && _is_text_char(c)) {
int pos = i;
@@ -549,7 +557,9 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
pos++;
}
String word = code.substr(i, pos - i);
- if (keywords.has(word)) {
+ if (control_flow_keywords.has(word)) {
+ in_control_flow_keyword = true;
+ } else if (keywords.has(word)) {
in_keyword = true;
}
@@ -557,11 +567,12 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
in_keyword = false;
}
- if (in_keyword) {
+ if (in_control_flow_keyword) {
+ color = control_flow_keyword_color;
+ } else if (in_keyword) {
color = keyword_color;
}
}
-
Color ul = color;
ul.a *= 0.5;
img->set_pixel(col, y0 + line * 2, bg_color.blend(ul));
@@ -572,6 +583,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
col++;
} else {
prev_is_text = false;
+ in_control_flow_keyword = false;
in_keyword = false;
if (c == '\n') {
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index bc33d03d8b..adfeead33b 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -140,10 +140,15 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
/* Reserved words. */
const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ const Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color");
List<String> keywords;
script->get_language()->get_reserved_words(&keywords);
for (List<String>::Element *E = keywords.front(); E; E = E->next()) {
- highlighter->add_keyword_color(E->get(), keyword_color);
+ if (script->get_language()->is_control_flow_keyword(E->get())) {
+ highlighter->add_keyword_color(E->get(), control_flow_keyword_color);
+ } else {
+ highlighter->add_keyword_color(E->get(), keyword_color);
+ }
}
/* Member types. */
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index ed3b746678..3cdba9cf16 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -141,9 +141,14 @@ void ShaderTextEditor::_load_theme_settings() {
List<String> keywords;
ShaderLanguage::get_keyword_list(&keywords);
const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ const Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color");
for (List<String>::Element *E = keywords.front(); E; E = E->next()) {
- syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ if (ShaderLanguage::is_control_flow_keyword(E->get())) {
+ syntax_highlighter->add_keyword_color(E->get(), control_flow_keyword_color);
+ } else {
+ syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ }
}
// Colorize built-ins like `COLOR` differently to make them easier
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 7d5e72ff8e..1d4c23fee6 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -736,6 +736,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
Color background_color = EDITOR_GET("text_editor/highlighting/background_color");
Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color");
Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color");
Color function_color = EDITOR_GET("text_editor/highlighting/function_color");
@@ -746,7 +747,11 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
expression_box->add_theme_color_override("background_color", background_color);
for (List<String>::Element *E = VisualShaderEditor::get_singleton()->keyword_list.front(); E; E = E->next()) {
- expression_syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ if (ShaderLanguage::is_control_flow_keyword(E->get())) {
+ expression_syntax_highlighter->add_keyword_color(E->get(), control_flow_keyword_color);
+ } else {
+ expression_syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ }
}
expression_box->add_theme_font_override("font", VisualShaderEditor::get_singleton()->get_theme_font("expression", "EditorFonts"));
@@ -2792,6 +2797,7 @@ void VisualShaderEditor::_notification(int p_what) {
Color background_color = EDITOR_GET("text_editor/highlighting/background_color");
Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color");
Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color");
Color function_color = EDITOR_GET("text_editor/highlighting/function_color");
@@ -2801,7 +2807,11 @@ void VisualShaderEditor::_notification(int p_what) {
preview_text->add_theme_color_override("background_color", background_color);
for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) {
- syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ if (ShaderLanguage::is_control_flow_keyword(E->get())) {
+ syntax_highlighter->add_keyword_color(E->get(), control_flow_keyword_color);
+ } else {
+ syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ }
}
preview_text->add_theme_font_override("font", get_theme_font("expression", "EditorFonts"));
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index faec3355ac..76290b4b62 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -649,8 +649,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
action_map->connect("action_removed", callable_mp(this, &ProjectSettingsEditor::_action_removed));
action_map->connect("action_renamed", callable_mp(this, &ProjectSettingsEditor::_action_renamed));
action_map->connect("action_reordered", callable_mp(this, &ProjectSettingsEditor::_action_reordered));
- action_map->set_toggle_editable_label(TTR("Show Built-in Actions"));
- action_map->set_show_uneditable(false);
tab_container->add_child(action_map);
localization_editor = memnew(LocalizationEditor);
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 3283f28de5..46af70f73c 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -1289,6 +1289,10 @@ void NativeScriptLanguage::finish() {
void NativeScriptLanguage::get_reserved_words(List<String> *p_words) const {
}
+bool NativeScriptLanguage::is_control_flow_keyword(String p_keyword) const {
+ return false;
+}
+
void NativeScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
}
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index 4bd54f9c46..ca5e76e43e 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -336,6 +336,7 @@ public:
virtual Error execute_file(const String &p_path);
virtual void finish();
virtual void get_reserved_words(List<String> *p_words) const;
+ virtual bool is_control_flow_keyword(String p_keyword) const;
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp
index 3ed1dcaca9..1360cf0299 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_language.cpp
@@ -77,6 +77,10 @@ void PluginScriptLanguage::get_reserved_words(List<String> *p_words) const {
}
}
+bool PluginScriptLanguage::is_control_flow_keyword(String p_keyword) const {
+ return false;
+}
+
void PluginScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
if (_desc.comment_delimiters) {
const char **w = _desc.comment_delimiters;
diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h
index 226b039265..957bf355ca 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.h
+++ b/modules/gdnative/pluginscript/pluginscript_language.h
@@ -71,6 +71,7 @@ public:
/* EDITOR FUNCTIONS */
virtual void get_reserved_words(List<String> *p_words) const;
+ virtual bool is_control_flow_keyword(String p_keyword) const;
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index ccc942d86b..ca646dff15 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -485,10 +485,15 @@ void GDScriptSyntaxHighlighter::_update_cache() {
/* Reserved words. */
const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ const Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color");
List<String> keyword_list;
gdscript->get_reserved_words(&keyword_list);
for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) {
- keywords[E->get()] = keyword_color;
+ if (gdscript->is_control_flow_keyword(E->get())) {
+ keywords[E->get()] = control_flow_keyword_color;
+ } else {
+ keywords[E->get()] = keyword_color;
+ }
}
/* Comments */
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 5f590383d0..859c1acde9 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2135,6 +2135,19 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
}
}
+bool GDScriptLanguage::is_control_flow_keyword(String p_keyword) const {
+ return p_keyword == "break" ||
+ p_keyword == "continue" ||
+ p_keyword == "elif" ||
+ p_keyword == "else" ||
+ p_keyword == "if" ||
+ p_keyword == "for" ||
+ p_keyword == "match" ||
+ p_keyword == "pass" ||
+ p_keyword == "return" ||
+ p_keyword == "while";
+}
+
bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
return p_type == "GDScript";
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 98da5ad4cb..6df66e876d 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -461,6 +461,7 @@ public:
/* EDITOR FUNCTIONS */
virtual void get_reserved_words(List<String> *p_words) const;
+ virtual bool is_control_flow_keyword(String p_keywords) const;
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual String _get_processed_template(const String &p_template, const String &p_base_class_name) const;
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 09f3ea1f50..ffb04bfd37 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -304,6 +304,26 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const {
}
}
+bool CSharpLanguage::is_control_flow_keyword(String p_keyword) const {
+ return p_keyword == "break" ||
+ p_keyword == "case" ||
+ p_keyword == "catch" ||
+ p_keyword == "continue" ||
+ p_keyword == "default" ||
+ p_keyword == "do" ||
+ p_keyword == "else" ||
+ p_keyword == "finally" ||
+ p_keyword == "for" ||
+ p_keyword == "foreach" ||
+ p_keyword == "goto" ||
+ p_keyword == "if" ||
+ p_keyword == "return" ||
+ p_keyword == "switch" ||
+ p_keyword == "throw" ||
+ p_keyword == "try" ||
+ p_keyword == "while";
+}
+
void CSharpLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("//"); // single-line comment
p_delimiters->push_back("/* */"); // delimited comment
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index dd93a86d7a..992c7e93c8 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -470,6 +470,7 @@ public:
/* EDITOR FUNCTIONS */
void get_reserved_words(List<String> *p_words) const override;
+ bool is_control_flow_keyword(String p_keyword) const;
void get_comment_delimiters(List<String> *p_delimiters) const override;
void get_string_delimiters(List<String> *p_delimiters) const override;
Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const override;
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 765a5fe023..b863f622bd 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -2336,6 +2336,10 @@ void VisualScriptLanguage::finish() {
void VisualScriptLanguage::get_reserved_words(List<String> *p_words) const {
}
+bool VisualScriptLanguage::is_control_flow_keyword(String p_keyword) const {
+ return false;
+}
+
void VisualScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
}
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index 72362e0ef4..cc78b3242d 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -586,6 +586,7 @@ public:
/* EDITOR FUNCTIONS */
virtual void get_reserved_words(List<String> *p_words) const;
+ virtual bool is_control_flow_keyword(String p_keyword) const;
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 826fd0189b..ac067aa001 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -155,6 +155,9 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
}
status.pressed = !status.pressed;
_unpress_group();
+ if (button_group.is_valid()) {
+ button_group->emit_signal("pressed", this);
+ }
_toggled(status.pressed);
_pressed();
}
@@ -218,6 +221,9 @@ void BaseButton::set_pressed(bool p_pressed) {
if (p_pressed) {
_unpress_group();
+ if (button_group.is_valid()) {
+ button_group->emit_signal("pressed", this);
+ }
}
_toggled(status.pressed);
@@ -487,6 +493,7 @@ BaseButton *ButtonGroup::get_pressed_button() {
void ButtonGroup::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_pressed_button"), &ButtonGroup::get_pressed_button);
ClassDB::bind_method(D_METHOD("get_buttons"), &ButtonGroup::_get_buttons);
+ ADD_SIGNAL(MethodInfo("pressed", PropertyInfo(Variant::OBJECT, "button")));
}
ButtonGroup::ButtonGroup() {
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index b78f9cad24..114abbd4da 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -189,6 +189,18 @@ void ColorPicker::set_pick_color(const Color &p_color) {
_set_pick_color(p_color, true); //because setters can't have more arguments
}
+void ColorPicker::set_old_color(const Color &p_color) {
+ old_color = p_color;
+}
+
+void ColorPicker::set_display_old_color(bool p_enabled) {
+ display_old_color = p_enabled;
+}
+
+bool ColorPicker::is_displaying_old_color() const {
+ return display_old_color;
+}
+
void ColorPicker::set_edit_alpha(bool p_show) {
edit_alpha = p_show;
_update_controls();
@@ -459,17 +471,39 @@ void ColorPicker::_update_text_value() {
}
void ColorPicker::_sample_draw() {
- const Rect2 r = Rect2(Point2(), Size2(sample->get_size().width, sample->get_size().height * 0.95));
+ // Covers the right half of the sample if the old color is being displayed,
+ // or the whole sample if it's not being displayed.
+ Rect2 rect_new;
+
+ if (display_old_color) {
+ rect_new = Rect2(Point2(sample->get_size().width * 0.5, 0), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95));
+
+ // Draw both old and new colors for easier comparison (only if spawned from a ColorPickerButton).
+ const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95));
+
+ if (display_old_color && old_color.a < 1.0) {
+ sample->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), rect_old, true);
+ }
+
+ sample->draw_rect(rect_old, old_color);
+
+ if (old_color.r > 1 || old_color.g > 1 || old_color.b > 1) {
+ // Draw an indicator to denote that the old color is "overbright" and can't be displayed accurately in the preview.
+ sample->draw_texture(get_theme_icon("overbright_indicator", "ColorPicker"), Point2());
+ }
+ } else {
+ rect_new = Rect2(Point2(), Size2(sample->get_size().width, sample->get_size().height * 0.95));
+ }
if (color.a < 1.0) {
- sample->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), r, true);
+ sample->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), rect_new, true);
}
- sample->draw_rect(r, color);
+ sample->draw_rect(rect_new, color);
if (color.r > 1 || color.g > 1 || color.b > 1) {
- // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview
- sample->draw_texture(get_theme_icon("overbright_indicator", "ColorPicker"), Point2());
+ // Draw an indicator to denote that the new color is "overbright" and can't be displayed accurately in the preview.
+ sample->draw_texture(get_theme_icon("overbright_indicator", "ColorPicker"), Point2(uv_edit->get_size().width * 0.5, 0));
}
}
@@ -1174,6 +1208,11 @@ ColorPicker::ColorPicker() :
/////////////////
+void ColorPickerButton::_about_to_popup() {
+ set_pressed(true);
+ picker->set_old_color(color);
+}
+
void ColorPickerButton::_color_changed(const Color &p_color) {
color = p_color;
update();
@@ -1286,10 +1325,11 @@ void ColorPickerButton::_update_picker() {
popup->add_child(picker);
add_child(popup);
picker->connect("color_changed", callable_mp(this, &ColorPickerButton::_color_changed));
- popup->connect("about_to_popup", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true));
+ popup->connect("about_to_popup", callable_mp(this, &ColorPickerButton::_about_to_popup));
popup->connect("popup_hide", callable_mp(this, &ColorPickerButton::_modal_closed));
picker->set_pick_color(color);
picker->set_edit_alpha(edit_alpha);
+ picker->set_display_old_color(true);
emit_signal("picker_created");
}
}
@@ -1301,6 +1341,7 @@ void ColorPickerButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_popup"), &ColorPickerButton::get_popup);
ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPickerButton::set_edit_alpha);
ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPickerButton::is_editing_alpha);
+ ClassDB::bind_method(D_METHOD("_about_to_popup"), &ColorPickerButton::_about_to_popup);
ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
ADD_SIGNAL(MethodInfo("popup_closed"));
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index a0d2aa95ca..13fe5fd60e 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -86,6 +86,8 @@ private:
PickerShapeType picker_type = SHAPE_HSV_WHEEL;
Color color;
+ Color old_color;
+ bool display_old_color = false;
bool raw_mode_enabled = false;
bool hsv_mode_enabled = false;
bool deferred_mode_enabled = false;
@@ -131,6 +133,10 @@ public:
void _set_pick_color(const Color &p_color, bool p_update_sliders);
void set_pick_color(const Color &p_color);
Color get_pick_color() const;
+ void set_old_color(const Color &p_color);
+
+ void set_display_old_color(bool p_enabled);
+ bool is_displaying_old_color() const;
void set_picker_shape(PickerShapeType p_picker_type);
PickerShapeType get_picker_shape() const;
@@ -171,6 +177,7 @@ class ColorPickerButton : public Button {
Color color;
bool edit_alpha = true;
+ void _about_to_popup();
void _color_changed(const Color &p_color);
void _modal_closed();
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index c30bd7927d..ff682a40f4 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -663,6 +663,8 @@ void SurfaceTool::deindex() {
}
void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat) {
+ ERR_FAIL_NULL_MSG(p_existing, "First argument in SurfaceTool::_create_list() must be a valid object of type Mesh");
+
Array arr = p_existing->surface_get_arrays(p_surface);
ERR_FAIL_COND(arr.size() != RS::ARRAY_MAX);
_create_list_from_arrays(arr, r_vertex, r_index, lformat);
@@ -824,6 +826,8 @@ void SurfaceTool::create_from_triangle_arrays(const Array &p_arrays) {
}
void SurfaceTool::create_from(const Ref<Mesh> &p_existing, int p_surface) {
+ ERR_FAIL_NULL_MSG(p_existing, "First argument in SurfaceTool::create_from() must be a valid object of type Mesh");
+
clear();
primitive = p_existing->surface_get_primitive_type(p_surface);
_create_list(p_existing, p_surface, &vertex_array, &index_array, format);
@@ -831,6 +835,8 @@ void SurfaceTool::create_from(const Ref<Mesh> &p_existing, int p_surface) {
}
void SurfaceTool::create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String &p_blend_shape_name) {
+ ERR_FAIL_NULL_MSG(p_existing, "First argument in SurfaceTool::create_from_blend_shape() must be a valid object of type Mesh");
+
clear();
primitive = p_existing->surface_get_primitive_type(p_surface);
Array arr = p_existing->surface_get_blend_shape_arrays(p_surface);
@@ -851,6 +857,8 @@ void SurfaceTool::create_from_blend_shape(const Ref<Mesh> &p_existing, int p_sur
}
void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform) {
+ ERR_FAIL_NULL_MSG(p_existing, "First argument in SurfaceTool::append_from() must be a valid object of type Mesh");
+
if (vertex_array.size() == 0) {
primitive = p_existing->surface_get_primitive_type(p_surface);
format = 0;
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 0d6d3f5e13..a81306b97d 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -2969,6 +2969,20 @@ void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
}
}
+bool ShaderLanguage::is_control_flow_keyword(String p_keyword) {
+ return p_keyword == "break" ||
+ p_keyword == "case" ||
+ p_keyword == "continue" ||
+ p_keyword == "default" ||
+ p_keyword == "do" ||
+ p_keyword == "else" ||
+ p_keyword == "for" ||
+ p_keyword == "if" ||
+ p_keyword == "return" ||
+ p_keyword == "switch" ||
+ p_keyword == "while";
+}
+
void ShaderLanguage::get_builtin_funcs(List<String> *r_keywords) {
Set<String> kws;
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 470f3d38d5..e00f4dce19 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -748,6 +748,7 @@ public:
static uint32_t get_type_size(DataType p_type);
static void get_keyword_list(List<String> *r_keywords);
+ static bool is_control_flow_keyword(String p_keyword);
static void get_builtin_funcs(List<String> *r_keywords);
struct BuiltInInfo {