diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 86ddcb6b108..9df3a31a967 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -666,7 +666,7 @@
The extra spacing to add to various GUI elements in the editor (in pixels). Increasing this value is useful to improve usability on touch screens, at the cost of reducing the amount of usable screen real estate.
- See also [member interface/theme/spacing_preset].
+ See also [member interface/theme/spacing_preset].
The base color to use for user interface elements in the editor. Secondary colors (such as darker/lighter variants) are derived from this color.
@@ -724,6 +724,9 @@
Specify the multiplier to apply to the scale for the editor gizmo handles to improve usability on touchscreen devices.
[b]Note:[/b] Defaults to [code]1[/code] on non-touchscreen devices.
+
+ Determines whether online features are enabled in the editor, such as the Asset Library. Setting this property to "Offline" is recommended to limit editor's internet activity, especially if privacy is a concern.
+
The address to listen to when starting the remote debugger. This can be set to [code]0.0.0.0[/code] to allow external clients to connect to the remote debugger (instead of restricting the remote debugger to connections from [code]localhost[/code]).
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index e676d24c67e..3691172c180 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -498,45 +498,43 @@ void EditorNode::_update_theme(bool p_skip_creation) {
update_preview_themes(CanvasItemEditor::THEME_PREVIEW_EDITOR);
}
- gui_base->add_theme_style_override("panel", theme->get_stylebox(SNAME("Background"), EditorStringName(EditorStyles)));
- main_vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, theme->get_constant(SNAME("window_border_margin"), EditorStringName(Editor)));
- main_vbox->add_theme_constant_override("separation", theme->get_constant(SNAME("top_bar_separation"), EditorStringName(Editor)));
+ // Update styles.
+ {
+ gui_base->add_theme_style_override("panel", theme->get_stylebox(SNAME("Background"), EditorStringName(EditorStyles)));
+ main_vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, theme->get_constant(SNAME("window_border_margin"), EditorStringName(Editor)));
+ main_vbox->add_theme_constant_override("separation", theme->get_constant(SNAME("top_bar_separation"), EditorStringName(Editor)));
- scene_root_parent->add_theme_style_override("panel", theme->get_stylebox(SNAME("Content"), EditorStringName(EditorStyles)));
- bottom_panel->add_theme_style_override("panel", theme->get_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles)));
- main_menu->add_theme_style_override("hover", theme->get_stylebox(SNAME("MenuHover"), EditorStringName(EditorStyles)));
- distraction_free->set_icon(theme->get_icon(SNAME("DistractionFree"), EditorStringName(EditorIcons)));
- bottom_panel_raise->set_icon(theme->get_icon(SNAME("ExpandBottomDock"), EditorStringName(EditorIcons)));
+ scene_root_parent->add_theme_style_override("panel", theme->get_stylebox(SNAME("Content"), EditorStringName(EditorStyles)));
+ bottom_panel->add_theme_style_override("panel", theme->get_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles)));
+ main_menu->add_theme_style_override("hover", theme->get_stylebox(SNAME("MenuHover"), EditorStringName(EditorStyles)));
+ distraction_free->set_icon(theme->get_icon(SNAME("DistractionFree"), EditorStringName(EditorIcons)));
+ bottom_panel_raise->set_icon(theme->get_icon(SNAME("ExpandBottomDock"), EditorStringName(EditorIcons)));
- help_menu->set_item_icon(help_menu->get_item_index(HELP_SEARCH), theme->get_icon(SNAME("HelpSearch"), EditorStringName(EditorIcons)));
- help_menu->set_item_icon(help_menu->get_item_index(HELP_DOCS), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
- help_menu->set_item_icon(help_menu->get_item_index(HELP_QA), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
- help_menu->set_item_icon(help_menu->get_item_index(HELP_REPORT_A_BUG), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
- help_menu->set_item_icon(help_menu->get_item_index(HELP_COPY_SYSTEM_INFO), theme->get_icon(SNAME("ActionCopy"), EditorStringName(EditorIcons)));
- help_menu->set_item_icon(help_menu->get_item_index(HELP_SUGGEST_A_FEATURE), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
- help_menu->set_item_icon(help_menu->get_item_index(HELP_SEND_DOCS_FEEDBACK), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
- help_menu->set_item_icon(help_menu->get_item_index(HELP_COMMUNITY), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
- help_menu->set_item_icon(help_menu->get_item_index(HELP_ABOUT), theme->get_icon(SNAME("Godot"), EditorStringName(EditorIcons)));
- help_menu->set_item_icon(help_menu->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), theme->get_icon(SNAME("Heart"), EditorStringName(EditorIcons)));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SEARCH), theme->get_icon(SNAME("HelpSearch"), EditorStringName(EditorIcons)));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_DOCS), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_QA), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_REPORT_A_BUG), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_COPY_SYSTEM_INFO), theme->get_icon(SNAME("ActionCopy"), EditorStringName(EditorIcons)));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SUGGEST_A_FEATURE), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SEND_DOCS_FEEDBACK), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_COMMUNITY), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons)));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_ABOUT), theme->get_icon(SNAME("Godot"), EditorStringName(EditorIcons)));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), theme->get_icon(SNAME("Heart"), EditorStringName(EditorIcons)));
- for (int i = 0; i < main_editor_buttons.size(); i++) {
- main_editor_buttons.write[i]->add_theme_font_override("font", theme->get_font(SNAME("main_button_font"), EditorStringName(EditorFonts)));
- main_editor_buttons.write[i]->add_theme_font_size_override("font_size", theme->get_font_size(SNAME("main_button_font_size"), EditorStringName(EditorFonts)));
- }
+ if (EditorDebuggerNode::get_singleton()->is_visible()) {
+ bottom_panel->add_theme_style_override("panel", theme->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles)));
+ }
- if (EditorDebuggerNode::get_singleton()->is_visible()) {
- bottom_panel->add_theme_style_override("panel", theme->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles)));
- }
+ for (int i = 0; i < main_editor_buttons.size(); i++) {
+ Button *tb = main_editor_buttons[i];
+ EditorPlugin *p_editor = editor_table[i];
+ Ref icon = p_editor->get_icon();
- for (int i = 0; i < main_editor_buttons.size(); i++) {
- Button *tb = main_editor_buttons[i];
- EditorPlugin *p_editor = editor_table[i];
- Ref icon = p_editor->get_icon();
-
- if (icon.is_valid()) {
- tb->set_icon(icon);
- } else if (theme->has_icon(p_editor->get_name(), EditorStringName(EditorIcons))) {
- tb->set_icon(theme->get_icon(p_editor->get_name(), EditorStringName(EditorIcons)));
+ if (icon.is_valid()) {
+ tb->set_icon(icon);
+ } else if (theme->has_icon(p_editor->get_name(), EditorStringName(EditorIcons))) {
+ tb->set_icon(theme->get_icon(p_editor->get_name(), EditorStringName(EditorIcons)));
+ }
}
}
}
@@ -3279,21 +3277,21 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
Button *tb = memnew(Button);
tb->set_flat(true);
tb->set_toggle_mode(true);
- tb->connect("pressed", callable_mp(singleton, &EditorNode::editor_select).bind(singleton->main_editor_buttons.size()));
+ tb->set_theme_type_variation("MainScreenButton");
tb->set_name(p_editor->get_name());
tb->set_text(p_editor->get_name());
Ref icon = p_editor->get_icon();
+ if (icon.is_null() && singleton->theme->has_icon(p_editor->get_name(), EditorStringName(EditorIcons))) {
+ icon = singleton->theme->get_icon(p_editor->get_name(), EditorStringName(EditorIcons));
+ }
if (icon.is_valid()) {
tb->set_icon(icon);
// Make sure the control is updated if the icon is reimported.
icon->connect_changed(callable_mp((Control *)tb, &Control::update_minimum_size));
- } else if (singleton->theme->has_icon(p_editor->get_name(), EditorStringName(EditorIcons))) {
- tb->set_icon(singleton->theme->get_icon(p_editor->get_name(), EditorStringName(EditorIcons)));
}
- tb->add_theme_font_override("font", singleton->theme->get_font(SNAME("main_button_font"), EditorStringName(EditorFonts)));
- tb->add_theme_font_size_override("font_size", singleton->theme->get_font_size(SNAME("main_button_font_size"), EditorStringName(EditorFonts)));
+ tb->connect("pressed", callable_mp(singleton, &EditorNode::editor_select).bind(singleton->main_editor_buttons.size()));
singleton->main_editor_buttons.push_back(tb);
singleton->main_editor_button_hb->add_child(tb);
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 5a197134778..060f2054165 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -770,15 +770,22 @@ void EditorSettings::_load_defaults(Ref p_extra_config) {
/* Network */
- // Debug
- _initial_set("network/debug/remote_host", "127.0.0.1"); // Hints provided in setup_network
+ // General
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "network/connection/network_mode", 0, "Offline,Online");
- EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/debug/remote_port", 6007, "1,65535,1")
+ // HTTP Proxy
+ _initial_set("network/http_proxy/host", "");
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/http_proxy/port", 8080, "1,65535,1")
// SSL
EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "network/tls/editor_tls_certificates", _SYSTEM_CERTS_PATH, "*.crt,*.pem", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
- // Debugger/profiler
+ // Debug
+ _initial_set("network/debug/remote_host", "127.0.0.1"); // Hints provided in setup_network
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/debug/remote_port", 6007, "1,65535,1")
+
+ /* Debugger/profiler */
+
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/auto_switch_to_remote_scene_tree", false, "")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_history_size", 3600, "60,10000,1")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_max_functions", 64, "16,512,1")
@@ -786,10 +793,6 @@ void EditorSettings::_load_defaults(Ref p_extra_config) {
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "debugger/remote_inspect_refresh_interval", 0.2, "0.02,10,0.01,or_greater")
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/profile_native_calls", false, "")
- // HTTP Proxy
- _initial_set("network/http_proxy/host", "");
- EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/http_proxy/port", 8080, "1,65535,1")
-
/* Extra config */
// TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects.
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index 2e280ac9d6e..87ce0cfd579 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -57,6 +57,11 @@ public:
Vector install_files;
};
+ enum NetworkMode {
+ NETWORK_OFFLINE,
+ NETWORK_ONLINE,
+ };
+
private:
struct VariantContainer {
int order = 0;
diff --git a/editor/icons/ProjectList.svg b/editor/icons/ProjectList.svg
new file mode 100644
index 00000000000..ee72c39c7de
--- /dev/null
+++ b/editor/icons/ProjectList.svg
@@ -0,0 +1 @@
+
diff --git a/editor/icons/TitleBarLogo.svg b/editor/icons/TitleBarLogo.svg
new file mode 100644
index 00000000000..65bb367c617
--- /dev/null
+++ b/editor/icons/TitleBarLogo.svg
@@ -0,0 +1 @@
+
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 20129556860..4477884b7af 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -643,6 +643,15 @@ void EditorAssetLibrary::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
_update_repository_options();
setup_http_request(request);
+
+ const bool loading_blocked_new = ((int)EDITOR_GET("network/connection/network_mode") == EditorSettings::NETWORK_OFFLINE);
+ if (loading_blocked_new != loading_blocked) {
+ loading_blocked = loading_blocked_new;
+
+ if (!loading_blocked && is_visible()) {
+ _request_current_config(); // Reload config now that the network is available.
+ }
+ }
} break;
}
}
@@ -929,9 +938,7 @@ void EditorAssetLibrary::_request_image(ObjectID p_for, String p_image_url, Imag
}
void EditorAssetLibrary::_repository_changed(int p_repository_id) {
- library_error->hide();
- library_info->set_text(TTR("Loading..."));
- library_info->show();
+ _set_library_message(TTR("Loading..."));
asset_top_page->hide();
asset_bottom_page->hide();
@@ -1036,6 +1043,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
Button *first = memnew(Button);
first->set_text(TTR("First", "Pagination"));
+ first->set_theme_type_variation("PanelBackgroundButton");
if (p_page != 0) {
first->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search).bind(0));
} else {
@@ -1046,6 +1054,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
Button *prev = memnew(Button);
prev->set_text(TTR("Previous", "Pagination"));
+ prev->set_theme_type_variation("PanelBackgroundButton");
if (p_page > 0) {
prev->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search).bind(p_page - 1));
} else {
@@ -1056,26 +1065,22 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
hbc->add_child(memnew(VSeparator));
for (int i = from; i < to; i++) {
+ Button *current = memnew(Button);
+ // Add padding to make page number buttons easier to click.
+ current->set_text(vformat(" %d ", i + 1));
+ current->set_theme_type_variation("PanelBackgroundButton");
if (i == p_page) {
- Button *current = memnew(Button);
- // Keep the extended padding for the currently active page (see below).
- current->set_text(vformat(" %d ", i + 1));
current->set_disabled(true);
current->set_focus_mode(Control::FOCUS_NONE);
-
- hbc->add_child(current);
} else {
- Button *current = memnew(Button);
- // Add padding to make page number buttons easier to click.
- current->set_text(vformat(" %d ", i + 1));
current->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search).bind(i));
-
- hbc->add_child(current);
}
+ hbc->add_child(current);
}
Button *next = memnew(Button);
next->set_text(TTR("Next", "Pagination"));
+ next->set_theme_type_variation("PanelBackgroundButton");
if (p_page < p_page_count - 1) {
next->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search).bind(p_page + 1));
} else {
@@ -1087,6 +1092,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
Button *last = memnew(Button);
last->set_text(TTR("Last", "Pagination"));
+ last->set_theme_type_variation("PanelBackgroundButton");
if (p_page != p_page_count - 1) {
last->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search).bind(p_page_count - 1));
} else {
@@ -1104,10 +1110,14 @@ void EditorAssetLibrary::_api_request(const String &p_request, RequestType p_req
if (requesting != REQUESTING_NONE) {
request->cancel_request();
}
+ error_hb->hide();
+
+ if (loading_blocked) {
+ _set_library_message_with_action(TTR("The Asset Library requires an online connection and involves sending data over the internet."), TTR("Go Online"), callable_mp(this, &EditorAssetLibrary::_force_online_mode));
+ return;
+ }
requesting = p_request_type;
-
- error_hb->hide();
request->request(host + "/" + p_request + p_arguments);
}
@@ -1156,8 +1166,7 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
if (error_abort) {
if (requesting == REQUESTING_CONFIG) {
- library_info->hide();
- library_error->show();
+ _set_library_message_with_action(TTR("Failed to get repository configuration."), TTR("Retry"), callable_mp(this, &EditorAssetLibrary::_request_current_config));
}
error_hb->show();
return;
@@ -1265,18 +1274,17 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
}
if (!filter->get_text().is_empty()) {
- library_info->set_text(
+ _set_library_message(
vformat(TTR("No results for \"%s\" for support level(s): %s."), filter->get_text(), support_list));
} else {
// No results, even though the user didn't search for anything specific.
// This is typically because the version number changed recently
// and no assets compatible with the new version have been published yet.
- library_info->set_text(
+ _set_library_message(
vformat(TTR("No results compatible with %s %s for support level(s): %s.\nCheck the enabled support levels using the 'Support' button in the top-right corner."), String(VERSION_SHORT_NAME).capitalize(), String(VERSION_BRANCH), support_list));
}
- library_info->show();
} else {
- library_info->hide();
+ library_message_box->hide();
}
for (int i = 0; i < result.size(); i++) {
@@ -1432,6 +1440,39 @@ void EditorAssetLibrary::_update_asset_items_columns() {
asset_items_column_width = (get_size().x / new_columns) - (100 * EDSCALE);
}
+void EditorAssetLibrary::_set_library_message(const String &p_message) {
+ library_message->set_text(p_message);
+
+ if (library_message_action.is_valid()) {
+ library_message_button->disconnect("pressed", library_message_action);
+ library_message_action = Callable();
+ }
+ library_message_button->hide();
+
+ library_message_box->show();
+}
+
+void EditorAssetLibrary::_set_library_message_with_action(const String &p_message, const String &p_action_text, const Callable &p_action) {
+ library_message->set_text(p_message);
+
+ library_message_button->set_text(p_action_text);
+ if (library_message_action.is_valid()) {
+ library_message_button->disconnect("pressed", library_message_action);
+ library_message_action = Callable();
+ }
+ library_message_action = p_action;
+ library_message_button->connect("pressed", library_message_action);
+ library_message_button->show();
+
+ library_message_box->show();
+}
+
+void EditorAssetLibrary::_force_online_mode() {
+ EditorSettings::get_singleton()->set_setting("network/connection/network_mode", EditorSettings::NETWORK_ONLINE);
+ EditorSettings::get_singleton()->notify_changes();
+ EditorSettings::get_singleton()->save();
+}
+
void EditorAssetLibrary::disable_community_support() {
support->get_popup()->set_item_checked(SUPPORT_COMMUNITY, false);
}
@@ -1443,7 +1484,7 @@ void EditorAssetLibrary::_bind_methods() {
EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
requesting = REQUESTING_NONE;
templates_only = p_templates_only;
- initial_loading = true;
+ loading_blocked = ((int)EDITOR_GET("network/connection/network_mode") == EditorSettings::NETWORK_OFFLINE);
VBoxContainer *library_main = memnew(VBoxContainer);
add_child(library_main);
@@ -1567,22 +1608,18 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
library_vb_border->add_child(library_vb);
- library_info = memnew(Label);
- library_info->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- library_vb->add_child(library_info);
+ library_message_box = memnew(VBoxContainer);
+ library_message_box->hide();
+ library_vb->add_child(library_message_box);
- library_error = memnew(VBoxContainer);
- library_error->hide();
- library_vb->add_child(library_error);
+ library_message = memnew(Label);
+ library_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ library_message_box->add_child(library_message);
- library_error_label = memnew(Label(TTR("Failed to get repository configuration.")));
- library_error_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- library_error->add_child(library_error_label);
-
- library_error_retry = memnew(Button(TTR("Retry")));
- library_error_retry->set_h_size_flags(SIZE_SHRINK_CENTER);
- library_error_retry->connect("pressed", callable_mp(this, &EditorAssetLibrary::_request_current_config));
- library_error->add_child(library_error_retry);
+ library_message_button = memnew(Button);
+ library_message_button->set_h_size_flags(SIZE_SHRINK_CENTER);
+ library_message_button->set_theme_type_variation("PanelBackgroundButton");
+ library_message_box->add_child(library_message_button);
asset_top_page = memnew(HBoxContainer);
library_vb->add_child(asset_top_page);
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index 2dff1869ef2..bbce14a9dd1 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -191,10 +191,14 @@ class EditorAssetLibrary : public PanelContainer {
PanelContainer *library_scroll_bg = nullptr;
ScrollContainer *library_scroll = nullptr;
VBoxContainer *library_vb = nullptr;
- Label *library_info = nullptr;
- VBoxContainer *library_error = nullptr;
- Label *library_error_label = nullptr;
- Button *library_error_retry = nullptr;
+ VBoxContainer *library_message_box = nullptr;
+ Label *library_message = nullptr;
+ Button *library_message_button = nullptr;
+ Callable library_message_action;
+
+ void _set_library_message(const String &p_message);
+ void _set_library_message_with_action(const String &p_message, const String &p_action_text, const Callable &p_action);
+
LineEdit *filter = nullptr;
Timer *filter_debounce_timer = nullptr;
OptionButton *categories = nullptr;
@@ -213,8 +217,11 @@ class EditorAssetLibrary : public PanelContainer {
HTTPRequest *request = nullptr;
- bool templates_only;
- bool initial_loading;
+ bool templates_only = false;
+ bool initial_loading = true;
+ bool loading_blocked = false;
+
+ void _force_online_mode();
enum Support {
SUPPORT_OFFICIAL,
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index d18e5a237f3..ffb482d103a 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -38,7 +38,6 @@
#include "core/io/stream_peer_tls.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
-#include "core/string/translation.h"
#include "core/version.h"
#include "editor/editor_about.h"
#include "editor/editor_settings.h"
@@ -48,11 +47,11 @@
#include "editor/project_manager/project_dialog.h"
#include "editor/project_manager/project_list.h"
#include "editor/project_manager/project_tag.h"
+#include "editor/project_manager/quick_settings_dialog.h"
#include "editor/themes/editor_icons.h"
#include "editor/themes/editor_scale.h"
#include "editor/themes/editor_theme_manager.h"
#include "main/main.h"
-#include "scene/gui/center_container.h"
#include "scene/gui/check_box.h"
#include "scene/gui/color_rect.h"
#include "scene/gui/flow_container.h"
@@ -60,9 +59,11 @@
#include "scene/gui/margin_container.h"
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
+#include "scene/gui/rich_text_label.h"
#include "scene/gui/separator.h"
#include "scene/gui/texture_rect.h"
#include "scene/main/window.h"
+#include "scene/theme/theme_db.h"
#include "servers/display_server.h"
#include "servers/navigation_server_3d.h"
#include "servers/physics_server_2d.h"
@@ -75,91 +76,20 @@ ProjectManager *ProjectManager::singleton = nullptr;
void ProjectManager::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_TRANSLATION_CHANGED:
- case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
- settings_hb->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT);
- queue_redraw();
- } break;
-
case NOTIFICATION_ENTER_TREE: {
Engine::get_singleton()->set_editor_hint(false);
- } break;
- case NOTIFICATION_THEME_CHANGED: {
- background_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("Background"), EditorStringName(EditorStyles)));
- loading_label->add_theme_font_override("font", get_theme_font(SNAME("bold"), EditorStringName(EditorFonts)));
- search_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("search_panel"), SNAME("ProjectManager")));
-
- // Top bar.
- search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
- language_btn->set_icon(get_editor_theme_icon(SNAME("Environment")));
-
- // Sidebar.
- create_btn->set_icon(get_editor_theme_icon(SNAME("Add")));
- import_btn->set_icon(get_editor_theme_icon(SNAME("Load")));
- scan_btn->set_icon(get_editor_theme_icon(SNAME("Search")));
- open_btn->set_icon(get_editor_theme_icon(SNAME("Edit")));
- run_btn->set_icon(get_editor_theme_icon(SNAME("Play")));
- rename_btn->set_icon(get_editor_theme_icon(SNAME("Rename")));
- manage_tags_btn->set_icon(get_editor_theme_icon("Script"));
- erase_btn->set_icon(get_editor_theme_icon(SNAME("Remove")));
- erase_missing_btn->set_icon(get_editor_theme_icon(SNAME("Clear")));
- create_tag_btn->set_icon(get_editor_theme_icon("Add"));
-
- tag_error->add_theme_color_override("font_color", get_theme_color("error_color", EditorStringName(Editor)));
- tag_edit_error->add_theme_color_override("font_color", get_theme_color("error_color", EditorStringName(Editor)));
-
- create_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
- import_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
- scan_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
- open_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
- run_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
- rename_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
- manage_tags_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
- erase_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
- erase_missing_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
-
- // Asset library popup.
- if (asset_library) {
- // Removes extra border margins.
- asset_library->add_theme_style_override("panel", memnew(StyleBoxEmpty));
- }
- } break;
-
- case NOTIFICATION_RESIZED: {
- if (open_templates && open_templates->is_visible()) {
- open_templates->popup_centered();
- }
- if (asset_library) {
- real_t size = get_size().x / EDSCALE;
- // Adjust names of tabs to fit the new size.
- if (size < 650) {
- local_projects_vb->set_name(TTR("Local"));
- asset_library->set_name(TTR("Asset Library"));
- } else {
- local_projects_vb->set_name(TTR("Local Projects"));
- asset_library->set_name(TTR("Asset Library Projects"));
- }
- }
+ // Theme has already been created in the constructor, so we can skip that step.
+ _update_theme(true);
} break;
case NOTIFICATION_READY: {
- int default_sorting = (int)EDITOR_GET("project_manager/sorting_order");
+ const int default_sorting = (int)EDITOR_GET("project_manager/sorting_order");
filter_option->select(default_sorting);
- _project_list->set_order_option(default_sorting);
+ project_list->set_order_option(default_sorting);
-#ifndef ANDROID_ENABLED
- if (_project_list->get_project_count() >= 1) {
- // Focus on the search box immediately to allow the user
- // to search without having to reach for their mouse
- search_box->grab_focus();
- }
-#endif
-
- // Suggest browsing asset library to get templates/demos.
- if (asset_library && open_templates && _project_list->get_project_count() == 0) {
- open_templates->popup_centered();
- }
+ _select_main_view(MAIN_VIEW_PROJECTS);
+ _update_list_placeholder();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -173,6 +103,13 @@ void ProjectManager::_notification(int p_what) {
case NOTIFICATION_WM_ABOUT: {
_show_about();
} break;
+
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ if (EditorThemeManager::is_generated_theme_outdated()) {
+ _update_theme();
+ }
+ _update_list_placeholder();
+ } break;
}
}
@@ -233,21 +170,166 @@ void ProjectManager::_update_size_limits() {
// We try to set it to half the screen resolution, but no smaller than the minimum window size.
Size2 half_screen_rect = (screen_rect.size * EDSCALE) / 2;
Size2 maximum_popup_size = MAX(half_screen_rect, minimum_size);
- language_btn->get_popup()->set_max_size(maximum_popup_size);
+ quick_settings_dialog->update_size_limits(maximum_popup_size);
}
}
-void ProjectManager::_show_about() {
- about->popup_centered(Size2(780, 500) * EDSCALE);
+void ProjectManager::_update_theme(bool p_skip_creation) {
+ if (!p_skip_creation) {
+ theme = EditorThemeManager::generate_theme(theme);
+ DisplayServer::set_early_window_clear_color_override(true, theme->get_color(SNAME("background"), EditorStringName(Editor)));
+ }
+
+ List[> editor_themes;
+ editor_themes.push_back(theme);
+ editor_themes.push_back(ThemeDB::get_singleton()->get_default_theme());
+
+ ThemeContext *node_tc = ThemeDB::get_singleton()->get_theme_context(this);
+ if (node_tc) {
+ node_tc->set_themes(editor_themes);
+ } else {
+ ThemeDB::get_singleton()->create_theme_context(this, editor_themes);
+ }
+
+ Window *owner_window = get_window();
+ if (owner_window) {
+ ThemeContext *window_tc = ThemeDB::get_singleton()->get_theme_context(owner_window);
+ if (window_tc) {
+ window_tc->set_themes(editor_themes);
+ } else {
+ ThemeDB::get_singleton()->create_theme_context(owner_window, editor_themes);
+ }
+ }
+
+ // Update styles.
+ {
+ const int top_bar_separation = get_theme_constant(SNAME("top_bar_separation"), EditorStringName(Editor));
+ root_container->add_theme_constant_override("margin_left", top_bar_separation);
+ root_container->add_theme_constant_override("margin_top", top_bar_separation);
+ root_container->add_theme_constant_override("margin_bottom", top_bar_separation);
+ root_container->add_theme_constant_override("margin_right", top_bar_separation);
+ main_vbox->add_theme_constant_override("separation", top_bar_separation);
+
+ background_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("Background"), EditorStringName(EditorStyles)));
+ main_view_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+
+ title_bar_logo->set_icon(get_editor_theme_icon(SNAME("TitleBarLogo")));
+
+ _set_main_view_icon(MAIN_VIEW_PROJECTS, get_editor_theme_icon(SNAME("ProjectList")));
+ _set_main_view_icon(MAIN_VIEW_ASSETLIB, get_editor_theme_icon(SNAME("AssetLib")));
+
+ // Project list.
+ {
+ loading_label->add_theme_font_override("font", get_theme_font(SNAME("bold"), EditorStringName(EditorFonts)));
+ project_list_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("project_list"), SNAME("ProjectManager")));
+
+ empty_list_create_project->set_icon(get_editor_theme_icon(SNAME("Add")));
+ empty_list_import_project->set_icon(get_editor_theme_icon(SNAME("Load")));
+ empty_list_open_assetlib->set_icon(get_editor_theme_icon(SNAME("AssetLib")));
+
+ empty_list_online_warning->add_theme_font_override("font", get_theme_font(SNAME("italic"), EditorStringName(EditorFonts)));
+ empty_list_online_warning->add_theme_color_override("font_color", get_theme_color(SNAME("font_placeholder_color"), EditorStringName(Editor)));
+
+ // Top bar.
+ search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
+ quick_settings_button->set_icon(get_editor_theme_icon(SNAME("Tools")));
+
+ // Sidebar.
+ create_btn->set_icon(get_editor_theme_icon(SNAME("Add")));
+ import_btn->set_icon(get_editor_theme_icon(SNAME("Load")));
+ scan_btn->set_icon(get_editor_theme_icon(SNAME("Search")));
+ open_btn->set_icon(get_editor_theme_icon(SNAME("Edit")));
+ run_btn->set_icon(get_editor_theme_icon(SNAME("Play")));
+ rename_btn->set_icon(get_editor_theme_icon(SNAME("Rename")));
+ manage_tags_btn->set_icon(get_editor_theme_icon("Script"));
+ erase_btn->set_icon(get_editor_theme_icon(SNAME("Remove")));
+ erase_missing_btn->set_icon(get_editor_theme_icon(SNAME("Clear")));
+ create_tag_btn->set_icon(get_editor_theme_icon("Add"));
+
+ tag_error->add_theme_color_override("font_color", get_theme_color("error_color", EditorStringName(Editor)));
+ tag_edit_error->add_theme_color_override("font_color", get_theme_color("error_color", EditorStringName(Editor)));
+
+ create_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
+ import_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
+ scan_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
+ open_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
+ run_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
+ rename_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
+ manage_tags_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
+ erase_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
+ erase_missing_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager")));
+ }
+
+ // Asset library popup.
+ if (asset_library) {
+ // Removes extra border margins.
+ asset_library->add_theme_style_override("panel", memnew(StyleBoxEmpty));
+ }
+ }
}
-void ProjectManager::_version_button_pressed() {
- DisplayServer::get_singleton()->clipboard_set(version_btn->get_text());
+Button *ProjectManager::_add_main_view(MainViewTab p_id, const String &p_name, const Ref &p_icon, Control *p_view_control) {
+ ERR_FAIL_INDEX_V(p_id, MAIN_VIEW_MAX, nullptr);
+ ERR_FAIL_COND_V(main_view_map.has(p_id), nullptr);
+ ERR_FAIL_COND_V(main_view_toggle_map.has(p_id), nullptr);
+
+ Button *toggle_button = memnew(Button);
+ toggle_button->set_flat(true);
+ toggle_button->set_theme_type_variation("MainScreenButton");
+ toggle_button->set_toggle_mode(true);
+ toggle_button->set_button_group(main_view_toggles_group);
+ toggle_button->set_text(p_name);
+ toggle_button->connect("pressed", callable_mp(this, &ProjectManager::_select_main_view).bind((int)p_id));
+
+ main_view_toggles->add_child(toggle_button);
+ main_view_toggle_map[p_id] = toggle_button;
+
+ _set_main_view_icon(p_id, p_icon);
+
+ p_view_control->set_visible(false);
+ main_view_container->add_child(p_view_control);
+ main_view_map[p_id] = p_view_control;
+
+ return toggle_button;
}
-void ProjectManager::_on_tab_changed(int p_tab) {
+void ProjectManager::_set_main_view_icon(MainViewTab p_id, const Ref &p_icon) {
+ ERR_FAIL_INDEX(p_id, MAIN_VIEW_MAX);
+ ERR_FAIL_COND(!main_view_toggle_map.has(p_id));
+
+ Button *toggle_button = main_view_toggle_map[p_id];
+
+ Ref old_icon = toggle_button->get_icon();
+ if (old_icon.is_valid()) {
+ old_icon->disconnect_changed(callable_mp((Control *)toggle_button, &Control::update_minimum_size));
+ }
+
+ if (p_icon.is_valid()) {
+ toggle_button->set_icon(p_icon);
+ // Make sure the control is updated if the icon is reimported.
+ p_icon->connect_changed(callable_mp((Control *)toggle_button, &Control::update_minimum_size));
+ } else {
+ toggle_button->set_icon(Ref());
+ }
+}
+
+void ProjectManager::_select_main_view(int p_id) {
+ MainViewTab view_id = (MainViewTab)p_id;
+
+ ERR_FAIL_INDEX(view_id, MAIN_VIEW_MAX);
+ ERR_FAIL_COND(!main_view_map.has(view_id));
+ ERR_FAIL_COND(!main_view_toggle_map.has(view_id));
+
+ if (current_main_view != view_id) {
+ main_view_toggle_map[current_main_view]->set_pressed_no_signal(false);
+ main_view_map[current_main_view]->set_visible(false);
+ current_main_view = view_id;
+ }
+ main_view_toggle_map[current_main_view]->set_pressed_no_signal(true);
+ main_view_map[current_main_view]->set_visible(true);
+
#ifndef ANDROID_ENABLED
- if (p_tab == 0) { // Projects
+ if (current_main_view == MAIN_VIEW_PROJECTS && search_box->is_inside_tree()) {
// Automatically grab focus when the user moves from the Templates tab
// back to the Projects tab.
search_box->grab_focus();
@@ -258,27 +340,25 @@ void ProjectManager::_on_tab_changed(int p_tab) {
#endif
}
-void ProjectManager::_open_asset_library() {
+void ProjectManager::_show_about() {
+ about_dialog->popup_centered(Size2(780, 500) * EDSCALE);
+}
+
+void ProjectManager::_open_asset_library_confirmed() {
+ const int network_mode = EDITOR_GET("network/connection/network_mode");
+ if (network_mode == EditorSettings::NETWORK_OFFLINE) {
+ EditorSettings::get_singleton()->set_setting("network/connection/network_mode", EditorSettings::NETWORK_ONLINE);
+ EditorSettings::get_singleton()->notify_changes();
+ EditorSettings::get_singleton()->save();
+ }
+
asset_library->disable_community_support();
- tabs->set_current_tab(1);
+ _select_main_view(MAIN_VIEW_ASSETLIB);
}
-// Quick settings.
-
-void ProjectManager::_language_selected(int p_id) {
- String lang = language_btn->get_item_metadata(p_id);
- EditorSettings::get_singleton()->set("interface/editor/editor_language", lang);
-
- restart_required_dialog->popup_centered();
-}
-
-void ProjectManager::_restart_confirm() {
- List args = OS::get_singleton()->get_cmdline_args();
- Error err = OS::get_singleton()->create_instance(args);
- ERR_FAIL_COND(err);
-
- _dim_window();
- get_tree()->quit();
+void ProjectManager::_show_error(const String &p_message, const Size2 &p_min_size) {
+ error_dialog->set_text(p_message);
+ error_dialog->popup_centered(p_min_size);
}
void ProjectManager::_dim_window() {
@@ -292,14 +372,55 @@ void ProjectManager::_dim_window() {
set_modulate(dim_color);
}
+// Quick settings.
+
+void ProjectManager::_show_quick_settings() {
+ quick_settings_dialog->popup_centered(Size2(600, 200) * EDSCALE);
+}
+
+void ProjectManager::_restart_confirmed() {
+ List args = OS::get_singleton()->get_cmdline_args();
+ Error err = OS::get_singleton()->create_instance(args);
+ ERR_FAIL_COND(err);
+
+ _dim_window();
+ get_tree()->quit();
+}
+
+// Footer.
+
+void ProjectManager::_version_button_pressed() {
+ DisplayServer::get_singleton()->clipboard_set(version_btn->get_text());
+}
+
// Project list.
+void ProjectManager::_update_list_placeholder() {
+ if (project_list->get_project_count() > 0) {
+ empty_list_placeholder->hide();
+ return;
+ }
+
+ empty_list_open_assetlib->set_visible(asset_library);
+
+ const int network_mode = EDITOR_GET("network/connection/network_mode");
+ if (network_mode == EditorSettings::NETWORK_OFFLINE) {
+ empty_list_open_assetlib->set_text(TTR("Go Online and Open Asset Library"));
+ empty_list_online_warning->set_visible(true);
+ } else {
+ empty_list_open_assetlib->set_text(TTR("Open Asset Library"));
+ empty_list_online_warning->set_visible(false);
+ }
+
+ empty_list_placeholder->show();
+}
+
void ProjectManager::_scan_projects() {
scan_dir->popup_file_dialog();
}
void ProjectManager::_run_project() {
- const HashSet &selected_list = _project_list->get_selected_project_keys();
+ const HashSet &selected_list = project_list->get_selected_project_keys();
if (selected_list.size() < 1) {
return;
@@ -314,13 +435,12 @@ void ProjectManager::_run_project() {
}
void ProjectManager::_run_project_confirm() {
- Vector selected_list = _project_list->get_selected_projects();
+ Vector selected_list = project_list->get_selected_projects();
for (int i = 0; i < selected_list.size(); ++i) {
const String &selected_main = selected_list[i].main_scene;
if (selected_main.is_empty()) {
- run_error_diag->set_text(TTR("Can't run project: no main scene defined.\nPlease edit the project and set the main scene in the Project Settings under the \"Application\" category."));
- run_error_diag->popup_centered();
+ _show_error(TTR("Can't run project: Project has no main scene defined.\nPlease edit the project and set the main scene in the Project Settings under the \"Application\" category."));
continue;
}
@@ -328,8 +448,7 @@ void ProjectManager::_run_project_confirm() {
// `.substr(6)` on `ProjectSettings::get_singleton()->get_imported_files_path()` strips away the leading "res://".
if (!DirAccess::exists(path.path_join(ProjectSettings::get_singleton()->get_imported_files_path().substr(6)))) {
- run_error_diag->set_text(TTR("Can't run project: Assets need to be imported.\nPlease edit the project to trigger the initial import."));
- run_error_diag->popup_centered();
+ _show_error(TTR("Can't run project: Assets need to be imported first.\nPlease edit the project to trigger the initial import."));
continue;
}
@@ -354,14 +473,13 @@ void ProjectManager::_open_selected_projects() {
// This is especially important for the Web project manager.
loading_label->show();
- const HashSet &selected_list = _project_list->get_selected_project_keys();
-
+ const HashSet &selected_list = project_list->get_selected_project_keys();
for (const String &path : selected_list) {
String conf = path.path_join("project.godot");
if (!FileAccess::exists(conf)) {
- dialog_error->set_text(vformat(TTR("Can't open project at '%s'."), path));
- dialog_error->popup_centered();
+ loading_label->hide();
+ _show_error(vformat(TTR("Can't open project at '%s'.\nProject file doesn't exist or is inaccessible."), path));
return;
}
@@ -379,18 +497,22 @@ void ProjectManager::_open_selected_projects() {
args.push_back("--editor");
Error err = OS::get_singleton()->create_instance(args);
- ERR_FAIL_COND(err);
+ if (err != OK) {
+ loading_label->hide();
+ _show_error(vformat(TTR("Can't open project at '%s'.\nFailed to start the editor."), path));
+ ERR_PRINT(vformat("Failed to start an editor instance for the project at '%s', error code %d.", path, err));
+ return;
+ }
}
- _project_list->project_opening_initiated = true;
+ project_list->project_opening_initiated = true;
_dim_window();
get_tree()->quit();
}
void ProjectManager::_open_selected_projects_ask() {
- const HashSet &selected_list = _project_list->get_selected_project_keys();
-
+ const HashSet &selected_list = project_list->get_selected_project_keys();
if (selected_list.size() < 1) {
return;
}
@@ -403,7 +525,7 @@ void ProjectManager::_open_selected_projects_ask() {
return;
}
- ProjectList::Item project = _project_list->get_selected_projects()[0];
+ ProjectList::Item project = project_list->get_selected_projects()[0];
if (project.missing) {
return;
}
@@ -440,8 +562,7 @@ void ProjectManager::_open_selected_projects_ask() {
}
// Check if the file was generated by a newer, incompatible engine version.
if (config_version > ProjectSettings::CONFIG_VERSION) {
- dialog_error->set_text(vformat(TTR("Can't open project \"%s\" at the following path:\n\n%s\n\nThe project settings were created by a newer engine version, whose settings are not compatible with this version."), project.project_name, project.path));
- dialog_error->popup_centered(popup_min_size);
+ _show_error(vformat(TTR("Can't open project \"%s\" at the following path:\n\n%s\n\nThe project settings were created by a newer engine version, whose settings are not compatible with this version."), project.project_name, project.path), popup_min_size);
return;
}
// Check if the project is using features not supported by this build of Godot.
@@ -479,38 +600,38 @@ void ProjectManager::_open_selected_projects_ask() {
}
void ProjectManager::_install_project(const String &p_zip_path, const String &p_title) {
- npdialog->set_mode(ProjectDialog::MODE_INSTALL);
- npdialog->set_zip_path(p_zip_path);
- npdialog->set_zip_title(p_title);
- npdialog->show_dialog();
+ project_dialog->set_mode(ProjectDialog::MODE_INSTALL);
+ project_dialog->set_zip_path(p_zip_path);
+ project_dialog->set_zip_title(p_title);
+ project_dialog->show_dialog();
}
void ProjectManager::_import_project() {
- npdialog->set_mode(ProjectDialog::MODE_IMPORT);
- npdialog->ask_for_path_and_show();
+ project_dialog->set_mode(ProjectDialog::MODE_IMPORT);
+ project_dialog->ask_for_path_and_show();
}
void ProjectManager::_new_project() {
- npdialog->set_mode(ProjectDialog::MODE_NEW);
- npdialog->show_dialog();
+ project_dialog->set_mode(ProjectDialog::MODE_NEW);
+ project_dialog->show_dialog();
}
void ProjectManager::_rename_project() {
- const HashSet &selected_list = _project_list->get_selected_project_keys();
+ const HashSet &selected_list = project_list->get_selected_project_keys();
if (selected_list.size() == 0) {
return;
}
for (const String &E : selected_list) {
- npdialog->set_project_path(E);
- npdialog->set_mode(ProjectDialog::MODE_RENAME);
- npdialog->show_dialog();
+ project_dialog->set_project_path(E);
+ project_dialog->set_mode(ProjectDialog::MODE_RENAME);
+ project_dialog->show_dialog();
}
}
void ProjectManager::_erase_project() {
- const HashSet &selected_list = _project_list->get_selected_project_keys();
+ const HashSet &selected_list = project_list->get_selected_project_keys();
if (selected_list.size() == 0) {
return;
@@ -534,17 +655,19 @@ void ProjectManager::_erase_missing_projects() {
}
void ProjectManager::_erase_project_confirm() {
- _project_list->erase_selected_projects(false);
+ project_list->erase_selected_projects(false);
_update_project_buttons();
+ _update_list_placeholder();
}
void ProjectManager::_erase_missing_projects_confirm() {
- _project_list->erase_missing_projects();
+ project_list->erase_missing_projects();
_update_project_buttons();
+ _update_list_placeholder();
}
void ProjectManager::_update_project_buttons() {
- Vector selected_projects = _project_list->get_selected_projects();
+ Vector selected_projects = project_list->get_selected_projects();
bool empty_selection = selected_projects.is_empty();
bool is_missing_project_selected = false;
@@ -561,53 +684,53 @@ void ProjectManager::_update_project_buttons() {
manage_tags_btn->set_disabled(empty_selection || is_missing_project_selected || selected_projects.size() > 1);
run_btn->set_disabled(empty_selection || is_missing_project_selected);
- erase_missing_btn->set_disabled(!_project_list->is_any_project_missing());
+ erase_missing_btn->set_disabled(!project_list->is_any_project_missing());
}
void ProjectManager::_on_projects_updated() {
- Vector selected_projects = _project_list->get_selected_projects();
+ Vector selected_projects = project_list->get_selected_projects();
int index = 0;
for (int i = 0; i < selected_projects.size(); ++i) {
- index = _project_list->refresh_project(selected_projects[i].path);
+ index = project_list->refresh_project(selected_projects[i].path);
}
if (index != -1) {
- _project_list->ensure_project_visible(index);
+ project_list->ensure_project_visible(index);
}
- _project_list->update_dock_menu();
+ project_list->update_dock_menu();
}
void ProjectManager::_on_project_created(const String &dir) {
- _project_list->add_project(dir, false);
- _project_list->save_config();
+ project_list->add_project(dir, false);
+ project_list->save_config();
search_box->clear();
- int i = _project_list->refresh_project(dir);
- _project_list->select_project(i);
- _project_list->ensure_project_visible(i);
+ int i = project_list->refresh_project(dir);
+ project_list->select_project(i);
+ project_list->ensure_project_visible(i);
_open_selected_projects_ask();
- _project_list->update_dock_menu();
+ project_list->update_dock_menu();
}
void ProjectManager::_on_order_option_changed(int p_idx) {
if (is_inside_tree()) {
- _project_list->set_order_option(p_idx);
+ project_list->set_order_option(p_idx);
}
}
void ProjectManager::_on_search_term_changed(const String &p_term) {
- _project_list->set_search_term(p_term);
- _project_list->sort_projects();
+ project_list->set_search_term(p_term);
+ project_list->sort_projects();
// Select the first visible project in the list.
// This makes it possible to open a project without ever touching the mouse,
// as the search field is automatically focused on startup.
- _project_list->select_first_visible_project();
+ project_list->select_first_visible_project();
_update_project_buttons();
}
void ProjectManager::_on_search_term_submitted(const String &p_text) {
- if (tabs->get_current_tab() != 0) {
+ if (current_main_view != MAIN_VIEW_PROJECTS) {
return;
}
@@ -625,7 +748,7 @@ void ProjectManager::_manage_project_tags() {
project_tags->get_child(i)->queue_free();
}
- const ProjectList::Item item = _project_list->get_selected_projects()[0];
+ const ProjectList::Item item = project_list->get_selected_projects()[0];
current_project_tags = item.tags;
for (const String &tag : current_project_tags) {
ProjectTag *tag_control = memnew(ProjectTag(tag, true));
@@ -669,7 +792,7 @@ void ProjectManager::_apply_project_tags() {
}
ConfigFile cfg;
- const String project_godot = _project_list->get_selected_projects()[0].path.path_join("project.godot");
+ const String project_godot = project_list->get_selected_projects()[0].path.path_join("project.godot");
Error err = cfg.load(project_godot);
if (err != OK) {
tag_edit_error->set_text(vformat(TTR("Couldn't load project at '%s' (error %d). It may be missing or corrupted."), project_godot, err));
@@ -747,7 +870,7 @@ void ProjectManager::_full_convert_button_pressed() {
}
void ProjectManager::_perform_full_project_conversion() {
- Vector selected_list = _project_list->get_selected_projects();
+ Vector selected_list = project_list->get_selected_projects();
if (selected_list.is_empty()) {
return;
}
@@ -765,7 +888,7 @@ void ProjectManager::_perform_full_project_conversion() {
Error err = OS::get_singleton()->create_instance(args);
ERR_FAIL_COND(err);
- _project_list->set_project_version(path, GODOT4_CONFIG_VERSION);
+ project_list->set_project_version(path, GODOT4_CONFIG_VERSION);
}
// Input and I/O.
@@ -790,7 +913,7 @@ void ProjectManager::shortcut_input(const Ref &p_ev) {
}
#endif
- if (tabs->get_current_tab() != 0) {
+ if (current_main_view != MAIN_VIEW_PROJECTS) {
return;
}
@@ -801,15 +924,15 @@ void ProjectManager::shortcut_input(const Ref &p_ev) {
_open_selected_projects_ask();
} break;
case Key::HOME: {
- if (_project_list->get_project_count() > 0) {
- _project_list->select_project(0);
+ if (project_list->get_project_count() > 0) {
+ project_list->select_project(0);
_update_project_buttons();
}
} break;
case Key::END: {
- if (_project_list->get_project_count() > 0) {
- _project_list->select_project(_project_list->get_project_count() - 1);
+ if (project_list->get_project_count() > 0) {
+ project_list->select_project(project_list->get_project_count() - 1);
_update_project_buttons();
}
@@ -819,10 +942,10 @@ void ProjectManager::shortcut_input(const Ref &p_ev) {
break;
}
- int index = _project_list->get_single_selected_index();
+ int index = project_list->get_single_selected_index();
if (index > 0) {
- _project_list->select_project(index - 1);
- _project_list->ensure_project_visible(index - 1);
+ project_list->select_project(index - 1);
+ project_list->ensure_project_visible(index - 1);
_update_project_buttons();
}
@@ -833,10 +956,10 @@ void ProjectManager::shortcut_input(const Ref &p_ev) {
break;
}
- int index = _project_list->get_single_selected_index();
- if (index + 1 < _project_list->get_project_count()) {
- _project_list->select_project(index + 1);
- _project_list->ensure_project_visible(index + 1);
+ int index = project_list->get_single_selected_index();
+ if (index + 1 < project_list->get_project_count()) {
+ project_list->select_project(index + 1);
+ project_list->ensure_project_visible(index + 1);
_update_project_buttons();
}
@@ -879,7 +1002,7 @@ void ProjectManager::_files_dropped(PackedStringArray p_files) {
for (const String &E : folders_set) {
folders.push_back(E);
}
- _project_list->find_projects_multiple(folders);
+ project_list->find_projects_multiple(folders);
}
// Object methods.
@@ -955,10 +1078,9 @@ ProjectManager::ProjectManager() {
Window::set_root_layout_direction(pm_root_dir);
EditorThemeManager::initialize();
- Ref theme = EditorThemeManager::generate_theme();
+ theme = EditorThemeManager::generate_theme();
DisplayServer::set_early_window_clear_color_override(true, theme->get_color(SNAME("background"), EditorStringName(Editor)));
- set_theme(theme);
set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
_build_icon_type_cache(theme);
@@ -970,95 +1092,59 @@ ProjectManager::ProjectManager() {
add_child(background_panel);
background_panel->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
- VBoxContainer *vb = memnew(VBoxContainer);
- background_panel->add_child(vb);
- vb->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 8 * EDSCALE);
+ root_container = memnew(MarginContainer);
+ add_child(root_container);
+ root_container->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
- Control *center_box = memnew(Control);
- center_box->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- vb->add_child(center_box);
+ main_vbox = memnew(VBoxContainer);
+ root_container->add_child(main_vbox);
- tabs = memnew(TabContainer);
- tabs->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
- center_box->add_child(tabs);
- tabs->connect("tab_changed", callable_mp(this, &ProjectManager::_on_tab_changed));
-
- // Quick settings.
+ // Title bar.
{
- settings_hb = memnew(HBoxContainer);
- settings_hb->set_alignment(BoxContainer::ALIGNMENT_END);
- settings_hb->set_h_grow_direction(Control::GROW_DIRECTION_BEGIN);
- settings_hb->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT);
+ title_bar = memnew(HBoxContainer);
+ main_vbox->add_child(title_bar);
- // A VBoxContainer that contains a dummy Control node to adjust the LinkButton's vertical position.
- VBoxContainer *spacer_vb = memnew(VBoxContainer);
- settings_hb->add_child(spacer_vb);
+ HBoxContainer *left_hbox = memnew(HBoxContainer);
+ left_hbox->set_alignment(BoxContainer::ALIGNMENT_BEGIN);
+ left_hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ left_hbox->set_stretch_ratio(1.0);
+ title_bar->add_child(left_hbox);
- Control *v_spacer = memnew(Control);
- spacer_vb->add_child(v_spacer);
+ title_bar_logo = memnew(Button);
+ title_bar_logo->set_flat(true);
+ left_hbox->add_child(title_bar_logo);
+ title_bar_logo->connect("pressed", callable_mp(this, &ProjectManager::_show_about));
- version_btn = memnew(LinkButton);
- String hash = String(VERSION_HASH);
- if (hash.length() != 0) {
- hash = " " + vformat("[%s]", hash.left(9));
- }
- version_btn->set_text("v" VERSION_FULL_BUILD + hash);
- // Fade the version label to be less prominent, but still readable.
- version_btn->set_self_modulate(Color(1, 1, 1, 0.6));
- version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
- version_btn->set_tooltip_text(TTR("Click to copy."));
- version_btn->connect("pressed", callable_mp(this, &ProjectManager::_version_button_pressed));
- spacer_vb->add_child(version_btn);
+ main_view_toggles = memnew(HBoxContainer);
+ main_view_toggles->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ main_view_toggles->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ main_view_toggles->set_stretch_ratio(2.0);
+ title_bar->add_child(main_view_toggles);
- // Add a small horizontal spacer between the version and language buttons
- // to distinguish them.
- Control *h_spacer = memnew(Control);
- settings_hb->add_child(h_spacer);
+ main_view_toggles_group.instantiate();
- language_btn = memnew(OptionButton);
- language_btn->set_focus_mode(Control::FOCUS_NONE);
- language_btn->set_fit_to_longest_item(false);
- language_btn->set_flat(true);
- language_btn->connect("item_selected", callable_mp(this, &ProjectManager::_language_selected));
-#ifdef ANDROID_ENABLED
- // The language selection dropdown doesn't work on Android (as the setting isn't saved), see GH-60353.
- // Also, the dropdown it spawns is very tall and can't be scrolled without a hardware mouse.
- // Hiding the language selection dropdown also leaves more space for the version label to display.
- language_btn->hide();
-#endif
+ HBoxContainer *right_hbox = memnew(HBoxContainer);
+ right_hbox->set_alignment(BoxContainer::ALIGNMENT_END);
+ right_hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ right_hbox->set_stretch_ratio(1.0);
+ title_bar->add_child(right_hbox);
- Vector editor_languages;
- List editor_settings_properties;
- EditorSettings::get_singleton()->get_property_list(&editor_settings_properties);
- for (const PropertyInfo &pi : editor_settings_properties) {
- if (pi.name == "interface/editor/editor_language") {
- editor_languages = pi.hint_string.split(",");
- break;
- }
- }
-
- String current_lang = EDITOR_GET("interface/editor/editor_language");
- language_btn->set_text(current_lang);
-
- for (int i = 0; i < editor_languages.size(); i++) {
- const String &lang = editor_languages[i];
- String lang_name = TranslationServer::get_singleton()->get_locale_name(lang);
- language_btn->add_item(vformat("[%s] %s", lang, lang_name), i);
- language_btn->set_item_metadata(i, lang);
- if (current_lang == lang) {
- language_btn->select(i);
- }
- }
-
- settings_hb->add_child(language_btn);
- center_box->add_child(settings_hb);
+ quick_settings_button = memnew(Button);
+ quick_settings_button->set_flat(true);
+ quick_settings_button->set_text(TTR("Settings"));
+ right_hbox->add_child(quick_settings_button);
+ quick_settings_button->connect("pressed", callable_mp(this, &ProjectManager::_show_quick_settings));
}
+ main_view_container = memnew(PanelContainer);
+ main_view_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ main_vbox->add_child(main_view_container);
+
// Project list view.
{
local_projects_vb = memnew(VBoxContainer);
- local_projects_vb->set_name(TTR("Local Projects"));
- tabs->add_child(local_projects_vb);
+ local_projects_vb->set_name("LocalProjectsTab");
+ _add_main_view(MAIN_VIEW_PROJECTS, TTR("Projects"), Ref(), local_projects_vb);
// Project list's top bar.
{
@@ -1067,7 +1153,7 @@ ProjectManager::ProjectManager() {
local_projects_vb->add_child(hb);
create_btn = memnew(Button);
- create_btn->set_text(TTR("New"));
+ create_btn->set_text(TTR("Create"));
create_btn->set_shortcut(ED_SHORTCUT("project_manager/new_project", TTR("New Project"), KeyModifierMask::CMD_OR_CTRL | Key::N));
create_btn->connect("pressed", callable_mp(this, &ProjectManager::_new_project));
hb->add_child(create_btn);
@@ -1086,9 +1172,8 @@ ProjectManager::ProjectManager() {
loading_label = memnew(Label(TTR("Loading, please wait...")));
loading_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- hb->add_child(loading_label);
- // The loading label is shown later.
loading_label->hide();
+ hb->add_child(loading_label);
search_box = memnew(LineEdit);
search_box->set_placeholder(TTR("Filter Projects"));
@@ -1123,88 +1208,158 @@ ProjectManager::ProjectManager() {
// Project list and its sidebar.
{
- HBoxContainer *search_tree_hb = memnew(HBoxContainer);
- local_projects_vb->add_child(search_tree_hb);
- search_tree_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ HBoxContainer *project_list_hbox = memnew(HBoxContainer);
+ local_projects_vb->add_child(project_list_hbox);
+ project_list_hbox->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- search_panel = memnew(PanelContainer);
- search_panel->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- search_tree_hb->add_child(search_panel);
+ project_list_panel = memnew(PanelContainer);
+ project_list_panel->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ project_list_hbox->add_child(project_list_panel);
- _project_list = memnew(ProjectList);
- _project_list->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
- search_panel->add_child(_project_list);
- _project_list->connect(ProjectList::SIGNAL_LIST_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
- _project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
- _project_list->connect(ProjectList::SIGNAL_PROJECT_ASK_OPEN, callable_mp(this, &ProjectManager::_open_selected_projects_ask));
+ project_list = memnew(ProjectList);
+ project_list->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
+ project_list_panel->add_child(project_list);
+ project_list->connect(ProjectList::SIGNAL_LIST_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
+ project_list->connect(ProjectList::SIGNAL_LIST_CHANGED, callable_mp(this, &ProjectManager::_update_list_placeholder));
+ project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
+ project_list->connect(ProjectList::SIGNAL_PROJECT_ASK_OPEN, callable_mp(this, &ProjectManager::_open_selected_projects_ask));
+
+ // Empty project list placeholder.
+ {
+ empty_list_placeholder = memnew(VBoxContainer);
+ empty_list_placeholder->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
+ empty_list_placeholder->add_theme_constant_override("separation", 16 * EDSCALE);
+ empty_list_placeholder->hide();
+ project_list_panel->add_child(empty_list_placeholder);
+
+ RichTextLabel *empty_list_message = memnew(RichTextLabel);
+ empty_list_message->set_use_bbcode(true);
+ empty_list_message->set_fit_content(true);
+ empty_list_message->set_h_size_flags(SIZE_EXPAND_FILL);
+ empty_list_message->add_theme_style_override("normal", memnew(StyleBoxEmpty));
+
+ const String line1 = TTR("You don't have any projects yet.");
+ const String line2 = TTR("Get started by creating a new one,\nimporting one that exists, or by downloading a project template from the Asset Library!");
+ empty_list_message->set_text(vformat("[center][b]%s[/b] %s[/center]", line1, line2));
+ empty_list_placeholder->add_child(empty_list_message);
+
+ HBoxContainer *empty_list_actions = memnew(HBoxContainer);
+ empty_list_actions->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ empty_list_placeholder->add_child(empty_list_actions);
+
+ empty_list_create_project = memnew(Button);
+ empty_list_create_project->set_text(TTR("Create New Project"));
+ empty_list_create_project->set_theme_type_variation("PanelBackgroundButton");
+ empty_list_actions->add_child(empty_list_create_project);
+ empty_list_create_project->connect("pressed", callable_mp(this, &ProjectManager::_new_project));
+
+ empty_list_import_project = memnew(Button);
+ empty_list_import_project->set_text(TTR("Import Existing Project"));
+ empty_list_import_project->set_theme_type_variation("PanelBackgroundButton");
+ empty_list_actions->add_child(empty_list_import_project);
+ empty_list_import_project->connect("pressed", callable_mp(this, &ProjectManager::_import_project));
+
+ empty_list_open_assetlib = memnew(Button);
+ empty_list_open_assetlib->set_text(TTR("Open Asset Library"));
+ empty_list_open_assetlib->set_theme_type_variation("PanelBackgroundButton");
+ empty_list_actions->add_child(empty_list_open_assetlib);
+ empty_list_open_assetlib->connect("pressed", callable_mp(this, &ProjectManager::_open_asset_library_confirmed));
+
+ empty_list_online_warning = memnew(Label);
+ empty_list_online_warning->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
+ empty_list_online_warning->set_custom_minimum_size(Size2(220, 0) * EDSCALE);
+ empty_list_online_warning->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
+ empty_list_online_warning->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ empty_list_online_warning->set_text(TTR("Note: The Asset Library requires an online connection and involves sending data over the internet."));
+ empty_list_placeholder->add_child(empty_list_online_warning);
+ }
// The side bar with the edit, run, rename, etc. buttons.
- VBoxContainer *tree_vb = memnew(VBoxContainer);
- tree_vb->set_custom_minimum_size(Size2(120, 120));
- search_tree_hb->add_child(tree_vb);
+ VBoxContainer *project_list_sidebar = memnew(VBoxContainer);
+ project_list_sidebar->set_custom_minimum_size(Size2(120, 120));
+ project_list_hbox->add_child(project_list_sidebar);
- tree_vb->add_child(memnew(HSeparator));
+ project_list_sidebar->add_child(memnew(HSeparator));
open_btn = memnew(Button);
open_btn->set_text(TTR("Edit"));
open_btn->set_shortcut(ED_SHORTCUT("project_manager/edit_project", TTR("Edit Project"), KeyModifierMask::CMD_OR_CTRL | Key::E));
open_btn->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects_ask));
- tree_vb->add_child(open_btn);
+ project_list_sidebar->add_child(open_btn);
run_btn = memnew(Button);
run_btn->set_text(TTR("Run"));
run_btn->set_shortcut(ED_SHORTCUT("project_manager/run_project", TTR("Run Project"), KeyModifierMask::CMD_OR_CTRL | Key::R));
run_btn->connect("pressed", callable_mp(this, &ProjectManager::_run_project));
- tree_vb->add_child(run_btn);
+ project_list_sidebar->add_child(run_btn);
rename_btn = memnew(Button);
rename_btn->set_text(TTR("Rename"));
// The F2 shortcut isn't overridden with Enter on macOS as Enter is already used to edit a project.
rename_btn->set_shortcut(ED_SHORTCUT("project_manager/rename_project", TTR("Rename Project"), Key::F2));
rename_btn->connect("pressed", callable_mp(this, &ProjectManager::_rename_project));
- tree_vb->add_child(rename_btn);
+ project_list_sidebar->add_child(rename_btn);
manage_tags_btn = memnew(Button);
manage_tags_btn->set_text(TTR("Manage Tags"));
- tree_vb->add_child(manage_tags_btn);
+ project_list_sidebar->add_child(manage_tags_btn);
erase_btn = memnew(Button);
erase_btn->set_text(TTR("Remove"));
erase_btn->set_shortcut(ED_SHORTCUT("project_manager/remove_project", TTR("Remove Project"), Key::KEY_DELETE));
erase_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_project));
- tree_vb->add_child(erase_btn);
+ project_list_sidebar->add_child(erase_btn);
+
+ Control *filler = memnew(Control);
+ filler->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ project_list_sidebar->add_child(filler);
erase_missing_btn = memnew(Button);
erase_missing_btn->set_text(TTR("Remove Missing"));
erase_missing_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects));
- tree_vb->add_child(erase_missing_btn);
-
- tree_vb->add_spacer();
-
- about_btn = memnew(Button);
- about_btn->set_text(TTR("About"));
- about_btn->connect("pressed", callable_mp(this, &ProjectManager::_show_about));
- tree_vb->add_child(about_btn);
+ project_list_sidebar->add_child(erase_missing_btn);
}
}
+ // Asset library view.
if (AssetLibraryEditorPlugin::is_available()) {
asset_library = memnew(EditorAssetLibrary(true));
- asset_library->set_name(TTR("Asset Library Projects"));
- tabs->add_child(asset_library);
+ asset_library->set_name("AssetLibraryTab");
+ _add_main_view(MAIN_VIEW_ASSETLIB, TTR("Asset Library"), Ref(), asset_library);
asset_library->connect("install_asset", callable_mp(this, &ProjectManager::_install_project));
} else {
- print_verbose("Asset Library not available (due to using Web editor, or SSL support disabled).");
+ VBoxContainer *asset_library_filler = memnew(VBoxContainer);
+ asset_library_filler->set_name("AssetLibraryTab");
+ Button *asset_library_toggle = _add_main_view(MAIN_VIEW_ASSETLIB, TTR("Asset Library"), Ref(), asset_library_filler);
+ asset_library_toggle->set_disabled(true);
+ asset_library_toggle->set_tooltip_text(TTR("Asset Library not available (due to using Web editor, or because SSL support disabled)."));
+ }
+
+ // Footer bar.
+ {
+ HBoxContainer *footer_bar = memnew(HBoxContainer);
+ footer_bar->set_alignment(BoxContainer::ALIGNMENT_END);
+ main_vbox->add_child(footer_bar);
+
+ version_btn = memnew(LinkButton);
+ String hash = String(VERSION_HASH);
+ if (hash.length() != 0) {
+ hash = " " + vformat("[%s]", hash.left(9));
+ }
+ version_btn->set_text("v" VERSION_FULL_BUILD + hash);
+ // Fade the version label to be less prominent, but still readable.
+ version_btn->set_self_modulate(Color(1, 1, 1, 0.6));
+ version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
+ version_btn->set_tooltip_text(TTR("Click to copy the version information."));
+ version_btn->connect("pressed", callable_mp(this, &ProjectManager::_version_button_pressed));
+ footer_bar->add_child(version_btn);
}
// Dialogs.
{
- restart_required_dialog = memnew(ConfirmationDialog);
- restart_required_dialog->set_ok_button_text(TTR("Restart Now"));
- restart_required_dialog->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_restart_confirm));
- restart_required_dialog->set_cancel_button_text(TTR("Continue"));
- restart_required_dialog->set_text(TTR("Settings changed!\nThe project manager must be restarted for changes to take effect."));
- add_child(restart_required_dialog);
+ quick_settings_dialog = memnew(QuickSettingsDialog);
+ add_child(quick_settings_dialog);
+ quick_settings_dialog->connect("restart_required", callable_mp(this, &ProjectManager::_restart_confirmed));
scan_dir = memnew(EditorFileDialog);
scan_dir->set_previews_enabled(false);
@@ -1213,7 +1368,7 @@ ProjectManager::ProjectManager() {
scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden
scan_dir->set_current_dir(EDITOR_GET("filesystem/directories/default_project_path"));
add_child(scan_dir);
- scan_dir->connect("dir_selected", callable_mp(_project_list, &ProjectList::find_projects));
+ scan_dir->connect("dir_selected", callable_mp(project_list, &ProjectList::find_projects));
erase_missing_ask = memnew(ConfirmationDialog);
erase_missing_ask->set_ok_button_text(TTR("Remove All"));
@@ -1260,28 +1415,17 @@ ProjectManager::ProjectManager() {
ask_full_convert_dialog->connect("confirmed", callable_mp(this, &ProjectManager::_perform_full_project_conversion));
add_child(ask_full_convert_dialog);
- npdialog = memnew(ProjectDialog);
- npdialog->connect("projects_updated", callable_mp(this, &ProjectManager::_on_projects_updated));
- npdialog->connect("project_created", callable_mp(this, &ProjectManager::_on_project_created));
- add_child(npdialog);
+ project_dialog = memnew(ProjectDialog);
+ project_dialog->connect("projects_updated", callable_mp(this, &ProjectManager::_on_projects_updated));
+ project_dialog->connect("project_created", callable_mp(this, &ProjectManager::_on_project_created));
+ add_child(project_dialog);
- run_error_diag = memnew(AcceptDialog);
- run_error_diag->set_title(TTR("Can't run project"));
- add_child(run_error_diag);
+ error_dialog = memnew(AcceptDialog);
+ error_dialog->set_title(TTR("Error"));
+ add_child(error_dialog);
- dialog_error = memnew(AcceptDialog);
- add_child(dialog_error);
-
- if (asset_library) {
- open_templates = memnew(ConfirmationDialog);
- open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?"));
- open_templates->set_ok_button_text(TTR("Open Asset Library"));
- open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library));
- add_child(open_templates);
- }
-
- about = memnew(EditorAbout);
- add_child(about);
+ about_dialog = memnew(EditorAbout);
+ add_child(about_dialog);
}
// Tag management.
@@ -1370,7 +1514,7 @@ ProjectManager::ProjectManager() {
String autoscan_path = EDITOR_GET("filesystem/directories/autoscan_project_path");
if (!autoscan_path.is_empty()) {
if (dir_access->dir_exists(autoscan_path)) {
- _project_list->find_projects(autoscan_path);
+ project_list->find_projects(autoscan_path);
scanned_for_projects = true;
} else {
Error error = dir_access->make_dir_recursive(autoscan_path);
@@ -1381,7 +1525,7 @@ ProjectManager::ProjectManager() {
}
if (!scanned_for_projects) {
- _project_list->update_project_list();
+ project_list->update_project_list();
}
}
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 7ed8df8a9da..1c829e971d2 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -41,11 +41,15 @@ class EditorFileDialog;
class HFlowContainer;
class LineEdit;
class LinkButton;
+class MarginContainer;
class OptionButton;
class PanelContainer;
class ProjectDialog;
class ProjectList;
+class QuickSettingsDialog;
+class RichTextLabel;
class TabContainer;
+class VBoxContainer;
class ProjectManager : public Control {
GDCLASS(ProjectManager, Control);
@@ -63,42 +67,79 @@ class ProjectManager : public Control {
// Main layout.
+ Ref theme;
+
void _update_size_limits();
+ void _update_theme(bool p_skip_creation = false);
+ MarginContainer *root_container = nullptr;
Panel *background_panel = nullptr;
- Button *about_btn = nullptr;
- LinkButton *version_btn = nullptr;
+ VBoxContainer *main_vbox = nullptr;
- ConfirmationDialog *open_templates = nullptr;
- EditorAbout *about = nullptr;
+ HBoxContainer *title_bar = nullptr;
+ Button *title_bar_logo = nullptr;
+ HBoxContainer *main_view_toggles = nullptr;
+ Button *quick_settings_button = nullptr;
- void _show_about();
- void _version_button_pressed();
+ enum MainViewTab {
+ MAIN_VIEW_PROJECTS,
+ MAIN_VIEW_ASSETLIB,
+ MAIN_VIEW_MAX
+ };
+
+ MainViewTab current_main_view = MAIN_VIEW_PROJECTS;
+ HashMap main_view_map;
+ HashMap main_view_toggle_map;
+
+ PanelContainer *main_view_container = nullptr;
+ Ref main_view_toggles_group;
+
+ Button *_add_main_view(MainViewTab p_id, const String &p_name, const Ref &p_icon, Control *p_view_control);
+ void _set_main_view_icon(MainViewTab p_id, const Ref &p_icon);
+ void _select_main_view(int p_id);
- TabContainer *tabs = nullptr;
VBoxContainer *local_projects_vb = nullptr;
EditorAssetLibrary *asset_library = nullptr;
- void _on_tab_changed(int p_tab);
- void _open_asset_library();
+ EditorAbout *about_dialog = nullptr;
+
+ void _show_about();
+ void _open_asset_library_confirmed();
+
+ AcceptDialog *error_dialog = nullptr;
+
+ void _show_error(const String &p_message, const Size2 &p_min_size = Size2());
+ void _dim_window();
// Quick settings.
- OptionButton *language_btn = nullptr;
- ConfirmationDialog *restart_required_dialog = nullptr;
+ QuickSettingsDialog *quick_settings_dialog = nullptr;
- void _language_selected(int p_id);
- void _restart_confirm();
- void _dim_window();
+ void _show_quick_settings();
+ void _restart_confirmed();
+
+ // Footer.
+
+ LinkButton *version_btn = nullptr;
+
+ void _version_button_pressed();
// Project list.
- ProjectList *_project_list = nullptr;
+ VBoxContainer *empty_list_placeholder = nullptr;
+ Button *empty_list_create_project = nullptr;
+ Button *empty_list_import_project = nullptr;
+ Button *empty_list_open_assetlib = nullptr;
+ Label *empty_list_online_warning = nullptr;
+
+ void _update_list_placeholder();
+
+ ProjectList *project_list = nullptr;
LineEdit *search_box = nullptr;
Label *loading_label = nullptr;
OptionButton *filter_option = nullptr;
- PanelContainer *search_panel = nullptr;
+ PanelContainer *project_list_panel = nullptr;
Button *create_btn = nullptr;
Button *import_btn = nullptr;
@@ -121,11 +162,7 @@ class ProjectManager : public Control {
ConfirmationDialog *multi_open_ask = nullptr;
ConfirmationDialog *multi_run_ask = nullptr;
- HBoxContainer *settings_hb = nullptr;
-
- AcceptDialog *run_error_diag = nullptr;
- AcceptDialog *dialog_error = nullptr;
- ProjectDialog *npdialog = nullptr;
+ ProjectDialog *project_dialog = nullptr;
void _scan_projects();
void _run_project();
diff --git a/editor/project_manager/quick_settings_dialog.cpp b/editor/project_manager/quick_settings_dialog.cpp
new file mode 100644
index 00000000000..255b15f7f67
--- /dev/null
+++ b/editor/project_manager/quick_settings_dialog.cpp
@@ -0,0 +1,306 @@
+/**************************************************************************/
+/* quick_settings_dialog.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 "quick_settings_dialog.h"
+
+#include "core/config/project_settings.h"
+#include "core/string/translation.h"
+#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
+#include "editor/themes/editor_scale.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/label.h"
+#include "scene/gui/margin_container.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/panel_container.h"
+
+void QuickSettingsDialog::_fetch_setting_values() {
+ editor_languages.clear();
+ editor_themes.clear();
+ editor_scales.clear();
+ editor_network_modes.clear();
+
+ {
+ List editor_settings_properties;
+ EditorSettings::get_singleton()->get_property_list(&editor_settings_properties);
+
+ for (const PropertyInfo &pi : editor_settings_properties) {
+ if (pi.name == "interface/editor/editor_language") {
+ editor_languages = pi.hint_string.split(",");
+ } else if (pi.name == "interface/theme/preset") {
+ editor_themes = pi.hint_string.split(",");
+ } else if (pi.name == "interface/editor/display_scale") {
+ editor_scales = pi.hint_string.split(",");
+ } else if (pi.name == "network/connection/network_mode") {
+ editor_network_modes = pi.hint_string.split(",");
+ }
+ }
+ }
+}
+
+void QuickSettingsDialog::_update_current_values() {
+ // Language options.
+ {
+ const String current_lang = EDITOR_GET("interface/editor/editor_language");
+
+ for (int i = 0; i < editor_languages.size(); i++) {
+ const String &lang_value = editor_languages[i];
+ if (current_lang == lang_value) {
+ language_option_button->set_text(current_lang);
+ language_option_button->select(i);
+ }
+ }
+ }
+
+ // Theme options.
+ {
+ const String current_theme = EDITOR_GET("interface/theme/preset");
+
+ for (int i = 0; i < editor_themes.size(); i++) {
+ const String &theme_value = editor_themes[i];
+ if (current_theme == theme_value) {
+ theme_option_button->set_text(current_theme);
+ theme_option_button->select(i);
+
+ custom_theme_label->set_visible(current_theme == "Custom");
+ }
+ }
+ }
+
+ // Scale options.
+ {
+ const int current_scale = EDITOR_GET("interface/editor/display_scale");
+
+ for (int i = 0; i < editor_scales.size(); i++) {
+ const String &scale_value = editor_scales[i];
+ if (current_scale == i) {
+ scale_option_button->set_text(scale_value);
+ scale_option_button->select(i);
+ }
+ }
+ }
+
+ // Network mode options.
+ {
+ const int current_network_mode = EDITOR_GET("network/connection/network_mode");
+
+ for (int i = 0; i < editor_network_modes.size(); i++) {
+ const String &network_mode_value = editor_network_modes[i];
+ if (current_network_mode == i) {
+ network_mode_option_button->set_text(network_mode_value);
+ network_mode_option_button->select(i);
+ }
+ }
+ }
+}
+
+void QuickSettingsDialog::_add_setting_control(const String &p_text, Control *p_control) {
+ HBoxContainer *container = memnew(HBoxContainer);
+ settings_list->add_child(container);
+
+ Label *label = memnew(Label(p_text));
+ label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ container->add_child(label);
+
+ p_control->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ p_control->set_stretch_ratio(2.0);
+ container->add_child(p_control);
+}
+
+void QuickSettingsDialog::_language_selected(int p_id) {
+ const String selected_language = language_option_button->get_item_metadata(p_id);
+ _set_setting_value("interface/editor/editor_language", selected_language, true);
+}
+
+void QuickSettingsDialog::_theme_selected(int p_id) {
+ const String selected_theme = theme_option_button->get_item_text(p_id);
+ _set_setting_value("interface/theme/preset", selected_theme);
+
+ custom_theme_label->set_visible(selected_theme == "Custom");
+}
+
+void QuickSettingsDialog::_scale_selected(int p_id) {
+ _set_setting_value("interface/editor/display_scale", p_id, true);
+}
+
+void QuickSettingsDialog::_network_mode_selected(int p_id) {
+ _set_setting_value("network/connection/network_mode", p_id);
+}
+
+void QuickSettingsDialog::_set_setting_value(const String &p_setting, const Variant &p_value, bool p_restart_required) {
+ EditorSettings::get_singleton()->set(p_setting, p_value);
+ EditorSettings::get_singleton()->notify_changes();
+ EditorSettings::get_singleton()->save();
+
+ if (p_restart_required) {
+ restart_required_label->show();
+
+ if (!restart_required_button) {
+ restart_required_button = add_button(TTR("Restart Now"), !GLOBAL_GET("gui/common/swap_cancel_ok"));
+ restart_required_button->connect("pressed", callable_mp(this, &QuickSettingsDialog::_request_restart));
+ }
+ }
+}
+
+void QuickSettingsDialog::_request_restart() {
+ emit_signal("restart_required");
+}
+
+void QuickSettingsDialog::update_size_limits(const Size2 &p_max_popup_size) {
+ language_option_button->get_popup()->set_max_size(p_max_popup_size);
+}
+
+void QuickSettingsDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ settings_list_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("Background"), EditorStringName(EditorStyles)));
+
+ restart_required_label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
+ custom_theme_label->add_theme_color_override("font_color", get_theme_color(SNAME("font_placeholder_color"), EditorStringName(Editor)));
+ } break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (is_visible()) {
+ _update_current_values();
+ }
+ } break;
+ }
+}
+
+void QuickSettingsDialog::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("restart_required"));
+}
+
+QuickSettingsDialog::QuickSettingsDialog() {
+ set_title(TTR("Quick Settings"));
+ set_ok_button_text(TTR("Close"));
+
+ VBoxContainer *main_vbox = memnew(VBoxContainer);
+ add_child(main_vbox);
+ main_vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
+
+ // Settings grid.
+ {
+ _fetch_setting_values();
+
+ settings_list_panel = memnew(PanelContainer);
+ main_vbox->add_child(settings_list_panel);
+
+ settings_list = memnew(VBoxContainer);
+ settings_list_panel->add_child(settings_list);
+
+ // Language options.
+ {
+ language_option_button = memnew(OptionButton);
+ language_option_button->set_fit_to_longest_item(false);
+ language_option_button->connect("item_selected", callable_mp(this, &QuickSettingsDialog::_language_selected));
+
+ for (int i = 0; i < editor_languages.size(); i++) {
+ const String &lang_value = editor_languages[i];
+ String lang_name = TranslationServer::get_singleton()->get_locale_name(lang_value);
+ language_option_button->add_item(vformat("[%s] %s", lang_value, lang_name), i);
+ language_option_button->set_item_metadata(i, lang_value);
+ }
+
+ _add_setting_control(TTR("Language"), language_option_button);
+ }
+
+ // Theme options.
+ {
+ theme_option_button = memnew(OptionButton);
+ theme_option_button->set_fit_to_longest_item(false);
+ theme_option_button->connect("item_selected", callable_mp(this, &QuickSettingsDialog::_theme_selected));
+
+ for (int i = 0; i < editor_themes.size(); i++) {
+ const String &theme_value = editor_themes[i];
+ theme_option_button->add_item(theme_value, i);
+ }
+
+ _add_setting_control(TTR("Interface Theme"), theme_option_button);
+
+ custom_theme_label = memnew(Label(TTR("Custom preset can be further configured in the editor.")));
+ custom_theme_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
+ custom_theme_label->set_custom_minimum_size(Size2(220, 0) * EDSCALE);
+ custom_theme_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
+ custom_theme_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ custom_theme_label->set_stretch_ratio(2.0);
+ custom_theme_label->hide();
+ settings_list->add_child(custom_theme_label);
+ }
+
+ // Scale options.
+ {
+ scale_option_button = memnew(OptionButton);
+ scale_option_button->set_fit_to_longest_item(false);
+ scale_option_button->connect("item_selected", callable_mp(this, &QuickSettingsDialog::_scale_selected));
+
+ for (int i = 0; i < editor_scales.size(); i++) {
+ const String &scale_value = editor_scales[i];
+ scale_option_button->add_item(scale_value, i);
+ }
+
+ _add_setting_control(TTR("Display Scale"), scale_option_button);
+ }
+
+ // Network mode options.
+ {
+ network_mode_option_button = memnew(OptionButton);
+ network_mode_option_button->set_fit_to_longest_item(false);
+ network_mode_option_button->connect("item_selected", callable_mp(this, &QuickSettingsDialog::_network_mode_selected));
+
+ for (int i = 0; i < editor_network_modes.size(); i++) {
+ const String &network_mode_value = editor_network_modes[i];
+ network_mode_option_button->add_item(network_mode_value, i);
+ }
+
+ _add_setting_control(TTR("Network Mode"), network_mode_option_button);
+ }
+
+ _update_current_values();
+
+#ifdef ANDROID_ENABLED
+ // The language selection dropdown doesn't work on Android (as the setting isn't saved), see GH-60353.
+ // Also, the dropdown it spawns is very tall and can't be scrolled without a hardware mouse.
+ language_option_button->hide();
+ scale_option_button->hide();
+#endif
+ }
+
+ // Restart required panel.
+ {
+ restart_required_label = memnew(Label(TTR("Settings changed! The project manager must be restarted for changes to take effect.")));
+ restart_required_label->set_custom_minimum_size(Size2(560, 0) * EDSCALE);
+ restart_required_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
+ restart_required_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ restart_required_label->hide();
+ main_vbox->add_child(restart_required_label);
+ }
+}
diff --git a/editor/project_manager/quick_settings_dialog.h b/editor/project_manager/quick_settings_dialog.h
new file mode 100644
index 00000000000..c4c4e601c93
--- /dev/null
+++ b/editor/project_manager/quick_settings_dialog.h
@@ -0,0 +1,87 @@
+/**************************************************************************/
+/* quick_settings_dialog.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 QUICK_SETTINGS_DIALOG_H
+#define QUICK_SETTINGS_DIALOG_H
+
+#include "scene/gui/dialogs.h"
+
+class Button;
+class Label;
+class MarginContainer;
+class OptionButton;
+class PanelContainer;
+class VBoxContainer;
+
+class QuickSettingsDialog : public AcceptDialog {
+ GDCLASS(QuickSettingsDialog, AcceptDialog);
+
+ Vector editor_languages;
+ Vector editor_themes;
+ Vector editor_scales;
+ Vector editor_network_modes;
+
+ void _fetch_setting_values();
+ void _update_current_values();
+
+ PanelContainer *settings_list_panel = nullptr;
+ VBoxContainer *settings_list = nullptr;
+
+ void _add_setting_control(const String &p_text, Control *p_control);
+
+ OptionButton *language_option_button = nullptr;
+ OptionButton *theme_option_button = nullptr;
+ OptionButton *scale_option_button = nullptr;
+ OptionButton *network_mode_option_button = nullptr;
+
+ Label *custom_theme_label = nullptr;
+
+ void _language_selected(int p_id);
+ void _theme_selected(int p_id);
+ void _scale_selected(int p_id);
+ void _network_mode_selected(int p_id);
+ void _set_setting_value(const String &p_setting, const Variant &p_value, bool p_restart_required = false);
+
+ Label *restart_required_label = nullptr;
+ Button *restart_required_button = nullptr;
+
+ void _request_restart();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void update_size_limits(const Size2 &p_max_popup_size);
+
+ QuickSettingsDialog();
+};
+
+#endif // QUICK_SETTINGS_DIALOG_H
diff --git a/editor/themes/editor_fonts.cpp b/editor/themes/editor_fonts.cpp
index ee613877027..c13ee6e6b0b 100644
--- a/editor/themes/editor_fonts.cpp
+++ b/editor/themes/editor_fonts.cpp
@@ -370,6 +370,9 @@ void editor_register_fonts(const Ref &p_theme) {
Ref italic_fc = default_fc->duplicate();
italic_fc->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
+ Ref bold_italic_fc = bold_fc->duplicate();
+ bold_italic_fc->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
+
// Setup theme.
p_theme->set_default_font(default_fc); // Default theme font config.
@@ -385,13 +388,19 @@ void editor_register_fonts(const Ref &p_theme) {
p_theme->set_font("main_bold_msdf", EditorStringName(EditorFonts), bold_fc_msdf);
p_theme->set_font_size("bold_size", EditorStringName(EditorFonts), default_font_size);
+ p_theme->set_font("italic", EditorStringName(EditorFonts), italic_fc);
+ p_theme->set_font_size("italic_size", EditorStringName(EditorFonts), default_font_size);
+
// Title font.
p_theme->set_font("title", EditorStringName(EditorFonts), bold_fc);
p_theme->set_font_size("title_size", EditorStringName(EditorFonts), default_font_size + 1 * EDSCALE);
- p_theme->set_font("main_button_font", EditorStringName(EditorFonts), bold_fc);
- p_theme->set_font_size("main_button_font_size", EditorStringName(EditorFonts), default_font_size + 1 * EDSCALE);
+ p_theme->set_type_variation("MainScreenButton", "Button");
+ p_theme->set_font("font", "MainScreenButton", bold_fc);
+ p_theme->set_font_size("font_size", "MainScreenButton", default_font_size + 2 * EDSCALE);
+
+ // Labels.
p_theme->set_font("font", "Label", default_fc);
@@ -407,6 +416,11 @@ void editor_register_fonts(const Ref &p_theme) {
p_theme->set_font("font", "HeaderLarge", bold_fc);
p_theme->set_font_size("font_size", "HeaderLarge", default_font_size + 3 * EDSCALE);
+ p_theme->set_font("normal_font", "RichTextLabel", default_fc);
+ p_theme->set_font("bold_font", "RichTextLabel", bold_fc);
+ p_theme->set_font("italics_font", "RichTextLabel", italic_fc);
+ p_theme->set_font("bold_italics_font", "RichTextLabel", bold_italic_fc);
+
// Documentation fonts
p_theme->set_font_size("doc_size", EditorStringName(EditorFonts), int(EDITOR_GET("text_editor/help/help_font_size")) * EDSCALE);
p_theme->set_font("doc", EditorStringName(EditorFonts), default_fc);
diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp
index bccfe6d7866..d89bbb72232 100644
--- a/editor/themes/editor_theme_manager.cpp
+++ b/editor/themes/editor_theme_manager.cpp
@@ -1590,7 +1590,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref &p_the
void EditorThemeManager::_populate_editor_styles(const Ref &p_theme, ThemeConfiguration &p_config) {
// Project manager.
{
- p_theme->set_stylebox("search_panel", "ProjectManager", p_config.tree_panel_style);
+ p_theme->set_stylebox("project_list", "ProjectManager", p_config.tree_panel_style);
p_theme->set_constant("sidebar_button_icon_separation", "ProjectManager", int(6 * EDSCALE));
// ProjectTag.
@@ -1769,6 +1769,28 @@ void EditorThemeManager::_populate_editor_styles(const Ref &p_theme
p_theme->set_stylebox("pressed", "EditorLogFilterButton", editor_log_button_pressed);
}
+ // Buttons styles that stand out against the panel background (e.g. AssetLib).
+ {
+ p_theme->set_type_variation("PanelBackgroundButton", "Button");
+
+ Ref panel_button_style = p_config.button_style->duplicate();
+ panel_button_style->set_bg_color(p_config.base_color.lerp(p_config.mono_color, 0.08));
+
+ Ref panel_button_style_hover = p_config.button_style_hover->duplicate();
+ panel_button_style_hover->set_bg_color(p_config.base_color.lerp(p_config.mono_color, 0.16));
+
+ Ref panel_button_style_pressed = p_config.button_style_pressed->duplicate();
+ panel_button_style_pressed->set_bg_color(p_config.base_color.lerp(p_config.mono_color, 0.20));
+
+ Ref panel_button_style_disabled = p_config.button_style_disabled->duplicate();
+ panel_button_style_disabled->set_bg_color(p_config.disabled_bg_color);
+
+ p_theme->set_stylebox("normal", "PanelBackgroundButton", panel_button_style);
+ p_theme->set_stylebox("hover", "PanelBackgroundButton", panel_button_style_hover);
+ p_theme->set_stylebox("pressed", "PanelBackgroundButton", panel_button_style_pressed);
+ p_theme->set_stylebox("disabled", "PanelBackgroundButton", panel_button_style_disabled);
+ }
+
// Top bar selectors.
{
p_theme->set_type_variation("TopBarOptionButton", "OptionButton");
]