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