Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/editor/docks/import_dock.cpp
9896 views
1
/**************************************************************************/
2
/* import_dock.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "import_dock.h"
32
33
#include "core/config/project_settings.h"
34
#include "editor/editor_node.h"
35
#include "editor/editor_string_names.h"
36
#include "editor/editor_undo_redo_manager.h"
37
#include "editor/inspector/editor_resource_preview.h"
38
#include "editor/settings/editor_settings.h"
39
#include "editor/themes/editor_scale.h"
40
#include "editor/themes/editor_theme_manager.h"
41
42
class ImportDockParameters : public Object {
43
GDCLASS(ImportDockParameters, Object);
44
45
public:
46
HashMap<StringName, Variant> values;
47
List<PropertyInfo> properties;
48
Ref<ResourceImporter> importer;
49
Vector<String> paths;
50
HashSet<StringName> checked;
51
bool checking = false;
52
bool skip = false;
53
String base_options_path;
54
55
bool _set(const StringName &p_name, const Variant &p_value) {
56
if (values.has(p_name)) {
57
values[p_name] = p_value;
58
if (checking) {
59
checked.insert(p_name);
60
notify_property_list_changed();
61
}
62
return true;
63
}
64
65
return false;
66
}
67
68
bool _get(const StringName &p_name, Variant &r_ret) const {
69
if (values.has(p_name)) {
70
r_ret = values[p_name];
71
return true;
72
}
73
74
return false;
75
}
76
void _get_property_list(List<PropertyInfo> *p_list) const {
77
for (const PropertyInfo &E : properties) {
78
if (!importer->get_option_visibility(base_options_path, E.name, values)) {
79
continue;
80
}
81
PropertyInfo pi = E;
82
if (checking) {
83
pi.usage |= PROPERTY_USAGE_CHECKABLE;
84
if (checked.has(E.name)) {
85
pi.usage |= PROPERTY_USAGE_CHECKED;
86
}
87
}
88
p_list->push_back(pi);
89
}
90
}
91
92
void update() {
93
notify_property_list_changed();
94
}
95
};
96
97
ImportDock *ImportDock::singleton = nullptr;
98
99
void ImportDock::set_edit_path(const String &p_path) {
100
Ref<ConfigFile> config;
101
config.instantiate();
102
Error err = config->load(p_path + ".import");
103
if (err != OK) {
104
clear();
105
return;
106
}
107
108
String importer_name = config->get_value("remap", "importer");
109
if (importer_name == "keep") {
110
params->importer.unref();
111
params->skip = false;
112
} else if (importer_name == "skip") {
113
params->importer.unref();
114
params->skip = true;
115
} else {
116
params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
117
params->skip = false;
118
}
119
120
params->paths.clear();
121
params->paths.push_back(p_path);
122
params->base_options_path = p_path;
123
124
_update_options(p_path, config);
125
126
List<Ref<ResourceImporter>> importers;
127
ResourceFormatImporter::get_singleton()->get_importers_for_file(p_path, &importers);
128
List<Pair<String, String>> importer_names;
129
130
for (const Ref<ResourceImporter> &E : importers) {
131
importer_names.push_back(Pair<String, String>(E->get_visible_name(), E->get_importer_name()));
132
}
133
134
importer_names.sort_custom<PairSort<String, String>>();
135
136
import_as->clear();
137
138
for (const Pair<String, String> &E : importer_names) {
139
import_as->add_item(E.first);
140
import_as->set_item_metadata(-1, E.second);
141
if (E.second == importer_name) {
142
import_as->select(import_as->get_item_count() - 1);
143
}
144
}
145
146
_add_keep_import_option(importer_name);
147
148
import->set_disabled(false);
149
_set_dirty(false);
150
import_as->set_disabled(false);
151
preset->set_disabled(false);
152
content->show();
153
select_a_resource->hide();
154
155
imported->set_text(p_path.get_file());
156
}
157
158
void ImportDock::_add_keep_import_option(const String &p_importer_name) {
159
import_as->add_separator();
160
import_as->add_item(TTRC("Keep File (exported as is)"));
161
import_as->set_item_metadata(-1, "keep");
162
import_as->add_item(TTRC("Skip File (not exported)"));
163
import_as->set_item_metadata(-1, "skip");
164
if (p_importer_name == "keep") {
165
import_as->select(import_as->get_item_count() - 2);
166
} else if (p_importer_name == "skip") {
167
import_as->select(import_as->get_item_count() - 1);
168
}
169
}
170
171
void ImportDock::_update_options(const String &p_path, const Ref<ConfigFile> &p_config) {
172
// Set the importer class to fetch the correct class in the XML class reference.
173
// This allows tooltips to display when hovering properties.
174
if (params->importer.is_valid()) {
175
// Null check to avoid crashing if the "Keep File (exported as is)" mode is selected.
176
import_opts->set_object_class(params->importer->get_class_name());
177
}
178
179
List<ResourceImporter::ImportOption> options;
180
181
if (params->importer.is_valid()) {
182
params->importer->get_import_options(p_path, &options);
183
}
184
185
params->properties.clear();
186
params->values.clear();
187
params->checking = params->paths.size() > 1;
188
params->checked.clear();
189
params->base_options_path = p_path;
190
191
HashMap<StringName, Variant> import_options;
192
if (p_config.is_valid() && p_config->has_section("params")) {
193
Vector<String> section_keys = p_config->get_section_keys("params");
194
for (const String &section_key : section_keys) {
195
import_options[section_key] = p_config->get_value("params", section_key);
196
}
197
if (params->importer.is_valid()) {
198
params->importer->handle_compatibility_options(import_options);
199
}
200
}
201
202
for (const ResourceImporter::ImportOption &E : options) {
203
params->properties.push_back(E.option);
204
if (p_config.is_valid() && import_options.has(E.option.name)) {
205
params->values[E.option.name] = import_options[E.option.name];
206
} else {
207
params->values[E.option.name] = E.default_value;
208
}
209
}
210
211
params->update();
212
_update_preset_menu();
213
214
bool was_imported = p_config.is_valid() && p_config->get_value("remap", "importer") != "skip" && p_config->get_value("remap", "importer") != "keep";
215
if (was_imported && params->importer.is_valid() && params->paths.size() == 1 && params->importer->has_advanced_options()) {
216
advanced->show();
217
advanced_spacer->show();
218
} else {
219
advanced->hide();
220
advanced_spacer->hide();
221
}
222
}
223
224
void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
225
clear();
226
227
// Use the value that is repeated the most.
228
HashMap<String, Dictionary> value_frequency;
229
HashSet<String> extensions;
230
231
for (int i = 0; i < p_paths.size(); i++) {
232
Ref<ConfigFile> config;
233
config.instantiate();
234
extensions.insert(p_paths[i].get_extension());
235
Error err = config->load(p_paths[i] + ".import");
236
ERR_CONTINUE(err != OK);
237
238
if (i == 0) {
239
String importer_name = config->get_value("remap", "importer");
240
if (importer_name == "keep") {
241
params->importer.unref();
242
params->skip = false;
243
} else if (importer_name == "skip") {
244
params->importer.unref();
245
params->skip = true;
246
} else {
247
params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
248
params->skip = false;
249
}
250
if (params->importer.is_null()) {
251
clear();
252
return;
253
}
254
}
255
256
if (!config->has_section("params")) {
257
continue;
258
}
259
260
Vector<String> keys = config->get_section_keys("params");
261
262
for (const String &E : keys) {
263
if (!value_frequency.has(E)) {
264
value_frequency[E] = Dictionary();
265
}
266
267
Variant value = config->get_value("params", E);
268
269
if (value_frequency[E].has(value)) {
270
value_frequency[E][value] = int(value_frequency[E][value]) + 1;
271
} else {
272
value_frequency[E][value] = 1;
273
}
274
}
275
}
276
277
ERR_FAIL_COND(params->importer.is_null());
278
279
String base_path;
280
if (extensions.size() == 1 && p_paths.size() > 0) {
281
base_path = p_paths[0];
282
}
283
List<ResourceImporter::ImportOption> options;
284
params->importer->get_import_options(base_path, &options);
285
286
params->properties.clear();
287
params->values.clear();
288
params->checking = true;
289
params->checked.clear();
290
params->base_options_path = base_path;
291
292
for (const ResourceImporter::ImportOption &E : options) {
293
params->properties.push_back(E.option);
294
295
if (value_frequency.has(E.option.name)) {
296
Dictionary d = value_frequency[E.option.name];
297
int freq = 0;
298
Variant value;
299
for (const KeyValue<Variant, Variant> &kv : d) {
300
int f = kv.value;
301
if (f > freq) {
302
value = kv.key;
303
}
304
}
305
306
params->values[E.option.name] = value;
307
} else {
308
params->values[E.option.name] = E.default_value;
309
}
310
}
311
312
params->update();
313
314
List<Ref<ResourceImporter>> importers;
315
ResourceFormatImporter::get_singleton()->get_importers_for_file(p_paths[0], &importers);
316
List<Pair<String, String>> importer_names;
317
318
for (const Ref<ResourceImporter> &E : importers) {
319
importer_names.push_back(Pair<String, String>(E->get_visible_name(), E->get_importer_name()));
320
}
321
322
importer_names.sort_custom<PairSort<String, String>>();
323
324
import_as->clear();
325
326
for (const Pair<String, String> &E : importer_names) {
327
import_as->add_item(E.first);
328
import_as->set_item_metadata(-1, E.second);
329
if (E.second == params->importer->get_importer_name()) {
330
import_as->select(import_as->get_item_count() - 1);
331
}
332
}
333
334
_add_keep_import_option(params->importer->get_importer_name());
335
336
_update_preset_menu();
337
338
params->paths = p_paths;
339
import->set_disabled(false);
340
_set_dirty(false);
341
import_as->set_disabled(false);
342
preset->set_disabled(false);
343
content->show();
344
select_a_resource->hide();
345
346
imported->set_text(vformat(TTR("%d Files"), p_paths.size()));
347
348
if (params->paths.size() == 1 && params->importer->has_advanced_options()) {
349
advanced->show();
350
advanced_spacer->show();
351
} else {
352
advanced->hide();
353
advanced_spacer->hide();
354
}
355
}
356
357
void ImportDock::reimport_resources(const Vector<String> &p_paths) {
358
switch (p_paths.size()) {
359
case 0:
360
ERR_FAIL_MSG("You need to select files to reimport them.");
361
case 1:
362
set_edit_path(p_paths[0]);
363
break;
364
default:
365
set_edit_multiple_paths(p_paths);
366
break;
367
}
368
369
_reimport_attempt();
370
}
371
372
void ImportDock::_update_preset_menu() {
373
preset->get_popup()->clear();
374
375
if (params->importer.is_null()) {
376
preset->get_popup()->add_item(TTRC("Default"));
377
preset->hide();
378
return;
379
}
380
preset->show();
381
382
if (params->importer->get_preset_count() <= 0) {
383
preset->get_popup()->add_item(TTRC("Default"));
384
} else {
385
for (int i = 0; i < params->importer->get_preset_count(); i++) {
386
preset->get_popup()->add_item(params->importer->get_preset_name(i));
387
}
388
}
389
390
preset->get_popup()->add_separator();
391
preset->get_popup()->add_item(vformat(TTR("Set as Default for '%s'"), params->importer->get_visible_name()), ITEM_SET_AS_DEFAULT);
392
if (ProjectSettings::get_singleton()->has_setting("importer_defaults/" + params->importer->get_importer_name())) {
393
preset->get_popup()->add_item(TTRC("Load Default"), ITEM_LOAD_DEFAULT);
394
preset->get_popup()->add_separator();
395
preset->get_popup()->add_item(vformat(TTR("Clear Default for '%s'"), params->importer->get_visible_name()), ITEM_CLEAR_DEFAULT);
396
}
397
}
398
399
void ImportDock::_importer_selected(int i_idx) {
400
String name = import_as->get_selected_metadata();
401
if (name == "keep") {
402
params->importer.unref();
403
params->skip = false;
404
_update_options(params->base_options_path, Ref<ConfigFile>());
405
} else if (name == "skip") {
406
params->importer.unref();
407
params->skip = true;
408
_update_options(params->base_options_path, Ref<ConfigFile>());
409
} else {
410
Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(name);
411
ERR_FAIL_COND(importer.is_null());
412
413
params->importer = importer;
414
params->skip = false;
415
Ref<ConfigFile> config;
416
if (params->paths.size()) {
417
String path = params->paths[0];
418
config.instantiate();
419
Error err = config->load(path + ".import");
420
if (err != OK) {
421
config.unref();
422
}
423
}
424
_update_options(params->base_options_path, config);
425
}
426
}
427
428
void ImportDock::_preset_selected(int p_idx) {
429
int item_id = preset->get_popup()->get_item_id(p_idx);
430
String setting_name = "importer_defaults/" + params->importer->get_importer_name();
431
432
switch (item_id) {
433
case ITEM_SET_AS_DEFAULT: {
434
Dictionary import_settings;
435
// When import settings already exist, we will update these settings
436
// to ensure that the dictionary retains settings that are not displayed in the
437
// editor. For Scene, the dictionary is the same for FBX, GLTF, and Blender, but each
438
// file type has some different settings.
439
if (ProjectSettings::get_singleton()->has_setting(setting_name)) {
440
import_settings = GLOBAL_GET(setting_name);
441
}
442
443
for (const PropertyInfo &E : params->properties) {
444
import_settings[E.name] = params->values[E.name];
445
}
446
447
ProjectSettings::get_singleton()->set(setting_name, import_settings);
448
ProjectSettings::get_singleton()->save();
449
_update_preset_menu();
450
} break;
451
case ITEM_LOAD_DEFAULT: {
452
ERR_FAIL_COND(!ProjectSettings::get_singleton()->has_setting(setting_name));
453
454
Dictionary import_settings = GLOBAL_GET(setting_name);
455
456
if (params->checking) {
457
params->checked.clear();
458
}
459
for (const KeyValue<Variant, Variant> &kv : import_settings) {
460
params->values[kv.key] = kv.value;
461
if (params->checking) {
462
params->checked.insert(kv.key);
463
}
464
}
465
params->update();
466
} break;
467
case ITEM_CLEAR_DEFAULT: {
468
ProjectSettings::get_singleton()->set(setting_name, Variant());
469
ProjectSettings::get_singleton()->save();
470
_update_preset_menu();
471
} break;
472
default: {
473
List<ResourceImporter::ImportOption> options;
474
475
params->importer->get_import_options(params->base_options_path, &options, p_idx);
476
477
if (params->checking) {
478
params->checked.clear();
479
}
480
for (const ResourceImporter::ImportOption &E : options) {
481
params->values[E.option.name] = E.default_value;
482
if (params->checking) {
483
params->checked.insert(E.option.name);
484
}
485
}
486
params->update();
487
} break;
488
}
489
}
490
491
void ImportDock::clear() {
492
imported->set_text("");
493
import->set_disabled(true);
494
import_as->clear();
495
import_as->set_disabled(true);
496
preset->set_disabled(true);
497
params->values.clear();
498
params->properties.clear();
499
params->update();
500
preset->get_popup()->clear();
501
content->hide();
502
select_a_resource->show();
503
}
504
505
static bool _find_owners(EditorFileSystemDirectory *efsd, const String &p_path) {
506
if (!efsd) {
507
return false;
508
}
509
510
for (int i = 0; i < efsd->get_subdir_count(); i++) {
511
if (_find_owners(efsd->get_subdir(i), p_path)) {
512
return true;
513
}
514
}
515
516
for (int i = 0; i < efsd->get_file_count(); i++) {
517
Vector<String> deps = efsd->get_file_deps(i);
518
if (deps.has(p_path)) {
519
return true;
520
}
521
}
522
523
return false;
524
}
525
526
void ImportDock::_reimport_pressed() {
527
_reimport_attempt();
528
529
if (params->importer.is_valid() && params->paths.size() == 1 && params->importer->has_advanced_options()) {
530
advanced->show();
531
advanced_spacer->show();
532
} else {
533
advanced->hide();
534
advanced_spacer->hide();
535
}
536
}
537
538
void ImportDock::_reimport_attempt() {
539
bool used_in_resources = false;
540
541
String importer_name;
542
if (params->importer.is_valid()) {
543
importer_name = params->importer->get_importer_name();
544
} else {
545
if (params->skip) {
546
importer_name = "skip";
547
} else {
548
importer_name = "keep";
549
}
550
}
551
for (int i = 0; i < params->paths.size(); i++) {
552
Ref<ConfigFile> config;
553
config.instantiate();
554
Error err = config->load(params->paths[i] + ".import");
555
ERR_CONTINUE(err != OK);
556
557
String imported_with = config->get_value("remap", "importer");
558
if (imported_with != importer_name && imported_with != "keep" && imported_with != "skip") {
559
Ref<Resource> resource = ResourceLoader::load(params->paths[i]);
560
if (resource.is_valid()) {
561
need_cleanup.push_back(params->paths[i]);
562
if (_find_owners(EditorFileSystem::get_singleton()->get_filesystem(), params->paths[i])) {
563
used_in_resources = true;
564
}
565
}
566
}
567
}
568
569
if (!need_cleanup.is_empty() || used_in_resources) {
570
cleanup_warning->set_visible(!need_cleanup.is_empty());
571
label_warning->set_visible(used_in_resources);
572
reimport_confirm->popup_centered();
573
return;
574
}
575
576
_reimport();
577
}
578
579
void ImportDock::_reimport_and_cleanup() {
580
HashMap<String, Ref<Resource>> old_resources;
581
582
for (const String &path : need_cleanup) {
583
Ref<Resource> res = ResourceLoader::load(path);
584
res->set_path("");
585
res->set_meta(SNAME("_skip_save_"), true);
586
old_resources[path] = res;
587
}
588
589
EditorResourcePreview::get_singleton()->stop(); // Don't try to re-create previews after import.
590
_reimport();
591
592
if (need_cleanup.is_empty()) {
593
return;
594
}
595
596
// After changing resource type we need to make sure that all old instances are unloaded or replaced.
597
EditorNode::get_singleton()->push_item(nullptr);
598
EditorUndoRedoManager::get_singleton()->clear_history();
599
600
List<Ref<Resource>> external_resources;
601
ResourceCache::get_cached_resources(&external_resources);
602
603
Vector<Ref<Resource>> old_resources_to_replace;
604
Vector<Ref<Resource>> new_resources_to_replace;
605
for (const String &path : need_cleanup) {
606
Ref<Resource> old_res = old_resources[path];
607
if (params->importer.is_valid()) {
608
Ref<Resource> new_res = ResourceLoader::load(path);
609
if (new_res.is_valid()) {
610
old_resources_to_replace.append(old_res);
611
new_resources_to_replace.append(new_res);
612
}
613
}
614
}
615
616
EditorNode::get_singleton()->replace_resources_in_scenes(old_resources_to_replace, new_resources_to_replace);
617
618
for (Ref<Resource> res : external_resources) {
619
EditorNode::get_singleton()->replace_resources_in_object(res.ptr(), old_resources_to_replace, new_resources_to_replace);
620
}
621
622
need_cleanup.clear();
623
}
624
625
void ImportDock::_advanced_options() {
626
if (params->paths.size() == 1 && params->importer.is_valid()) {
627
params->importer->show_advanced_options(params->paths[0]);
628
}
629
}
630
631
void ImportDock::_reimport() {
632
for (int i = 0; i < params->paths.size(); i++) {
633
Ref<ConfigFile> config;
634
config.instantiate();
635
Error err = config->load(params->paths[i] + ".import");
636
ERR_CONTINUE(err != OK);
637
638
if (params->importer.is_valid()) {
639
String importer_name = params->importer->get_importer_name();
640
641
if (params->checking && config->get_value("remap", "importer") == params->importer->get_importer_name()) {
642
//update only what is edited (checkboxes) if the importer is the same
643
for (const PropertyInfo &E : params->properties) {
644
if (params->checked.has(E.name)) {
645
config->set_value("params", E.name, params->values[E.name]);
646
}
647
}
648
} else {
649
//override entirely
650
config->set_value("remap", "importer", importer_name);
651
if (config->has_section("params")) {
652
config->erase_section("params");
653
}
654
655
for (const PropertyInfo &E : params->properties) {
656
config->set_value("params", E.name, params->values[E.name]);
657
}
658
}
659
660
//handle group file
661
Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
662
ERR_CONTINUE(importer.is_null());
663
String group_file_property = importer->get_option_group_file();
664
if (!group_file_property.is_empty()) {
665
//can import from a group (as in, atlas)
666
ERR_CONTINUE(!params->values.has(group_file_property));
667
String group_file = params->values[group_file_property];
668
config->set_value("remap", "group_file", group_file);
669
} else {
670
config->set_value("remap", "group_file", Variant()); //clear group file if unused
671
}
672
673
} else {
674
//set to no import
675
config->clear();
676
if (params->skip) {
677
config->set_value("remap", "importer", "skip");
678
} else {
679
config->set_value("remap", "importer", "keep");
680
}
681
}
682
683
config->save(params->paths[i] + ".import");
684
}
685
686
EditorFileSystem::get_singleton()->reimport_files(params->paths);
687
EditorFileSystem::get_singleton()->emit_signal(SNAME("filesystem_changed")); //it changed, so force emitting the signal
688
689
_set_dirty(false);
690
}
691
692
void ImportDock::_notification(int p_what) {
693
switch (p_what) {
694
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
695
if (EditorThemeManager::is_generated_theme_outdated()) {
696
imported->add_theme_style_override(CoreStringName(normal), get_theme_stylebox(CoreStringName(normal), SNAME("LineEdit")));
697
}
698
} break;
699
700
case NOTIFICATION_ENTER_TREE: {
701
import_opts->edit(params);
702
label_warning->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
703
} break;
704
}
705
}
706
707
void ImportDock::_property_edited(const StringName &p_prop) {
708
_set_dirty(true);
709
}
710
711
void ImportDock::_set_dirty(bool p_dirty) {
712
if (p_dirty) {
713
// Add a dirty marker to notify the user that they should reimport the selected resource to see changes.
714
import->set_text(TTR("Reimport") + " (*)");
715
import->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
716
import->set_tooltip_text(TTRC("You have pending changes that haven't been applied yet. Click Reimport to apply changes made to the import options.\nSelecting another resource in the FileSystem dock without clicking Reimport first will discard changes made in the Import dock."));
717
} else {
718
// Remove the dirty marker on the Reimport button.
719
import->set_text(TTRC("Reimport"));
720
import->remove_theme_color_override(SceneStringName(font_color));
721
import->set_tooltip_text("");
722
}
723
}
724
725
void ImportDock::_property_toggled(const StringName &p_prop, bool p_checked) {
726
if (p_checked) {
727
params->checked.insert(p_prop);
728
} else {
729
params->checked.erase(p_prop);
730
}
731
}
732
733
void ImportDock::_bind_methods() {
734
ClassDB::bind_method(D_METHOD("_reimport"), &ImportDock::_reimport);
735
}
736
737
void ImportDock::initialize_import_options() const {
738
ERR_FAIL_COND(!import_opts || !params);
739
740
import_opts->edit(params);
741
}
742
743
ImportDock::ImportDock() {
744
singleton = this;
745
set_name("Import");
746
747
content = memnew(VBoxContainer);
748
content->set_v_size_flags(SIZE_EXPAND_FILL);
749
add_child(content);
750
content->hide();
751
752
imported = memnew(Label);
753
imported->set_focus_mode(FOCUS_ACCESSIBILITY);
754
imported->add_theme_style_override(CoreStringName(normal), EditorNode::get_singleton()->get_editor_theme()->get_stylebox(CoreStringName(normal), SNAME("LineEdit")));
755
imported->set_clip_text(true);
756
content->add_child(imported);
757
HBoxContainer *hb = memnew(HBoxContainer);
758
content->add_margin_child(TTRC("Import As:"), hb);
759
import_as = memnew(OptionButton);
760
import_as->set_disabled(true);
761
import_as->set_fit_to_longest_item(false);
762
import_as->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
763
import_as->set_h_size_flags(SIZE_EXPAND_FILL);
764
import_as->connect(SceneStringName(item_selected), callable_mp(this, &ImportDock::_importer_selected));
765
import_as->set_accessibility_name(TTRC("Import As:"));
766
hb->add_child(import_as);
767
import_as->set_h_size_flags(SIZE_EXPAND_FILL);
768
preset = memnew(MenuButton);
769
preset->set_text(TTRC("Preset"));
770
preset->set_disabled(true);
771
preset->get_popup()->connect("index_pressed", callable_mp(this, &ImportDock::_preset_selected));
772
hb->add_child(preset);
773
774
import_opts = memnew(EditorInspector);
775
content->add_child(import_opts);
776
import_opts->set_v_size_flags(SIZE_EXPAND_FILL);
777
import_opts->connect("property_edited", callable_mp(this, &ImportDock::_property_edited));
778
import_opts->connect("property_toggled", callable_mp(this, &ImportDock::_property_toggled));
779
// Make it possible to display tooltips stored in the XML class reference.
780
// The object name is set when the importer changes in `_update_options()`.
781
import_opts->set_use_doc_hints(true);
782
783
hb = memnew(HBoxContainer);
784
content->add_child(hb);
785
import = memnew(Button);
786
import->set_text(TTRC("Reimport"));
787
import->set_disabled(true);
788
import->connect(SceneStringName(pressed), callable_mp(this, &ImportDock::_reimport_pressed));
789
advanced_spacer = hb->add_spacer();
790
advanced = memnew(Button);
791
advanced->set_text(TTRC("Advanced..."));
792
hb->add_child(advanced);
793
hb->add_spacer();
794
hb->add_child(import);
795
hb->add_spacer();
796
797
advanced->hide();
798
advanced_spacer->hide();
799
advanced->connect(SceneStringName(pressed), callable_mp(this, &ImportDock::_advanced_options));
800
801
reimport_confirm = memnew(ConfirmationDialog);
802
content->add_child(reimport_confirm);
803
reimport_confirm->connect(SceneStringName(confirmed), callable_mp(this, &ImportDock::_reimport_and_cleanup));
804
805
VBoxContainer *vbc_confirm = memnew(VBoxContainer());
806
cleanup_warning = memnew(Label(TTRC("The imported resource is currently loaded. All instances will be replaced and undo history will be cleared.")));
807
vbc_confirm->add_child(cleanup_warning);
808
label_warning = memnew(Label(TTRC("WARNING: Assets exist that use this resource. They may stop loading properly after changing type.")));
809
vbc_confirm->add_child(label_warning);
810
reimport_confirm->add_child(vbc_confirm);
811
812
params = memnew(ImportDockParameters);
813
814
select_a_resource = memnew(Label);
815
select_a_resource->set_focus_mode(FOCUS_ACCESSIBILITY);
816
select_a_resource->set_text(TTRC("Select a resource file in the filesystem or in the inspector to adjust import settings."));
817
select_a_resource->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
818
select_a_resource->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
819
select_a_resource->set_v_size_flags(SIZE_EXPAND_FILL);
820
select_a_resource->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
821
select_a_resource->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
822
add_child(select_a_resource);
823
}
824
825
ImportDock::~ImportDock() {
826
singleton = nullptr;
827
memdelete(params);
828
}
829
830