Path: blob/master/editor/settings/editor_build_profile.cpp
9896 views
/**************************************************************************/1/* editor_build_profile.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "editor_build_profile.h"3132#include "core/config/project_settings.h"33#include "core/io/json.h"34#include "editor/editor_node.h"35#include "editor/editor_string_names.h"36#include "editor/file_system/editor_file_system.h"37#include "editor/file_system/editor_paths.h"38#include "editor/gui/editor_file_dialog.h"39#include "editor/settings/editor_settings.h"40#include "editor/themes/editor_scale.h"41#include "scene/gui/line_edit.h"42#include "scene/gui/separator.h"4344#include "modules/modules_enabled.gen.h" // For mono.4546const char *EditorBuildProfile::build_option_identifiers[BUILD_OPTION_MAX] = {47// This maps to SCons build options.48"disable_3d",49"disable_navigation_2d",50"disable_navigation_3d",51"disable_xr",52"module_openxr_enabled",53"wayland",54"x11",55"rendering_device", // FIXME: There's no scons option to disable rendering device.56"forward_plus_renderer",57"forward_mobile_renderer",58"vulkan",59"d3d12",60"metal",61"opengl3",62"disable_physics_2d",63"module_godot_physics_2d_enabled",64"disable_physics_3d",65"module_godot_physics_3d_enabled",66"module_jolt_physics_enabled",67"module_text_server_fb_enabled",68"module_text_server_adv_enabled",69"module_freetype_enabled",70"brotli",71"graphite",72"module_msdfgen_enabled",73};7475const bool EditorBuildProfile::build_option_disabled_by_default[BUILD_OPTION_MAX] = {76// This maps to SCons build options.77false, // 3D78false, // NAVIGATION_2D79false, // NAVIGATION_3D80false, // XR81false, // OPENXR82false, // WAYLAND83false, // X1184false, // RENDERING_DEVICE85false, // FORWARD_RENDERER86false, // MOBILE_RENDERER87false, // VULKAN88false, // D3D1289false, // METAL90false, // OPENGL91false, // PHYSICS_2D92false, // PHYSICS_GODOT_2D93false, // PHYSICS_3D94false, // PHYSICS_GODOT_3D95false, // PHYSICS_JOLT96true, // TEXT_SERVER_FALLBACK97false, // TEXT_SERVER_ADVANCED98false, // DYNAMIC_FONTS99false, // WOFF2_FONTS100false, // GRAPHITE_FONTS101false, // MSDFGEN102};103104const bool EditorBuildProfile::build_option_disable_values[BUILD_OPTION_MAX] = {105// This maps to SCons build options.106true, // 3D107true, // NAVIGATION_2D108true, // NAVIGATION_3D109true, // XR110false, // OPENXR111false, // WAYLAND112false, // X11113false, // RENDERING_DEVICE114false, // FORWARD_RENDERER115false, // MOBILE_RENDERER116false, // VULKAN117false, // D3D12118false, // METAL119false, // OPENGL120true, // PHYSICS_2D121false, // PHYSICS_GODOT_2D122true, // PHYSICS_3D123false, // PHYSICS_GODOT_3D124false, // PHYSICS_JOLT125false, // TEXT_SERVER_FALLBACK126false, // TEXT_SERVER_ADVANCED127false, // DYNAMIC_FONTS128false, // WOFF2_FONTS129false, // GRAPHITE_FONTS130false, // MSDFGEN131};132133// Options that require some resource explicitly asking for them when detecting from the project.134const bool EditorBuildProfile::build_option_explicit_use[BUILD_OPTION_MAX] = {135false, // 3D136false, // NAVIGATION_2D137false, // NAVIGATION_3D138false, // XR139false, // OPENXR140false, // WAYLAND141false, // X11142false, // RENDERING_DEVICE143false, // FORWARD_RENDERER144false, // MOBILE_RENDERER145false, // VULKAN146false, // D3D12147false, // METAL148false, // OPENGL149false, // PHYSICS_2D150false, // PHYSICS_GODOT_2D151false, // PHYSICS_3D152false, // PHYSICS_GODOT_3D153false, // PHYSICS_JOLT154false, // TEXT_SERVER_FALLBACK155false, // TEXT_SERVER_ADVANCED156false, // DYNAMIC_FONTS157false, // WOFF2_FONTS158false, // GRAPHITE_FONTS159true, // MSDFGEN160};161162const EditorBuildProfile::BuildOptionCategory EditorBuildProfile::build_option_category[BUILD_OPTION_MAX] = {163BUILD_OPTION_CATEGORY_GENERAL, // 3D164BUILD_OPTION_CATEGORY_GENERAL, // NAVIGATION_2D165BUILD_OPTION_CATEGORY_GENERAL, // NAVIGATION_3D166BUILD_OPTION_CATEGORY_GENERAL, // XR167BUILD_OPTION_CATEGORY_GENERAL, // OPENXR168BUILD_OPTION_CATEGORY_GENERAL, // WAYLAND169BUILD_OPTION_CATEGORY_GENERAL, // X11170BUILD_OPTION_CATEGORY_GRAPHICS, // RENDERING_DEVICE171BUILD_OPTION_CATEGORY_GRAPHICS, // FORWARD_RENDERER172BUILD_OPTION_CATEGORY_GRAPHICS, // MOBILE_RENDERER173BUILD_OPTION_CATEGORY_GRAPHICS, // VULKAN174BUILD_OPTION_CATEGORY_GRAPHICS, // D3D12175BUILD_OPTION_CATEGORY_GRAPHICS, // METAL176BUILD_OPTION_CATEGORY_GRAPHICS, // OPENGL177BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_2D178BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_GODOT_2D179BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_3D180BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_GODOT_3D181BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_JOLT182BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_FALLBACK183BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_ADVANCED184BUILD_OPTION_CATEGORY_TEXT_SERVER, // DYNAMIC_FONTS185BUILD_OPTION_CATEGORY_TEXT_SERVER, // WOFF2_FONTS186BUILD_OPTION_CATEGORY_TEXT_SERVER, // GRAPHITE_FONTS187BUILD_OPTION_CATEGORY_TEXT_SERVER, // MSDFGEN188};189190// Can't assign HashMaps to a HashMap at declaration, so do it in the class' constructor.191HashMap<EditorBuildProfile::BuildOption, HashMap<String, LocalVector<Variant>>> EditorBuildProfile::build_option_settings = {};192193/* clang-format off */194195const HashMap<EditorBuildProfile::BuildOption, LocalVector<EditorBuildProfile::BuildOption>> EditorBuildProfile::build_option_dependencies = {196{ BUILD_OPTION_OPENXR, {197BUILD_OPTION_XR,198} },199{ BUILD_OPTION_FORWARD_RENDERER, {200BUILD_OPTION_RENDERING_DEVICE,201} },202{ BUILD_OPTION_MOBILE_RENDERER, {203BUILD_OPTION_RENDERING_DEVICE,204} },205{ BUILD_OPTION_VULKAN, {206BUILD_OPTION_FORWARD_RENDERER,207BUILD_OPTION_MOBILE_RENDERER,208} },209{ BUILD_OPTION_D3D12, {210BUILD_OPTION_FORWARD_RENDERER,211BUILD_OPTION_MOBILE_RENDERER,212} },213{ BUILD_OPTION_METAL, {214BUILD_OPTION_FORWARD_RENDERER,215BUILD_OPTION_MOBILE_RENDERER,216} },217{ BUILD_OPTION_PHYSICS_GODOT_2D, {218BUILD_OPTION_PHYSICS_2D,219} },220{ BUILD_OPTION_PHYSICS_GODOT_3D, {221BUILD_OPTION_PHYSICS_3D,222} },223{ BUILD_OPTION_PHYSICS_JOLT, {224BUILD_OPTION_PHYSICS_3D,225} },226{ BUILD_OPTION_DYNAMIC_FONTS, {227BUILD_OPTION_TEXT_SERVER_ADVANCED,228} },229{ BUILD_OPTION_WOFF2_FONTS, {230BUILD_OPTION_TEXT_SERVER_ADVANCED,231} },232{ BUILD_OPTION_GRAPHITE_FONTS, {233BUILD_OPTION_TEXT_SERVER_ADVANCED,234} },235};236237const HashMap<EditorBuildProfile::BuildOption, LocalVector<String>> EditorBuildProfile::build_option_classes = {238{ BUILD_OPTION_3D, {239"Node3D",240} },241{ BUILD_OPTION_NAVIGATION_2D, {242"NavigationAgent2D",243"NavigationLink2D",244"NavigationMeshSourceGeometryData2D",245"NavigationObstacle2D"246"NavigationPolygon",247"NavigationRegion2D",248} },249{ BUILD_OPTION_NAVIGATION_3D, {250"NavigationAgent3D",251"NavigationLink3D",252"NavigationMeshSourceGeometryData3D",253"NavigationObstacle3D",254"NavigationRegion3D",255} },256{ BUILD_OPTION_XR, {257"XRBodyModifier3D",258"XRBodyTracker",259"XRControllerTracker",260"XRFaceModifier3D",261"XRFaceTracker",262"XRHandModifier3D",263"XRHandTracker",264"XRInterface",265"XRInterfaceExtension",266"XRNode3D",267"XROrigin3D",268"XRPose",269"XRPositionalTracker",270"XRServer",271"XRTracker",272"XRVRS",273} },274{ BUILD_OPTION_RENDERING_DEVICE, {275"RenderingDevice",276} },277{ BUILD_OPTION_PHYSICS_2D, {278"CollisionObject2D",279"CollisionPolygon2D",280"CollisionShape2D",281"Joint2D",282"PhysicsServer2D",283"PhysicsServer2DManager",284"ShapeCast2D",285"RayCast2D",286"TouchScreenButton",287} },288{ BUILD_OPTION_PHYSICS_3D, {289"CollisionObject3D",290"CollisionPolygon3D",291"CollisionShape3D",292"CSGShape3D",293"GPUParticlesAttractor3D",294"GPUParticlesCollision3D",295"Joint3D",296"PhysicalBoneSimulator3D",297"PhysicsServer3D",298"PhysicsServer3DManager",299"PhysicsServer3DRenderingServerHandler",300"RayCast3D",301"SoftBody3D",302"SpringArm3D",303"SpringBoneCollision3D",304"SpringBoneSimulator3D",305"VehicleWheel3D",306} },307{ BUILD_OPTION_TEXT_SERVER_ADVANCED, {308"CanvasItem",309"Label3D",310"TextServerAdvanced",311} },312};313314/* clang-format on */315316void EditorBuildProfile::set_disable_class(const StringName &p_class, bool p_disabled) {317if (p_disabled) {318disabled_classes.insert(p_class);319} else {320disabled_classes.erase(p_class);321}322}323324bool EditorBuildProfile::is_class_disabled(const StringName &p_class) const {325if (p_class == StringName()) {326return false;327}328return disabled_classes.has(p_class) || is_class_disabled(ClassDB::get_parent_class_nocheck(p_class));329}330331void EditorBuildProfile::set_item_collapsed(const StringName &p_class, bool p_collapsed) {332if (p_collapsed) {333collapsed_classes.insert(p_class);334} else {335collapsed_classes.erase(p_class);336}337}338339bool EditorBuildProfile::is_item_collapsed(const StringName &p_class) const {340return collapsed_classes.has(p_class);341}342343void EditorBuildProfile::set_disable_build_option(BuildOption p_build_option, bool p_disable) {344ERR_FAIL_INDEX(p_build_option, BUILD_OPTION_MAX);345build_options_disabled[p_build_option] = p_disable;346}347348void EditorBuildProfile::clear_disabled_classes() {349disabled_classes.clear();350collapsed_classes.clear();351}352353bool EditorBuildProfile::is_build_option_disabled(BuildOption p_build_option) const {354ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, false);355return build_options_disabled[p_build_option];356}357358bool EditorBuildProfile::get_build_option_disable_value(BuildOption p_build_option) {359ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, false);360return build_option_disable_values[p_build_option];361}362363bool EditorBuildProfile::get_build_option_explicit_use(BuildOption p_build_option) {364ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, false);365return build_option_explicit_use[p_build_option];366}367368void EditorBuildProfile::reset_build_options() {369for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) {370build_options_disabled[i] = build_option_disabled_by_default[i];371}372}373374void EditorBuildProfile::set_force_detect_classes(const String &p_classes) {375force_detect_classes = p_classes;376}377378String EditorBuildProfile::get_force_detect_classes() const {379return force_detect_classes;380}381382String EditorBuildProfile::get_build_option_name(BuildOption p_build_option) {383ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, String());384const char *build_option_names[BUILD_OPTION_MAX] = {385TTRC("3D Engine"),386TTRC("Navigation (2D)"),387TTRC("Navigation (3D)"),388TTRC("XR"),389TTRC("OpenXR"),390TTRC("Wayland"),391TTRC("X11"),392TTRC("RenderingDevice"),393TTRC("Forward+ Renderer"),394TTRC("Mobile Renderer"),395TTRC("Vulkan"),396TTRC("D3D12"),397TTRC("Metal"),398TTRC("OpenGL"),399TTRC("Physics Server (2D)"),400TTRC("Godot Physics (2D)"),401TTRC("Physics Server (3D)"),402TTRC("Godot Physics (3D)"),403TTRC("Jolt Physics"),404TTRC("Text Server: Fallback"),405TTRC("Text Server: Advanced"),406TTRC("TTF, OTF, Type 1, WOFF1 Fonts"),407TTRC("WOFF2 Fonts"),408TTRC("SIL Graphite Fonts"),409TTRC("Multi-channel Signed Distance Field Font Rendering"),410};411return TTRGET(build_option_names[p_build_option]);412}413414String EditorBuildProfile::get_build_option_description(BuildOption p_build_option) {415ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, String());416417const char *build_option_descriptions[BUILD_OPTION_MAX] = {418TTRC("3D Nodes as well as RenderingServer access to 3D features."),419TTRC("Navigation Server and capabilities for 2D."),420TTRC("Navigation Server and capabilities for 3D."),421TTRC("XR (AR and VR)."),422TTRC("OpenXR standard implementation (requires XR to be enabled)."),423TTRC("Wayland display (Linux only)."),424TTRC("X11 display (Linux only)."),425TTRC("RenderingDevice based rendering (if disabled, the OpenGL backend is required)."),426TTRC("Forward+ renderer for advanced 3D graphics."),427TTRC("Mobile renderer for less advanced 3D graphics."),428TTRC("Vulkan backend of RenderingDevice."),429TTRC("Direct3D 12 backend of RenderingDevice."),430TTRC("Metal backend of RenderingDevice (Apple arm64 only)."),431TTRC("OpenGL backend (if disabled, the RenderingDevice backend is required)."),432TTRC("Physics Server and capabilities for 2D."),433TTRC("Godot Physics backend (2D)."),434TTRC("Physics Server and capabilities for 3D."),435TTRC("Godot Physics backend (3D)."),436TTRC("Jolt Physics backend (3D only)."),437TTRC("Fallback implementation of Text Server\nSupports basic text layouts."),438TTRC("Text Server implementation powered by ICU and HarfBuzz libraries.\nSupports complex text layouts, BiDi, and contextual OpenType font features."),439TTRC("TrueType, OpenType, Type 1, and WOFF1 font format support using FreeType library (if disabled, WOFF2 support is also disabled)."),440TTRC("WOFF2 font format support using FreeType and Brotli libraries."),441TTRC("SIL Graphite smart font technology support (supported by Advanced Text Server only)."),442TTRC("Multi-channel signed distance field font rendering support using msdfgen library (pre-rendered MSDF fonts can be used even if this option disabled)."),443};444445return TTRGET(build_option_descriptions[p_build_option]);446}447448String EditorBuildProfile::get_build_option_identifier(BuildOption p_build_option) {449ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, String());450return build_option_identifiers[p_build_option];451}452453EditorBuildProfile::BuildOptionCategory EditorBuildProfile::get_build_option_category(BuildOption p_build_option) {454ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, BUILD_OPTION_CATEGORY_GENERAL);455return build_option_category[p_build_option];456}457458LocalVector<EditorBuildProfile::BuildOption> EditorBuildProfile::get_build_option_dependencies(BuildOption p_build_option) {459ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, LocalVector<EditorBuildProfile::BuildOption>());460return build_option_dependencies.has(p_build_option) ? build_option_dependencies[p_build_option] : LocalVector<EditorBuildProfile::BuildOption>();461}462463HashMap<String, LocalVector<Variant>> EditorBuildProfile::get_build_option_settings(BuildOption p_build_option) {464ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, (HashMap<String, LocalVector<Variant>>()));465return build_option_settings.has(p_build_option) ? build_option_settings[p_build_option] : HashMap<String, LocalVector<Variant>>();466}467468LocalVector<String> EditorBuildProfile::get_build_option_classes(BuildOption p_build_option) {469ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, LocalVector<String>());470return build_option_classes.has(p_build_option) ? build_option_classes[p_build_option] : LocalVector<String>();471}472473String EditorBuildProfile::get_build_option_category_name(BuildOptionCategory p_build_option_category) {474ERR_FAIL_INDEX_V(p_build_option_category, BUILD_OPTION_CATEGORY_MAX, String());475476const char *build_option_subcategories[BUILD_OPTION_CATEGORY_MAX]{477TTRC("General Features:"),478TTRC("Graphics and Rendering:"),479TTRC("Physics Systems:"),480TTRC("Text Rendering and Font Options:"),481};482483return TTRGET(build_option_subcategories[p_build_option_category]);484}485486Error EditorBuildProfile::save_to_file(const String &p_path) {487Dictionary data;488data["type"] = "build_profile";489Array dis_classes;490for (const StringName &E : disabled_classes) {491dis_classes.push_back(String(E));492}493dis_classes.sort();494data["disabled_classes"] = dis_classes;495496Dictionary dis_build_options;497for (int i = 0; i < BUILD_OPTION_MAX; i++) {498if (build_options_disabled[i] != build_option_disabled_by_default[i]) {499if (build_options_disabled[i]) {500dis_build_options[build_option_identifiers[i]] = build_option_disable_values[i];501} else {502dis_build_options[build_option_identifiers[i]] = !build_option_disable_values[i];503}504}505}506507data["disabled_build_options"] = dis_build_options;508509if (!force_detect_classes.is_empty()) {510data["force_detect_classes"] = force_detect_classes;511}512513Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);514ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");515516String text = JSON::stringify(data, "\t");517f->store_string(text);518return OK;519}520521Error EditorBuildProfile::load_from_file(const String &p_path) {522Error err;523String text = FileAccess::get_file_as_string(p_path, &err);524if (err != OK) {525return err;526}527528JSON json;529err = json.parse(text);530if (err != OK) {531ERR_PRINT("Error parsing '" + p_path + "' on line " + itos(json.get_error_line()) + ": " + json.get_error_message());532return ERR_PARSE_ERROR;533}534535Dictionary data = json.get_data();536537if (!data.has("type") || String(data["type"]) != "build_profile") {538ERR_PRINT("Error parsing '" + p_path + "', it's not a build profile.");539return ERR_PARSE_ERROR;540}541542disabled_classes.clear();543544if (data.has("disabled_classes")) {545Array disabled_classes_arr = data["disabled_classes"];546for (int i = 0; i < disabled_classes_arr.size(); i++) {547disabled_classes.insert(disabled_classes_arr[i]);548}549}550551for (int i = 0; i < BUILD_OPTION_MAX; i++) {552build_options_disabled[i] = build_option_disabled_by_default[i];553}554555if (data.has("disabled_build_options")) {556Dictionary disabled_build_options_arr = data["disabled_build_options"];557558for (const KeyValue<Variant, Variant> &kv : disabled_build_options_arr) {559String key = kv.key;560561for (int i = 0; i < BUILD_OPTION_MAX; i++) {562String f = build_option_identifiers[i];563if (f == key) {564build_options_disabled[i] = true;565break;566}567}568}569}570571if (data.has("force_detect_classes")) {572force_detect_classes = data["force_detect_classes"];573}574575return OK;576}577578void EditorBuildProfile::_bind_methods() {579ClassDB::bind_method(D_METHOD("set_disable_class", "class_name", "disable"), &EditorBuildProfile::set_disable_class);580ClassDB::bind_method(D_METHOD("is_class_disabled", "class_name"), &EditorBuildProfile::is_class_disabled);581582ClassDB::bind_method(D_METHOD("set_disable_build_option", "build_option", "disable"), &EditorBuildProfile::set_disable_build_option);583ClassDB::bind_method(D_METHOD("is_build_option_disabled", "build_option"), &EditorBuildProfile::is_build_option_disabled);584585ClassDB::bind_method(D_METHOD("get_build_option_name", "build_option"), &EditorBuildProfile::_get_build_option_name);586587ClassDB::bind_method(D_METHOD("save_to_file", "path"), &EditorBuildProfile::save_to_file);588ClassDB::bind_method(D_METHOD("load_from_file", "path"), &EditorBuildProfile::load_from_file);589590BIND_ENUM_CONSTANT(BUILD_OPTION_3D);591BIND_ENUM_CONSTANT(BUILD_OPTION_NAVIGATION_2D);592BIND_ENUM_CONSTANT(BUILD_OPTION_NAVIGATION_3D);593BIND_ENUM_CONSTANT(BUILD_OPTION_XR);594BIND_ENUM_CONSTANT(BUILD_OPTION_OPENXR);595BIND_ENUM_CONSTANT(BUILD_OPTION_WAYLAND);596BIND_ENUM_CONSTANT(BUILD_OPTION_X11);597BIND_ENUM_CONSTANT(BUILD_OPTION_RENDERING_DEVICE);598BIND_ENUM_CONSTANT(BUILD_OPTION_FORWARD_RENDERER);599BIND_ENUM_CONSTANT(BUILD_OPTION_MOBILE_RENDERER);600BIND_ENUM_CONSTANT(BUILD_OPTION_VULKAN);601BIND_ENUM_CONSTANT(BUILD_OPTION_D3D12);602BIND_ENUM_CONSTANT(BUILD_OPTION_METAL);603BIND_ENUM_CONSTANT(BUILD_OPTION_OPENGL);604BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_2D);605BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_GODOT_2D);606BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_3D);607BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_GODOT_3D);608BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_JOLT);609BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_FALLBACK);610BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_ADVANCED);611BIND_ENUM_CONSTANT(BUILD_OPTION_DYNAMIC_FONTS);612BIND_ENUM_CONSTANT(BUILD_OPTION_WOFF2_FONTS);613BIND_ENUM_CONSTANT(BUILD_OPTION_GRAPHITE_FONTS);614BIND_ENUM_CONSTANT(BUILD_OPTION_MSDFGEN);615BIND_ENUM_CONSTANT(BUILD_OPTION_MAX);616617BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_GENERAL);618BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_GRAPHICS);619BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_PHYSICS);620BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_TEXT_SERVER);621BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_MAX);622}623624EditorBuildProfile::EditorBuildProfile() {625reset_build_options();626627HashMap<String, LocalVector<Variant>> settings_openxr = {628{ "xr/openxr/enabled", { true } },629};630build_option_settings.insert(BUILD_OPTION_OPENXR, settings_openxr);631HashMap<String, LocalVector<Variant>> settings_wayland = {632{ "display/display_server/driver.linuxbsd", { "default", "wayland" } },633};634build_option_settings.insert(BUILD_OPTION_OPENXR, settings_wayland);635HashMap<String, LocalVector<Variant>> settings_x11 = {636{ "display/display_server/driver.linuxbsd", { "default", "x11" } },637};638build_option_settings.insert(BUILD_OPTION_OPENXR, settings_x11);639HashMap<String, LocalVector<Variant>> settings_rd = {640{ "rendering/renderer/rendering_method", { "forward_plus", "mobile" } },641{ "rendering/renderer/rendering_method.mobile", { "forward_plus", "mobile" } },642{ "rendering/renderer/rendering_method.web", { "forward_plus", "mobile" } },643};644build_option_settings.insert(BUILD_OPTION_RENDERING_DEVICE, settings_rd);645HashMap<String, LocalVector<Variant>> settings_vulkan = {646{ "rendering/rendering_device/driver", { "vulkan" } },647{ "rendering/rendering_device/driver.windows", { "vulkan" } },648{ "rendering/rendering_device/driver.linuxbsd", { "vulkan" } },649{ "rendering/rendering_device/driver.android", { "vulkan" } },650{ "rendering/rendering_device/driver.ios", { "vulkan" } },651{ "rendering/rendering_device/driver.macos", { "vulkan" } },652{ "rendering/rendering_device/fallback_to_vulkan", { true } },653};654build_option_settings.insert(BUILD_OPTION_VULKAN, settings_vulkan);655HashMap<String, LocalVector<Variant>> settings_d3d12 = {656{ "rendering/rendering_device/driver", { "d3d12" } },657{ "rendering/rendering_device/driver.windows", { "d3d12" } },658{ "rendering/rendering_device/driver.linuxbsd", { "d3d12" } },659{ "rendering/rendering_device/driver.android", { "d3d12" } },660{ "rendering/rendering_device/driver.ios", { "d3d12" } },661{ "rendering/rendering_device/driver.macos", { "d3d12" } },662{ "rendering/rendering_device/fallback_to_d3d12", { true } },663};664build_option_settings.insert(BUILD_OPTION_VULKAN, settings_vulkan);665HashMap<String, LocalVector<Variant>> settings_metal = {666{ "rendering/rendering_device/driver", { "metal" } },667{ "rendering/rendering_device/driver.ios", { "metal" } },668{ "rendering/rendering_device/driver.macos", { "metal" } },669};670build_option_settings.insert(BUILD_OPTION_METAL, settings_metal);671HashMap<String, LocalVector<Variant>> settings_opengl = {672{ "rendering/renderer/rendering_method", { "gl_compatibility" } },673{ "rendering/renderer/rendering_method.mobile", { "gl_compatibility" } },674{ "rendering/renderer/rendering_method.web", { "gl_compatibility" } },675{ "rendering/rendering_device/fallback_to_opengl3", { true } },676};677build_option_settings.insert(BUILD_OPTION_OPENGL, settings_opengl);678HashMap<String, LocalVector<Variant>> settings_phy_godot_3d = {679{ "physics/3d/physics_engine", { "DEFAULT", "GodotPhysics3D" } },680};681build_option_settings.insert(BUILD_OPTION_PHYSICS_GODOT_3D, settings_phy_godot_3d);682HashMap<String, LocalVector<Variant>> settings_jolt = {683{ "physics/3d/physics_engine", { "Jolt Physics" } },684};685build_option_settings.insert(BUILD_OPTION_PHYSICS_JOLT, settings_jolt);686HashMap<String, LocalVector<Variant>> settings_msdfgen = {687{ "gui/theme/default_font_multichannel_signed_distance_field", { true } },688};689build_option_settings.insert(BUILD_OPTION_MSDFGEN, settings_msdfgen);690}691692//////////////////////////693694void EditorBuildProfileManager::_notification(int p_what) {695switch (p_what) {696case NOTIFICATION_READY: {697String last_file = EditorSettings::get_singleton()->get_project_metadata("build_profile", "last_file_path", "");698if (!last_file.is_empty()) {699_import_profile(last_file);700}701if (edited.is_null()) {702edited.instantiate();703_update_edited_profile();704}705706} break;707}708}709710void EditorBuildProfileManager::_profile_action(int p_action) {711last_action = Action(p_action);712713switch (p_action) {714case ACTION_RESET: {715confirm_dialog->set_text(TTR("Reset the edited profile?"));716confirm_dialog->popup_centered();717} break;718case ACTION_LOAD: {719import_profile->popup_file_dialog();720} break;721case ACTION_SAVE: {722if (!profile_path->get_text().is_empty()) {723Error err = edited->save_to_file(profile_path->get_text());724if (err != OK) {725EditorNode::get_singleton()->show_warning(TTR("File saving failed."));726}727break;728}729[[fallthrough]];730}731case ACTION_SAVE_AS: {732export_profile->popup_file_dialog();733export_profile->set_current_file(profile_path->get_text());734} break;735case ACTION_NEW: {736confirm_dialog->set_text(TTR("Create a new profile?"));737confirm_dialog->popup_centered();738} break;739case ACTION_DETECT: {740String text = TTR("This will scan all files in the current project to detect used classes.\nNote that the first scan may take a while, specially in larger projects.");741#ifdef MODULE_MONO_ENABLED742text += "\n\n" + TTR("Warning: Class detection for C# scripts is not currently available, and such files will be ignored.");743#endif // MODULE_MONO_ENABLED744confirm_dialog->set_text(text);745confirm_dialog->popup_centered();746} break;747case ACTION_MAX: {748} break;749}750}751752void EditorBuildProfileManager::_find_files(EditorFileSystemDirectory *p_dir, const HashMap<String, DetectedFile> &p_cache, HashMap<String, DetectedFile> &r_detected) {753if (p_dir == nullptr || p_dir->get_path().get_file().begins_with(".")) {754return;755}756757for (int i = 0; i < p_dir->get_file_count(); i++) {758String p = p_dir->get_file_path(i);759760if (EditorNode::get_singleton()->progress_task_step("detect_classes_from_project", p, 1)) {761project_scan_canceled = true;762return;763}764765String p_check = p;766// Make so that the import file is the one checked if available,767// so the cache can be updated when it changes.768if (ResourceFormatImporter::get_singleton()->exists(p_check)) {769p_check += ".import";770}771772uint64_t timestamp = 0;773String md5;774775if (p_cache.has(p)) {776const DetectedFile &cache = p_cache[p];777// Check if timestamp and MD5 match.778timestamp = FileAccess::get_modified_time(p_check);779bool cache_valid = true;780if (cache.timestamp != timestamp) {781md5 = FileAccess::get_md5(p_check);782if (md5 != cache.md5) {783cache_valid = false;784}785}786787if (cache_valid) {788r_detected.insert(p, cache);789continue;790}791}792793// Not cached, or cache invalid.794795DetectedFile cache;796797HashSet<StringName> classes;798ResourceLoader::get_classes_used(p, &classes);799for (const StringName &E : classes) {800cache.classes.push_back(E);801}802803HashSet<String> build_deps;804ResourceFormatImporter::get_singleton()->get_build_dependencies(p, &build_deps);805for (const String &E : build_deps) {806cache.build_deps.push_back(E);807}808809if (md5.is_empty()) {810cache.timestamp = FileAccess::get_modified_time(p_check);811cache.md5 = FileAccess::get_md5(p_check);812} else {813cache.timestamp = timestamp;814cache.md5 = md5;815}816817r_detected.insert(p, cache);818}819820for (int i = 0; i < p_dir->get_subdir_count(); i++) {821_find_files(p_dir->get_subdir(i), p_cache, r_detected);822}823}824825void EditorBuildProfileManager::_detect_from_project() {826EditorNode::get_singleton()->progress_add_task("detect_classes_from_project", TTRC("Scanning Project for Used Classes"), 3, true);827828HashMap<String, DetectedFile> previous_file_cache;829830Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("used_class_cache"), FileAccess::READ);831if (f.is_valid()) {832while (!f->eof_reached()) {833String l = f->get_line();834Vector<String> fields = l.split("::");835if (fields.size() == 5) {836const String &path = fields[0];837DetectedFile df;838df.timestamp = fields[1].to_int();839df.md5 = fields[2];840df.classes = fields[3].split(",", false);841df.build_deps = fields[4].split(",", false);842previous_file_cache.insert(path, df);843}844}845f.unref();846}847848HashMap<String, DetectedFile> updated_file_cache;849850_find_files(EditorFileSystem::get_singleton()->get_filesystem(), previous_file_cache, updated_file_cache);851852if (project_scan_canceled) {853project_scan_canceled = false;854EditorNode::get_singleton()->progress_end_task("detect_classes_from_project");855856return;857}858859EditorNode::get_singleton()->progress_task_step("detect_classes_from_project", TTRC("Processing Classes Found"), 2);860861HashSet<StringName> used_classes;862LocalVector<String> used_build_deps;863864// Find classes and update the disk cache in the process.865f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("used_class_cache"), FileAccess::WRITE);866867for (const KeyValue<String, DetectedFile> &E : updated_file_cache) {868String l = E.key + "::" + itos(E.value.timestamp) + "::" + E.value.md5 + "::";869for (int i = 0; i < E.value.classes.size(); i++) {870String c = E.value.classes[i];871if (i > 0) {872l += ",";873}874l += c;875used_classes.insert(c);876}877l += "::";878for (int i = 0; i < E.value.build_deps.size(); i++) {879String c = E.value.build_deps[i];880if (i > 0) {881l += ",";882}883l += c;884used_build_deps.push_back(c);885}886f->store_line(l);887}888889f.unref();890891// Add classes that are either necessary for the engine to work properly, or there isn't a way to infer their use.892893const LocalVector<String> hardcoded_classes = { "InputEvent", "MainLoop", "StyleBox" };894for (const String &hc_class : hardcoded_classes) {895used_classes.insert(hc_class);896897LocalVector<StringName> inheriters;898ClassDB::get_inheriters_from_class(hc_class, inheriters);899for (const StringName &inheriter : inheriters) {900used_classes.insert(inheriter);901}902}903904// Add forced classes typed by the user.905906const Vector<String> force_detect = edited->get_force_detect_classes().split(",");907for (const String &class_name : force_detect) {908const String class_stripped = class_name.strip_edges();909if (!class_stripped.is_empty()) {910used_classes.insert(class_stripped);911}912}913914// Filter all classes to discard inherited ones.915916HashSet<StringName> all_used_classes;917918for (const StringName &E : used_classes) {919StringName c = E;920if (!ClassDB::class_exists(c)) {921// Maybe this is an old class that got replaced? Try getting compat class.922c = ClassDB::get_compatibility_class(c);923if (!c) {924// No luck, skip.925continue;926}927}928929List<StringName> dependencies;930ClassDB::get_class_dependencies(E, &dependencies);931for (const StringName &dep : dependencies) {932if (!all_used_classes.has(dep)) {933// Add classes which this class depends upon.934all_used_classes.insert(dep);935}936}937938while (c) {939all_used_classes.insert(c);940c = ClassDB::get_parent_class(c);941}942}943944edited->clear_disabled_classes();945946List<StringName> all_classes;947ClassDB::get_class_list(&all_classes);948949for (const StringName &E : all_classes) {950if (String(E).begins_with("Editor") || ClassDB::get_api_type(E) != ClassDB::API_CORE || all_used_classes.has(E)) {951// This class is valid or editor-only, do nothing.952continue;953}954955StringName p = ClassDB::get_parent_class(E);956if (!p || all_used_classes.has(p)) {957// If no parent, or if the parent is enabled, then add to disabled classes.958// This way we avoid disabling redundant classes.959edited->set_disable_class(E, true);960}961}962963edited->reset_build_options();964965for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) {966// Check if the build option requires other options that are currently disabled.967LocalVector<EditorBuildProfile::BuildOption> dependencies = EditorBuildProfile::get_build_option_dependencies(EditorBuildProfile::BuildOption(i));968if (!dependencies.is_empty()) {969bool disable = true;970for (EditorBuildProfile::BuildOption dependency : dependencies) {971if (!edited->is_build_option_disabled(dependency)) {972disable = false;973break;974}975}976977if (disable) {978edited->set_disable_build_option(EditorBuildProfile::BuildOption(i), true);979continue;980}981}982983bool skip = false;984bool ignore = true;985986// Check if the build option has enabled classes using it.987const LocalVector<String> classes = EditorBuildProfile::get_build_option_classes(EditorBuildProfile::BuildOption(i));988if (!classes.is_empty()) {989for (StringName class_name : classes) {990if (!edited->is_class_disabled(class_name)) {991skip = true;992break;993}994}995996if (skip) {997continue;998}9991000ignore = false;1001}10021003// Check if there's project settings requiring it.1004const HashMap<String, LocalVector<Variant>> settings_list = EditorBuildProfile::get_build_option_settings(EditorBuildProfile::BuildOption(i));1005if (!settings_list.is_empty()) {1006for (KeyValue<String, LocalVector<Variant>> KV : settings_list) {1007Variant proj_value = GLOBAL_GET(KV.key);1008for (Variant value : KV.value) {1009if (proj_value == value) {1010skip = true;1011break;1012}1013}10141015if (skip) {1016break;1017}1018}10191020if (skip) {1021continue;1022}10231024ignore = false;1025}10261027// Check if a resource setting depends on it.1028if (used_build_deps.has(EditorBuildProfile::get_build_option_identifier(EditorBuildProfile::BuildOption(i)))) {1029continue;1030} else if (EditorBuildProfile::get_build_option_explicit_use(EditorBuildProfile::BuildOption(i))) {1031ignore = false;1032}10331034if (!skip && !ignore) {1035edited->set_disable_build_option(EditorBuildProfile::BuildOption(i), true);1036}1037}10381039if (edited->is_build_option_disabled(EditorBuildProfile::BUILD_OPTION_TEXT_SERVER_ADVANCED)) {1040edited->set_disable_build_option(EditorBuildProfile::BUILD_OPTION_TEXT_SERVER_FALLBACK, false);1041}10421043EditorNode::get_singleton()->progress_end_task("detect_classes_from_project");1044}10451046void EditorBuildProfileManager::_action_confirm() {1047switch (last_action) {1048case ACTION_RESET: {1049edited.instantiate();1050_update_edited_profile();1051} break;1052case ACTION_LOAD: {1053} break;1054case ACTION_SAVE: {1055} break;1056case ACTION_SAVE_AS: {1057} break;1058case ACTION_NEW: {1059profile_path->set_text("");1060edited.instantiate();1061_update_edited_profile();1062} break;1063case ACTION_DETECT: {1064_detect_from_project();1065_update_edited_profile();1066} break;1067case ACTION_MAX: {1068} break;1069}1070}10711072void EditorBuildProfileManager::_hide_requested() {1073_cancel_pressed(); // From AcceptDialog.1074}10751076void EditorBuildProfileManager::_fill_classes_from(TreeItem *p_parent, const String &p_class, const String &p_selected) {1077TreeItem *class_item = class_list->create_item(p_parent);1078class_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);1079class_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_class));1080const String &text = p_class;10811082bool disabled = edited->is_class_disabled(p_class);1083if (disabled) {1084class_item->set_custom_color(0, class_list->get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));1085}10861087class_item->set_text(0, text);1088class_item->set_editable(0, true);1089class_item->set_selectable(0, true);1090class_item->set_metadata(0, p_class);10911092bool collapsed = edited->is_item_collapsed(p_class);1093class_item->set_collapsed(collapsed);10941095if (p_class == p_selected) {1096class_item->select(0);1097}1098if (disabled) {1099// Class disabled, do nothing else (do not show further).1100return;1101}11021103class_item->set_checked(0, true); // If it's not disabled, its checked.11041105List<StringName> child_classes;1106ClassDB::get_direct_inheriters_from_class(p_class, &child_classes);1107child_classes.sort_custom<StringName::AlphCompare>();11081109for (const StringName &name : child_classes) {1110if (String(name).begins_with("Editor") || ClassDB::get_api_type(name) != ClassDB::API_CORE) {1111continue;1112}1113_fill_classes_from(class_item, name, p_selected);1114}1115}11161117void EditorBuildProfileManager::_class_list_item_selected() {1118if (updating_build_options) {1119return;1120}11211122TreeItem *item = class_list->get_selected();1123if (!item) {1124return;1125}11261127Variant md = item->get_metadata(0);1128if (md.is_string()) {1129description_bit->parse_symbol("class|" + md.operator String() + "|");1130} else if (md.get_type() == Variant::INT) {1131String build_option_description = EditorBuildProfile::get_build_option_description(EditorBuildProfile::BuildOption((int)md));1132description_bit->set_custom_text(TTR(item->get_text(0)), String(), TTRGET(build_option_description));1133}1134}11351136void EditorBuildProfileManager::_class_list_item_edited() {1137if (updating_build_options) {1138return;1139}11401141TreeItem *item = class_list->get_edited();1142if (!item) {1143return;1144}11451146bool checked = item->is_checked(0);11471148Variant md = item->get_metadata(0);1149if (md.is_string()) {1150String class_selected = md;1151edited->set_disable_class(class_selected, !checked);1152_update_edited_profile();1153} else if (md.get_type() == Variant::INT) {1154int build_option_selected = md;1155edited->set_disable_build_option(EditorBuildProfile::BuildOption(build_option_selected), !checked);1156}1157}11581159void EditorBuildProfileManager::_class_list_item_collapsed(Object *p_item) {1160if (updating_build_options) {1161return;1162}11631164TreeItem *item = Object::cast_to<TreeItem>(p_item);1165if (!item) {1166return;1167}11681169Variant md = item->get_metadata(0);1170if (!md.is_string()) {1171return;1172}11731174String class_name = md;1175bool collapsed = item->is_collapsed();1176edited->set_item_collapsed(class_name, collapsed);1177}11781179void EditorBuildProfileManager::_update_edited_profile() {1180String class_selected;1181int build_option_selected = -1;11821183if (class_list->get_selected()) {1184Variant md = class_list->get_selected()->get_metadata(0);1185if (md.is_string()) {1186class_selected = md;1187} else if (md.get_type() == Variant::INT) {1188build_option_selected = md;1189}1190}11911192class_list->clear();11931194updating_build_options = true;11951196TreeItem *root = class_list->create_item();11971198HashMap<EditorBuildProfile::BuildOptionCategory, TreeItem *> subcats;1199for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_CATEGORY_MAX; i++) {1200TreeItem *build_cat;1201build_cat = class_list->create_item(root);12021203build_cat->set_text(0, EditorBuildProfile::get_build_option_category_name(EditorBuildProfile::BuildOptionCategory(i)));1204subcats[EditorBuildProfile::BuildOptionCategory(i)] = build_cat;1205}12061207for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) {1208TreeItem *build_option;1209build_option = class_list->create_item(subcats[EditorBuildProfile::get_build_option_category(EditorBuildProfile::BuildOption(i))]);12101211build_option->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);1212build_option->set_text(0, EditorBuildProfile::get_build_option_name(EditorBuildProfile::BuildOption(i)));1213build_option->set_selectable(0, true);1214build_option->set_editable(0, true);1215build_option->set_metadata(0, i);1216if (!edited->is_build_option_disabled(EditorBuildProfile::BuildOption(i))) {1217build_option->set_checked(0, true);1218}12191220if (i == build_option_selected) {1221build_option->select(0);1222}1223}12241225TreeItem *classes = class_list->create_item(root);1226classes->set_text(0, TTR("Nodes and Classes:"));12271228_fill_classes_from(classes, "Node", class_selected);1229_fill_classes_from(classes, "Resource", class_selected);12301231force_detect_classes->set_text(edited->get_force_detect_classes());12321233updating_build_options = false;12341235_class_list_item_selected();1236}12371238void EditorBuildProfileManager::_force_detect_classes_changed(const String &p_text) {1239if (updating_build_options) {1240return;1241}1242edited->set_force_detect_classes(force_detect_classes->get_text());1243}12441245void EditorBuildProfileManager::_import_profile(const String &p_path) {1246Ref<EditorBuildProfile> profile;1247profile.instantiate();1248Error err = profile->load_from_file(p_path);1249String basefile = p_path.get_file();1250if (err != OK) {1251EditorNode::get_singleton()->show_warning(vformat(TTR("File '%s' format is invalid, import aborted."), basefile));1252return;1253}12541255profile_path->set_text(p_path);1256EditorSettings::get_singleton()->set_project_metadata("build_profile", "last_file_path", p_path);12571258edited = profile;1259_update_edited_profile();1260}12611262void EditorBuildProfileManager::_export_profile(const String &p_path) {1263ERR_FAIL_COND(edited.is_null());1264Error err = edited->save_to_file(p_path);1265if (err != OK) {1266EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving profile to path: '%s'."), p_path));1267} else {1268profile_path->set_text(p_path);1269EditorSettings::get_singleton()->set_project_metadata("build_profile", "last_file_path", p_path);1270}1271}12721273Ref<EditorBuildProfile> EditorBuildProfileManager::get_current_profile() {1274return edited;1275}12761277EditorBuildProfileManager *EditorBuildProfileManager::singleton = nullptr;12781279void EditorBuildProfileManager::_bind_methods() {1280ClassDB::bind_method("_update_selected_profile", &EditorBuildProfileManager::_update_edited_profile);1281}12821283EditorBuildProfileManager::EditorBuildProfileManager() {1284VBoxContainer *main_vbc = memnew(VBoxContainer);1285add_child(main_vbc);12861287HBoxContainer *path_hbc = memnew(HBoxContainer);1288profile_path = memnew(LineEdit);1289path_hbc->add_child(profile_path);1290profile_path->set_accessibility_name(TTRC("Profile Path"));1291profile_path->set_editable(true);1292profile_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);12931294profile_actions[ACTION_NEW] = memnew(Button(TTR("New")));1295path_hbc->add_child(profile_actions[ACTION_NEW]);1296profile_actions[ACTION_NEW]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_NEW));12971298profile_actions[ACTION_LOAD] = memnew(Button(TTR("Load")));1299path_hbc->add_child(profile_actions[ACTION_LOAD]);1300profile_actions[ACTION_LOAD]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_LOAD));13011302profile_actions[ACTION_SAVE] = memnew(Button(TTR("Save")));1303path_hbc->add_child(profile_actions[ACTION_SAVE]);1304profile_actions[ACTION_SAVE]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_SAVE));13051306profile_actions[ACTION_SAVE_AS] = memnew(Button(TTR("Save As")));1307path_hbc->add_child(profile_actions[ACTION_SAVE_AS]);1308profile_actions[ACTION_SAVE_AS]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_SAVE_AS));13091310main_vbc->add_margin_child(TTR("Profile:"), path_hbc);13111312main_vbc->add_child(memnew(HSeparator));13131314HBoxContainer *profiles_hbc = memnew(HBoxContainer);13151316profile_actions[ACTION_RESET] = memnew(Button(TTR("Reset to Defaults")));1317profiles_hbc->add_child(profile_actions[ACTION_RESET]);1318profile_actions[ACTION_RESET]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_RESET));13191320profile_actions[ACTION_DETECT] = memnew(Button(TTR("Detect from Project")));1321profiles_hbc->add_child(profile_actions[ACTION_DETECT]);1322profile_actions[ACTION_DETECT]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_DETECT));13231324main_vbc->add_margin_child(TTR("Actions:"), profiles_hbc);13251326class_list = memnew(Tree);1327class_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);1328class_list->set_hide_root(true);1329class_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);1330class_list->connect("cell_selected", callable_mp(this, &EditorBuildProfileManager::_class_list_item_selected));1331class_list->connect("item_edited", callable_mp(this, &EditorBuildProfileManager::_class_list_item_edited), CONNECT_DEFERRED);1332class_list->connect("item_collapsed", callable_mp(this, &EditorBuildProfileManager::_class_list_item_collapsed));1333// It will be displayed once the user creates or chooses a profile.1334main_vbc->add_margin_child(TTR("Configure Engine Compilation Profile:"), class_list, true);13351336description_bit = memnew(EditorHelpBit);1337description_bit->set_content_height_limits(80 * EDSCALE, 80 * EDSCALE);1338description_bit->connect("request_hide", callable_mp(this, &EditorBuildProfileManager::_hide_requested));1339main_vbc->add_margin_child(TTR("Description:"), description_bit, false);13401341confirm_dialog = memnew(ConfirmationDialog);1342add_child(confirm_dialog);1343confirm_dialog->set_title(TTR("Please Confirm:"));1344confirm_dialog->connect(SceneStringName(confirmed), callable_mp(this, &EditorBuildProfileManager::_action_confirm));13451346import_profile = memnew(EditorFileDialog);1347add_child(import_profile);1348import_profile->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);1349import_profile->add_filter("*.gdbuild,*.build", TTR("Engine Compilation Profile"));1350import_profile->connect("file_selected", callable_mp(this, &EditorBuildProfileManager::_import_profile));1351import_profile->set_title(TTR("Load Profile"));1352import_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM);13531354export_profile = memnew(EditorFileDialog);1355add_child(export_profile);1356export_profile->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);1357export_profile->add_filter("*.gdbuild,*.build", TTR("Engine Compilation Profile"));1358export_profile->connect("file_selected", callable_mp(this, &EditorBuildProfileManager::_export_profile));1359export_profile->set_title(TTR("Export Profile"));1360export_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM);13611362force_detect_classes = memnew(LineEdit);1363force_detect_classes->set_accessibility_name(TTRC("Forced Classes on Detect:"));1364main_vbc->add_margin_child(TTR("Forced Classes on Detect:"), force_detect_classes);1365force_detect_classes->connect(SceneStringName(text_changed), callable_mp(this, &EditorBuildProfileManager::_force_detect_classes_changed));13661367set_title(TTR("Edit Compilation Configuration Profile"));13681369singleton = this;1370}137113721373