feat: modules moved and engine moved to submodule
This commit is contained in:
parent
dfb5e645cd
commit
c33d2130cc
5136 changed files with 225275 additions and 64485 deletions
|
|
@ -5,7 +5,6 @@ Import("env")
|
|||
|
||||
env.editor_sources = []
|
||||
|
||||
import glob
|
||||
import os
|
||||
|
||||
import editor_builders
|
||||
|
|
@ -17,17 +16,16 @@ if env.editor_build:
|
|||
def doc_data_class_path_builder(target, source, env):
|
||||
paths = dict(sorted(source[0].read().items()))
|
||||
data = "\n".join([f'\t{{"{key}", "{value}"}},' for key, value in paths.items()])
|
||||
with methods.generated_wrapper(target) as file:
|
||||
with methods.generated_wrapper(str(target[0])) as file:
|
||||
file.write(
|
||||
f"""\
|
||||
static const int _doc_data_class_path_count = {len(paths)};
|
||||
|
||||
struct _DocDataClassPath {{
|
||||
const char *name;
|
||||
const char *path;
|
||||
}};
|
||||
|
||||
static const _DocDataClassPath _doc_data_class_paths[{len(env.doc_class_path) + 1}] = {{
|
||||
inline constexpr int _doc_data_class_path_count = {len(paths)};
|
||||
inline constexpr _DocDataClassPath _doc_data_class_paths[{len(env.doc_class_path) + 1}] = {{
|
||||
{data}
|
||||
{{nullptr, nullptr}},
|
||||
}};
|
||||
|
|
@ -42,7 +40,7 @@ static const _DocDataClassPath _doc_data_class_paths[{len(env.doc_class_path) +
|
|||
exp_inc = "\n".join([f'#include "platform/{p}/export/export.h"' for p in platforms])
|
||||
exp_reg = "\n".join([f"\tregister_{p}_exporter();" for p in platforms])
|
||||
exp_type = "\n".join([f"\tregister_{p}_exporter_types();" for p in platforms])
|
||||
with methods.generated_wrapper(target) as file:
|
||||
with methods.generated_wrapper(str(target[0])) as file:
|
||||
file.write(
|
||||
f"""\
|
||||
#include "register_exporters.h"
|
||||
|
|
@ -83,7 +81,6 @@ void register_exporter_types() {{
|
|||
docs += Glob(d + "/*.xml") # Custom.
|
||||
|
||||
docs = sorted(docs)
|
||||
env.Depends("#editor/doc_data_compressed.gen.h", docs)
|
||||
env.CommandNoCache(
|
||||
"#editor/doc_data_compressed.gen.h",
|
||||
docs,
|
||||
|
|
@ -97,40 +94,31 @@ void register_exporter_types() {{
|
|||
# Generated with `make include-list` for each resource.
|
||||
|
||||
# Editor translations
|
||||
tlist = glob.glob(env.Dir("#editor/translations/editor").abspath + "/*.po")
|
||||
env.Depends("#editor/editor_translations.gen.h", tlist)
|
||||
env.CommandNoCache(
|
||||
"#editor/editor_translations.gen.h",
|
||||
tlist,
|
||||
env.Run(editor_builders.make_editor_translations_header),
|
||||
Glob("#editor/translations/editor/*"),
|
||||
env.Run(editor_builders.make_translations_header),
|
||||
)
|
||||
|
||||
# Property translations
|
||||
tlist = glob.glob(env.Dir("#editor/translations/properties").abspath + "/*.po")
|
||||
env.Depends("#editor/property_translations.gen.h", tlist)
|
||||
env.CommandNoCache(
|
||||
"#editor/property_translations.gen.h",
|
||||
tlist,
|
||||
env.Run(editor_builders.make_property_translations_header),
|
||||
Glob("#editor/translations/properties/*"),
|
||||
env.Run(editor_builders.make_translations_header),
|
||||
)
|
||||
|
||||
# Documentation translations
|
||||
tlist = glob.glob(env.Dir("#doc/translations").abspath + "/*.po")
|
||||
env.Depends("#editor/doc_translations.gen.h", tlist)
|
||||
env.CommandNoCache(
|
||||
"#editor/doc_translations.gen.h",
|
||||
tlist,
|
||||
env.Run(editor_builders.make_doc_translations_header),
|
||||
Glob("#doc/translations/*"),
|
||||
env.Run(editor_builders.make_translations_header),
|
||||
)
|
||||
|
||||
# Extractable translations
|
||||
tlist = glob.glob(env.Dir("#editor/translations/extractable").abspath + "/*.po")
|
||||
tlist.extend(glob.glob(env.Dir("#editor/translations/extractable").abspath + "/extractable.pot"))
|
||||
env.Depends("#editor/extractable_translations.gen.h", tlist)
|
||||
env.CommandNoCache(
|
||||
"#editor/extractable_translations.gen.h",
|
||||
tlist,
|
||||
env.Run(editor_builders.make_extractable_translations_header),
|
||||
Glob("#editor/translations/extractable/*"),
|
||||
env.Run(editor_builders.make_translations_header),
|
||||
)
|
||||
|
||||
env.add_source_files(env.editor_sources, "*.cpp")
|
||||
|
|
|
|||
|
|
@ -257,6 +257,8 @@ Variant ActionMapEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from
|
|||
label->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
action_tree->set_drag_preview(label);
|
||||
|
||||
get_viewport()->gui_set_drag_description(vformat(RTR("Action %s"), name));
|
||||
|
||||
Dictionary drag_data;
|
||||
|
||||
if (selected->has_meta("__action")) {
|
||||
|
|
@ -267,6 +269,8 @@ Variant ActionMapEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from
|
|||
drag_data["input_type"] = "event";
|
||||
}
|
||||
|
||||
drag_data["source"] = selected->get_instance_id();
|
||||
|
||||
action_tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
|
||||
|
||||
return drag_data;
|
||||
|
|
@ -278,9 +282,11 @@ bool ActionMapEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_d
|
|||
return false;
|
||||
}
|
||||
|
||||
TreeItem *source = Object::cast_to<TreeItem>(ObjectDB::get_instance(d["source"].operator ObjectID()));
|
||||
TreeItem *selected = action_tree->get_selected();
|
||||
TreeItem *item = action_tree->get_item_at_position(p_point);
|
||||
if (!selected || !item || item == selected) {
|
||||
|
||||
TreeItem *item = (p_point == Vector2(Math::INF, Math::INF)) ? selected : action_tree->get_item_at_position(p_point);
|
||||
if (!selected || !item || item == source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -303,13 +309,13 @@ void ActionMapEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data,
|
|||
}
|
||||
|
||||
TreeItem *selected = action_tree->get_selected();
|
||||
TreeItem *target = action_tree->get_item_at_position(p_point);
|
||||
bool drop_above = action_tree->get_drop_section_at_position(p_point) == -1;
|
||||
|
||||
TreeItem *target = (p_point == Vector2(Math::INF, Math::INF)) ? selected : action_tree->get_item_at_position(p_point);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool drop_above = ((p_point == Vector2(Math::INF, Math::INF)) ? action_tree->get_drop_section_at_position(action_tree->get_item_rect(target).position) : action_tree->get_drop_section_at_position(p_point)) == -1;
|
||||
|
||||
Dictionary d = p_data;
|
||||
if (d["input_type"] == "action") {
|
||||
// Change action order.
|
||||
|
|
@ -501,8 +507,8 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info
|
|||
}
|
||||
|
||||
// Third Column - Buttons
|
||||
event_item->add_button(2, action_tree->get_editor_theme_icon(SNAME("Edit")), BUTTON_EDIT_EVENT, false, TTR("Edit Event"));
|
||||
event_item->add_button(2, action_tree->get_editor_theme_icon(SNAME("Remove")), BUTTON_REMOVE_EVENT, false, TTR("Remove Event"));
|
||||
event_item->add_button(2, action_tree->get_editor_theme_icon(SNAME("Edit")), BUTTON_EDIT_EVENT, false, TTR("Edit Event"), TTR("Edit Event"));
|
||||
event_item->add_button(2, action_tree->get_editor_theme_icon(SNAME("Remove")), BUTTON_REMOVE_EVENT, false, TTR("Remove Event"), TTR("Remove Event"));
|
||||
event_item->set_button_color(2, 0, Color(1, 1, 1, 0.75));
|
||||
event_item->set_button_color(2, 1, Color(1, 1, 1, 0.75));
|
||||
}
|
||||
|
|
@ -543,6 +549,7 @@ ActionMapEditor::ActionMapEditor() {
|
|||
action_list_search = memnew(LineEdit);
|
||||
action_list_search->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
action_list_search->set_placeholder(TTR("Filter by Name"));
|
||||
action_list_search->set_accessibility_name(TTRC("Filter by Name"));
|
||||
action_list_search->set_clear_button_enabled(true);
|
||||
action_list_search->connect(SceneStringName(text_changed), callable_mp(this, &ActionMapEditor::_search_term_updated));
|
||||
top_hbox->add_child(action_list_search);
|
||||
|
|
@ -550,6 +557,7 @@ ActionMapEditor::ActionMapEditor() {
|
|||
action_list_search_by_event = memnew(EventListenerLineEdit);
|
||||
action_list_search_by_event->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
action_list_search_by_event->set_stretch_ratio(0.75);
|
||||
action_list_search_by_event->set_accessibility_name(TTRC("Action Event"));
|
||||
action_list_search_by_event->connect("event_changed", callable_mp(this, &ActionMapEditor::_search_by_event));
|
||||
action_list_search_by_event->connect(SceneStringName(focus_entered), callable_mp(this, &ActionMapEditor::_on_filter_focused));
|
||||
action_list_search_by_event->connect(SceneStringName(focus_exited), callable_mp(this, &ActionMapEditor::_on_filter_unfocused));
|
||||
|
|
@ -569,6 +577,7 @@ ActionMapEditor::ActionMapEditor() {
|
|||
add_edit = memnew(LineEdit);
|
||||
add_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
add_edit->set_placeholder(TTR("Add New Action"));
|
||||
add_edit->set_accessibility_name(TTRC("Add New Action"));
|
||||
add_edit->set_clear_button_enabled(true);
|
||||
add_edit->set_keep_editing_on_text_submit(true);
|
||||
add_edit->connect(SceneStringName(text_changed), callable_mp(this, &ActionMapEditor::_add_edit_text_changed));
|
||||
|
|
@ -597,6 +606,7 @@ ActionMapEditor::ActionMapEditor() {
|
|||
// Action Editor Tree
|
||||
action_tree = memnew(Tree);
|
||||
action_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
action_tree->set_accessibility_name(TTRC("Action Map"));
|
||||
action_tree->set_columns(3);
|
||||
action_tree->set_hide_root(true);
|
||||
action_tree->set_column_titles_visible(true);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ACTION_MAP_EDITOR_H
|
||||
#define ACTION_MAP_EDITOR_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/control.h"
|
||||
|
||||
|
|
@ -132,5 +131,3 @@ public:
|
|||
|
||||
ActionMapEditor();
|
||||
};
|
||||
|
||||
#endif // ACTION_MAP_EDITOR_H
|
||||
|
|
|
|||
|
|
@ -41,11 +41,13 @@ AddMetadataDialog::AddMetadataDialog() {
|
|||
hbc->add_child(memnew(Label(TTR("Name:"))));
|
||||
|
||||
add_meta_name = memnew(LineEdit);
|
||||
add_meta_name->set_accessibility_name(TTRC("Name:"));
|
||||
add_meta_name->set_custom_minimum_size(Size2(200 * EDSCALE, 1));
|
||||
hbc->add_child(add_meta_name);
|
||||
hbc->add_child(memnew(Label(TTR("Type:"))));
|
||||
|
||||
add_meta_type = memnew(OptionButton);
|
||||
add_meta_type->set_accessibility_name(TTRC("Type:"));
|
||||
|
||||
hbc->add_child(add_meta_type);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ADD_METADATA_DIALOG_H
|
||||
#define ADD_METADATA_DIALOG_H
|
||||
#pragma once
|
||||
|
||||
#include "editor/gui/editor_validation_panel.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
|
|
@ -56,4 +55,3 @@ private:
|
|||
OptionButton *add_meta_type = nullptr;
|
||||
EditorValidationPanel *validation_panel = nullptr;
|
||||
};
|
||||
#endif // ADD_METADATA_DIALOG_H
|
||||
|
|
|
|||
|
|
@ -60,8 +60,12 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
|
|||
|
||||
for (int i = 0; i < animation->track_get_key_count(p_track); i++) {
|
||||
real_t ofs = animation->track_get_key_time(p_track, i);
|
||||
if (moving_selection && selection.has(IntPair(p_track, i))) {
|
||||
ofs += moving_selection_offset.x;
|
||||
if (selection.has(IntPair(p_track, i))) {
|
||||
if (moving_selection) {
|
||||
ofs += moving_selection_offset.x;
|
||||
} else if (scaling_selection) {
|
||||
ofs += -scaling_selection_offset.x + (ofs - scaling_selection_pivot.x) * (scaling_selection_scale.x - 1);
|
||||
}
|
||||
}
|
||||
|
||||
key_order[ofs] = i;
|
||||
|
|
@ -83,9 +87,14 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
|
|||
out_handle = moving_handle_right;
|
||||
}
|
||||
|
||||
if (moving_selection && selection.has(IntPair(p_track, i))) {
|
||||
offset += moving_selection_offset.x;
|
||||
height += moving_selection_offset.y;
|
||||
if (selection.has(IntPair(p_track, i))) {
|
||||
if (moving_selection) {
|
||||
offset += moving_selection_offset.x;
|
||||
height += moving_selection_offset.y;
|
||||
} else if (scaling_selection) {
|
||||
offset += -scaling_selection_offset.x + (offset - scaling_selection_pivot.x) * (scaling_selection_scale.x - 1);
|
||||
height += -scaling_selection_offset.y + (height - scaling_selection_pivot.y) * (scaling_selection_scale.y - 1);
|
||||
}
|
||||
}
|
||||
|
||||
out_handle += Vector2(offset, height);
|
||||
|
|
@ -97,9 +106,14 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
|
|||
in_handle = moving_handle_left;
|
||||
}
|
||||
|
||||
if (moving_selection && selection.has(IntPair(p_track, i_n))) {
|
||||
offset_n += moving_selection_offset.x;
|
||||
height_n += moving_selection_offset.y;
|
||||
if (selection.has(IntPair(p_track, i_n))) {
|
||||
if (moving_selection) {
|
||||
offset_n += moving_selection_offset.x;
|
||||
height_n += moving_selection_offset.y;
|
||||
} else if (scaling_selection) {
|
||||
offset_n += -scaling_selection_offset.x + (offset_n - scaling_selection_pivot.x) * (scaling_selection_scale.x - 1);
|
||||
height_n += -scaling_selection_offset.y + (height_n - scaling_selection_pivot.y) * (scaling_selection_scale.y - 1);
|
||||
}
|
||||
}
|
||||
|
||||
in_handle += Vector2(offset_n, height_n);
|
||||
|
|
@ -231,6 +245,15 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
|||
selected_icon = get_editor_theme_icon(SNAME("KeyBezierSelected"));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
//TODO
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_STATIC_TEXT);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, TTR(vformat("The %s is not accessible at this time.", "Animation bezier track editor")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAW: {
|
||||
if (animation.is_null()) {
|
||||
return;
|
||||
|
|
@ -506,29 +529,46 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
|||
}
|
||||
}
|
||||
|
||||
const bool draw_selection_handles = selection.size() > 1;
|
||||
LocalVector<Point2> selected_pos;
|
||||
|
||||
// Draw editor handles.
|
||||
{
|
||||
edit_points.clear();
|
||||
float scale = timeline->get_zoom_scale();
|
||||
|
||||
for (int i = 0; i < track_count; ++i) {
|
||||
if (!_is_track_curves_displayed(i) || locked_tracks.has(i)) {
|
||||
bool draw_track = _is_track_curves_displayed(i) && !locked_tracks.has(i);
|
||||
if (!draw_selection_handles && !draw_track) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int key_count = animation->track_get_key_count(i);
|
||||
|
||||
for (int j = 0; j < key_count; ++j) {
|
||||
float offset = animation->track_get_key_time(i, j);
|
||||
float value = animation->bezier_track_get_key_value(i, j);
|
||||
bool is_selected = selection.has(IntPair(i, j));
|
||||
|
||||
if (moving_selection && selection.has(IntPair(i, j))) {
|
||||
offset += moving_selection_offset.x;
|
||||
value += moving_selection_offset.y;
|
||||
if (is_selected) {
|
||||
if (moving_selection) {
|
||||
offset += moving_selection_offset.x;
|
||||
value += moving_selection_offset.y;
|
||||
} else if (scaling_selection) {
|
||||
offset += -scaling_selection_offset.x + (offset - scaling_selection_pivot.x) * (scaling_selection_scale.x - 1);
|
||||
value += -scaling_selection_offset.y + (value - scaling_selection_pivot.y) * (scaling_selection_scale.y - 1);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 pos((offset - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value));
|
||||
|
||||
if (draw_selection_handles && is_selected) {
|
||||
selected_pos.push_back(pos);
|
||||
}
|
||||
|
||||
if (!draw_track) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector2 in_vec = animation->bezier_track_get_key_in_handle(i, j);
|
||||
|
||||
if ((moving_handle == 1 || moving_handle == -1) && moving_handle_track == i && moving_handle_key == j) {
|
||||
|
|
@ -544,7 +584,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
|||
|
||||
Vector2 pos_out(((offset + out_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + out_vec.y));
|
||||
|
||||
if (i == selected_track || selection.has(IntPair(i, j))) {
|
||||
if (i == selected_track || is_selected) {
|
||||
_draw_line_clipped(pos, pos_in, accent, limit, right_limit);
|
||||
_draw_line_clipped(pos, pos_out, accent, limit, right_limit);
|
||||
}
|
||||
|
|
@ -555,7 +595,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
|||
if (pos.x >= limit && pos.x <= right_limit) {
|
||||
ep.point_rect.position = (pos - bezier_icon->get_size() / 2.0).floor();
|
||||
ep.point_rect.size = bezier_icon->get_size();
|
||||
if (selection.has(IntPair(i, j))) {
|
||||
if (is_selected) {
|
||||
draw_texture(selected_icon, ep.point_rect.position);
|
||||
draw_string(font, ep.point_rect.position + Vector2(8, -font->get_height(font_size) - 8), TTR("Time:") + " " + TS->format_number(rtos(Math::snapped(offset, 0.0001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
|
||||
draw_string(font, ep.point_rect.position + Vector2(8, -8), TTR("Value:") + " " + TS->format_number(rtos(Math::snapped(value, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
|
||||
|
|
@ -570,7 +610,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
|||
}
|
||||
ep.point_rect = ep.point_rect.grow(ep.point_rect.size.width * 0.5);
|
||||
|
||||
if (i == selected_track || selection.has(IntPair(i, j))) {
|
||||
if (i == selected_track || is_selected) {
|
||||
if (animation->bezier_track_get_key_handle_mode(i, j) != Animation::HANDLE_MODE_LINEAR) {
|
||||
if (pos_in.x >= limit && pos_in.x <= right_limit) {
|
||||
ep.in_rect.position = (pos_in - bezier_handle_icon->get_size() / 2.0).floor();
|
||||
|
|
@ -601,6 +641,34 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
|||
}
|
||||
}
|
||||
|
||||
selection_rect = Rect2();
|
||||
selection_handles_rect = Rect2();
|
||||
// Draw scale handles.
|
||||
if (draw_selection_handles) {
|
||||
selection_rect.position = selected_pos[0];
|
||||
selected_pos.remove_at(0);
|
||||
for (const Point2 &pos : selected_pos) {
|
||||
selection_rect = selection_rect.expand(pos);
|
||||
}
|
||||
|
||||
const int outer_ofs = Math::round(12 * EDSCALE);
|
||||
const int inner_ofs = Math::round(outer_ofs / 2.0);
|
||||
|
||||
// Draw horizontal handles.
|
||||
if (selection_rect.size.height > CMP_EPSILON) {
|
||||
_draw_line_clipped(selection_rect.position - Vector2(inner_ofs, inner_ofs), selection_rect.position + Vector2(selection_rect.size.width + inner_ofs, -inner_ofs), accent, limit, right_limit);
|
||||
_draw_line_clipped(selection_rect.position + Vector2(-inner_ofs, selection_rect.size.height + inner_ofs), selection_rect.position + selection_rect.size + Vector2(inner_ofs, inner_ofs), accent, limit, right_limit);
|
||||
}
|
||||
// Draw vertical handles.
|
||||
if (selection_rect.size.width > CMP_EPSILON) {
|
||||
_draw_line_clipped(selection_rect.position - Vector2(inner_ofs, inner_ofs), selection_rect.position + Vector2(-inner_ofs, selection_rect.size.height + inner_ofs), accent, limit, right_limit);
|
||||
_draw_line_clipped(selection_rect.position + Vector2(selection_rect.size.width + inner_ofs, -inner_ofs), selection_rect.position + selection_rect.size + Vector2(inner_ofs, inner_ofs), accent, limit, right_limit);
|
||||
}
|
||||
|
||||
selection_handles_rect.position = selection_rect.position - Vector2(outer_ofs, outer_ofs);
|
||||
selection_handles_rect.size = selection_rect.size + Vector2(outer_ofs, outer_ofs) * 2;
|
||||
}
|
||||
|
||||
if (box_selecting) {
|
||||
Vector2 bs_from = box_selection_from;
|
||||
Vector2 bs_to = box_selection_to;
|
||||
|
|
@ -756,8 +824,8 @@ void AnimationBezierTrackEdit::set_filtered(bool p_filtered) {
|
|||
|
||||
void AnimationBezierTrackEdit::auto_fit_vertically() {
|
||||
int track_count = animation->get_track_count();
|
||||
real_t minimum_value = INFINITY;
|
||||
real_t maximum_value = -INFINITY;
|
||||
real_t minimum_value = Math::INF;
|
||||
real_t maximum_value = -Math::INF;
|
||||
|
||||
int nb_track_visible = 0;
|
||||
for (int i = 0; i < track_count; ++i) {
|
||||
|
|
@ -968,10 +1036,10 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
return;
|
||||
}
|
||||
|
||||
real_t minimum_time = INFINITY;
|
||||
real_t maximum_time = -INFINITY;
|
||||
real_t minimum_value = INFINITY;
|
||||
real_t maximum_value = -INFINITY;
|
||||
real_t minimum_time = Math::INF;
|
||||
real_t maximum_time = -Math::INF;
|
||||
real_t minimum_value = Math::INF;
|
||||
real_t maximum_value = -Math::INF;
|
||||
|
||||
for (const IntPair &E : focused_keys) {
|
||||
IntPair key_pair = E;
|
||||
|
|
@ -1193,15 +1261,17 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check this first, to allow manipulating key handles while ignoring keyframes before scaling/moving.
|
||||
bool inside_selection_handles_rect = !read_only && selection_handles_rect.has_point(mb->get_position());
|
||||
|
||||
// First, check keyframe.
|
||||
// Command/Control makes it ignore the keyframe, so control point editors can be force-edited.
|
||||
if (!mb->is_command_or_control_pressed()) {
|
||||
if (!inside_selection_handles_rect && !mb->is_command_or_control_pressed()) {
|
||||
if (_try_select_at_ui_pos(mb->get_position(), mb->is_shift_pressed(), true)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Second, check handles.
|
||||
// Second, check key handles.
|
||||
for (int i = 0; i < edit_points.size(); i++) {
|
||||
if (!read_only) {
|
||||
if (edit_points[i].in_rect.has_point(mb->get_position())) {
|
||||
|
|
@ -1226,6 +1296,50 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
}
|
||||
|
||||
// Box scaling/movement.
|
||||
if (inside_selection_handles_rect) {
|
||||
const Vector2i rel_pos = mb->get_position() - selection_rect.position;
|
||||
scaling_selection_handles = Vector2i();
|
||||
|
||||
// Check which scaling handles are available.
|
||||
if (selection_rect.size.width > CMP_EPSILON) {
|
||||
if (rel_pos.x <= 0) {
|
||||
scaling_selection_handles.x = -1;
|
||||
} else if (rel_pos.x >= selection_rect.size.width) {
|
||||
scaling_selection_handles.x = 1;
|
||||
}
|
||||
}
|
||||
if (selection_rect.size.height > CMP_EPSILON) {
|
||||
if (rel_pos.y <= 0) {
|
||||
scaling_selection_handles.y = -1;
|
||||
} else if (rel_pos.y >= selection_rect.size.height) {
|
||||
scaling_selection_handles.y = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (scaling_selection_handles != Vector2i()) {
|
||||
scaling_selection = true;
|
||||
|
||||
const float time = ((selection_rect.position.x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
|
||||
const float h = (get_size().height / 2.0 - selection_rect.position.y) * timeline_v_zoom + timeline_v_scroll;
|
||||
scaling_selection_pivot = Point2(time, h);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If not scaling, that means we're moving.
|
||||
moving_selection_attempt = true;
|
||||
moving_selection = false;
|
||||
moving_selection_mouse_begin = mb->get_position();
|
||||
// The pivot will be from the mouse click location, not a specific key.
|
||||
moving_selection_from_key = -1;
|
||||
moving_selection_from_track = selected_track;
|
||||
moving_selection_offset = Vector2();
|
||||
select_single_attempt = IntPair(-1, -1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert new point.
|
||||
if (mb->get_position().x >= limit && mb->get_position().x < get_size().width && mb->is_command_or_control_pressed()) {
|
||||
float h = (get_size().height / 2.0 - mb->get_position().y) * timeline_v_zoom + timeline_v_scroll;
|
||||
|
|
@ -1250,7 +1364,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
|
||||
moving_selection_attempt = true;
|
||||
moving_selection = false;
|
||||
moving_selection_mouse_begin_x = mb->get_position().x;
|
||||
moving_selection_mouse_begin = mb->get_position();
|
||||
moving_selection_from_key = index;
|
||||
moving_selection_from_track = selected_track;
|
||||
moving_selection_offset = Vector2();
|
||||
|
|
@ -1285,12 +1399,12 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
if (bs_from.y > bs_to.y) {
|
||||
SWAP(bs_from.y, bs_to.y);
|
||||
}
|
||||
Rect2 selection_rect(bs_from, bs_to - bs_from);
|
||||
Rect2 rect(bs_from, bs_to - bs_from);
|
||||
|
||||
bool track_set = false;
|
||||
int j = 0;
|
||||
for (int i = 0; i < edit_points.size(); i++) {
|
||||
if (edit_points[i].point_rect.intersects(selection_rect)) {
|
||||
if (edit_points[i].point_rect.intersects(rect)) {
|
||||
_select_at_anim(animation, edit_points[i].track, animation->track_get_key_time(edit_points[i].track, edit_points[i].key), j == 0 && !box_selecting_add);
|
||||
if (!track_set) {
|
||||
track_set = true;
|
||||
|
|
@ -1335,8 +1449,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
|
||||
if (!read_only) {
|
||||
if (moving_selection && (abs(moving_selection_offset.x) > CMP_EPSILON || abs(moving_selection_offset.y) > CMP_EPSILON)) {
|
||||
//combit it
|
||||
|
||||
// Commit it.
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Move Bezier Points"));
|
||||
|
||||
|
|
@ -1459,11 +1572,141 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
|
||||
moving_selection = false;
|
||||
moving_selection_attempt = false;
|
||||
moving_selection_mouse_begin_x = 0.0;
|
||||
moving_selection_mouse_begin = Point2();
|
||||
queue_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
if (scaling_selection && mb.is_valid() && !read_only && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
|
||||
if (abs(scaling_selection_scale.x - 1) > CMP_EPSILON || abs(scaling_selection_scale.y - 1) > CMP_EPSILON) {
|
||||
// Scale it.
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Scale Bezier Points"));
|
||||
|
||||
List<AnimMoveRestore> to_restore;
|
||||
List<Animation::HandleMode> to_restore_handle_modes;
|
||||
// 1 - Remove the keys.
|
||||
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
|
||||
undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second);
|
||||
}
|
||||
// 2 - Remove overlapped keys.
|
||||
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
|
||||
real_t newtime = animation->track_get_key_time(E->get().first, E->get().second);
|
||||
newtime += -scaling_selection_offset.x + (newtime - scaling_selection_pivot.x) * (scaling_selection_scale.x - 1);
|
||||
|
||||
int idx = animation->track_find_key(E->get().first, newtime, Animation::FIND_MODE_APPROX);
|
||||
if (idx == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selection.has(IntPair(E->get().first, idx))) {
|
||||
continue; // Already in selection, don't save.
|
||||
}
|
||||
|
||||
undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newtime);
|
||||
AnimMoveRestore amr;
|
||||
|
||||
amr.key = animation->track_get_key_value(E->get().first, idx);
|
||||
amr.track = E->get().first;
|
||||
amr.time = newtime;
|
||||
|
||||
to_restore.push_back(amr);
|
||||
to_restore_handle_modes.push_back(animation->bezier_track_get_key_handle_mode(E->get().first, idx));
|
||||
}
|
||||
|
||||
// 3 - Scale the keys (re-insert them).
|
||||
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
|
||||
real_t newpos = animation->track_get_key_time(E->get().first, E->get().second);
|
||||
newpos += -scaling_selection_offset.x + (newpos - scaling_selection_pivot.x) * (scaling_selection_scale.x - 1);
|
||||
|
||||
Array key = animation->track_get_key_value(E->get().first, E->get().second);
|
||||
real_t h = key[0];
|
||||
h += -scaling_selection_offset.y + (h - scaling_selection_pivot.y) * (scaling_selection_scale.y - 1);
|
||||
key[0] = h;
|
||||
|
||||
undo_redo->add_do_method(
|
||||
this,
|
||||
"_bezier_track_insert_key_at_anim",
|
||||
animation,
|
||||
E->get().first,
|
||||
newpos,
|
||||
key[0],
|
||||
Vector2(key[1], key[2]),
|
||||
Vector2(key[3], key[4]),
|
||||
animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second));
|
||||
}
|
||||
|
||||
// 4 - (undo) Remove inserted keys.
|
||||
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
|
||||
real_t newpos = animation->track_get_key_time(E->get().first, E->get().second);
|
||||
newpos += -scaling_selection_offset.x + (newpos - scaling_selection_pivot.x) * (scaling_selection_scale.x - 1);
|
||||
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos);
|
||||
}
|
||||
|
||||
// 5 - (undo) Reinsert keys.
|
||||
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
|
||||
real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second);
|
||||
Array key = animation->track_get_key_value(E->get().first, E->get().second);
|
||||
undo_redo->add_undo_method(
|
||||
this,
|
||||
"_bezier_track_insert_key_at_anim",
|
||||
animation,
|
||||
E->get().first,
|
||||
oldpos,
|
||||
key[0],
|
||||
Vector2(key[1], key[2]),
|
||||
Vector2(key[3], key[4]),
|
||||
animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second));
|
||||
}
|
||||
|
||||
// 6 - (undo) Reinsert overlapped keys.
|
||||
List<AnimMoveRestore>::ConstIterator restore_itr = to_restore.begin();
|
||||
List<Animation::HandleMode>::ConstIterator handle_itr = to_restore_handle_modes.begin();
|
||||
for (; restore_itr != to_restore.end() && handle_itr != to_restore_handle_modes.end(); ++restore_itr, ++handle_itr) {
|
||||
const AnimMoveRestore &amr = *restore_itr;
|
||||
Array key = amr.key;
|
||||
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, 1);
|
||||
undo_redo->add_undo_method(
|
||||
this,
|
||||
"_bezier_track_insert_key_at_anim",
|
||||
animation,
|
||||
amr.track,
|
||||
amr.time,
|
||||
key[0],
|
||||
Vector2(key[1], key[2]),
|
||||
Vector2(key[3], key[4]),
|
||||
*handle_itr);
|
||||
}
|
||||
|
||||
undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
|
||||
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
|
||||
|
||||
// 7 - Reselect.
|
||||
int i = 0;
|
||||
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
|
||||
real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second);
|
||||
real_t newpos = animation->track_get_key_time(E->get().first, E->get().second);
|
||||
newpos += -scaling_selection_offset.x + (newpos - scaling_selection_pivot.x) * (scaling_selection_scale.x - 1);
|
||||
|
||||
undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos, i == 0);
|
||||
undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos, i == 0);
|
||||
i++;
|
||||
}
|
||||
|
||||
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||
if (ape) {
|
||||
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||
}
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
scaling_selection = false;
|
||||
scaling_selection_scale = Vector2(1, 1);
|
||||
scaling_selection_offset = Vector2();
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
Ref<InputEventMouseMotion> mm = p_event;
|
||||
if (moving_selection_attempt && mm.is_valid()) {
|
||||
if (!moving_selection) {
|
||||
|
|
@ -1473,9 +1716,9 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
|
||||
if (!read_only) {
|
||||
float y = (get_size().height / 2.0 - mm->get_position().y) * timeline_v_zoom + timeline_v_scroll;
|
||||
float moving_selection_begin_time = ((moving_selection_mouse_begin_x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
|
||||
float moving_selection_begin_time = ((moving_selection_mouse_begin.x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
|
||||
float new_time = ((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
|
||||
float moving_selection_pivot = animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key);
|
||||
float moving_selection_pivot = moving_selection_from_key != -1 ? animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key) : 0;
|
||||
float time_delta = new_time - moving_selection_begin_time;
|
||||
|
||||
float snapped_time = editor->snap_time(moving_selection_pivot + time_delta);
|
||||
|
|
@ -1483,9 +1726,15 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
if (abs(moving_selection_offset.x) > CMP_EPSILON || (snapped_time > moving_selection_pivot && time_delta > CMP_EPSILON) || (snapped_time < moving_selection_pivot && time_delta < -CMP_EPSILON)) {
|
||||
time_offset = snapped_time - moving_selection_pivot;
|
||||
}
|
||||
float moving_selection_begin_value = animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key);
|
||||
float y_offset = y - moving_selection_begin_value;
|
||||
|
||||
float moving_selection_begin_value;
|
||||
if (moving_selection_from_key == -1) {
|
||||
moving_selection_begin_value = (get_size().height / 2.0 - moving_selection_mouse_begin.y) * timeline_v_zoom + timeline_v_scroll;
|
||||
} else {
|
||||
moving_selection_begin_value = animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key);
|
||||
}
|
||||
|
||||
float y_offset = y - moving_selection_begin_value;
|
||||
moving_selection_offset = Vector2(time_offset, y_offset);
|
||||
}
|
||||
|
||||
|
|
@ -1505,11 +1754,82 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
queue_redraw();
|
||||
}
|
||||
|
||||
if (scaling_selection && mm.is_valid() && !read_only) {
|
||||
Point2 mp = mm->get_position();
|
||||
const int handle_length = Math::round((selection_handles_rect.size.width - selection_rect.size.width) / 4.0);
|
||||
Point2 rel_pos;
|
||||
|
||||
// Calculate the scale according with the distance between the mouse's position (adjusted so that the cursor appears inside the handles)
|
||||
// and the opposite end of the `selection_rect`.
|
||||
|
||||
if (scaling_selection_handles.x != 0) {
|
||||
if (scaling_selection_handles.x == 1) { // Right Handle
|
||||
const int handle_adjust = Math::round(mp.x - (scaling_selection_scale.x >= 0 ? selection_rect.position.x : (selection_rect.position.x + selection_rect.size.width)));
|
||||
mp.x -= MIN(Math::abs(handle_adjust), handle_length) * scaling_selection_handles.x * SIGN(handle_adjust);
|
||||
|
||||
if (editor->is_snap_keys_enabled()) {
|
||||
mp.x = editor->snap_time((mp.x - limit) / timeline->get_zoom_scale(), true) + timeline->get_value();
|
||||
mp.x = (mp.x - timeline->get_value()) * timeline->get_zoom_scale() + limit;
|
||||
}
|
||||
|
||||
rel_pos.x = scaling_selection_scale.x >= 0 ? (mp.x - selection_rect.position.x) : selection_rect.position.x + selection_rect.size.width - mp.x;
|
||||
} else { // Left Handle
|
||||
const int handle_adjust = Math::round((scaling_selection_scale.x >= 0 ? (selection_rect.position.x + selection_rect.size.width) : selection_rect.position.x) - mp.x);
|
||||
mp.x -= MIN(Math::abs(handle_adjust), handle_length) * scaling_selection_handles.x * SIGN(handle_adjust);
|
||||
|
||||
const float x = editor->snap_time((mp.x - limit) / timeline->get_zoom_scale(), true) + timeline->get_value();
|
||||
if (editor->is_snap_keys_enabled()) {
|
||||
mp.x = (x - timeline->get_value()) * timeline->get_zoom_scale() + limit;
|
||||
}
|
||||
|
||||
rel_pos.x = scaling_selection_scale.x >= 0 ? (selection_rect.position.x + selection_rect.size.width - mp.x) : (mp.x - selection_rect.position.x);
|
||||
scaling_selection_offset.x = scaling_selection_pivot.x - x;
|
||||
}
|
||||
|
||||
scaling_selection_scale.x *= rel_pos.x / selection_rect.size.width;
|
||||
if (scaling_selection_scale.x == 0) {
|
||||
scaling_selection_scale.x = CMP_EPSILON;
|
||||
}
|
||||
}
|
||||
|
||||
if (scaling_selection_handles.y != 0) {
|
||||
if (scaling_selection_handles.y == 1) { // Bottom Handle
|
||||
const int handle_adjust = Math::round(mp.y - (scaling_selection_scale.y >= 0 ? selection_rect.position.y : (selection_rect.position.y + selection_rect.size.height)));
|
||||
mp.y -= MIN(Math::abs(handle_adjust), handle_length) * scaling_selection_handles.y * SIGN(handle_adjust);
|
||||
|
||||
if (scaling_selection_scale.y >= 0) {
|
||||
rel_pos.y = mp.y - selection_rect.position.y;
|
||||
} else {
|
||||
rel_pos.y = selection_rect.position.y + selection_rect.size.height - mp.y;
|
||||
}
|
||||
} else { // Top Handle
|
||||
const int handle_adjust = Math::round((scaling_selection_scale.y >= 0 ? (selection_rect.position.y + selection_rect.size.height) : selection_rect.position.y) - mp.y);
|
||||
mp.y -= MIN(Math::abs(handle_adjust), handle_length) * scaling_selection_handles.y * SIGN(handle_adjust);
|
||||
|
||||
if (scaling_selection_scale.y >= 0) {
|
||||
rel_pos.y = selection_rect.position.y + selection_rect.size.height - mp.y;
|
||||
} else {
|
||||
rel_pos.y = mp.y - selection_rect.position.y;
|
||||
}
|
||||
|
||||
const float h = (get_size().height / 2.0 - mp.y) * timeline_v_zoom + timeline_v_scroll;
|
||||
scaling_selection_offset.y = scaling_selection_pivot.y - h;
|
||||
}
|
||||
|
||||
scaling_selection_scale.y *= rel_pos.y / selection_rect.size.height;
|
||||
if (scaling_selection_scale.y == 0) {
|
||||
scaling_selection_scale.y = CMP_EPSILON;
|
||||
}
|
||||
}
|
||||
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
if ((moving_handle == 1 || moving_handle == -1) && mm.is_valid()) {
|
||||
float y = (get_size().height / 2.0 - mm->get_position().y) * timeline_v_zoom + timeline_v_scroll;
|
||||
float x = editor->snap_time((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
|
||||
float x = editor->snap_time((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
|
||||
|
||||
Vector2 key_pos = Vector2(animation->track_get_key_time(selected_track, moving_handle_key), animation->bezier_track_get_key_value(selected_track, moving_handle_key));
|
||||
Vector2 key_pos = Vector2(animation->track_get_key_time(moving_handle_track, moving_handle_key), animation->bezier_track_get_key_value(moving_handle_track, moving_handle_key));
|
||||
|
||||
Vector2 moving_handle_value = Vector2(x, y) - key_pos;
|
||||
|
||||
|
|
@ -1601,7 +1921,7 @@ bool AnimationBezierTrackEdit::_try_select_at_ui_pos(const Point2 &p_pos, bool p
|
|||
moving_selection_attempt = true;
|
||||
moving_selection_from_key = pair.second;
|
||||
moving_selection_from_track = pair.first;
|
||||
moving_selection_mouse_begin_x = p_pos.x;
|
||||
moving_selection_mouse_begin = p_pos;
|
||||
moving_selection_offset = Vector2();
|
||||
moving_handle_track = pair.first;
|
||||
moving_handle_left = animation->bezier_track_get_key_in_handle(pair.first, pair.second);
|
||||
|
|
@ -1731,7 +2051,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
|
|||
}
|
||||
|
||||
void AnimationBezierTrackEdit::duplicate_selected_keys(real_t p_ofs, bool p_ofs_valid) {
|
||||
if (selection.size() == 0) {
|
||||
if (selection.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ANIMATION_BEZIER_EDITOR_H
|
||||
#define ANIMATION_BEZIER_EDITOR_H
|
||||
#pragma once
|
||||
|
||||
#include "animation_track_editor.h"
|
||||
#include "core/templates/hashfuncs.h"
|
||||
|
|
@ -109,7 +108,7 @@ class AnimationBezierTrackEdit : public Control {
|
|||
typedef Pair<int, int> IntPair;
|
||||
|
||||
bool moving_selection_attempt = false;
|
||||
float moving_selection_mouse_begin_x = 0.0;
|
||||
Point2 moving_selection_mouse_begin;
|
||||
IntPair select_single_attempt;
|
||||
bool moving_selection = false;
|
||||
int moving_selection_from_key = 0;
|
||||
|
|
@ -123,6 +122,15 @@ class AnimationBezierTrackEdit : public Control {
|
|||
Vector2 box_selection_from;
|
||||
Vector2 box_selection_to;
|
||||
|
||||
Rect2 selection_rect;
|
||||
Rect2 selection_handles_rect;
|
||||
|
||||
bool scaling_selection = false;
|
||||
Vector2i scaling_selection_handles;
|
||||
Vector2 scaling_selection_scale = Vector2(1, 1);
|
||||
Vector2 scaling_selection_offset;
|
||||
Point2 scaling_selection_pivot;
|
||||
|
||||
int moving_handle = 0; //0 no move -1 or +1 out, 2 both (drawing only)
|
||||
int moving_handle_key = 0;
|
||||
int moving_handle_track = 0;
|
||||
|
|
@ -225,5 +233,3 @@ public:
|
|||
|
||||
AnimationBezierTrackEdit();
|
||||
};
|
||||
|
||||
#endif // ANIMATION_BEZIER_EDITOR_H
|
||||
|
|
|
|||
|
|
@ -221,10 +221,10 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu
|
|||
change_notify_deserved = true;
|
||||
} else if (name.begins_with("args/")) {
|
||||
Vector<Variant> args = d_old["args"];
|
||||
int idx = name.get_slice("/", 1).to_int();
|
||||
int idx = name.get_slicec('/', 1).to_int();
|
||||
ERR_FAIL_INDEX_V(idx, args.size(), false);
|
||||
|
||||
String what = name.get_slice("/", 2);
|
||||
String what = name.get_slicec('/', 2);
|
||||
if (what == "type") {
|
||||
Variant::Type t = Variant::Type(int(p_value));
|
||||
|
||||
|
|
@ -478,10 +478,10 @@ bool AnimationTrackKeyEdit::_get(const StringName &p_name, Variant &r_ret) const
|
|||
}
|
||||
|
||||
if (name.begins_with("args/")) {
|
||||
int idx = name.get_slice("/", 1).to_int();
|
||||
int idx = name.get_slicec('/', 1).to_int();
|
||||
ERR_FAIL_INDEX_V(idx, args.size(), false);
|
||||
|
||||
String what = name.get_slice("/", 2);
|
||||
String what = name.get_slicec('/', 2);
|
||||
if (what == "type") {
|
||||
r_ret = args[idx].get_type();
|
||||
return true;
|
||||
|
|
@ -833,10 +833,10 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p
|
|||
change_notify_deserved = true;
|
||||
} else if (name.begins_with("args/")) {
|
||||
Vector<Variant> args = d_old["args"];
|
||||
int idx = name.get_slice("/", 1).to_int();
|
||||
int idx = name.get_slicec('/', 1).to_int();
|
||||
ERR_FAIL_INDEX_V(idx, args.size(), false);
|
||||
|
||||
String what = name.get_slice("/", 2);
|
||||
String what = name.get_slicec('/', 2);
|
||||
if (what == "type") {
|
||||
Variant::Type t = Variant::Type(int(p_value));
|
||||
|
||||
|
|
@ -1055,10 +1055,10 @@ bool AnimationMultiTrackKeyEdit::_get(const StringName &p_name, Variant &r_ret)
|
|||
}
|
||||
|
||||
if (name.begins_with("args/")) {
|
||||
int idx = name.get_slice("/", 1).to_int();
|
||||
int idx = name.get_slicec('/', 1).to_int();
|
||||
ERR_FAIL_INDEX_V(idx, args.size(), false);
|
||||
|
||||
String what = name.get_slice("/", 2);
|
||||
String what = name.get_slicec('/', 2);
|
||||
if (what == "type") {
|
||||
r_ret = args[idx].get_type();
|
||||
return true;
|
||||
|
|
@ -1251,12 +1251,12 @@ void AnimationMultiTrackKeyEdit::_get_property_list(List<PropertyInfo> *p_list)
|
|||
if (ap) {
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (List<StringName>::Element *G = anims.front(); G; G = G->next()) {
|
||||
for (const StringName &anim : anims) {
|
||||
if (!animations.is_empty()) {
|
||||
animations += ",";
|
||||
}
|
||||
|
||||
animations += String(G->get());
|
||||
animations += String(anim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1485,6 +1485,15 @@ void AnimationTimelineEdit::_notification(int p_what) {
|
|||
len_hb->set_size(Size2(get_buttons_width(), get_size().height));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
//TODO
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_STATIC_TEXT);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, TTR(vformat("The %s is not accessible at this time.", "Animation timeline editor")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAW: {
|
||||
int key_range = get_size().width - get_buttons_width() - get_name_limit();
|
||||
|
||||
|
|
@ -2008,10 +2017,12 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
|
|||
expander->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
expander->set_mouse_filter(MOUSE_FILTER_IGNORE);
|
||||
len_hb->add_child(expander);
|
||||
|
||||
time_icon = memnew(TextureRect);
|
||||
time_icon->set_v_size_flags(SIZE_SHRINK_CENTER);
|
||||
time_icon->set_tooltip_text(TTR("Animation length (seconds)"));
|
||||
len_hb->add_child(time_icon);
|
||||
|
||||
length = memnew(EditorSpinSlider);
|
||||
length->set_min(SECOND_DECIMAL);
|
||||
length->set_max(36000);
|
||||
|
|
@ -2020,11 +2031,14 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
|
|||
length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0));
|
||||
length->set_hide_slider(true);
|
||||
length->set_tooltip_text(TTR("Animation length (seconds)"));
|
||||
length->set_accessibility_name(TTRC("Animation length"));
|
||||
length->connect(SceneStringName(value_changed), callable_mp(this, &AnimationTimelineEdit::_anim_length_changed));
|
||||
len_hb->add_child(length);
|
||||
|
||||
loop = memnew(Button);
|
||||
loop->set_flat(true);
|
||||
loop->set_tooltip_text(TTR("Animation Looping"));
|
||||
loop->set_accessibility_name(TTRC("Animation Looping"));
|
||||
loop->connect(SceneStringName(pressed), callable_mp(this, &AnimationTimelineEdit::_anim_loop_pressed));
|
||||
loop->set_toggle_mode(true);
|
||||
len_hb->add_child(loop);
|
||||
|
|
@ -2056,6 +2070,15 @@ void AnimationTrackEdit::_notification(int p_what) {
|
|||
selected_icon = get_editor_theme_icon(SNAME("KeySelected"));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
//TODO
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_STATIC_TEXT);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, TTR(vformat("The %s is not accessible at this time.", "Animation track editor")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAW: {
|
||||
if (animation.is_null()) {
|
||||
return;
|
||||
|
|
@ -2235,8 +2258,21 @@ void AnimationTrackEdit::_notification(int p_what) {
|
|||
offset_n = offset_n + editor->get_moving_selection_offset();
|
||||
}
|
||||
offset_n = offset_n * scale + limit;
|
||||
|
||||
float offset_last = limit_end;
|
||||
if (i < animation->track_get_key_count(track) - 2) {
|
||||
offset_last = animation->track_get_key_time(track, i + 2) - timeline->get_value();
|
||||
if (editor->is_key_selected(track, i + 2) && editor->is_moving_selection()) {
|
||||
offset_last = offset_last + editor->get_moving_selection_offset();
|
||||
}
|
||||
offset_last = offset_last * scale + limit;
|
||||
}
|
||||
int limit_string = (editor->is_key_selected(track, i + 1) && editor->is_moving_selection()) ? int(offset_last) : int(offset_n);
|
||||
if (editor->is_key_selected(track, i) && editor->is_moving_selection()) {
|
||||
limit_string = int(MAX(limit_end, offset_last));
|
||||
}
|
||||
draw_key_link(i, scale, int(offset), int(offset_n), limit, limit_end);
|
||||
draw_key(i, scale, int(offset), editor->is_key_selected(track, i), limit, limit_string);
|
||||
continue;
|
||||
}
|
||||
|
||||
draw_key(i, scale, int(offset), editor->is_key_selected(track, i), limit, limit_end);
|
||||
|
|
@ -2541,7 +2577,8 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool
|
|||
}
|
||||
text += ")";
|
||||
|
||||
int limit = MAX(0, p_clip_right - p_x - icon_to_draw->get_width());
|
||||
int limit = ((p_selected && editor->is_moving_selection()) || editor->is_function_name_pressed()) ? 0 : MAX(0, p_clip_right - p_x - icon_to_draw->get_width() * 2);
|
||||
|
||||
if (limit > 0) {
|
||||
draw_string(font, Vector2(p_x + icon_to_draw->get_width(), int(get_size().height - font->get_height(font_size)) / 2 + font->get_ascent(font_size)), text, HORIZONTAL_ALIGNMENT_LEFT, limit, font_size, color);
|
||||
}
|
||||
|
|
@ -2792,7 +2829,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
|
|||
|
||||
if (rect.has_point(p_pos)) {
|
||||
if (const_cast<AnimationTrackEdit *>(this)->is_key_selectable_by_distance()) {
|
||||
float distance = ABS(offset - p_pos.x);
|
||||
float distance = Math::abs(offset - p_pos.x);
|
||||
if (key_idx == -1 || distance < key_distance) {
|
||||
key_idx = i;
|
||||
key_distance = distance;
|
||||
|
|
@ -3197,7 +3234,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
|
||||
if (rect.has_point(pos)) {
|
||||
if (is_key_selectable_by_distance()) {
|
||||
const float distance = ABS(offset - pos.x);
|
||||
const float distance = Math::abs(offset - pos.x);
|
||||
if (key_idx == -1 || distance < key_distance) {
|
||||
key_idx = i;
|
||||
key_distance = distance;
|
||||
|
|
@ -3261,7 +3298,7 @@ bool AnimationTrackEdit::_try_select_at_ui_pos(const Point2 &p_pos, bool p_aggre
|
|||
|
||||
if (rect.has_point(p_pos)) {
|
||||
if (is_key_selectable_by_distance()) {
|
||||
float distance = ABS(offset - p_pos.x);
|
||||
float distance = Math::abs(offset - p_pos.x);
|
||||
if (key_idx == -1 || distance < key_distance) {
|
||||
key_idx = i;
|
||||
key_distance = distance;
|
||||
|
|
@ -3324,7 +3361,7 @@ Variant AnimationTrackEdit::get_drag_data(const Point2 &p_point) {
|
|||
Dictionary drag_data;
|
||||
drag_data["type"] = "animation_track";
|
||||
String base_path = animation->track_get_path(track);
|
||||
base_path = base_path.get_slice(":", 0); // Remove sub-path.
|
||||
base_path = base_path.get_slicec(':', 0); // Remove sub-path.
|
||||
drag_data["group"] = base_path;
|
||||
drag_data["index"] = track;
|
||||
|
||||
|
|
@ -3355,7 +3392,7 @@ bool AnimationTrackEdit::can_drop_data(const Point2 &p_point, const Variant &p_d
|
|||
// Don't allow moving tracks outside their groups.
|
||||
if (get_editor()->is_grouping_tracks()) {
|
||||
String base_path = animation->track_get_path(track);
|
||||
base_path = base_path.get_slice(":", 0); // Remove sub-path.
|
||||
base_path = base_path.get_slicec(':', 0); // Remove sub-path.
|
||||
if (d["group"] != base_path) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3386,7 +3423,7 @@ void AnimationTrackEdit::drop_data(const Point2 &p_point, const Variant &p_data)
|
|||
// Don't allow moving tracks outside their groups.
|
||||
if (get_editor()->is_grouping_tracks()) {
|
||||
String base_path = animation->track_get_path(track);
|
||||
base_path = base_path.get_slice(":", 0); // Remove sub-path.
|
||||
base_path = base_path.get_slicec(':', 0); // Remove sub-path.
|
||||
if (d["group"] != base_path) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -3590,6 +3627,15 @@ void AnimationTrackEditGroup::_notification(int p_what) {
|
|||
icon_size = Vector2(1, 1) * get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
//TODO
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_STATIC_TEXT);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, TTR(vformat("The %s is not accessible at this time.", "Animation track group")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAW: {
|
||||
const Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));
|
||||
const int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));
|
||||
|
|
@ -3894,6 +3940,7 @@ bool AnimationTrackEditor::has_keying() const {
|
|||
Dictionary AnimationTrackEditor::get_state() const {
|
||||
Dictionary state;
|
||||
state["fps_mode"] = timeline->is_using_fps();
|
||||
state["fps_compat"] = fps_compat->is_pressed();
|
||||
state["zoom"] = zoom->get_value();
|
||||
state["offset"] = timeline->get_value();
|
||||
state["v_scroll"] = scroll->get_v_scroll_bar()->get_value();
|
||||
|
|
@ -3909,27 +3956,34 @@ void AnimationTrackEditor::set_state(const Dictionary &p_state) {
|
|||
snap_mode->select(0);
|
||||
}
|
||||
_snap_mode_changed(snap_mode->get_selected());
|
||||
} else {
|
||||
snap_mode->select(0);
|
||||
_snap_mode_changed(snap_mode->get_selected());
|
||||
}
|
||||
|
||||
if (p_state.has("fps_compat")) {
|
||||
fps_compat->set_pressed(p_state["fps_compat"]);
|
||||
}
|
||||
|
||||
if (p_state.has("zoom")) {
|
||||
zoom->set_value(p_state["zoom"]);
|
||||
} else {
|
||||
zoom->set_value(1.0);
|
||||
}
|
||||
|
||||
if (p_state.has("offset")) {
|
||||
timeline->set_value(p_state["offset"]);
|
||||
} else {
|
||||
timeline->set_value(0);
|
||||
}
|
||||
|
||||
if (p_state.has("v_scroll")) {
|
||||
scroll->get_v_scroll_bar()->set_value(p_state["v_scroll"]);
|
||||
} else {
|
||||
scroll->get_v_scroll_bar()->set_value(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationTrackEditor::clear() {
|
||||
snap_mode->select(EDITOR_GET("editors/animation/default_fps_mode"));
|
||||
_snap_mode_changed(snap_mode->get_selected());
|
||||
fps_compat->set_pressed(EDITOR_GET("editors/animation/default_fps_compatibility"));
|
||||
zoom->set_value(1.0);
|
||||
timeline->set_value(0);
|
||||
scroll->get_v_scroll_bar()->set_value(0);
|
||||
}
|
||||
|
||||
void AnimationTrackEditor::cleanup() {
|
||||
set_animation(Ref<Animation>(), read_only);
|
||||
}
|
||||
|
|
@ -4662,7 +4716,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
|
|||
for (int i = 0; i < subindices.size(); i++) {
|
||||
InsertData id = p_id;
|
||||
id.type = Animation::TYPE_BEZIER;
|
||||
id.value = subindices[i].is_empty() ? p_id.value : p_id.value.get(subindices[i].substr(1, subindices[i].length()));
|
||||
id.value = subindices[i].is_empty() ? p_id.value : p_id.value.get(subindices[i].substr(1));
|
||||
id.path = String(p_id.path) + subindices[i];
|
||||
p_next_tracks = _confirm_insert(id, p_next_tracks, p_reset_wanted, p_reset_anim, false);
|
||||
}
|
||||
|
|
@ -4935,7 +4989,7 @@ void AnimationTrackEditor::_update_tracks() {
|
|||
|
||||
if (use_grouping) {
|
||||
String base_path = animation->track_get_path(i);
|
||||
base_path = base_path.get_slice(":", 0); // Remove sub-path.
|
||||
base_path = base_path.get_slicec(':', 0); // Remove sub-path.
|
||||
|
||||
if (!group_sort.has(base_path)) {
|
||||
AnimationTrackEditGroup *g = memnew(AnimationTrackEditGroup);
|
||||
|
|
@ -5088,7 +5142,7 @@ void AnimationTrackEditor::_update_nearest_fps_label() {
|
|||
nearest_fps_label->hide();
|
||||
} else {
|
||||
nearest_fps_label->show();
|
||||
nearest_fps_label->set_text("Nearest FPS: " + itos(nearest_fps));
|
||||
nearest_fps_label->set_text(vformat(TTR("Nearest FPS: %d"), nearest_fps));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5154,6 +5208,7 @@ void AnimationTrackEditor::_notification(int p_what) {
|
|||
snap_keys->set_button_icon(get_editor_theme_icon(SNAME("SnapKeys")));
|
||||
fps_compat->set_button_icon(get_editor_theme_icon(SNAME("FPS")));
|
||||
view_group->set_button_icon(get_editor_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup")));
|
||||
function_name_toggler->set_button_icon(get_editor_theme_icon(SNAME("MemberMethod")));
|
||||
selected_filter->set_button_icon(get_editor_theme_icon(SNAME("AnimationFilter")));
|
||||
imported_anim_warning->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
|
||||
dummy_player_warning->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
|
||||
|
|
@ -5168,6 +5223,8 @@ void AnimationTrackEditor::_notification(int p_what) {
|
|||
|
||||
const int track_separation = get_theme_constant(SNAME("track_v_separation"), SNAME("AnimationTrackEditor"));
|
||||
track_vbox->add_theme_constant_override("separation", track_separation);
|
||||
|
||||
function_name_toggler->add_theme_color_override("icon_pressed_color", get_theme_color("icon_disabled_color", EditorStringName(Editor)));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_READY: {
|
||||
|
|
@ -5628,17 +5685,16 @@ void AnimationTrackEditor::_add_method_key(const String &p_method) {
|
|||
Dictionary d;
|
||||
d["method"] = p_method;
|
||||
Array params;
|
||||
int first_defarg = E.arguments.size() - E.default_arguments.size();
|
||||
int64_t first_defarg = E.arguments.size() - E.default_arguments.size();
|
||||
|
||||
int i = 0;
|
||||
for (List<PropertyInfo>::ConstIterator itr = E.arguments.begin(); itr != E.arguments.end(); ++itr, ++i) {
|
||||
for (int64_t i = 0; i < E.arguments.size(); ++i) {
|
||||
if (i >= first_defarg) {
|
||||
Variant arg = E.default_arguments[i - first_defarg];
|
||||
params.push_back(arg);
|
||||
} else {
|
||||
Callable::CallError ce;
|
||||
Variant arg;
|
||||
Variant::construct(itr->type, arg, nullptr, 0, ce);
|
||||
Variant::construct(E.arguments[i].type, arg, nullptr, 0, ce);
|
||||
params.push_back(arg);
|
||||
}
|
||||
}
|
||||
|
|
@ -6515,7 +6571,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
|
|||
text = path;
|
||||
int sep = text.find_char(':');
|
||||
if (sep != -1) {
|
||||
text = text.substr(sep + 1, text.length());
|
||||
text = text.substr(sep + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6599,7 +6655,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
|
|||
}
|
||||
} break;
|
||||
case EDIT_PASTE_TRACKS: {
|
||||
if (track_clipboard.size() == 0) {
|
||||
if (track_clipboard.is_empty()) {
|
||||
EditorNode::get_singleton()->show_warning(TTR("Clipboard is empty!"));
|
||||
break;
|
||||
}
|
||||
|
|
@ -6713,7 +6769,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
|
|||
to_restore.push_back(amr);
|
||||
}
|
||||
|
||||
#define NEW_POS(m_ofs) (((s > 0) ? m_ofs : from_t + (len - (m_ofs - from_t))) - pivot) * ABS(s) + from_t
|
||||
#define NEW_POS(m_ofs) (((s > 0) ? m_ofs : from_t + (len - (m_ofs - from_t))) - pivot) * Math::abs(s) + from_t
|
||||
// 3 - Move the keys (re insert them).
|
||||
for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
|
||||
float newpos = NEW_POS(E->get().pos);
|
||||
|
|
@ -6874,8 +6930,8 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
|
|||
if (is_using_angle) {
|
||||
real_t a = from_v;
|
||||
real_t b = to_v;
|
||||
real_t to_diff = fmod(b - a, Math_TAU);
|
||||
to_v = a + fmod(2.0 * to_diff, Math_TAU) - to_diff;
|
||||
real_t to_diff = fmod(b - a, Math::TAU);
|
||||
to_v = a + fmod(2.0 * to_diff, Math::TAU) - to_diff;
|
||||
}
|
||||
Variant delta_v = Animation::subtract_variant(to_v, from_v);
|
||||
double duration = to_t - from_t;
|
||||
|
|
@ -7338,6 +7394,10 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
|
|||
_update_tracks();
|
||||
}
|
||||
|
||||
void AnimationTrackEditor::_toggle_function_names() {
|
||||
_redraw_tracks();
|
||||
}
|
||||
|
||||
void AnimationTrackEditor::_view_group_toggle() {
|
||||
_update_tracks();
|
||||
view_group->set_button_icon(get_editor_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup")));
|
||||
|
|
@ -7352,6 +7412,10 @@ bool AnimationTrackEditor::is_grouping_tracks() {
|
|||
return !view_group->is_pressed();
|
||||
}
|
||||
|
||||
bool AnimationTrackEditor::is_function_name_pressed() {
|
||||
return function_name_toggler->is_pressed();
|
||||
}
|
||||
|
||||
void AnimationTrackEditor::_auto_fit() {
|
||||
timeline->auto_fit();
|
||||
}
|
||||
|
|
@ -7642,14 +7706,26 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
bezier_edit_icon->set_toggle_mode(true);
|
||||
bezier_edit_icon->connect(SceneStringName(pressed), callable_mp(this, &AnimationTrackEditor::_toggle_bezier_edit));
|
||||
bezier_edit_icon->set_tooltip_text(TTR("Toggle between the bezier curve editor and track editor."));
|
||||
bezier_edit_icon->set_accessibility_name(TTRC("Bezier Curve Editor"));
|
||||
|
||||
bottom_hf->add_child(bezier_edit_icon);
|
||||
|
||||
function_name_toggler = memnew(Button);
|
||||
function_name_toggler->set_flat(true);
|
||||
function_name_toggler->connect(SceneStringName(pressed), callable_mp(this, &AnimationTrackEditor::_toggle_function_names));
|
||||
function_name_toggler->set_shortcut(ED_SHORTCUT("animation_editor/toggle_function_names", TTRC("Toggle method names")));
|
||||
function_name_toggler->set_toggle_mode(true);
|
||||
function_name_toggler->set_shortcut_in_tooltip(false);
|
||||
function_name_toggler->set_tooltip_text(TTRC("Toggle function names in the track editor."));
|
||||
|
||||
bottom_hf->add_child(function_name_toggler);
|
||||
|
||||
selected_filter = memnew(Button);
|
||||
selected_filter->set_flat(true);
|
||||
selected_filter->connect(SceneStringName(pressed), callable_mp(this, &AnimationTrackEditor::_view_group_toggle)); // Same function works the same.
|
||||
selected_filter->set_toggle_mode(true);
|
||||
selected_filter->set_tooltip_text(TTR("Only show tracks from nodes selected in tree."));
|
||||
selected_filter->set_accessibility_name(TTRC("Show Tracks from Selected Nodes"));
|
||||
|
||||
bottom_hf->add_child(selected_filter);
|
||||
|
||||
|
|
@ -7658,6 +7734,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
view_group->connect(SceneStringName(pressed), callable_mp(this, &AnimationTrackEditor::_view_group_toggle));
|
||||
view_group->set_toggle_mode(true);
|
||||
view_group->set_tooltip_text(TTR("Group tracks by node or display them as plain list."));
|
||||
view_group->set_accessibility_name(TTRC("Group Tracks by Node"));
|
||||
|
||||
bottom_hf->add_child(view_group);
|
||||
bottom_hf->add_child(memnew(VSeparator));
|
||||
|
|
@ -7669,6 +7746,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
snap_timeline->set_toggle_mode(true);
|
||||
snap_timeline->set_pressed(false);
|
||||
snap_timeline->set_tooltip_text(TTR("Apply snapping to timeline cursor."));
|
||||
snap_timeline->set_accessibility_name(TTRC("Apply Snapping to Cursor"));
|
||||
|
||||
snap_keys = memnew(Button);
|
||||
snap_keys->set_flat(true);
|
||||
|
|
@ -7677,6 +7755,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
snap_keys->set_toggle_mode(true);
|
||||
snap_keys->set_pressed(true);
|
||||
snap_keys->set_tooltip_text(TTR("Apply snapping to selected key(s)."));
|
||||
snap_keys->set_accessibility_name(TTRC("Apply Snapping to Selected Key"));
|
||||
|
||||
fps_compat = memnew(Button);
|
||||
fps_compat->set_flat(true);
|
||||
|
|
@ -7685,9 +7764,11 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
fps_compat->set_toggle_mode(true);
|
||||
fps_compat->set_pressed(true);
|
||||
fps_compat->set_tooltip_text(TTR("Apply snapping to the nearest integer FPS."));
|
||||
fps_compat->set_accessibility_name(TTRC("Apply Snapping to Nearest Integer FPS"));
|
||||
fps_compat->connect(SceneStringName(toggled), callable_mp(this, &AnimationTrackEditor::_update_fps_compat_mode));
|
||||
|
||||
nearest_fps_label = memnew(Label);
|
||||
nearest_fps_label->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
bottom_hf->add_child(nearest_fps_label);
|
||||
|
||||
step = memnew(EditorSpinSlider);
|
||||
|
|
@ -7697,6 +7778,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
step->set_hide_slider(true);
|
||||
step->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
|
||||
step->set_tooltip_text(TTR("Animation step value."));
|
||||
step->set_accessibility_name(TTRC("Animation Step Value"));
|
||||
bottom_hf->add_child(step);
|
||||
step->connect(SceneStringName(value_changed), callable_mp(this, &AnimationTrackEditor::_update_step));
|
||||
step->set_read_only(true);
|
||||
|
|
@ -7704,9 +7786,10 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
snap_mode = memnew(OptionButton);
|
||||
snap_mode->add_item(TTR("Seconds"));
|
||||
snap_mode->add_item(TTR("FPS"));
|
||||
snap_mode->set_accessibility_name(TTRC("Snap Mode"));
|
||||
snap_mode->set_disabled(true);
|
||||
bottom_hf->add_child(snap_mode);
|
||||
snap_mode->connect(SceneStringName(item_selected), callable_mp(this, &AnimationTrackEditor::_snap_mode_changed));
|
||||
snap_mode->set_disabled(true);
|
||||
|
||||
bottom_hf->add_child(memnew(VSeparator));
|
||||
|
||||
|
|
@ -7721,6 +7804,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
zoom->set_value(1.0);
|
||||
zoom->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
|
||||
zoom->set_v_size_flags(SIZE_SHRINK_CENTER);
|
||||
zoom->set_accessibility_name(TTRC("Zoom"));
|
||||
zoom_hb->add_child(zoom);
|
||||
bottom_hf->add_child(zoom_hb);
|
||||
timeline->set_zoom(zoom);
|
||||
|
|
@ -7731,6 +7815,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
auto_fit->set_flat(true);
|
||||
auto_fit->connect(SceneStringName(pressed), callable_mp(this, &AnimationTrackEditor::_auto_fit));
|
||||
auto_fit->set_shortcut(ED_GET_SHORTCUT("animation_editor/auto_fit"));
|
||||
auto_fit->set_accessibility_name(TTRC("Auto Fit"));
|
||||
bottom_hf->add_child(auto_fit);
|
||||
|
||||
auto_fit_bezier = memnew(Button);
|
||||
|
|
@ -7738,6 +7823,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
auto_fit_bezier->set_visible(false);
|
||||
auto_fit_bezier->connect(SceneStringName(pressed), callable_mp(this, &AnimationTrackEditor::_auto_fit_bezier));
|
||||
auto_fit_bezier->set_shortcut(ED_GET_SHORTCUT("animation_editor/auto_fit"));
|
||||
auto_fit_bezier->set_accessibility_name(TTRC("Auto Fit Bezier"));
|
||||
bottom_hf->add_child(auto_fit_bezier);
|
||||
|
||||
edit = memnew(MenuButton);
|
||||
|
|
@ -7746,6 +7832,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
edit->set_flat(false);
|
||||
edit->set_disabled(true);
|
||||
edit->set_tooltip_text(TTR("Animation properties."));
|
||||
edit->set_accessibility_name(TTRC("Animation Properties"));
|
||||
edit->get_popup()->add_item(TTR("Copy Tracks..."), EDIT_COPY_TRACKS);
|
||||
edit->get_popup()->add_item(TTR("Paste Tracks"), EDIT_PASTE_TRACKS);
|
||||
edit->get_popup()->add_separator();
|
||||
|
|
@ -7790,10 +7877,12 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
prop_selector = memnew(PropertySelector);
|
||||
add_child(prop_selector);
|
||||
prop_selector->connect("selected", callable_mp(this, &AnimationTrackEditor::_new_track_property_selected));
|
||||
prop_selector->set_accessibility_name(TTRC("Track Property"));
|
||||
|
||||
method_selector = memnew(PropertySelector);
|
||||
add_child(method_selector);
|
||||
method_selector->connect("selected", callable_mp(this, &AnimationTrackEditor::_add_method_key));
|
||||
method_selector->set_accessibility_name(TTRC("Method Key"));
|
||||
|
||||
insert_confirm = memnew(ConfirmationDialog);
|
||||
add_child(insert_confirm);
|
||||
|
|
@ -7838,18 +7927,21 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
optimize_velocity_error->set_min(0.001);
|
||||
optimize_velocity_error->set_step(0.001);
|
||||
optimize_velocity_error->set_value(0.01);
|
||||
optimize_velocity_error->set_accessibility_name(TTRC("Max Velocity Error"));
|
||||
optimize_vb->add_margin_child(TTR("Max Velocity Error:"), optimize_velocity_error);
|
||||
optimize_angular_error = memnew(SpinBox);
|
||||
optimize_angular_error->set_max(1.0);
|
||||
optimize_angular_error->set_min(0.001);
|
||||
optimize_angular_error->set_step(0.001);
|
||||
optimize_angular_error->set_value(0.01);
|
||||
optimize_angular_error->set_accessibility_name(TTRC("Max Angular Error"));
|
||||
optimize_vb->add_margin_child(TTR("Max Angular Error:"), optimize_angular_error);
|
||||
optimize_precision_error = memnew(SpinBox);
|
||||
optimize_precision_error->set_max(6);
|
||||
optimize_precision_error->set_min(1);
|
||||
optimize_precision_error->set_step(1);
|
||||
optimize_precision_error->set_value(3);
|
||||
optimize_precision_error->set_accessibility_name(TTRC("Max Precision Error"));
|
||||
optimize_vb->add_margin_child(TTR("Max Precision Error:"), optimize_precision_error);
|
||||
|
||||
optimize_dialog->set_ok_button_text(TTR("Optimize"));
|
||||
|
|
@ -7900,6 +7992,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
scale->set_max(99999);
|
||||
scale->set_step(0.001);
|
||||
scale->set_select_all_on_focus(true);
|
||||
scale->set_accessibility_name(TTRC("Scale Ratio"));
|
||||
vbc->add_margin_child(TTR("Scale Ratio:"), scale);
|
||||
scale_dialog->connect(SceneStringName(confirmed), callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_SCALE_CONFIRM), CONNECT_DEFERRED);
|
||||
add_child(scale_dialog);
|
||||
|
|
@ -7915,6 +8008,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
ease_grid->set_columns(2);
|
||||
ease_dialog->add_child(ease_grid);
|
||||
transition_selection = memnew(OptionButton);
|
||||
transition_selection->set_accessibility_name(TTRC("Transition Type"));
|
||||
transition_selection->add_item(TTR("Linear", "Transition Type"), Tween::TRANS_LINEAR);
|
||||
transition_selection->add_item(TTR("Sine", "Transition Type"), Tween::TRANS_SINE);
|
||||
transition_selection->add_item(TTR("Quint", "Transition Type"), Tween::TRANS_QUINT);
|
||||
|
|
@ -7930,6 +8024,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
transition_selection->select(Tween::TRANS_LINEAR); // Default
|
||||
transition_selection->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // Translation context is needed.
|
||||
ease_selection = memnew(OptionButton);
|
||||
ease_selection->set_accessibility_name(TTRC("Ease Type"));
|
||||
ease_selection->add_item(TTR("In", "Ease Type"), Tween::EASE_IN);
|
||||
ease_selection->add_item(TTR("Out", "Ease Type"), Tween::EASE_OUT);
|
||||
ease_selection->add_item(TTR("InOut", "Ease Type"), Tween::EASE_IN_OUT);
|
||||
|
|
@ -7941,6 +8036,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
ease_fps->set_max(999);
|
||||
ease_fps->set_step(FPS_DECIMAL);
|
||||
ease_fps->set_value(30); // Default
|
||||
ease_fps->set_accessibility_name(TTRC("FPS"));
|
||||
ease_grid->add_child(memnew(Label(TTR("Transition Type:"))));
|
||||
ease_grid->add_child(transition_selection);
|
||||
ease_grid->add_child(memnew(Label(TTR("Ease Type:"))));
|
||||
|
|
@ -7957,12 +8053,16 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
bake_grid->set_columns(2);
|
||||
bake_dialog->add_child(bake_grid);
|
||||
bake_trs = memnew(CheckBox);
|
||||
bake_trs->set_accessibility_name(TTRC("3D Pos/Rot/Scl Track"));
|
||||
bake_trs->set_pressed(true);
|
||||
bake_blendshape = memnew(CheckBox);
|
||||
bake_blendshape->set_accessibility_name(TTRC("Blendshape Track"));
|
||||
bake_blendshape->set_pressed(true);
|
||||
bake_value = memnew(CheckBox);
|
||||
bake_value->set_accessibility_name(TTRC("Value Track"));
|
||||
bake_value->set_pressed(true);
|
||||
bake_fps = memnew(SpinBox);
|
||||
bake_fps->set_accessibility_name(TTRC("FPS"));
|
||||
bake_fps->set_min(FPS_DECIMAL);
|
||||
bake_fps->set_max(999);
|
||||
bake_fps->set_step(FPS_DECIMAL);
|
||||
|
|
@ -7990,6 +8090,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|||
track_copy_vbox->add_child(select_all_button);
|
||||
|
||||
track_copy_select = memnew(Tree);
|
||||
track_copy_select->set_accessibility_name(TTRC("Copy Selection"));
|
||||
track_copy_select->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
track_copy_select->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
track_copy_select->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
|
|
@ -8110,9 +8211,6 @@ AnimationTrackKeyEditEditor::AnimationTrackKeyEditEditor(Ref<Animation> p_animat
|
|||
spinner->connect("value_focus_exited", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
|
||||
}
|
||||
|
||||
AnimationTrackKeyEditEditor::~AnimationTrackKeyEditEditor() {
|
||||
}
|
||||
|
||||
void AnimationMarkerEdit::_zoom_changed() {
|
||||
queue_redraw();
|
||||
play_position->queue_redraw();
|
||||
|
|
@ -8329,6 +8427,15 @@ void AnimationMarkerEdit::_notification(int p_what) {
|
|||
selected_icon = get_editor_theme_icon(SNAME("MarkerSelected"));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
//TODO
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_STATIC_TEXT);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, TTR(vformat("The %s is not accessible at this time.", "Animation marker editor")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAW: {
|
||||
if (animation.is_null()) {
|
||||
return;
|
||||
|
|
@ -8635,7 +8742,7 @@ String AnimationMarkerEdit::get_tooltip(const Point2 &p_pos) const {
|
|||
|
||||
if (rect.has_point(p_pos)) {
|
||||
if (const_cast<AnimationMarkerEdit *>(this)->is_key_selectable_by_distance()) {
|
||||
float distance = ABS(offset - p_pos.x);
|
||||
float distance = Math::abs(offset - p_pos.x);
|
||||
if (key_idx == -1 || distance < key_distance) {
|
||||
key_idx = i;
|
||||
key_distance = distance;
|
||||
|
|
@ -8684,8 +8791,8 @@ PackedStringArray AnimationMarkerEdit::get_selected_section() const {
|
|||
PackedStringArray arr;
|
||||
arr.push_back(""); // Marker with smallest time.
|
||||
arr.push_back(""); // Marker with largest time.
|
||||
double min_time = INFINITY;
|
||||
double max_time = -INFINITY;
|
||||
double min_time = Math::INF;
|
||||
double max_time = -Math::INF;
|
||||
for (const StringName &marker_name : selection) {
|
||||
double time = animation->get_marker_time(marker_name);
|
||||
if (time < min_time) {
|
||||
|
|
@ -9101,9 +9208,6 @@ AnimationMarkerEdit::AnimationMarkerEdit() {
|
|||
marker_rename_confirm->add_child(marker_rename_error_dialog);
|
||||
}
|
||||
|
||||
AnimationMarkerEdit::~AnimationMarkerEdit() {
|
||||
}
|
||||
|
||||
float AnimationMarkerKeyEdit::get_time() const {
|
||||
return animation->get_marker_time(marker_name);
|
||||
}
|
||||
|
|
@ -9291,6 +9395,3 @@ AnimationMarkerKeyEditEditor::AnimationMarkerKeyEditEditor(Ref<Animation> p_anim
|
|||
spinner->connect("ungrabbed", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
|
||||
spinner->connect("value_focus_exited", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
|
||||
}
|
||||
|
||||
AnimationMarkerKeyEditEditor::~AnimationMarkerKeyEditEditor() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ANIMATION_TRACK_EDITOR_H
|
||||
#define ANIMATION_TRACK_EDITOR_H
|
||||
#pragma once
|
||||
|
||||
#include "editor/editor_data.h"
|
||||
#include "editor/editor_properties.h"
|
||||
|
|
@ -404,7 +403,6 @@ public:
|
|||
void _clear_selection(bool p_update);
|
||||
|
||||
AnimationMarkerEdit();
|
||||
~AnimationMarkerEdit();
|
||||
};
|
||||
|
||||
class AnimationTrackEdit : public Control {
|
||||
|
|
@ -803,6 +801,9 @@ class AnimationTrackEditor : public VBoxContainer {
|
|||
|
||||
void _anim_paste_keys(float p_ofs, bool p_ofs_valid, int p_track);
|
||||
|
||||
void _toggle_function_names();
|
||||
Button *function_name_toggler = nullptr;
|
||||
|
||||
void _view_group_toggle();
|
||||
Button *view_group = nullptr;
|
||||
Button *selected_filter = nullptr;
|
||||
|
|
@ -916,6 +917,7 @@ public:
|
|||
|
||||
Dictionary get_state() const;
|
||||
void set_state(const Dictionary &p_state);
|
||||
void clear();
|
||||
|
||||
void cleanup();
|
||||
|
||||
|
|
@ -947,6 +949,7 @@ public:
|
|||
bool is_marker_selected(const StringName &p_marker) const;
|
||||
bool is_marker_moving_selection() const;
|
||||
float get_marker_moving_selection_offset() const;
|
||||
bool is_function_name_pressed();
|
||||
|
||||
/** If `p_from_mouse_event` is `true`, handle Shift key presses for precise snapping. */
|
||||
void goto_prev_step(bool p_from_mouse_event);
|
||||
|
|
@ -983,7 +986,6 @@ class AnimationTrackKeyEditEditor : public EditorProperty {
|
|||
|
||||
public:
|
||||
AnimationTrackKeyEditEditor(Ref<Animation> p_animation, int p_track, real_t p_key_ofs, bool p_use_fps);
|
||||
~AnimationTrackKeyEditEditor();
|
||||
};
|
||||
|
||||
// AnimationMarkerKeyEditEditorPlugin
|
||||
|
|
@ -1001,7 +1003,4 @@ class AnimationMarkerKeyEditEditor : public EditorProperty {
|
|||
|
||||
public:
|
||||
AnimationMarkerKeyEditEditor(Ref<Animation> p_animation, const StringName &p_name, bool p_use_fps);
|
||||
~AnimationMarkerKeyEditEditor();
|
||||
};
|
||||
|
||||
#endif // ANIMATION_TRACK_EDITOR_H
|
||||
|
|
|
|||
|
|
@ -1051,13 +1051,13 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) {
|
|||
|
||||
int end = ofs + len * get_timeline()->get_zoom_scale();
|
||||
|
||||
if (end >= get_timeline()->get_name_limit() && end <= get_size().width - get_timeline()->get_buttons_width() && ABS(mm->get_position().x - end) < 5 * EDSCALE) {
|
||||
if (end >= get_timeline()->get_name_limit() && end <= get_size().width - get_timeline()->get_buttons_width() && Math::abs(mm->get_position().x - end) < 5 * EDSCALE) {
|
||||
len_resizing_start = false;
|
||||
use_hsize_cursor = true;
|
||||
len_resizing_index = i;
|
||||
}
|
||||
|
||||
if (ofs >= get_timeline()->get_name_limit() && ofs <= get_size().width - get_timeline()->get_buttons_width() && ABS(mm->get_position().x - ofs) < 5 * EDSCALE) {
|
||||
if (ofs >= get_timeline()->get_name_limit() && ofs <= get_size().width - get_timeline()->get_buttons_width() && Math::abs(mm->get_position().x - ofs) < 5 * EDSCALE) {
|
||||
len_resizing_start = true;
|
||||
use_hsize_cursor = true;
|
||||
len_resizing_index = i;
|
||||
|
|
@ -1322,9 +1322,6 @@ void AnimationTrackEditTypeAnimation::set_node(Object *p_object) {
|
|||
id = p_object->get_instance_id();
|
||||
}
|
||||
|
||||
AnimationTrackEditTypeAnimation::AnimationTrackEditTypeAnimation() {
|
||||
}
|
||||
|
||||
/////////
|
||||
AnimationTrackEdit *AnimationTrackEditDefaultPlugin::create_value_track_edit(Object *p_object, Variant::Type p_type, const String &p_property, PropertyHint p_hint, const String &p_hint_string, int p_usage) {
|
||||
if (p_property == "playing" && (p_object->is_class("AudioStreamPlayer") || p_object->is_class("AudioStreamPlayer2D") || p_object->is_class("AudioStreamPlayer3D"))) {
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ANIMATION_TRACK_EDITOR_PLUGINS_H
|
||||
#define ANIMATION_TRACK_EDITOR_PLUGINS_H
|
||||
#pragma once
|
||||
|
||||
#include "editor/animation_track_editor.h"
|
||||
|
||||
|
|
@ -88,8 +87,6 @@ public:
|
|||
|
||||
void set_node(Object *p_object);
|
||||
void set_as_coords();
|
||||
|
||||
AnimationTrackEditSpriteFrame() {}
|
||||
};
|
||||
|
||||
class AnimationTrackEditSubAnim : public AnimationTrackEdit {
|
||||
|
|
@ -146,7 +143,6 @@ public:
|
|||
virtual void draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) override;
|
||||
|
||||
void set_node(Object *p_object);
|
||||
AnimationTrackEditTypeAnimation();
|
||||
};
|
||||
|
||||
class AnimationTrackEditVolumeDB : public AnimationTrackEdit {
|
||||
|
|
@ -167,5 +163,3 @@ public:
|
|||
virtual AnimationTrackEdit *create_audio_track_edit() override;
|
||||
virtual AnimationTrackEdit *create_animation_track_edit(Object *p_object) override;
|
||||
};
|
||||
|
||||
#endif // ANIMATION_TRACK_EDITOR_PLUGINS_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef AUDIO_STREAM_PREVIEW_H
|
||||
#define AUDIO_STREAM_PREVIEW_H
|
||||
#pragma once
|
||||
|
||||
#include "core/os/thread.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
|
|
@ -104,5 +103,3 @@ public:
|
|||
|
||||
AudioStreamPreviewGenerator();
|
||||
};
|
||||
|
||||
#endif // AUDIO_STREAM_PREVIEW_H
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ GotoLinePopup::GotoLinePopup() {
|
|||
line_input->set_select_all_on_focus(true);
|
||||
line_input->connect(SceneStringName(text_changed), callable_mp(this, &GotoLinePopup::_goto_line).unbind(1));
|
||||
line_input->connect(SceneStringName(text_submitted), callable_mp(this, &GotoLinePopup::_submit).unbind(1));
|
||||
line_input->set_accessibility_name(TTRC("Line Number"));
|
||||
vbc->add_child(line_input);
|
||||
}
|
||||
|
||||
|
|
@ -144,6 +145,11 @@ void FindReplaceBar::_notification(int p_what) {
|
|||
_update_toggle_replace_button(replace_text->is_visible_in_tree());
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
|
||||
case NOTIFICATION_TRANSLATION_CHANGED: {
|
||||
_update_toggle_replace_button(replace_text->is_visible_in_tree());
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
set_process_input(is_visible_in_tree());
|
||||
} break;
|
||||
|
|
@ -748,6 +754,7 @@ void FindReplaceBar::_bind_methods() {
|
|||
FindReplaceBar::FindReplaceBar() {
|
||||
toggle_replace_button = memnew(Button);
|
||||
add_child(toggle_replace_button);
|
||||
toggle_replace_button->set_accessibility_name(TTRC("Replace Mode"));
|
||||
toggle_replace_button->set_flat(true);
|
||||
toggle_replace_button->set_focus_mode(FOCUS_NONE);
|
||||
toggle_replace_button->connect(SceneStringName(pressed), callable_mp(this, &FindReplaceBar::_toggle_replace_pressed));
|
||||
|
|
@ -779,6 +786,7 @@ FindReplaceBar::FindReplaceBar() {
|
|||
vbc_lineedit->add_child(search_text);
|
||||
search_text->set_placeholder(TTR("Find"));
|
||||
search_text->set_tooltip_text(TTR("Find"));
|
||||
search_text->set_accessibility_name(TTRC("Find"));
|
||||
search_text->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
|
||||
search_text->connect(SceneStringName(text_changed), callable_mp(this, &FindReplaceBar::_search_text_changed));
|
||||
search_text->connect(SceneStringName(text_submitted), callable_mp(this, &FindReplaceBar::_search_text_submitted));
|
||||
|
|
@ -790,6 +798,7 @@ FindReplaceBar::FindReplaceBar() {
|
|||
find_prev = memnew(Button);
|
||||
find_prev->set_flat(true);
|
||||
find_prev->set_tooltip_text(TTR("Previous Match"));
|
||||
find_prev->set_accessibility_name(TTRC("Previous Match"));
|
||||
hbc_button_search->add_child(find_prev);
|
||||
find_prev->set_focus_mode(FOCUS_NONE);
|
||||
find_prev->connect(SceneStringName(pressed), callable_mp(this, &FindReplaceBar::search_prev));
|
||||
|
|
@ -797,6 +806,7 @@ FindReplaceBar::FindReplaceBar() {
|
|||
find_next = memnew(Button);
|
||||
find_next->set_flat(true);
|
||||
find_next->set_tooltip_text(TTR("Next Match"));
|
||||
find_next->set_accessibility_name(TTRC("Next Match"));
|
||||
hbc_button_search->add_child(find_next);
|
||||
find_next->set_focus_mode(FOCUS_NONE);
|
||||
find_next->connect(SceneStringName(pressed), callable_mp(this, &FindReplaceBar::search_next));
|
||||
|
|
@ -818,6 +828,7 @@ FindReplaceBar::FindReplaceBar() {
|
|||
vbc_lineedit->add_child(replace_text);
|
||||
replace_text->set_placeholder(TTR("Replace"));
|
||||
replace_text->set_tooltip_text(TTR("Replace"));
|
||||
replace_text->set_accessibility_name(TTRC("Replace"));
|
||||
replace_text->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
|
||||
replace_text->connect(SceneStringName(text_submitted), callable_mp(this, &FindReplaceBar::_replace_text_submitted));
|
||||
|
||||
|
|
@ -840,6 +851,7 @@ FindReplaceBar::FindReplaceBar() {
|
|||
hide_button = memnew(TextureButton);
|
||||
add_child(hide_button);
|
||||
hide_button->set_tooltip_text(TTR("Hide"));
|
||||
hide_button->set_accessibility_name(TTRC("Hide"));
|
||||
hide_button->set_focus_mode(FOCUS_NONE);
|
||||
hide_button->connect(SceneStringName(pressed), callable_mp(this, &FindReplaceBar::_hide_bar));
|
||||
hide_button->set_v_size_flags(SIZE_SHRINK_CENTER);
|
||||
|
|
@ -1622,10 +1634,10 @@ void CodeTextEditor::_set_show_warnings_panel(bool p_show) {
|
|||
emit_signal(SNAME("show_warnings_panel"), p_show);
|
||||
}
|
||||
|
||||
void CodeTextEditor::_toggle_scripts_pressed() {
|
||||
ERR_FAIL_NULL(toggle_scripts_list);
|
||||
toggle_scripts_list->set_visible(!toggle_scripts_list->is_visible());
|
||||
update_toggle_scripts_button();
|
||||
void CodeTextEditor::_toggle_files_pressed() {
|
||||
ERR_FAIL_NULL(toggle_files_list);
|
||||
toggle_files_list->set_visible(!toggle_files_list->is_visible());
|
||||
update_toggle_files_button();
|
||||
}
|
||||
|
||||
void CodeTextEditor::_error_pressed(const Ref<InputEvent> &p_event) {
|
||||
|
|
@ -1643,15 +1655,22 @@ void CodeTextEditor::_notification(int p_what) {
|
|||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
if (toggle_scripts_button->is_visible()) {
|
||||
update_toggle_scripts_button();
|
||||
if (toggle_files_button->is_visible()) {
|
||||
update_toggle_files_button();
|
||||
}
|
||||
_update_text_editor_theme();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
|
||||
case NOTIFICATION_TRANSLATION_CHANGED: {
|
||||
if (toggle_files_button->is_visible()) {
|
||||
update_toggle_files_button();
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
if (toggle_scripts_button->is_visible()) {
|
||||
update_toggle_scripts_button();
|
||||
if (toggle_files_button->is_visible()) {
|
||||
update_toggle_files_button();
|
||||
}
|
||||
set_process_input(is_visible_in_tree());
|
||||
} break;
|
||||
|
|
@ -1718,7 +1737,7 @@ void CodeTextEditor::toggle_bookmark() {
|
|||
|
||||
void CodeTextEditor::goto_next_bookmark() {
|
||||
PackedInt32Array bmarks = text_editor->get_bookmarked_lines();
|
||||
if (bmarks.size() <= 0) {
|
||||
if (bmarks.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1734,7 +1753,7 @@ void CodeTextEditor::goto_next_bookmark() {
|
|||
|
||||
void CodeTextEditor::goto_prev_bookmark() {
|
||||
PackedInt32Array bmarks = text_editor->get_bookmarked_lines();
|
||||
if (bmarks.size() <= 0) {
|
||||
if (bmarks.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1808,18 +1827,18 @@ void CodeTextEditor::set_code_complete_func(CodeTextEditorCodeCompleteFunc p_cod
|
|||
}
|
||||
|
||||
void CodeTextEditor::set_toggle_list_control(Control *p_control) {
|
||||
toggle_scripts_list = p_control;
|
||||
toggle_files_list = p_control;
|
||||
}
|
||||
|
||||
void CodeTextEditor::show_toggle_scripts_button() {
|
||||
toggle_scripts_button->show();
|
||||
void CodeTextEditor::show_toggle_files_button() {
|
||||
toggle_files_button->show();
|
||||
}
|
||||
|
||||
void CodeTextEditor::update_toggle_scripts_button() {
|
||||
ERR_FAIL_NULL(toggle_scripts_list);
|
||||
bool forward = toggle_scripts_list->is_visible() == is_layout_rtl();
|
||||
toggle_scripts_button->set_button_icon(get_editor_theme_icon(forward ? SNAME("Forward") : SNAME("Back")));
|
||||
toggle_scripts_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
|
||||
void CodeTextEditor::update_toggle_files_button() {
|
||||
ERR_FAIL_NULL(toggle_files_list);
|
||||
bool forward = toggle_files_list->is_visible() == is_layout_rtl();
|
||||
toggle_files_button->set_button_icon(get_editor_theme_icon(forward ? SNAME("Forward") : SNAME("Back")));
|
||||
toggle_files_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Files Panel"), ED_GET_SHORTCUT("script_editor/toggle_files_panel")->get_as_text()));
|
||||
}
|
||||
|
||||
CodeTextEditor::CodeTextEditor() {
|
||||
|
|
@ -1856,12 +1875,13 @@ CodeTextEditor::CodeTextEditor() {
|
|||
error_line = 0;
|
||||
error_column = 0;
|
||||
|
||||
toggle_scripts_button = memnew(Button);
|
||||
toggle_scripts_button->set_flat(true);
|
||||
toggle_scripts_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
|
||||
toggle_scripts_button->connect(SceneStringName(pressed), callable_mp(this, &CodeTextEditor::_toggle_scripts_pressed));
|
||||
status_bar->add_child(toggle_scripts_button);
|
||||
toggle_scripts_button->hide();
|
||||
toggle_files_button = memnew(Button);
|
||||
toggle_files_button->set_flat(true);
|
||||
toggle_files_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
|
||||
toggle_files_button->connect(SceneStringName(pressed), callable_mp(this, &CodeTextEditor::_toggle_files_pressed));
|
||||
toggle_files_button->set_accessibility_name(TTRC("Scripts"));
|
||||
status_bar->add_child(toggle_files_button);
|
||||
toggle_files_button->hide();
|
||||
|
||||
// Error
|
||||
ScrollContainer *scroll = memnew(ScrollContainer);
|
||||
|
|
@ -1884,6 +1904,7 @@ CodeTextEditor::CodeTextEditor() {
|
|||
error_button->set_default_cursor_shape(CURSOR_POINTING_HAND);
|
||||
error_button->connect(SceneStringName(pressed), callable_mp(this, &CodeTextEditor::_error_button_pressed));
|
||||
error_button->set_tooltip_text(TTR("Errors"));
|
||||
error_button->set_accessibility_name(TTRC("Errors"));
|
||||
|
||||
// Warnings
|
||||
warning_button = memnew(Button);
|
||||
|
|
@ -1893,6 +1914,7 @@ CodeTextEditor::CodeTextEditor() {
|
|||
warning_button->set_default_cursor_shape(CURSOR_POINTING_HAND);
|
||||
warning_button->connect(SceneStringName(pressed), callable_mp(this, &CodeTextEditor::_warning_button_pressed));
|
||||
warning_button->set_tooltip_text(TTR("Warnings"));
|
||||
warning_button->set_accessibility_name(TTRC("Warnings"));
|
||||
|
||||
status_bar->add_child(memnew(VSeparator));
|
||||
|
||||
|
|
@ -1906,9 +1928,10 @@ CodeTextEditor::CodeTextEditor() {
|
|||
// TRANSLATORS: The placeholders are keyboard shortcuts. The first one is in the form of "Ctrl+"/"Cmd+".
|
||||
vformat(TTR("%sMouse wheel, %s/%s: Finetune\n%s: Reset"), keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL), ED_GET_SHORTCUT("script_editor/zoom_in")->get_as_text(), ED_GET_SHORTCUT("script_editor/zoom_out")->get_as_text(), ED_GET_SHORTCUT("script_editor/reset_zoom")->get_as_text()));
|
||||
zoom_button->set_text("100 %");
|
||||
zoom_button->set_accessibility_name(TTRC("Zoom Factor"));
|
||||
|
||||
PopupMenu *zoom_menu = zoom_button->get_popup();
|
||||
int preset_count = sizeof(ZOOM_FACTOR_PRESETS) / sizeof(float);
|
||||
constexpr int preset_count = std::size(ZOOM_FACTOR_PRESETS);
|
||||
|
||||
for (int i = 0; i < preset_count; i++) {
|
||||
float z = ZOOM_FACTOR_PRESETS[i];
|
||||
|
|
@ -1925,6 +1948,7 @@ CodeTextEditor::CodeTextEditor() {
|
|||
status_bar->add_child(line_and_col_txt);
|
||||
line_and_col_txt->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
|
||||
line_and_col_txt->set_tooltip_text(TTR("Line and column numbers."));
|
||||
line_and_col_txt->set_accessibility_name(TTRC("Line and Column Numbers"));
|
||||
line_and_col_txt->set_mouse_filter(MOUSE_FILTER_STOP);
|
||||
|
||||
status_bar->add_child(memnew(VSeparator));
|
||||
|
|
@ -1934,21 +1958,14 @@ CodeTextEditor::CodeTextEditor() {
|
|||
status_bar->add_child(indentation_txt);
|
||||
indentation_txt->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
|
||||
indentation_txt->set_tooltip_text(TTR("Indentation"));
|
||||
indentation_txt->set_accessibility_name(TTRC("Indentation"));
|
||||
indentation_txt->set_mouse_filter(MOUSE_FILTER_STOP);
|
||||
|
||||
text_editor->connect(SceneStringName(gui_input), callable_mp(this, &CodeTextEditor::_text_editor_gui_input));
|
||||
text_editor->connect("caret_changed", callable_mp(this, &CodeTextEditor::_line_col_changed));
|
||||
text_editor->connect(SceneStringName(text_changed), callable_mp(this, &CodeTextEditor::_text_changed));
|
||||
text_editor->connect("code_completion_requested", callable_mp(this, &CodeTextEditor::_complete_request));
|
||||
TypedArray<String> cs;
|
||||
cs.push_back(".");
|
||||
cs.push_back(",");
|
||||
cs.push_back("(");
|
||||
cs.push_back("=");
|
||||
cs.push_back("$");
|
||||
cs.push_back("@");
|
||||
cs.push_back("\"");
|
||||
cs.push_back("\'");
|
||||
TypedArray<String> cs = { ".", ",", "(", "=", "$", "@", "\"", "\'" };
|
||||
text_editor->set_code_completion_prefixes(cs);
|
||||
idle->connect("timeout", callable_mp(this, &CodeTextEditor::_text_changed_idle_timeout));
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CODE_EDITOR_H
|
||||
#define CODE_EDITOR_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
|
|
@ -166,8 +165,8 @@ class CodeTextEditor : public VBoxContainer {
|
|||
FindReplaceBar *find_replace_bar = nullptr;
|
||||
HBoxContainer *status_bar = nullptr;
|
||||
|
||||
Button *toggle_scripts_button = nullptr;
|
||||
Control *toggle_scripts_list = nullptr;
|
||||
Button *toggle_files_button = nullptr;
|
||||
Control *toggle_files_list = nullptr;
|
||||
Button *error_button = nullptr;
|
||||
Button *warning_button = nullptr;
|
||||
|
||||
|
|
@ -221,7 +220,7 @@ class CodeTextEditor : public VBoxContainer {
|
|||
|
||||
void _zoom_popup_id_pressed(int p_idx);
|
||||
|
||||
void _toggle_scripts_pressed();
|
||||
void _toggle_files_pressed();
|
||||
|
||||
protected:
|
||||
virtual void _load_theme_settings() {}
|
||||
|
|
@ -299,10 +298,8 @@ public:
|
|||
void validate_script();
|
||||
|
||||
void set_toggle_list_control(Control *p_control);
|
||||
void show_toggle_scripts_button();
|
||||
void update_toggle_scripts_button();
|
||||
void show_toggle_files_button();
|
||||
void update_toggle_files_button();
|
||||
|
||||
CodeTextEditor();
|
||||
};
|
||||
|
||||
#endif // CODE_EDITOR_H
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public:
|
|||
String name = p_name;
|
||||
|
||||
if (name.begins_with("bind/argument_")) {
|
||||
int which = name.get_slice("_", 1).to_int() - 1;
|
||||
int which = name.get_slicec('_', 1).to_int() - 1;
|
||||
ERR_FAIL_INDEX_V(which, params.size(), false);
|
||||
params.write[which] = p_value;
|
||||
} else {
|
||||
|
|
@ -95,7 +95,7 @@ public:
|
|||
String name = p_name;
|
||||
|
||||
if (name.begins_with("bind/argument_")) {
|
||||
int which = name.get_slice("_", 1).to_int() - 1;
|
||||
int which = name.get_slicec('_', 1).to_int() - 1;
|
||||
ERR_FAIL_INDEX_V(which, params.size(), false);
|
||||
r_ret = params[which];
|
||||
} else {
|
||||
|
|
@ -224,7 +224,7 @@ void ConnectDialog::_remove_bind() {
|
|||
if (st.is_empty()) {
|
||||
return;
|
||||
}
|
||||
int idx = st.get_slice("/", 1).to_int() - 1;
|
||||
int idx = st.get_slicec('/', 1).to_int() - 1;
|
||||
|
||||
ERR_FAIL_INDEX(idx, cdbinds->params.size());
|
||||
cdbinds->params.remove_at(idx);
|
||||
|
|
@ -255,10 +255,12 @@ StringName ConnectDialog::generate_method_callback_name(Node *p_source, const St
|
|||
subst["NodeName"] = node_name.to_pascal_case();
|
||||
subst["nodeName"] = node_name.to_camel_case();
|
||||
subst["node_name"] = node_name.to_snake_case();
|
||||
subst["node-name"] = node_name.to_kebab_case();
|
||||
|
||||
subst["SignalName"] = p_signal_name.to_pascal_case();
|
||||
subst["signalName"] = p_signal_name.to_camel_case();
|
||||
subst["signal_name"] = p_signal_name.to_snake_case();
|
||||
subst["signal-name"] = p_signal_name.to_kebab_case();
|
||||
|
||||
String dst_method;
|
||||
if (p_source == p_target) {
|
||||
|
|
@ -282,10 +284,11 @@ List<MethodInfo> ConnectDialog::_filter_method_list(const List<MethodInfo> &p_me
|
|||
bool check_signal = compatible_methods_only->is_pressed();
|
||||
List<MethodInfo> ret;
|
||||
|
||||
List<Pair<Variant::Type, StringName>> effective_args;
|
||||
LocalVector<Pair<Variant::Type, StringName>> effective_args;
|
||||
int unbind = get_unbinds();
|
||||
for (int i = 0; i < p_signal.arguments.size() - unbind; i++) {
|
||||
PropertyInfo pi = p_signal.arguments.get(i);
|
||||
effective_args.reserve(p_signal.arguments.size() - unbind);
|
||||
for (int64_t i = 0; i < p_signal.arguments.size() - unbind; i++) {
|
||||
PropertyInfo pi = p_signal.arguments[i];
|
||||
effective_args.push_back(Pair(pi.type, pi.class_name));
|
||||
}
|
||||
if (unbind == 0) {
|
||||
|
|
@ -312,17 +315,16 @@ List<MethodInfo> ConnectDialog::_filter_method_list(const List<MethodInfo> &p_me
|
|||
}
|
||||
|
||||
bool type_mismatch = false;
|
||||
const List<Pair<Variant::Type, StringName>>::Element *E = effective_args.front();
|
||||
for (const List<PropertyInfo>::Element *F = mi.arguments.front(); F; F = F->next(), E = E->next()) {
|
||||
Variant::Type stype = E->get().first;
|
||||
Variant::Type mtype = F->get().type;
|
||||
for (int64_t i = 0; i < mi.arguments.size(); ++i) {
|
||||
Variant::Type stype = effective_args[i].first;
|
||||
Variant::Type mtype = mi.arguments[i].type;
|
||||
|
||||
if (stype != Variant::NIL && mtype != Variant::NIL && stype != mtype) {
|
||||
type_mismatch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (stype == Variant::OBJECT && mtype == Variant::OBJECT && !ClassDB::is_parent_class(E->get().second, F->get().class_name)) {
|
||||
if (stype == Variant::OBJECT && mtype == Variant::OBJECT && !ClassDB::is_parent_class(effective_args[i].second, mi.arguments[i].class_name)) {
|
||||
type_mismatch = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -453,7 +455,13 @@ void ConnectDialog::_update_ok_enabled() {
|
|||
}
|
||||
|
||||
void ConnectDialog::_update_warning_label() {
|
||||
Ref<Script> scr = source->get_node(dst_path)->get_script();
|
||||
Node *dst = source->get_node(dst_path);
|
||||
if (dst == nullptr) {
|
||||
warning_label->set_visible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<Script> scr = dst->get_script();
|
||||
if (scr.is_null()) {
|
||||
warning_label->set_visible(false);
|
||||
return;
|
||||
|
|
@ -546,13 +554,12 @@ String ConnectDialog::get_signature(const MethodInfo &p_method, PackedStringArra
|
|||
signature.append(p_method.name);
|
||||
signature.append("(");
|
||||
|
||||
int i = 0;
|
||||
for (List<PropertyInfo>::ConstIterator itr = p_method.arguments.begin(); itr != p_method.arguments.end(); ++itr, ++i) {
|
||||
if (itr != p_method.arguments.begin()) {
|
||||
for (int64_t i = 0; i < p_method.arguments.size(); ++i) {
|
||||
if (i > 0) {
|
||||
signature.append(", ");
|
||||
}
|
||||
|
||||
const PropertyInfo &pi = *itr;
|
||||
const PropertyInfo &pi = p_method.arguments[i];
|
||||
String type_name;
|
||||
switch (pi.type) {
|
||||
case Variant::NIL:
|
||||
|
|
@ -575,8 +582,8 @@ String ConnectDialog::get_signature(const MethodInfo &p_method, PackedStringArra
|
|||
case Variant::DICTIONARY:
|
||||
type_name = "Dictionary";
|
||||
if (pi.hint == PROPERTY_HINT_DICTIONARY_TYPE && !pi.hint_string.is_empty()) {
|
||||
String key_hint = pi.hint_string.get_slice(";", 0);
|
||||
String value_hint = pi.hint_string.get_slice(";", 1);
|
||||
String key_hint = pi.hint_string.get_slicec(';', 0);
|
||||
String value_hint = pi.hint_string.get_slicec(';', 1);
|
||||
if (key_hint.is_empty() || key_hint.begins_with("res://")) {
|
||||
key_hint = "Variant";
|
||||
}
|
||||
|
|
@ -731,6 +738,7 @@ ConnectDialog::ConnectDialog() {
|
|||
vbc_left->set_custom_minimum_size(Vector2(400 * EDSCALE, 0));
|
||||
|
||||
from_signal = memnew(LineEdit);
|
||||
from_signal->set_accessibility_name(TTRC("From Signal"));
|
||||
vbc_left->add_margin_child(TTR("From Signal:"), from_signal);
|
||||
from_signal->set_editable(false);
|
||||
|
||||
|
|
@ -749,6 +757,7 @@ ConnectDialog::ConnectDialog() {
|
|||
hbc_filter->add_child(filter_nodes);
|
||||
filter_nodes->set_h_size_flags(Control::SIZE_FILL | Control::SIZE_EXPAND);
|
||||
filter_nodes->set_placeholder(TTR("Filter Nodes"));
|
||||
filter_nodes->set_accessibility_name(TTRC("Filter Nodes"));
|
||||
filter_nodes->set_clear_button_enabled(true);
|
||||
filter_nodes->connect(SceneStringName(text_changed), callable_mp(tree, &SceneTreeEditor::set_filter));
|
||||
|
||||
|
|
@ -781,11 +790,13 @@ ConnectDialog::ConnectDialog() {
|
|||
method_search = memnew(LineEdit);
|
||||
method_vbc->add_child(method_search);
|
||||
method_search->set_placeholder(TTR("Filter Methods"));
|
||||
method_search->set_accessibility_name(TTRC("Filter Methods"));
|
||||
method_search->set_clear_button_enabled(true);
|
||||
method_search->connect(SceneStringName(text_changed), callable_mp(this, &ConnectDialog::_update_method_tree).unbind(1));
|
||||
|
||||
method_tree = memnew(Tree);
|
||||
method_vbc->add_child(method_tree);
|
||||
method_tree->set_accessibility_name(TTRC("Methods"));
|
||||
method_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
method_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
method_tree->set_hide_root(true);
|
||||
|
|
@ -819,6 +830,7 @@ ConnectDialog::ConnectDialog() {
|
|||
HBoxContainer *add_bind_hb = memnew(HBoxContainer);
|
||||
|
||||
type_list = memnew(OptionButton);
|
||||
type_list->set_accessibility_name(TTRC("Type"));
|
||||
type_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
add_bind_hb->add_child(type_list);
|
||||
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
|
||||
|
|
@ -846,12 +858,14 @@ ConnectDialog::ConnectDialog() {
|
|||
vbc_right->add_margin_child(TTR("Add Extra Call Argument:"), add_bind_hb);
|
||||
|
||||
bind_editor = memnew(EditorInspector);
|
||||
bind_editor->set_accessibility_name(TTRC("Extra Call Arguments"));
|
||||
bind_controls.push_back(bind_editor);
|
||||
|
||||
vbc_right->add_margin_child(TTR("Extra Call Arguments:"), bind_editor, true);
|
||||
|
||||
unbind_count = memnew(SpinBox);
|
||||
unbind_count->set_tooltip_text(TTR("Allows to drop arguments sent by signal emitter."));
|
||||
unbind_count->set_accessibility_name(TTRC("Unbind Signal Arguments"));
|
||||
unbind_count->connect(SceneStringName(value_changed), callable_mp(this, &ConnectDialog::_unbind_count_changed));
|
||||
|
||||
vbc_right->add_margin_child(TTR("Unbind Signal Arguments:"), unbind_count);
|
||||
|
|
@ -860,14 +874,14 @@ ConnectDialog::ConnectDialog() {
|
|||
vbc_left->add_margin_child(TTR("Receiver Method:"), hbc_method);
|
||||
|
||||
dst_method = memnew(LineEdit);
|
||||
dst_method->set_accessibility_name(TTRC("Receiver Method"));
|
||||
dst_method->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
dst_method->connect(SceneStringName(text_changed), callable_mp(method_tree, &Tree::deselect_all).unbind(1));
|
||||
hbc_method->add_child(dst_method);
|
||||
register_text_enter(dst_method);
|
||||
|
||||
open_method_tree = memnew(Button);
|
||||
open_method_tree = memnew(Button(TTRC("Pick")));
|
||||
hbc_method->add_child(open_method_tree);
|
||||
open_method_tree->set_text("Pick");
|
||||
open_method_tree->connect(SceneStringName(pressed), callable_mp(this, &ConnectDialog::_open_method_popup));
|
||||
|
||||
advanced = memnew(CheckButton(TTR("Advanced")));
|
||||
|
|
@ -1287,11 +1301,14 @@ void ConnectionsDock::_slot_menu_about_to_popup() {
|
|||
}
|
||||
|
||||
void ConnectionsDock::_tree_gui_input(const Ref<InputEvent> &p_event) {
|
||||
TreeItem *item = nullptr;
|
||||
Point2 item_pos;
|
||||
|
||||
const Ref<InputEventKey> &key = p_event;
|
||||
|
||||
if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
|
||||
if (ED_IS_SHORTCUT("connections_editor/disconnect", p_event)) {
|
||||
TreeItem *item = tree->get_selected();
|
||||
item = tree->get_selected();
|
||||
if (item && _get_item_type(*item) == TREE_ITEM_TYPE_CONNECTION) {
|
||||
Connection connection = item->get_metadata(0);
|
||||
_disconnect(connection);
|
||||
|
|
@ -1309,22 +1326,32 @@ void ConnectionsDock::_tree_gui_input(const Ref<InputEvent> &p_event) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (key.is_valid() && key->is_pressed() && key->is_action("ui_menu", true)) {
|
||||
item = tree->get_selected();
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
item_pos = tree->get_item_rect(item).position;
|
||||
}
|
||||
|
||||
// Handle RMB press.
|
||||
const Ref<InputEventMouseButton> &mb_event = p_event;
|
||||
|
||||
if (mb_event.is_valid() && mb_event->is_pressed() && mb_event->get_button_index() == MouseButton::RIGHT) {
|
||||
TreeItem *item = tree->get_item_at_position(mb_event->get_position());
|
||||
item = tree->get_item_at_position(mb_event->get_position());
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
item_pos = mb_event->get_position();
|
||||
}
|
||||
|
||||
if (item) {
|
||||
if (item->is_selectable(0)) {
|
||||
// Update selection now, before `about_to_popup` signal. Needed for SIGNAL and CONNECTION context menus.
|
||||
tree->set_selected(item);
|
||||
}
|
||||
|
||||
Vector2 screen_position = tree->get_screen_position() + mb_event->get_position();
|
||||
Vector2 screen_position = tree->get_screen_position() + item_pos;
|
||||
|
||||
switch (_get_item_type(*item)) {
|
||||
case TREE_ITEM_TYPE_ROOT:
|
||||
|
|
@ -1459,8 +1486,8 @@ void ConnectionsDock::update_tree() {
|
|||
List<MethodInfo> base_signals;
|
||||
base->get_script_signal_list(&base_signals);
|
||||
HashSet<String> base_signal_names;
|
||||
for (List<MethodInfo>::Element *F = base_signals.front(); F; F = F->next()) {
|
||||
base_signal_names.insert(F->get().name);
|
||||
for (const MethodInfo &signal : base_signals) {
|
||||
base_signal_names.insert(signal.name);
|
||||
}
|
||||
for (List<MethodInfo>::Element *F = class_signals.front(); F; F = F->next()) {
|
||||
if (base_signal_names.has(F->get().name)) {
|
||||
|
|
@ -1597,11 +1624,13 @@ ConnectionsDock::ConnectionsDock() {
|
|||
search_box = memnew(LineEdit);
|
||||
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
search_box->set_placeholder(TTR("Filter Signals"));
|
||||
search_box->set_accessibility_name(TTRC("Filter Signals"));
|
||||
search_box->set_clear_button_enabled(true);
|
||||
search_box->connect(SceneStringName(text_changed), callable_mp(this, &ConnectionsDock::_filter_changed));
|
||||
vbc->add_child(search_box);
|
||||
|
||||
tree = memnew(ConnectionsDockTree);
|
||||
tree->set_accessibility_name(TTRC("Connections"));
|
||||
tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
tree->set_columns(1);
|
||||
tree->set_select_mode(Tree::SELECT_ROW);
|
||||
|
|
@ -1612,6 +1641,7 @@ ConnectionsDock::ConnectionsDock() {
|
|||
tree->set_allow_rmb_select(true);
|
||||
|
||||
connect_button = memnew(Button);
|
||||
connect_button->set_accessibility_name(TTRC("Connect"));
|
||||
HBoxContainer *hb = memnew(HBoxContainer);
|
||||
vbc->add_child(hb);
|
||||
hb->add_spacer();
|
||||
|
|
@ -1658,6 +1688,3 @@ ConnectionsDock::ConnectionsDock() {
|
|||
|
||||
add_theme_constant_override("separation", 3 * EDSCALE);
|
||||
}
|
||||
|
||||
ConnectionsDock::~ConnectionsDock() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CONNECTIONS_DIALOG_H
|
||||
#define CONNECTIONS_DIALOG_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/check_button.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
|
|
@ -269,7 +268,4 @@ public:
|
|||
void update_tree();
|
||||
|
||||
ConnectionsDock();
|
||||
~ConnectionsDock();
|
||||
};
|
||||
|
||||
#endif // CONNECTIONS_DIALOG_H
|
||||
|
|
|
|||
|
|
@ -83,8 +83,7 @@ void CreateDialog::_fill_type_list() {
|
|||
|
||||
EditorData &ed = EditorNode::get_editor_data();
|
||||
|
||||
for (List<StringName>::Element *I = complete_type_list.front(); I; I = I->next()) {
|
||||
StringName type = I->get();
|
||||
for (const StringName &type : complete_type_list) {
|
||||
if (!_should_hide_type(type)) {
|
||||
type_list.push_back(type);
|
||||
|
||||
|
|
@ -216,8 +215,7 @@ void CreateDialog::_update_search() {
|
|||
float highest_score = 0.0f;
|
||||
StringName best_match;
|
||||
|
||||
for (List<StringName>::Element *I = type_list.front(); I; I = I->next()) {
|
||||
StringName candidate = I->get();
|
||||
for (const StringName &candidate : type_list) {
|
||||
if (empty_search || search_text.is_subsequence_ofn(candidate)) {
|
||||
_add_type(candidate, ClassDB::class_exists(candidate) ? TypeCategory::CPP_TYPE : TypeCategory::OTHER_TYPE);
|
||||
|
||||
|
|
@ -637,7 +635,7 @@ void CreateDialog::_favorite_activated() {
|
|||
}
|
||||
|
||||
Variant CreateDialog::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
|
||||
TreeItem *ti = favorites->get_item_at_position(p_point);
|
||||
TreeItem *ti = (p_point == Vector2(Math::INF, Math::INF)) ? favorites->get_selected() : favorites->get_item_at_position(p_point);
|
||||
if (ti) {
|
||||
Dictionary d;
|
||||
d["type"] = "create_favorite_drag";
|
||||
|
|
@ -669,13 +667,13 @@ bool CreateDialog::can_drop_data_fw(const Point2 &p_point, const Variant &p_data
|
|||
void CreateDialog::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
|
||||
Dictionary d = p_data;
|
||||
|
||||
TreeItem *ti = favorites->get_item_at_position(p_point);
|
||||
TreeItem *ti = (p_point == Vector2(Math::INF, Math::INF)) ? favorites->get_selected() : favorites->get_item_at_position(p_point);
|
||||
if (!ti) {
|
||||
return;
|
||||
}
|
||||
|
||||
String drop_at = ti->get_text(0);
|
||||
int ds = favorites->get_drop_section_at_position(p_point);
|
||||
int ds = (p_point == Vector2(Math::INF, Math::INF)) ? favorites->get_drop_section_at_position(favorites->get_item_rect(ti).position) : favorites->get_drop_section_at_position(p_point);
|
||||
|
||||
int drop_idx = favorite_list.find(drop_at);
|
||||
if (drop_idx < 0) {
|
||||
|
|
@ -789,6 +787,7 @@ CreateDialog::CreateDialog() {
|
|||
vsc->add_child(fav_vb);
|
||||
|
||||
favorites = memnew(Tree);
|
||||
favorites->set_accessibility_name(TTRC("Favorites"));
|
||||
favorites->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
favorites->set_hide_root(true);
|
||||
favorites->set_hide_folding(true);
|
||||
|
|
@ -806,6 +805,7 @@ CreateDialog::CreateDialog() {
|
|||
rec_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
||||
recent = memnew(ItemList);
|
||||
recent->set_accessibility_name(TTRC("Recent"));
|
||||
recent->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
rec_vb->add_margin_child(TTR("Recent:"), recent, true);
|
||||
recent->set_allow_reselect(true);
|
||||
|
|
@ -820,6 +820,7 @@ CreateDialog::CreateDialog() {
|
|||
hsc->add_child(vbc);
|
||||
|
||||
search_box = memnew(LineEdit);
|
||||
search_box->set_accessibility_name(TTRC("Search"));
|
||||
search_box->set_clear_button_enabled(true);
|
||||
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
search_box->connect(SceneStringName(text_changed), callable_mp(this, &CreateDialog::_text_changed));
|
||||
|
|
@ -831,11 +832,13 @@ CreateDialog::CreateDialog() {
|
|||
favorite = memnew(Button);
|
||||
favorite->set_toggle_mode(true);
|
||||
favorite->set_tooltip_text(TTR("(Un)favorite selected item."));
|
||||
favorite->set_accessibility_name(TTRC("(Un)favorite"));
|
||||
favorite->connect(SceneStringName(pressed), callable_mp(this, &CreateDialog::_favorite_toggled));
|
||||
search_hb->add_child(favorite);
|
||||
vbc->add_margin_child(TTR("Search:"), search_hb);
|
||||
|
||||
search_options = memnew(Tree);
|
||||
search_options->set_accessibility_name(TTRC("Matches"));
|
||||
search_options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
search_options->connect("item_activated", callable_mp(this, &CreateDialog::_confirmed));
|
||||
search_options->connect("cell_selected", callable_mp(this, &CreateDialog::_item_selected));
|
||||
|
|
@ -843,6 +846,7 @@ CreateDialog::CreateDialog() {
|
|||
vbc->add_margin_child(TTR("Matches:"), search_options, true);
|
||||
|
||||
help_bit = memnew(EditorHelpBit);
|
||||
help_bit->set_accessibility_name(TTRC("Description"));
|
||||
help_bit->set_content_height_limits(80 * EDSCALE, 80 * EDSCALE);
|
||||
help_bit->connect("request_hide", callable_mp(this, &CreateDialog::_hide_requested));
|
||||
vbc->add_margin_child(TTR("Description:"), help_bit);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef CREATE_DIALOG_H
|
||||
#define CREATE_DIALOG_H
|
||||
#pragma once
|
||||
|
||||
#include "editor/editor_help.h"
|
||||
#include "scene/gui/button.h"
|
||||
|
|
@ -124,5 +123,3 @@ public:
|
|||
|
||||
CreateDialog();
|
||||
};
|
||||
|
||||
#endif // CREATE_DIALOG_H
|
||||
|
|
|
|||
|
|
@ -144,9 +144,7 @@ Dictionary DebugAdapterParser::req_initialize(const Dictionary &p_params) const
|
|||
// Send all current breakpoints
|
||||
List<String> breakpoints;
|
||||
ScriptEditor::get_singleton()->get_breakpoints(&breakpoints);
|
||||
for (List<String>::Element *E = breakpoints.front(); E; E = E->next()) {
|
||||
String breakpoint = E->get();
|
||||
|
||||
for (const String &breakpoint : breakpoints) {
|
||||
String path = breakpoint.left(breakpoint.find_char(':', 6)); // Skip initial part of path, aka "res://"
|
||||
int line = breakpoint.substr(path.size()).to_int();
|
||||
|
||||
|
|
@ -301,12 +299,11 @@ Dictionary DebugAdapterParser::req_threads(const Dictionary &p_params) const {
|
|||
Dictionary response = prepare_success_response(p_params), body;
|
||||
response["body"] = body;
|
||||
|
||||
Array arr;
|
||||
DAP::Thread thread;
|
||||
|
||||
thread.id = 1; // Hardcoded because Godot only supports debugging one thread at the moment
|
||||
thread.name = "Main";
|
||||
arr.push_back(thread.to_json());
|
||||
Array arr = { thread.to_json() };
|
||||
body["threads"] = arr;
|
||||
|
||||
return response;
|
||||
|
|
@ -325,8 +322,7 @@ Dictionary DebugAdapterParser::req_stackTrace(const Dictionary &p_params) const
|
|||
|
||||
Array arr;
|
||||
DebugAdapterProtocol *dap = DebugAdapterProtocol::get_singleton();
|
||||
for (const KeyValue<DAP::StackFrame, List<int>> &E : dap->stackframe_list) {
|
||||
DAP::StackFrame sf = E.key;
|
||||
for (DAP::StackFrame sf : dap->stackframe_list) {
|
||||
if (!lines_at_one) {
|
||||
sf.line--;
|
||||
}
|
||||
|
|
@ -360,7 +356,7 @@ Dictionary DebugAdapterParser::req_setBreakpoints(const Dictionary &p_params) co
|
|||
|
||||
// If path contains \, it's a Windows path, so we need to convert it to /, and make the drive letter uppercase
|
||||
if (source.path.contains_char('\\')) {
|
||||
source.path = source.path.replace("\\", "/");
|
||||
source.path = source.path.replace_char('\\', '/');
|
||||
source.path = source.path.substr(0, 1).to_upper() + source.path.substr(1);
|
||||
}
|
||||
|
||||
|
|
@ -372,6 +368,8 @@ Dictionary DebugAdapterParser::req_setBreakpoints(const Dictionary &p_params) co
|
|||
lines.push_back(breakpoint.line + !lines_at_one);
|
||||
}
|
||||
|
||||
// Always update the source checksum for the requested path, as it might have been modified externally.
|
||||
DebugAdapterProtocol::get_singleton()->update_source(source.path);
|
||||
Array updated_breakpoints = DebugAdapterProtocol::get_singleton()->update_breakpoints(source.path, lines);
|
||||
body["breakpoints"] = updated_breakpoints;
|
||||
|
||||
|
|
@ -383,13 +381,12 @@ Dictionary DebugAdapterParser::req_breakpointLocations(const Dictionary &p_param
|
|||
response["body"] = body;
|
||||
Dictionary args = p_params["arguments"];
|
||||
|
||||
Array locations;
|
||||
DAP::BreakpointLocation location;
|
||||
location.line = args["line"];
|
||||
if (args.has("endLine")) {
|
||||
location.endLine = args["endLine"];
|
||||
}
|
||||
locations.push_back(location.to_json());
|
||||
Array locations = { location.to_json() };
|
||||
|
||||
body["breakpoints"] = locations;
|
||||
return response;
|
||||
|
|
@ -403,15 +400,13 @@ Dictionary DebugAdapterParser::req_scopes(const Dictionary &p_params) const {
|
|||
int frame_id = args["frameId"];
|
||||
Array scope_list;
|
||||
|
||||
DAP::StackFrame frame;
|
||||
frame.id = frame_id;
|
||||
HashMap<DAP::StackFrame, List<int>, DAP::StackFrame>::Iterator E = DebugAdapterProtocol::get_singleton()->stackframe_list.find(frame);
|
||||
HashMap<DebugAdapterProtocol::DAPStackFrameID, Vector<int>>::Iterator E = DebugAdapterProtocol::get_singleton()->scope_list.find(frame_id);
|
||||
if (E) {
|
||||
ERR_FAIL_COND_V(E->value.size() != 3, prepare_error_response(p_params, DAP::ErrorType::UNKNOWN));
|
||||
List<int>::ConstIterator itr = E->value.begin();
|
||||
for (int i = 0; i < 3; ++itr, ++i) {
|
||||
const Vector<int> &scope_ids = E->value;
|
||||
ERR_FAIL_COND_V(scope_ids.size() != 3, prepare_error_response(p_params, DAP::ErrorType::UNKNOWN));
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
DAP::Scope scope;
|
||||
scope.variablesReference = *itr;
|
||||
scope.variablesReference = scope_ids[i];
|
||||
switch (i) {
|
||||
case 0:
|
||||
scope.name = "Locals";
|
||||
|
|
@ -595,8 +590,7 @@ Dictionary DebugAdapterParser::ev_stopped_breakpoint(const int &p_id) const {
|
|||
body["reason"] = "breakpoint";
|
||||
body["description"] = "Breakpoint";
|
||||
|
||||
Array breakpoints;
|
||||
breakpoints.push_back(p_id);
|
||||
Array breakpoints = { p_id };
|
||||
body["hitBreakpointIds"] = breakpoints;
|
||||
|
||||
return event;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEBUG_ADAPTER_PARSER_H
|
||||
#define DEBUG_ADAPTER_PARSER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/debugger/remote_debugger.h"
|
||||
|
|
@ -49,7 +48,7 @@ private:
|
|||
// If path contains \, it's a Windows path, so we need to convert it to /, and check as case-insensitive.
|
||||
if (p_path.contains_char('\\')) {
|
||||
String project_path = ProjectSettings::get_singleton()->get_resource_path();
|
||||
String path = p_path.replace("\\", "/");
|
||||
String path = p_path.replace_char('\\', '/');
|
||||
return path.containsn(project_path);
|
||||
}
|
||||
return p_path.begins_with(ProjectSettings::get_singleton()->get_resource_path());
|
||||
|
|
@ -103,5 +102,3 @@ public:
|
|||
Dictionary ev_custom_data(const String &p_msg, const Array &p_data) const;
|
||||
Dictionary ev_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled) const;
|
||||
};
|
||||
|
||||
#endif // DEBUG_ADAPTER_PARSER_H
|
||||
|
|
|
|||
|
|
@ -66,8 +66,7 @@ Error DAPeer::handle_data() {
|
|||
// End of headers
|
||||
if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
|
||||
r[l - 3] = '\0'; // Null terminate to read string
|
||||
String header;
|
||||
header.parse_utf8(r);
|
||||
String header = String::utf8(r);
|
||||
content_length = header.substr(16).to_int();
|
||||
has_header = true;
|
||||
req_pos = 0;
|
||||
|
|
@ -93,8 +92,7 @@ Error DAPeer::handle_data() {
|
|||
}
|
||||
|
||||
// Parse data
|
||||
String msg;
|
||||
msg.parse_utf8((const char *)req_buf, req_pos);
|
||||
String msg = String::utf8((const char *)req_buf, req_pos);
|
||||
|
||||
// Apply a timestamp if it there's none yet
|
||||
if (!timestamp) {
|
||||
|
|
@ -118,12 +116,12 @@ Error DAPeer::send_data() {
|
|||
if (!data.has("seq")) {
|
||||
data["seq"] = ++seq;
|
||||
}
|
||||
String formatted_data = format_output(data);
|
||||
const Vector<uint8_t> &formatted_data = format_output(data);
|
||||
|
||||
int data_sent = 0;
|
||||
while (data_sent < formatted_data.length()) {
|
||||
while (data_sent < formatted_data.size()) {
|
||||
int curr_sent = 0;
|
||||
Error err = connection->put_partial_data((const uint8_t *)formatted_data.utf8().get_data(), formatted_data.size() - data_sent - 1, curr_sent);
|
||||
Error err = connection->put_partial_data(formatted_data.ptr() + data_sent, formatted_data.size() - data_sent, curr_sent);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
|
@ -134,15 +132,12 @@ Error DAPeer::send_data() {
|
|||
return OK;
|
||||
}
|
||||
|
||||
String DAPeer::format_output(const Dictionary &p_params) const {
|
||||
String response = Variant(p_params).to_json_string();
|
||||
String header = "Content-Length: ";
|
||||
CharString charstr = response.utf8();
|
||||
size_t len = charstr.length();
|
||||
header += itos(len);
|
||||
header += "\r\n\r\n";
|
||||
Vector<uint8_t> DAPeer::format_output(const Dictionary &p_params) const {
|
||||
const Vector<uint8_t> &content = Variant(p_params).to_json_string().to_utf8_buffer();
|
||||
Vector<uint8_t> response = vformat("Content-Length: %d\r\n\r\n", content.size()).to_utf8_buffer();
|
||||
|
||||
return header + response;
|
||||
response.append_array(content);
|
||||
return response;
|
||||
}
|
||||
|
||||
Error DebugAdapterProtocol::on_client_connected() {
|
||||
|
|
@ -176,6 +171,7 @@ void DebugAdapterProtocol::reset_current_info() {
|
|||
void DebugAdapterProtocol::reset_ids() {
|
||||
breakpoint_id = 0;
|
||||
breakpoint_list.clear();
|
||||
breakpoint_source_list.clear();
|
||||
|
||||
reset_stack_info();
|
||||
}
|
||||
|
|
@ -185,6 +181,7 @@ void DebugAdapterProtocol::reset_stack_info() {
|
|||
variable_id = 1;
|
||||
|
||||
stackframe_list.clear();
|
||||
scope_list.clear();
|
||||
variable_list.clear();
|
||||
object_list.clear();
|
||||
object_pending_set.clear();
|
||||
|
|
@ -205,9 +202,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
x.value = rtos(vec.x);
|
||||
y.value = rtos(vec.y);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
Array arr = { x.to_json(), y.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -230,11 +225,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
w.value = rtos(rect.size.x);
|
||||
h.value = rtos(rect.size.y);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
arr.push_back(w.to_json());
|
||||
arr.push_back(h.to_json());
|
||||
Array arr = { x.to_json(), y.to_json(), w.to_json(), h.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -254,10 +245,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
y.value = rtos(vec.y);
|
||||
z.value = rtos(vec.z);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
arr.push_back(z.to_json());
|
||||
Array arr = { x.to_json(), y.to_json(), z.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -279,10 +267,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
y.variablesReference = parse_variant(transform.columns[1]);
|
||||
origin.variablesReference = parse_variant(transform.columns[2]);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
arr.push_back(origin.to_json());
|
||||
Array arr = { x.to_json(), y.to_json(), origin.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -298,9 +283,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
normal.value = plane.normal;
|
||||
normal.variablesReference = parse_variant(plane.normal);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(d.to_json());
|
||||
arr.push_back(normal.to_json());
|
||||
Array arr = { d.to_json(), normal.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -322,11 +305,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
z.value = rtos(quat.z);
|
||||
w.value = rtos(quat.w);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
arr.push_back(z.to_json());
|
||||
arr.push_back(w.to_json());
|
||||
Array arr = { x.to_json(), y.to_json(), z.to_json(), w.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -344,9 +323,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
position.variablesReference = parse_variant(aabb.position);
|
||||
size.variablesReference = parse_variant(aabb.size);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(position.to_json());
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { position.to_json(), size.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -368,10 +345,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
y.variablesReference = parse_variant(basis.rows[1]);
|
||||
z.variablesReference = parse_variant(basis.rows[2]);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(x.to_json());
|
||||
arr.push_back(y.to_json());
|
||||
arr.push_back(z.to_json());
|
||||
Array arr = { x.to_json(), y.to_json(), z.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -388,9 +362,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
basis.variablesReference = parse_variant(transform.basis);
|
||||
origin.variablesReference = parse_variant(transform.origin);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(basis.to_json());
|
||||
arr.push_back(origin.to_json());
|
||||
Array arr = { basis.to_json(), origin.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -412,11 +384,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
b.value = rtos(color.b);
|
||||
a.value = rtos(color.a);
|
||||
|
||||
Array arr;
|
||||
arr.push_back(r.to_json());
|
||||
arr.push_back(g.to_json());
|
||||
arr.push_back(b.to_json());
|
||||
arr.push_back(a.to_json());
|
||||
Array arr = { r.to_json(), g.to_json(), b.to_json(), a.to_json() };
|
||||
variable_list.insert(id, arr);
|
||||
return id;
|
||||
}
|
||||
|
|
@ -428,8 +396,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -447,10 +414,10 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
Dictionary dictionary = p_var;
|
||||
Array arr;
|
||||
|
||||
for (int i = 0; i < dictionary.size(); i++) {
|
||||
for (const KeyValue<Variant, Variant> &kv : dictionary) {
|
||||
DAP::Variable var;
|
||||
var.name = dictionary.get_key_at_index(i);
|
||||
Variant value = dictionary.get_value_at_index(i);
|
||||
var.name = kv.key;
|
||||
Variant value = kv.value;
|
||||
var.type = Variant::get_type_name(value.get_type());
|
||||
var.value = value;
|
||||
var.variablesReference = parse_variant(value);
|
||||
|
|
@ -467,8 +434,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -488,8 +454,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -509,8 +474,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -530,8 +494,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -551,8 +514,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -572,8 +534,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -593,8 +554,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -615,8 +575,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -637,8 +596,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
|
|||
size.type = Variant::get_type_name(Variant::INT);
|
||||
size.value = itos(array.size());
|
||||
|
||||
Array arr;
|
||||
arr.push_back(size.to_json());
|
||||
Array arr = { size.to_json() };
|
||||
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
DAP::Variable var;
|
||||
|
|
@ -843,7 +801,9 @@ bool DebugAdapterProtocol::request_remote_object(const ObjectID &p_object_id) {
|
|||
return false;
|
||||
}
|
||||
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_object(p_object_id);
|
||||
TypedArray<uint64_t> arr;
|
||||
arr.append(p_object_id);
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_objects(arr);
|
||||
object_pending_set.insert(p_object_id);
|
||||
|
||||
return true;
|
||||
|
|
@ -861,6 +821,30 @@ bool DebugAdapterProtocol::request_remote_evaluate(const String &p_eval, int p_s
|
|||
return true;
|
||||
}
|
||||
|
||||
const DAP::Source &DebugAdapterProtocol::fetch_source(const String &p_path) {
|
||||
const String &global_path = ProjectSettings::get_singleton()->globalize_path(p_path);
|
||||
|
||||
HashMap<String, DAP::Source>::Iterator E = breakpoint_source_list.find(global_path);
|
||||
if (E != breakpoint_source_list.end()) {
|
||||
return E->value;
|
||||
}
|
||||
DAP::Source &added_source = breakpoint_source_list.insert(global_path, DAP::Source())->value;
|
||||
added_source.name = global_path.get_file();
|
||||
added_source.path = global_path;
|
||||
added_source.compute_checksums();
|
||||
|
||||
return added_source;
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::update_source(const String &p_path) {
|
||||
const String &global_path = ProjectSettings::get_singleton()->globalize_path(p_path);
|
||||
|
||||
HashMap<String, DAP::Source>::Iterator E = breakpoint_source_list.find(global_path);
|
||||
if (E != breakpoint_source_list.end()) {
|
||||
E->value.compute_checksums();
|
||||
}
|
||||
}
|
||||
|
||||
bool DebugAdapterProtocol::process_message(const String &p_text) {
|
||||
JSON json;
|
||||
ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Malformed message!");
|
||||
|
|
@ -878,8 +862,7 @@ bool DebugAdapterProtocol::process_message(const String &p_text) {
|
|||
if (parser->has_method(command)) {
|
||||
_current_request = params["command"];
|
||||
|
||||
Array args;
|
||||
args.push_back(params);
|
||||
Array args = { params };
|
||||
Dictionary response = parser->callv(command, args);
|
||||
if (!response.is_empty()) {
|
||||
_current_peer->res_queue.push_front(response);
|
||||
|
|
@ -904,66 +887,66 @@ void DebugAdapterProtocol::notify_process() {
|
|||
String launch_mode = _current_peer->attached ? "attach" : "launch";
|
||||
|
||||
Dictionary event = parser->ev_process(launch_mode);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_terminated() {
|
||||
Dictionary event = parser->ev_terminated();
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
if ((_current_request == "launch" || _current_request == "restart") && _current_peer == E->get()) {
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
if ((_current_request == "launch" || _current_request == "restart") && _current_peer == peer) {
|
||||
continue;
|
||||
}
|
||||
E->get()->res_queue.push_back(event);
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_exited(const int &p_exitcode) {
|
||||
Dictionary event = parser->ev_exited(p_exitcode);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
if ((_current_request == "launch" || _current_request == "restart") && _current_peer == E->get()) {
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
if ((_current_request == "launch" || _current_request == "restart") && _current_peer == peer) {
|
||||
continue;
|
||||
}
|
||||
E->get()->res_queue.push_back(event);
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_stopped_paused() {
|
||||
Dictionary event = parser->ev_stopped_paused();
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_stopped_exception(const String &p_error) {
|
||||
Dictionary event = parser->ev_stopped_exception(p_error);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_stopped_breakpoint(const int &p_id) {
|
||||
Dictionary event = parser->ev_stopped_breakpoint(p_id);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_stopped_step() {
|
||||
Dictionary event = parser->ev_stopped_step();
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_continued() {
|
||||
Dictionary event = parser->ev_continued();
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
if (_current_request == "continue" && E->get() == _current_peer) {
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
if (_current_request == "continue" && peer == _current_peer) {
|
||||
continue;
|
||||
}
|
||||
E->get()->res_queue.push_back(event);
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
|
||||
reset_stack_info();
|
||||
|
|
@ -971,15 +954,14 @@ void DebugAdapterProtocol::notify_continued() {
|
|||
|
||||
void DebugAdapterProtocol::notify_output(const String &p_message, RemoteDebugger::MessageType p_type) {
|
||||
Dictionary event = parser->ev_output(p_message, p_type);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->res_queue.push_back(event);
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::notify_custom_data(const String &p_msg, const Array &p_data) {
|
||||
Dictionary event = parser->ev_custom_data(p_msg, p_data);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
Ref<DAPeer> peer = E->get();
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
if (peer->supportsCustomData) {
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
|
|
@ -988,11 +970,11 @@ void DebugAdapterProtocol::notify_custom_data(const String &p_msg, const Array &
|
|||
|
||||
void DebugAdapterProtocol::notify_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled) {
|
||||
Dictionary event = parser->ev_breakpoint(p_breakpoint, p_enabled);
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
if (_current_request == "setBreakpoints" && E->get() == _current_peer) {
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
if (_current_request == "setBreakpoints" && peer == _current_peer) {
|
||||
continue;
|
||||
}
|
||||
E->get()->res_queue.push_back(event);
|
||||
peer->res_queue.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1001,23 +983,40 @@ Array DebugAdapterProtocol::update_breakpoints(const String &p_path, const Array
|
|||
|
||||
// Add breakpoints
|
||||
for (int i = 0; i < p_lines.size(); i++) {
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, p_lines[i], true);
|
||||
DAP::Breakpoint breakpoint;
|
||||
DAP::Breakpoint breakpoint(fetch_source(p_path));
|
||||
breakpoint.line = p_lines[i];
|
||||
breakpoint.source.path = p_path;
|
||||
|
||||
ERR_FAIL_COND_V(!breakpoint_list.find(breakpoint), Array());
|
||||
updated_breakpoints.push_back(breakpoint_list.find(breakpoint)->get().to_json());
|
||||
// Avoid duplicated entries.
|
||||
List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);
|
||||
if (E) {
|
||||
updated_breakpoints.push_back(E->get().to_json());
|
||||
continue;
|
||||
}
|
||||
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, p_lines[i], true);
|
||||
|
||||
// Breakpoints are inserted at the end of the breakpoint list.
|
||||
List<DAP::Breakpoint>::Element *added_breakpoint = breakpoint_list.back();
|
||||
ERR_FAIL_NULL_V(added_breakpoint, Array());
|
||||
ERR_FAIL_COND_V(!(added_breakpoint->get() == breakpoint), Array());
|
||||
updated_breakpoints.push_back(added_breakpoint->get().to_json());
|
||||
}
|
||||
|
||||
// Remove breakpoints
|
||||
for (List<DAP::Breakpoint>::Element *E = breakpoint_list.front(); E; E = E->next()) {
|
||||
DAP::Breakpoint b = E->get();
|
||||
if (b.source.path == p_path && !p_lines.has(b.line)) {
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, b.line, false);
|
||||
// Must be deferred because we are iterating the breakpoint list.
|
||||
Vector<int> to_remove;
|
||||
|
||||
for (const DAP::Breakpoint &b : breakpoint_list) {
|
||||
if (b.source->path == p_path && !p_lines.has(b.line)) {
|
||||
to_remove.push_back(b.line);
|
||||
}
|
||||
}
|
||||
|
||||
// Safe to remove queued data now.
|
||||
for (const int &line : to_remove) {
|
||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, line, false);
|
||||
}
|
||||
|
||||
return updated_breakpoints;
|
||||
}
|
||||
|
||||
|
|
@ -1032,6 +1031,7 @@ void DebugAdapterProtocol::on_debug_paused() {
|
|||
void DebugAdapterProtocol::on_debug_stopped() {
|
||||
notify_exited();
|
||||
notify_terminated();
|
||||
reset_ids();
|
||||
}
|
||||
|
||||
void DebugAdapterProtocol::on_debug_output(const String &p_message, int p_type) {
|
||||
|
|
@ -1059,10 +1059,8 @@ void DebugAdapterProtocol::on_debug_breaked(const bool &p_reallydid, const bool
|
|||
}
|
||||
|
||||
void DebugAdapterProtocol::on_debug_breakpoint_toggled(const String &p_path, const int &p_line, const bool &p_enabled) {
|
||||
DAP::Breakpoint breakpoint;
|
||||
DAP::Breakpoint breakpoint(fetch_source(p_path));
|
||||
breakpoint.verified = true;
|
||||
breakpoint.source.path = ProjectSettings::get_singleton()->globalize_path(p_path);
|
||||
breakpoint.source.compute_checksums();
|
||||
breakpoint.line = p_line;
|
||||
|
||||
if (p_enabled) {
|
||||
|
|
@ -1085,8 +1083,7 @@ void DebugAdapterProtocol::on_debug_stack_dump(const Array &p_stack_dump) {
|
|||
if (_processing_breakpoint && !p_stack_dump.is_empty()) {
|
||||
// Find existing breakpoint
|
||||
Dictionary d = p_stack_dump[0];
|
||||
DAP::Breakpoint breakpoint;
|
||||
breakpoint.source.path = ProjectSettings::get_singleton()->globalize_path(d["file"]);
|
||||
DAP::Breakpoint breakpoint(fetch_source(d["file"]));
|
||||
breakpoint.line = d["line"];
|
||||
|
||||
List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);
|
||||
|
|
@ -1099,25 +1096,26 @@ void DebugAdapterProtocol::on_debug_stack_dump(const Array &p_stack_dump) {
|
|||
|
||||
stackframe_id = 0;
|
||||
stackframe_list.clear();
|
||||
scope_list.clear();
|
||||
|
||||
// Fill in stacktrace information
|
||||
for (int i = 0; i < p_stack_dump.size(); i++) {
|
||||
Dictionary stack_info = p_stack_dump[i];
|
||||
DAP::StackFrame stackframe;
|
||||
|
||||
DAP::StackFrame stackframe(fetch_source(stack_info["file"]));
|
||||
stackframe.id = stackframe_id++;
|
||||
stackframe.name = stack_info["function"];
|
||||
stackframe.line = stack_info["line"];
|
||||
stackframe.column = 0;
|
||||
stackframe.source.path = ProjectSettings::get_singleton()->globalize_path(stack_info["file"]);
|
||||
stackframe.source.compute_checksums();
|
||||
|
||||
// Information for "Locals", "Members" and "Globals" variables respectively
|
||||
List<int> scope_ids;
|
||||
Vector<int> scope_ids;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
scope_ids.push_back(variable_id++);
|
||||
}
|
||||
|
||||
stackframe_list.insert(stackframe, scope_ids);
|
||||
stackframe_list.push_back(stackframe);
|
||||
scope_list.insert(stackframe.id, scope_ids);
|
||||
}
|
||||
|
||||
_current_frame = 0;
|
||||
|
|
@ -1126,12 +1124,9 @@ void DebugAdapterProtocol::on_debug_stack_dump(const Array &p_stack_dump) {
|
|||
|
||||
void DebugAdapterProtocol::on_debug_stack_frame_vars(const int &p_size) {
|
||||
_remaining_vars = p_size;
|
||||
DAP::StackFrame frame;
|
||||
frame.id = _current_frame;
|
||||
ERR_FAIL_COND(!stackframe_list.has(frame));
|
||||
List<int> scope_ids = stackframe_list.find(frame)->value;
|
||||
for (List<int>::Element *E = scope_ids.front(); E; E = E->next()) {
|
||||
int var_id = E->get();
|
||||
ERR_FAIL_COND(!scope_list.has(_current_frame));
|
||||
Vector<int> scope_ids = scope_list.find(_current_frame)->value;
|
||||
for (const int &var_id : scope_ids) {
|
||||
if (variable_list.has(var_id)) {
|
||||
variable_list.find(var_id)->value.clear();
|
||||
} else {
|
||||
|
|
@ -1144,11 +1139,9 @@ void DebugAdapterProtocol::on_debug_stack_frame_var(const Array &p_data) {
|
|||
DebuggerMarshalls::ScriptStackVariable stack_var;
|
||||
stack_var.deserialize(p_data);
|
||||
|
||||
ERR_FAIL_COND(stackframe_list.is_empty());
|
||||
DAP::StackFrame frame;
|
||||
frame.id = _current_frame;
|
||||
ERR_FAIL_COND(!scope_list.has(_current_frame));
|
||||
Vector<int> scope_ids = scope_list.find(_current_frame)->value;
|
||||
|
||||
List<int> scope_ids = stackframe_list.find(frame)->value;
|
||||
ERR_FAIL_COND(scope_ids.size() != 3);
|
||||
ERR_FAIL_INDEX(stack_var.type, 4);
|
||||
int var_id = scope_ids.get(stack_var.type);
|
||||
|
|
@ -1192,8 +1185,7 @@ void DebugAdapterProtocol::poll() {
|
|||
on_client_connected();
|
||||
}
|
||||
List<Ref<DAPeer>> to_delete;
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
Ref<DAPeer> peer = E->get();
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->connection->poll();
|
||||
StreamPeerTCP::Status status = peer->connection->get_status();
|
||||
if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {
|
||||
|
|
@ -1211,8 +1203,8 @@ void DebugAdapterProtocol::poll() {
|
|||
}
|
||||
}
|
||||
|
||||
for (List<Ref<DAPeer>>::Element *E = to_delete.front(); E; E = E->next()) {
|
||||
on_client_disconnected(E->get());
|
||||
for (const Ref<DAPeer> &peer : to_delete) {
|
||||
on_client_disconnected(peer);
|
||||
}
|
||||
to_delete.clear();
|
||||
}
|
||||
|
|
@ -1225,8 +1217,8 @@ Error DebugAdapterProtocol::start(int p_port, const IPAddress &p_bind_ip) {
|
|||
}
|
||||
|
||||
void DebugAdapterProtocol::stop() {
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
E->get()->connection->disconnect_from_host();
|
||||
for (const Ref<DAPeer> &peer : clients) {
|
||||
peer->connection->disconnect_from_host();
|
||||
}
|
||||
|
||||
clients.clear();
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEBUG_ADAPTER_PROTOCOL_H
|
||||
#define DEBUG_ADAPTER_PROTOCOL_H
|
||||
#pragma once
|
||||
|
||||
#include "core/debugger/debugger_marshalls.h"
|
||||
#include "core/io/stream_peer_tcp.h"
|
||||
|
|
@ -68,7 +67,7 @@ struct DAPeer : RefCounted {
|
|||
|
||||
Error handle_data();
|
||||
Error send_data();
|
||||
String format_output(const Dictionary &p_params) const;
|
||||
Vector<uint8_t> format_output(const Dictionary &p_params) const;
|
||||
};
|
||||
|
||||
class DebugAdapterProtocol : public Object {
|
||||
|
|
@ -77,6 +76,7 @@ class DebugAdapterProtocol : public Object {
|
|||
friend class DebugAdapterParser;
|
||||
|
||||
using DAPVarID = int;
|
||||
using DAPStackFrameID = int;
|
||||
|
||||
private:
|
||||
static DebugAdapterProtocol *singleton;
|
||||
|
|
@ -110,6 +110,9 @@ private:
|
|||
bool request_remote_object(const ObjectID &p_object_id);
|
||||
bool request_remote_evaluate(const String &p_eval, int p_stack_frame);
|
||||
|
||||
const DAP::Source &fetch_source(const String &p_path);
|
||||
void update_source(const String &p_path);
|
||||
|
||||
bool _initialized = false;
|
||||
bool _processing_breakpoint = false;
|
||||
bool _stepping = false;
|
||||
|
|
@ -126,7 +129,9 @@ private:
|
|||
int stackframe_id = 0;
|
||||
DAPVarID variable_id = 0;
|
||||
List<DAP::Breakpoint> breakpoint_list;
|
||||
HashMap<DAP::StackFrame, List<int>, DAP::StackFrame> stackframe_list;
|
||||
HashMap<String, DAP::Source> breakpoint_source_list;
|
||||
List<DAP::StackFrame> stackframe_list;
|
||||
HashMap<DAPStackFrameID, Vector<int>> scope_list;
|
||||
HashMap<DAPVarID, Array> variable_list;
|
||||
|
||||
HashMap<ObjectID, DAPVarID> object_list;
|
||||
|
|
@ -168,5 +173,3 @@ public:
|
|||
DebugAdapterProtocol();
|
||||
~DebugAdapterProtocol();
|
||||
};
|
||||
|
||||
#endif // DEBUG_ADAPTER_PROTOCOL_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEBUG_ADAPTER_SERVER_H
|
||||
#define DEBUG_ADAPTER_SERVER_H
|
||||
#pragma once
|
||||
|
||||
#include "debug_adapter_protocol.h"
|
||||
#include "editor/plugins/editor_plugin.h"
|
||||
|
|
@ -54,5 +53,3 @@ public:
|
|||
void start();
|
||||
void stop();
|
||||
};
|
||||
|
||||
#endif // DEBUG_ADAPTER_SERVER_H
|
||||
|
|
|
|||
|
|
@ -28,11 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEBUG_ADAPTER_TYPES_H
|
||||
#define DEBUG_ADAPTER_TYPES_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/json.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
#include "core/io/file_access.h"
|
||||
|
||||
namespace DAP {
|
||||
|
||||
|
|
@ -69,6 +67,8 @@ public:
|
|||
void compute_checksums() {
|
||||
ERR_FAIL_COND(path.is_empty());
|
||||
|
||||
_checksums.clear();
|
||||
|
||||
// MD5
|
||||
Checksum md5;
|
||||
md5.algorithm = "MD5";
|
||||
|
|
@ -102,18 +102,24 @@ public:
|
|||
struct Breakpoint {
|
||||
int id = 0;
|
||||
bool verified = false;
|
||||
Source source;
|
||||
const Source *source = nullptr;
|
||||
int line = 0;
|
||||
|
||||
Breakpoint() = default; // Empty constructor is invalid, but is necessary because Godot's collections don't support rvalues.
|
||||
Breakpoint(const Source &p_source) :
|
||||
source(&p_source) {}
|
||||
|
||||
bool operator==(const Breakpoint &p_other) const {
|
||||
return source.path == p_other.source.path && line == p_other.line;
|
||||
return source == p_other.source && line == p_other.line;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Dictionary to_json() const {
|
||||
Dictionary dict;
|
||||
dict["id"] = id;
|
||||
dict["verified"] = verified;
|
||||
dict["source"] = source.to_json();
|
||||
if (source) {
|
||||
dict["source"] = source->to_json();
|
||||
}
|
||||
dict["line"] = line;
|
||||
|
||||
return dict;
|
||||
|
|
@ -159,9 +165,7 @@ struct Capabilities {
|
|||
dict["supportsTerminateRequest"] = supportsTerminateRequest;
|
||||
dict["supportsBreakpointLocationsRequest"] = supportsBreakpointLocationsRequest;
|
||||
|
||||
Array arr;
|
||||
arr.push_back(supportedChecksumAlgorithms[0]);
|
||||
arr.push_back(supportedChecksumAlgorithms[1]);
|
||||
Array arr = { supportedChecksumAlgorithms[0], supportedChecksumAlgorithms[1] };
|
||||
dict["supportedChecksumAlgorithms"] = arr;
|
||||
|
||||
return dict;
|
||||
|
|
@ -215,30 +219,25 @@ struct SourceBreakpoint {
|
|||
struct StackFrame {
|
||||
int id = 0;
|
||||
String name;
|
||||
Source source;
|
||||
const Source *source = nullptr;
|
||||
int line = 0;
|
||||
int column = 0;
|
||||
|
||||
StackFrame() = default; // Empty constructor is invalid, but is necessary because Godot's collections don't support rvalues.
|
||||
StackFrame(const Source &p_source) :
|
||||
source(&p_source) {}
|
||||
|
||||
static uint32_t hash(const StackFrame &p_frame) {
|
||||
return hash_murmur3_one_32(p_frame.id);
|
||||
}
|
||||
bool operator==(const StackFrame &p_other) const {
|
||||
return id == p_other.id;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void from_json(const Dictionary &p_params) {
|
||||
id = p_params["id"];
|
||||
name = p_params["name"];
|
||||
source.from_json(p_params["source"]);
|
||||
line = p_params["line"];
|
||||
column = p_params["column"];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Dictionary to_json() const {
|
||||
Dictionary dict;
|
||||
dict["id"] = id;
|
||||
dict["name"] = name;
|
||||
dict["source"] = source.to_json();
|
||||
if (source) {
|
||||
dict["source"] = source->to_json();
|
||||
}
|
||||
dict["line"] = line;
|
||||
dict["column"] = column;
|
||||
|
||||
|
|
@ -277,5 +276,3 @@ struct Variable {
|
|||
};
|
||||
|
||||
} // namespace DAP
|
||||
|
||||
#endif // DEBUG_ADAPTER_TYPES_H
|
||||
|
|
|
|||
|
|
@ -33,29 +33,57 @@
|
|||
#include "core/debugger/debugger_marshalls.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "editor/inspector_dock.h"
|
||||
#include "scene/debugger/scene_debugger.h"
|
||||
|
||||
bool EditorDebuggerRemoteObject::_set(const StringName &p_name, const Variant &p_value) {
|
||||
if (!prop_values.has(p_name) || String(p_name).begins_with("Constants/")) {
|
||||
bool EditorDebuggerRemoteObjects::_set(const StringName &p_name, const Variant &p_value) {
|
||||
return _set_impl(p_name, p_value, "");
|
||||
}
|
||||
|
||||
bool EditorDebuggerRemoteObjects::_set_impl(const StringName &p_name, const Variant &p_value, const String &p_field) {
|
||||
String name = p_name;
|
||||
|
||||
if (name.begins_with("Metadata/")) {
|
||||
name = name.replace_first("Metadata/", "metadata/");
|
||||
}
|
||||
if (!prop_values.has(name) || String(name).begins_with("Constants/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
prop_values[p_name] = p_value;
|
||||
emit_signal(SNAME("value_edited"), remote_object_id, p_name, p_value);
|
||||
Dictionary &values = prop_values[p_name];
|
||||
Dictionary old_values = values.duplicate();
|
||||
for (const uint64_t key : values.keys()) {
|
||||
values.set(key, p_value);
|
||||
}
|
||||
|
||||
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
|
||||
const int size = remote_object_ids.size();
|
||||
ur->create_action(size == 1 ? vformat(TTR("Set %s"), name) : vformat(TTR("Set %s on %d objects"), name, size), UndoRedo::MERGE_ENDS);
|
||||
|
||||
ur->add_do_method(this, SNAME("emit_signal"), SNAME("values_edited"), name, values, p_field);
|
||||
ur->add_undo_method(this, SNAME("emit_signal"), SNAME("values_edited"), name, old_values, p_field);
|
||||
ur->commit_action();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditorDebuggerRemoteObject::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
if (!prop_values.has(p_name)) {
|
||||
bool EditorDebuggerRemoteObjects::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
String name = p_name;
|
||||
|
||||
if (name.begins_with("Metadata/")) {
|
||||
name = name.replace_first("Metadata/", "metadata/");
|
||||
}
|
||||
if (!prop_values.has(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r_ret = prop_values[p_name];
|
||||
r_ret = prop_values[p_name][remote_object_ids[0]];
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditorDebuggerRemoteObject::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
p_list->clear(); // Sorry, no want category.
|
||||
void EditorDebuggerRemoteObjects::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
p_list->clear(); // Sorry, don't want any categories.
|
||||
for (const PropertyInfo &prop : prop_list) {
|
||||
if (prop.name == "script") {
|
||||
// Skip the script property, it's always added by the non-virtual method.
|
||||
|
|
@ -66,31 +94,35 @@ void EditorDebuggerRemoteObject::_get_property_list(List<PropertyInfo> *p_list)
|
|||
}
|
||||
}
|
||||
|
||||
String EditorDebuggerRemoteObject::get_title() {
|
||||
if (remote_object_id.is_valid()) {
|
||||
return vformat(TTR("Remote %s:"), String(type_name)) + " " + itos(remote_object_id);
|
||||
} else {
|
||||
return "<null>";
|
||||
}
|
||||
void EditorDebuggerRemoteObjects::set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field) {
|
||||
_set_impl(p_property, p_value, p_field);
|
||||
}
|
||||
|
||||
Variant EditorDebuggerRemoteObject::get_variant(const StringName &p_name) {
|
||||
String EditorDebuggerRemoteObjects::get_title() {
|
||||
if (!remote_object_ids.is_empty() && ObjectID(remote_object_ids[0].operator uint64_t()).is_valid()) {
|
||||
const int size = remote_object_ids.size();
|
||||
return size == 1 ? vformat(TTR("Remote %s: %d"), type_name, remote_object_ids[0]) : vformat(TTR("Remote %s (%d Selected)"), type_name, size);
|
||||
}
|
||||
|
||||
return "<null>";
|
||||
}
|
||||
|
||||
Variant EditorDebuggerRemoteObjects::get_variant(const StringName &p_name) {
|
||||
Variant var;
|
||||
_get(p_name, var);
|
||||
return var;
|
||||
}
|
||||
|
||||
void EditorDebuggerRemoteObject::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_title"), &EditorDebuggerRemoteObject::get_title);
|
||||
ClassDB::bind_method(D_METHOD("get_variant"), &EditorDebuggerRemoteObject::get_variant);
|
||||
ClassDB::bind_method(D_METHOD("clear"), &EditorDebuggerRemoteObject::clear);
|
||||
ClassDB::bind_method(D_METHOD("get_remote_object_id"), &EditorDebuggerRemoteObject::get_remote_object_id);
|
||||
void EditorDebuggerRemoteObjects::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_title"), &EditorDebuggerRemoteObjects::get_title);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("value_edited", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value")));
|
||||
ADD_SIGNAL(MethodInfo("values_edited", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::DICTIONARY, "values", PROPERTY_HINT_DICTIONARY_TYPE, "uint64_t:Variant"), PropertyInfo(Variant::STRING, "field")));
|
||||
}
|
||||
|
||||
/// EditorDebuggerInspector
|
||||
|
||||
EditorDebuggerInspector::EditorDebuggerInspector() {
|
||||
variables = memnew(EditorDebuggerRemoteObject);
|
||||
variables = memnew(EditorDebuggerRemoteObjects);
|
||||
}
|
||||
|
||||
EditorDebuggerInspector::~EditorDebuggerInspector() {
|
||||
|
|
@ -100,7 +132,7 @@ EditorDebuggerInspector::~EditorDebuggerInspector() {
|
|||
|
||||
void EditorDebuggerInspector::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("object_selected", PropertyInfo(Variant::INT, "id")));
|
||||
ADD_SIGNAL(MethodInfo("object_edited", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value")));
|
||||
ADD_SIGNAL(MethodInfo("objects_edited", PropertyInfo(Variant::ARRAY, "ids"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value"), PropertyInfo(Variant::STRING, "field")));
|
||||
ADD_SIGNAL(MethodInfo("object_property_updated", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property")));
|
||||
}
|
||||
|
||||
|
|
@ -111,50 +143,143 @@ void EditorDebuggerInspector::_notification(int p_what) {
|
|||
} break;
|
||||
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
variables->remote_object_ids.append(0);
|
||||
edit(variables);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerInspector::_object_edited(ObjectID p_id, const String &p_prop, const Variant &p_value) {
|
||||
emit_signal(SNAME("object_edited"), p_id, p_prop, p_value);
|
||||
void EditorDebuggerInspector::_objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field) {
|
||||
emit_signal(SNAME("objects_edited"), p_prop, p_values, p_field);
|
||||
}
|
||||
|
||||
void EditorDebuggerInspector::_object_selected(ObjectID p_object) {
|
||||
emit_signal(SNAME("object_selected"), p_object);
|
||||
}
|
||||
|
||||
ObjectID EditorDebuggerInspector::add_object(const Array &p_arr) {
|
||||
EditorDebuggerRemoteObject *debug_obj = nullptr;
|
||||
EditorDebuggerRemoteObjects *EditorDebuggerInspector::set_objects(const Array &p_arr) {
|
||||
ERR_FAIL_COND_V(p_arr.is_empty(), nullptr);
|
||||
|
||||
SceneDebuggerObject obj;
|
||||
obj.deserialize(p_arr);
|
||||
ERR_FAIL_COND_V(obj.id.is_null(), ObjectID());
|
||||
TypedArray<uint64_t> ids;
|
||||
LocalVector<SceneDebuggerObject> objects;
|
||||
for (const Array arr : p_arr) {
|
||||
SceneDebuggerObject obj;
|
||||
obj.deserialize(arr);
|
||||
if (obj.id.is_valid()) {
|
||||
ids.push_back((uint64_t)obj.id);
|
||||
objects.push_back(obj);
|
||||
}
|
||||
}
|
||||
ERR_FAIL_COND_V(ids.is_empty(), nullptr);
|
||||
|
||||
if (remote_objects.has(obj.id)) {
|
||||
debug_obj = remote_objects[obj.id];
|
||||
} else {
|
||||
debug_obj = memnew(EditorDebuggerRemoteObject);
|
||||
debug_obj->remote_object_id = obj.id;
|
||||
debug_obj->type_name = obj.class_name;
|
||||
remote_objects[obj.id] = debug_obj;
|
||||
debug_obj->connect("value_edited", callable_mp(this, &EditorDebuggerInspector::_object_edited));
|
||||
// Sorting is necessary, as selected nodes in the remote tree are ordered by index.
|
||||
ids.sort();
|
||||
|
||||
EditorDebuggerRemoteObjects *remote_objects = nullptr;
|
||||
for (EditorDebuggerRemoteObjects *robjs : remote_objects_list) {
|
||||
if (robjs->remote_object_ids == ids) {
|
||||
remote_objects = robjs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int old_prop_size = debug_obj->prop_list.size();
|
||||
if (!remote_objects) {
|
||||
remote_objects = memnew(EditorDebuggerRemoteObjects);
|
||||
remote_objects->remote_object_ids = ids;
|
||||
remote_objects->remote_object_ids.make_read_only();
|
||||
remote_objects->connect("values_edited", callable_mp(this, &EditorDebuggerInspector::_objects_edited));
|
||||
remote_objects_list.push_back(remote_objects);
|
||||
}
|
||||
|
||||
debug_obj->prop_list.clear();
|
||||
StringName class_name = objects[0].class_name;
|
||||
if (class_name != SNAME("Object")) {
|
||||
// Search for the common class between all selected objects.
|
||||
bool check_type_again = true;
|
||||
while (check_type_again) {
|
||||
check_type_again = false;
|
||||
|
||||
if (class_name == SNAME("Object") || class_name == StringName()) {
|
||||
// All objects inherit from Object, so no need to continue checking.
|
||||
class_name = SNAME("Object");
|
||||
break;
|
||||
}
|
||||
|
||||
// Check that all objects inherit from type_name.
|
||||
for (const SceneDebuggerObject &obj : objects) {
|
||||
if (obj.class_name == class_name || ClassDB::is_parent_class(obj.class_name, class_name)) {
|
||||
continue; // class_name is the same or a parent of the object's class.
|
||||
}
|
||||
|
||||
// class_name is not a parent of the node's class, so check again with the parent class.
|
||||
class_name = ClassDB::get_parent_class(class_name);
|
||||
check_type_again = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
remote_objects->type_name = class_name;
|
||||
|
||||
// Search for properties that are present in all selected objects.
|
||||
struct UsageData {
|
||||
int qty = 0;
|
||||
SceneDebuggerObject::SceneDebuggerProperty prop;
|
||||
TypedDictionary<uint64_t, Variant> values;
|
||||
};
|
||||
HashMap<String, UsageData> usage;
|
||||
int nc = 0;
|
||||
for (const SceneDebuggerObject &obj : objects) {
|
||||
for (const SceneDebuggerObject::SceneDebuggerProperty &prop : obj.properties) {
|
||||
PropertyInfo pinfo = prop.first;
|
||||
if (pinfo.name == "script") {
|
||||
continue; // Added later manually, since this is intercepted before being set (check Variant Object::get()).
|
||||
} else if (pinfo.name.begins_with("metadata/")) {
|
||||
pinfo.name = pinfo.name.replace_first("metadata/", "Metadata/"); // Trick to not get actual metadata edited from EditorDebuggerRemoteObjects.
|
||||
}
|
||||
|
||||
if (!usage.has(pinfo.name)) {
|
||||
UsageData usage_dt;
|
||||
usage_dt.prop = prop;
|
||||
usage_dt.prop.first.name = pinfo.name;
|
||||
usage_dt.values[obj.id] = prop.second;
|
||||
usage[pinfo.name] = usage_dt;
|
||||
}
|
||||
|
||||
// Make sure only properties with the same exact PropertyInfo data will appear.
|
||||
if (usage[pinfo.name].prop.first == pinfo) {
|
||||
usage[pinfo.name].qty++;
|
||||
usage[pinfo.name].values[obj.id] = prop.second;
|
||||
}
|
||||
}
|
||||
|
||||
nc++;
|
||||
}
|
||||
for (HashMap<String, UsageData>::Iterator E = usage.begin(); E;) {
|
||||
HashMap<String, UsageData>::Iterator next = E;
|
||||
++next;
|
||||
|
||||
UsageData usage_dt = E->value;
|
||||
if (nc != usage_dt.qty) {
|
||||
// Doesn't appear on all of them, remove it.
|
||||
usage.erase(E->key);
|
||||
}
|
||||
|
||||
E = next;
|
||||
}
|
||||
|
||||
int old_prop_size = remote_objects->prop_list.size();
|
||||
|
||||
remote_objects->prop_list.clear();
|
||||
int new_props_added = 0;
|
||||
HashSet<String> changed;
|
||||
for (SceneDebuggerObject::SceneDebuggerProperty &property : obj.properties) {
|
||||
PropertyInfo &pinfo = property.first;
|
||||
Variant &var = property.second;
|
||||
for (KeyValue<String, UsageData> &KV : usage) {
|
||||
const PropertyInfo &pinfo = KV.value.prop.first;
|
||||
Variant var = KV.value.values[remote_objects->remote_object_ids[0]];
|
||||
|
||||
if (pinfo.type == Variant::OBJECT) {
|
||||
if (var.is_string()) {
|
||||
String path = var;
|
||||
if (path.contains("::")) {
|
||||
// built-in resource
|
||||
// Built-in resource.
|
||||
String base_path = path.get_slice("::", 0);
|
||||
Ref<Resource> dependency = ResourceLoader::load(base_path);
|
||||
if (dependency.is_valid()) {
|
||||
|
|
@ -162,15 +287,16 @@ ObjectID EditorDebuggerInspector::add_object(const Array &p_arr) {
|
|||
}
|
||||
}
|
||||
var = ResourceLoader::load(path);
|
||||
KV.value.values[remote_objects->remote_object_ids[0]] = var;
|
||||
|
||||
if (pinfo.hint_string == "Script") {
|
||||
if (debug_obj->get_script() != var) {
|
||||
debug_obj->set_script(Ref<RefCounted>());
|
||||
if (remote_objects->get_script() != var) {
|
||||
remote_objects->set_script(Ref<RefCounted>());
|
||||
Ref<Script> scr(var);
|
||||
if (scr.is_valid()) {
|
||||
ScriptInstance *scr_instance = scr->placeholder_instance_create(debug_obj);
|
||||
ScriptInstance *scr_instance = scr->placeholder_instance_create(remote_objects);
|
||||
if (scr_instance) {
|
||||
debug_obj->set_script_and_instance(var, scr_instance);
|
||||
remote_objects->set_script_and_instance(var, scr_instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -178,49 +304,67 @@ ObjectID EditorDebuggerInspector::add_object(const Array &p_arr) {
|
|||
}
|
||||
}
|
||||
|
||||
//always add the property, since props may have been added or removed
|
||||
debug_obj->prop_list.push_back(pinfo);
|
||||
// Always add the property, since props may have been added or removed.
|
||||
remote_objects->prop_list.push_back(pinfo);
|
||||
|
||||
if (!debug_obj->prop_values.has(pinfo.name)) {
|
||||
if (!remote_objects->prop_values.has(pinfo.name)) {
|
||||
new_props_added++;
|
||||
debug_obj->prop_values[pinfo.name] = var;
|
||||
} else {
|
||||
if (bool(Variant::evaluate(Variant::OP_NOT_EQUAL, debug_obj->prop_values[pinfo.name], var))) {
|
||||
debug_obj->prop_values[pinfo.name] = var;
|
||||
changed.insert(pinfo.name);
|
||||
}
|
||||
} else if (bool(Variant::evaluate(Variant::OP_NOT_EQUAL, remote_objects->prop_values[pinfo.name], var))) {
|
||||
changed.insert(pinfo.name);
|
||||
}
|
||||
|
||||
remote_objects->prop_values[pinfo.name] = KV.value.values;
|
||||
}
|
||||
|
||||
if (old_prop_size == debug_obj->prop_list.size() && new_props_added == 0) {
|
||||
//only some may have changed, if so, then update those, if exist
|
||||
if (old_prop_size == remote_objects->prop_list.size() && new_props_added == 0) {
|
||||
// Only some may have changed, if so, then update those, if they exist.
|
||||
for (const String &E : changed) {
|
||||
emit_signal(SNAME("object_property_updated"), debug_obj->remote_object_id, E);
|
||||
emit_signal(SNAME("object_property_updated"), remote_objects->get_instance_id(), E);
|
||||
}
|
||||
} else {
|
||||
//full update, because props were added or removed
|
||||
debug_obj->update();
|
||||
// Full update, because props were added or removed.
|
||||
remote_objects->update();
|
||||
}
|
||||
|
||||
return remote_objects;
|
||||
}
|
||||
|
||||
void EditorDebuggerInspector::clear_remote_inspector() {
|
||||
if (remote_objects_list.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Object *obj = InspectorDock::get_inspector_singleton()->get_edited_object();
|
||||
// Check if the inspector holds remote items, and take it out if so.
|
||||
if (Object::cast_to<EditorDebuggerRemoteObjects>(obj)) {
|
||||
EditorNode::get_singleton()->push_item(nullptr);
|
||||
}
|
||||
return obj.id;
|
||||
}
|
||||
|
||||
void EditorDebuggerInspector::clear_cache() {
|
||||
for (const KeyValue<ObjectID, EditorDebuggerRemoteObject *> &E : remote_objects) {
|
||||
EditorNode *editor = EditorNode::get_singleton();
|
||||
if (editor->get_editor_selection_history()->get_current() == E.value->get_instance_id()) {
|
||||
editor->push_item(nullptr);
|
||||
}
|
||||
memdelete(E.value);
|
||||
clear_remote_inspector();
|
||||
|
||||
for (EditorDebuggerRemoteObjects *robjs : remote_objects_list) {
|
||||
memdelete(robjs);
|
||||
}
|
||||
remote_objects.clear();
|
||||
remote_objects_list.clear();
|
||||
|
||||
remote_dependencies.clear();
|
||||
}
|
||||
|
||||
Object *EditorDebuggerInspector::get_object(ObjectID p_id) {
|
||||
if (remote_objects.has(p_id)) {
|
||||
return remote_objects[p_id];
|
||||
void EditorDebuggerInspector::invalidate_selection_from_cache(const TypedArray<uint64_t> &p_ids) {
|
||||
for (EditorDebuggerRemoteObjects *robjs : remote_objects_list) {
|
||||
if (robjs->remote_object_ids == p_ids) {
|
||||
const Object *obj = InspectorDock::get_inspector_singleton()->get_edited_object();
|
||||
if (obj == robjs) {
|
||||
EditorNode::get_singleton()->push_item(nullptr);
|
||||
}
|
||||
|
||||
remote_objects_list.erase(robjs);
|
||||
memdelete(robjs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void EditorDebuggerInspector::add_stack_variable(const Array &p_array, int p_offset) {
|
||||
|
|
@ -270,7 +414,7 @@ void EditorDebuggerInspector::add_stack_variable(const Array &p_array, int p_off
|
|||
}
|
||||
variables->prop_list.insert_before(current, pinfo);
|
||||
}
|
||||
variables->prop_values[type + n] = v;
|
||||
variables->prop_values[type + n][0] = v;
|
||||
variables->update();
|
||||
edit(variables);
|
||||
|
||||
|
|
@ -288,9 +432,9 @@ void EditorDebuggerInspector::clear_stack_variables() {
|
|||
}
|
||||
|
||||
String EditorDebuggerInspector::get_stack_variable(const String &p_var) {
|
||||
for (KeyValue<StringName, Variant> &E : variables->prop_values) {
|
||||
for (KeyValue<StringName, TypedDictionary<uint64_t, Variant>> &E : variables->prop_values) {
|
||||
String v = E.key.operator String();
|
||||
if (v.get_slice("/", 1) == p_var) {
|
||||
if (v.get_slicec('/', 1) == p_var) {
|
||||
return variables->get_variant(v);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,13 +28,18 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_DEBUGGER_INSPECTOR_H
|
||||
#define EDITOR_DEBUGGER_INSPECTOR_H
|
||||
#pragma once
|
||||
|
||||
#include "core/variant/typed_dictionary.h"
|
||||
#include "editor/editor_inspector.h"
|
||||
|
||||
class EditorDebuggerRemoteObject : public Object {
|
||||
GDCLASS(EditorDebuggerRemoteObject, Object);
|
||||
class SceneDebuggerObject;
|
||||
|
||||
class EditorDebuggerRemoteObjects : public Object {
|
||||
GDCLASS(EditorDebuggerRemoteObjects, Object);
|
||||
|
||||
private:
|
||||
bool _set_impl(const StringName &p_name, const Variant &p_value, const String &p_field);
|
||||
|
||||
protected:
|
||||
bool _set(const StringName &p_name, const Variant &p_value);
|
||||
|
|
@ -43,14 +48,13 @@ protected:
|
|||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
ObjectID remote_object_id;
|
||||
TypedArray<uint64_t> remote_object_ids;
|
||||
String type_name;
|
||||
List<PropertyInfo> prop_list;
|
||||
HashMap<StringName, Variant> prop_values;
|
||||
HashMap<StringName, TypedDictionary<uint64_t, Variant>> prop_values;
|
||||
|
||||
ObjectID get_remote_object_id() { return remote_object_id; }
|
||||
void set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field);
|
||||
String get_title();
|
||||
|
||||
Variant get_variant(const StringName &p_name);
|
||||
|
||||
void clear() {
|
||||
|
|
@ -59,21 +63,18 @@ public:
|
|||
}
|
||||
|
||||
void update() { notify_property_list_changed(); }
|
||||
|
||||
EditorDebuggerRemoteObject() {}
|
||||
};
|
||||
|
||||
class EditorDebuggerInspector : public EditorInspector {
|
||||
GDCLASS(EditorDebuggerInspector, EditorInspector);
|
||||
|
||||
private:
|
||||
ObjectID inspected_object_id;
|
||||
HashMap<ObjectID, EditorDebuggerRemoteObject *> remote_objects;
|
||||
LocalVector<EditorDebuggerRemoteObjects *> remote_objects_list;
|
||||
HashSet<Ref<Resource>> remote_dependencies;
|
||||
EditorDebuggerRemoteObject *variables = nullptr;
|
||||
EditorDebuggerRemoteObjects *variables = nullptr;
|
||||
|
||||
void _object_selected(ObjectID p_object);
|
||||
void _object_edited(ObjectID p_id, const String &p_prop, const Variant &p_value);
|
||||
void _objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field);
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
|
@ -84,14 +85,13 @@ public:
|
|||
~EditorDebuggerInspector();
|
||||
|
||||
// Remote Object cache
|
||||
ObjectID add_object(const Array &p_arr);
|
||||
Object *get_object(ObjectID p_id);
|
||||
EditorDebuggerRemoteObjects *set_objects(const Array &p_array);
|
||||
void clear_remote_inspector();
|
||||
void clear_cache();
|
||||
void invalidate_selection_from_cache(const TypedArray<uint64_t> &p_ids);
|
||||
|
||||
// Stack Dump variables
|
||||
String get_stack_variable(const String &p_var);
|
||||
void add_stack_variable(const Array &p_arr, int p_offset = -1);
|
||||
void clear_stack_variables();
|
||||
};
|
||||
|
||||
#endif // EDITOR_DEBUGGER_INSPECTOR_H
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ EditorDebuggerNode::EditorDebuggerNode() {
|
|||
|
||||
// Remote scene tree
|
||||
remote_scene_tree = memnew(EditorDebuggerTree);
|
||||
remote_scene_tree->connect("object_selected", callable_mp(this, &EditorDebuggerNode::_remote_object_requested));
|
||||
remote_scene_tree->connect("objects_selected", callable_mp(this, &EditorDebuggerNode::_remote_objects_requested));
|
||||
remote_scene_tree->connect("selection_cleared", callable_mp(this, &EditorDebuggerNode::_remote_selection_cleared));
|
||||
remote_scene_tree->connect("save_node", callable_mp(this, &EditorDebuggerNode::_save_node_requested));
|
||||
remote_scene_tree->connect("button_clicked", callable_mp(this, &EditorDebuggerNode::_remote_tree_button_pressed));
|
||||
SceneTreeDock::get_singleton()->add_remote_tree_editor(remote_scene_tree);
|
||||
|
|
@ -109,11 +110,13 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
|
|||
node->connect("breakpoint_selected", callable_mp(this, &EditorDebuggerNode::_error_selected).bind(id));
|
||||
node->connect("clear_execution", callable_mp(this, &EditorDebuggerNode::_clear_execution));
|
||||
node->connect("breaked", callable_mp(this, &EditorDebuggerNode::_breaked).bind(id));
|
||||
node->connect("debug_data", callable_mp(this, &EditorDebuggerNode::_debug_data).bind(id));
|
||||
node->connect("remote_tree_select_requested", callable_mp(this, &EditorDebuggerNode::_remote_tree_select_requested).bind(id));
|
||||
node->connect("remote_tree_clear_selection_requested", callable_mp(this, &EditorDebuggerNode::_remote_tree_clear_selection_requested).bind(id));
|
||||
node->connect("remote_tree_updated", callable_mp(this, &EditorDebuggerNode::_remote_tree_updated).bind(id));
|
||||
node->connect("remote_object_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_updated).bind(id));
|
||||
node->connect("remote_objects_updated", callable_mp(this, &EditorDebuggerNode::_remote_objects_updated).bind(id));
|
||||
node->connect("remote_object_property_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_property_updated).bind(id));
|
||||
node->connect("remote_object_requested", callable_mp(this, &EditorDebuggerNode::_remote_object_requested).bind(id));
|
||||
node->connect("remote_objects_requested", callable_mp(this, &EditorDebuggerNode::_remote_objects_requested).bind(id));
|
||||
node->connect("set_breakpoint", callable_mp(this, &EditorDebuggerNode::_breakpoint_set_in_tree).bind(id));
|
||||
node->connect("clear_breakpoints", callable_mp(this, &EditorDebuggerNode::_breakpoints_cleared_in_tree).bind(id));
|
||||
node->connect("errors_cleared", callable_mp(this, &EditorDebuggerNode::_update_errors));
|
||||
|
|
@ -222,10 +225,6 @@ void EditorDebuggerNode::register_undo_redo(UndoRedo *p_undo_redo) {
|
|||
p_undo_redo->set_property_notify_callback(_properties_changed, this);
|
||||
}
|
||||
|
||||
EditorDebuggerRemoteObject *EditorDebuggerNode::get_inspected_remote_object() {
|
||||
return Object::cast_to<EditorDebuggerRemoteObject>(ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_current()));
|
||||
}
|
||||
|
||||
ScriptEditorDebugger *EditorDebuggerNode::get_debugger(int p_id) const {
|
||||
return Object::cast_to<ScriptEditorDebugger>(tabs->get_tab_control(p_id));
|
||||
}
|
||||
|
|
@ -292,6 +291,10 @@ void EditorDebuggerNode::stop(bool p_force) {
|
|||
if (keep_open && !p_force) {
|
||||
return;
|
||||
}
|
||||
|
||||
remote_scene_tree_wait = false;
|
||||
inspect_edited_object_wait = false;
|
||||
|
||||
current_uri.clear();
|
||||
if (server.is_valid()) {
|
||||
server->stop();
|
||||
|
|
@ -304,6 +307,7 @@ void EditorDebuggerNode::stop(bool p_force) {
|
|||
|
||||
server.unref();
|
||||
}
|
||||
|
||||
// Also close all debugging sessions.
|
||||
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
|
||||
if (dbg->is_session_active()) {
|
||||
|
|
@ -351,21 +355,29 @@ void EditorDebuggerNode::_notification(int p_what) {
|
|||
|
||||
_update_errors();
|
||||
|
||||
// Remote scene tree update
|
||||
remote_scene_tree_timeout -= get_process_delta_time();
|
||||
if (remote_scene_tree_timeout < 0) {
|
||||
remote_scene_tree_timeout = EDITOR_GET("debugger/remote_scene_tree_refresh_interval");
|
||||
if (remote_scene_tree->is_visible_in_tree()) {
|
||||
get_current_debugger()->request_remote_tree();
|
||||
// Remote scene tree update.
|
||||
if (!remote_scene_tree_wait) {
|
||||
remote_scene_tree_timeout -= get_process_delta_time();
|
||||
if (remote_scene_tree_timeout < 0) {
|
||||
remote_scene_tree_timeout = EDITOR_GET("debugger/remote_scene_tree_refresh_interval");
|
||||
|
||||
if (remote_scene_tree->is_visible_in_tree()) {
|
||||
remote_scene_tree_wait = true;
|
||||
get_current_debugger()->request_remote_tree();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remote inspector update
|
||||
inspect_edited_object_timeout -= get_process_delta_time();
|
||||
if (inspect_edited_object_timeout < 0) {
|
||||
inspect_edited_object_timeout = EDITOR_GET("debugger/remote_inspect_refresh_interval");
|
||||
if (EditorDebuggerRemoteObject *obj = get_inspected_remote_object()) {
|
||||
get_current_debugger()->request_remote_object(obj->remote_object_id);
|
||||
// Remote inspector update.
|
||||
if (!inspect_edited_object_wait) {
|
||||
inspect_edited_object_timeout -= get_process_delta_time();
|
||||
if (inspect_edited_object_timeout < 0) {
|
||||
inspect_edited_object_timeout = EDITOR_GET("debugger/remote_inspect_refresh_interval");
|
||||
|
||||
if (EditorDebuggerRemoteObjects *robjs = Object::cast_to<EditorDebuggerRemoteObjects>(InspectorDock::get_inspector_singleton()->get_edited_object())) {
|
||||
inspect_edited_object_wait = true;
|
||||
get_current_debugger()->request_remote_objects(robjs->remote_object_ids, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -467,21 +479,26 @@ void EditorDebuggerNode::_debugger_stopped(int p_id) {
|
|||
|
||||
void EditorDebuggerNode::_debugger_wants_stop(int p_id) {
|
||||
// Ask editor to kill PID.
|
||||
int pid = get_debugger(p_id)->get_remote_pid();
|
||||
if (pid) {
|
||||
if (int pid = get_debugger(p_id)->get_remote_pid()) {
|
||||
callable_mp(EditorNode::get_singleton(), &EditorNode::stop_child_process).call_deferred(pid);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_debugger_changed(int p_tab) {
|
||||
if (get_inspected_remote_object()) {
|
||||
// Clear inspected object, you can only inspect objects in selected debugger.
|
||||
// Hopefully, in the future, we will have one inspector per debugger.
|
||||
EditorNode::get_singleton()->push_item(nullptr);
|
||||
remote_scene_tree_wait = false;
|
||||
inspect_edited_object_wait = false;
|
||||
|
||||
if (Object *robjs = InspectorDock::get_inspector_singleton()->get_edited_object()) {
|
||||
if (Object::cast_to<EditorDebuggerRemoteObjects>(robjs)) {
|
||||
// Clear inspected object, you can only inspect objects in selected debugger.
|
||||
// Hopefully, in the future, we will have one inspector per debugger.
|
||||
EditorNode::get_singleton()->push_item(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (get_previous_debugger()) {
|
||||
_text_editor_stack_clear(get_previous_debugger());
|
||||
if (ScriptEditorDebugger *prev_debug = get_previous_debugger()) {
|
||||
prev_debug->clear_inspector();
|
||||
_text_editor_stack_clear(prev_debug);
|
||||
}
|
||||
if (remote_scene_tree->is_visible_in_tree()) {
|
||||
get_current_debugger()->request_remote_tree();
|
||||
|
|
@ -493,6 +510,18 @@ void EditorDebuggerNode::_debugger_changed(int p_tab) {
|
|||
_break_state_changed();
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_debug_data(const String &p_msg, const Array &p_data, int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_msg == "scene:scene_tree") {
|
||||
remote_scene_tree_wait = false;
|
||||
} else if (p_msg == "scene:inspect_objects") {
|
||||
inspect_edited_object_wait = false;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::set_script_debug_button(MenuButton *p_button) {
|
||||
script_menu = p_button;
|
||||
script_menu->set_text(TTR("Debug"));
|
||||
|
|
@ -587,6 +616,10 @@ bool EditorDebuggerNode::is_skip_breakpoints() const {
|
|||
return get_current_debugger()->is_skip_breakpoints();
|
||||
}
|
||||
|
||||
bool EditorDebuggerNode::is_ignore_error_breaks() const {
|
||||
return get_default_debugger()->is_ignore_error_breaks();
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::set_breakpoint(const String &p_path, int p_line, bool p_enabled) {
|
||||
breakpoints[Breakpoint(p_path, p_line)] = p_enabled;
|
||||
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
|
||||
|
|
@ -646,11 +679,39 @@ void EditorDebuggerNode::request_remote_tree() {
|
|||
get_current_debugger()->request_remote_tree();
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_tree_select_requested(ObjectID p_id, int p_debugger) {
|
||||
void EditorDebuggerNode::set_remote_selection(const TypedArray<int64_t> &p_ids) {
|
||||
stop_waiting_inspection();
|
||||
get_current_debugger()->request_remote_objects(p_ids);
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::clear_remote_tree_selection() {
|
||||
remote_scene_tree->clear_selection();
|
||||
get_current_debugger()->clear_inspector(remote_scene_tree_clear_msg);
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::stop_waiting_inspection() {
|
||||
inspect_edited_object_timeout = EDITOR_GET("debugger/remote_inspect_refresh_interval");
|
||||
inspect_edited_object_wait = false;
|
||||
}
|
||||
|
||||
bool EditorDebuggerNode::match_remote_selection(const TypedArray<uint64_t> &p_ids) const {
|
||||
return p_ids == remote_scene_tree->get_selection();
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_tree_select_requested(const TypedArray<int64_t> &p_ids, int p_debugger) {
|
||||
if (p_debugger == tabs->get_current_tab()) {
|
||||
remote_scene_tree->select_nodes(p_ids);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_tree_clear_selection_requested(int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
}
|
||||
remote_scene_tree->select_node(p_id);
|
||||
remote_scene_tree->clear_selection();
|
||||
remote_scene_tree_clear_msg = false;
|
||||
get_current_debugger()->clear_inspector(false);
|
||||
remote_scene_tree_clear_msg = true;
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_tree_updated(int p_debugger) {
|
||||
|
|
@ -679,37 +740,37 @@ void EditorDebuggerNode::_remote_tree_button_pressed(Object *p_item, int p_colum
|
|||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_object_updated(ObjectID p_id, int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
void EditorDebuggerNode::_remote_objects_updated(EditorDebuggerRemoteObjects *p_objs, int p_debugger) {
|
||||
if (p_debugger == tabs->get_current_tab() && p_objs != InspectorDock::get_inspector_singleton()->get_edited_object()) {
|
||||
EditorNode::get_singleton()->push_item(p_objs);
|
||||
}
|
||||
if (EditorDebuggerRemoteObject *obj = get_inspected_remote_object()) {
|
||||
if (obj->remote_object_id == p_id) {
|
||||
return; // Already being edited
|
||||
}
|
||||
}
|
||||
|
||||
EditorNode::get_singleton()->push_item(get_current_debugger()->get_remote_object(p_id));
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_object_property_updated(ObjectID p_id, const String &p_property, int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
}
|
||||
if (EditorDebuggerRemoteObject *obj = get_inspected_remote_object()) {
|
||||
if (obj->remote_object_id != p_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object *obj = InspectorDock::get_inspector_singleton()->get_edited_object();
|
||||
if (obj && obj->get_instance_id() == p_id) {
|
||||
InspectorDock::get_inspector_singleton()->update_property(p_property);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_object_requested(ObjectID p_id, int p_debugger) {
|
||||
void EditorDebuggerNode::_remote_objects_requested(const TypedArray<uint64_t> &p_ids, int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
}
|
||||
inspect_edited_object_timeout = 0.7; // Temporarily disable timeout to avoid multiple requests.
|
||||
get_current_debugger()->request_remote_object(p_id);
|
||||
stop_waiting_inspection();
|
||||
get_current_debugger()->request_remote_objects(p_ids);
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_selection_cleared(int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
}
|
||||
stop_waiting_inspection();
|
||||
get_current_debugger()->clear_inspector();
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_save_node_requested(ObjectID p_id, const String &p_file, int p_debugger) {
|
||||
|
|
@ -809,6 +870,17 @@ void EditorDebuggerNode::live_debug_reparent_node(const NodePath &p_at, const No
|
|||
});
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::set_debug_mute_audio(bool p_mute) {
|
||||
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
|
||||
dbg->set_debug_mute_audio(p_mute);
|
||||
});
|
||||
debug_mute_audio = p_mute;
|
||||
}
|
||||
|
||||
bool EditorDebuggerNode::get_debug_mute_audio() const {
|
||||
return debug_mute_audio;
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::set_camera_override(CameraOverride p_override) {
|
||||
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
|
||||
dbg->set_camera_override(p_override);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_DEBUGGER_NODE_H
|
||||
#define EDITOR_DEBUGGER_NODE_H
|
||||
#pragma once
|
||||
|
||||
#include "core/object/script_language.h"
|
||||
#include "editor/debugger/editor_debugger_server.h"
|
||||
|
|
@ -39,7 +38,7 @@ class Button;
|
|||
class DebugAdapterParser;
|
||||
class EditorDebuggerPlugin;
|
||||
class EditorDebuggerTree;
|
||||
class EditorDebuggerRemoteObject;
|
||||
class EditorDebuggerRemoteObjects;
|
||||
class MenuButton;
|
||||
class ScriptEditorDebugger;
|
||||
class TabContainer;
|
||||
|
|
@ -103,21 +102,25 @@ private:
|
|||
int last_error_count = 0;
|
||||
int last_warning_count = 0;
|
||||
|
||||
bool inspect_edited_object_wait = false;
|
||||
float inspect_edited_object_timeout = 0;
|
||||
EditorDebuggerTree *remote_scene_tree = nullptr;
|
||||
bool remote_scene_tree_wait = false;
|
||||
float remote_scene_tree_timeout = 0.0;
|
||||
bool remote_scene_tree_clear_msg = true;
|
||||
bool auto_switch_remote_scene_tree = false;
|
||||
bool debug_with_external_editor = false;
|
||||
bool keep_open = false;
|
||||
String current_uri;
|
||||
|
||||
bool debug_mute_audio = false;
|
||||
|
||||
CameraOverride camera_override = OVERRIDE_NONE;
|
||||
HashMap<Breakpoint, bool, Breakpoint> breakpoints;
|
||||
|
||||
HashSet<Ref<EditorDebuggerPlugin>> debugger_plugins;
|
||||
|
||||
ScriptEditorDebugger *_add_debugger();
|
||||
EditorDebuggerRemoteObject *get_inspected_remote_object();
|
||||
void _update_errors();
|
||||
|
||||
friend class DebuggerEditorPlugin;
|
||||
|
|
@ -129,12 +132,15 @@ protected:
|
|||
void _debugger_stopped(int p_id);
|
||||
void _debugger_wants_stop(int p_id);
|
||||
void _debugger_changed(int p_tab);
|
||||
void _remote_tree_select_requested(ObjectID p_id, int p_debugger);
|
||||
void _debug_data(const String &p_msg, const Array &p_data, int p_debugger);
|
||||
void _remote_tree_select_requested(const TypedArray<int64_t> &p_ids, int p_debugger);
|
||||
void _remote_tree_clear_selection_requested(int p_debugger);
|
||||
void _remote_tree_updated(int p_debugger);
|
||||
void _remote_tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
|
||||
void _remote_object_updated(ObjectID p_id, int p_debugger);
|
||||
void _remote_objects_updated(EditorDebuggerRemoteObjects *p_objs, int p_debugger);
|
||||
void _remote_object_property_updated(ObjectID p_id, const String &p_property, int p_debugger);
|
||||
void _remote_object_requested(ObjectID p_id, int p_debugger);
|
||||
void _remote_objects_requested(const TypedArray<uint64_t> &p_ids, int p_debugger);
|
||||
void _remote_selection_cleared(int p_debugger);
|
||||
void _save_node_requested(ObjectID p_id, const String &p_file, int p_debugger);
|
||||
|
||||
void _breakpoint_set_in_tree(Ref<RefCounted> p_script, int p_line, bool p_enabled, int p_debugger);
|
||||
|
|
@ -184,6 +190,7 @@ public:
|
|||
bool get_debug_with_external_editor() { return debug_with_external_editor; }
|
||||
|
||||
bool is_skip_breakpoints() const;
|
||||
bool is_ignore_error_breaks() const;
|
||||
void set_breakpoint(const String &p_path, int p_line, bool p_enabled);
|
||||
void set_breakpoints(const String &p_path, const Array &p_lines);
|
||||
void reload_all_scripts();
|
||||
|
|
@ -191,6 +198,10 @@ public:
|
|||
|
||||
// Remote inspector/edit.
|
||||
void request_remote_tree();
|
||||
void set_remote_selection(const TypedArray<int64_t> &p_ids);
|
||||
void clear_remote_tree_selection();
|
||||
void stop_waiting_inspection();
|
||||
bool match_remote_selection(const TypedArray<uint64_t> &p_ids) const;
|
||||
static void _methods_changed(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount);
|
||||
static void _properties_changed(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value);
|
||||
|
||||
|
|
@ -205,6 +216,9 @@ public:
|
|||
void live_debug_duplicate_node(const NodePath &p_at, const String &p_new_name);
|
||||
void live_debug_reparent_node(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos);
|
||||
|
||||
void set_debug_mute_audio(bool p_mute);
|
||||
bool get_debug_mute_audio() const;
|
||||
|
||||
void set_camera_override(CameraOverride p_override);
|
||||
CameraOverride get_camera_override();
|
||||
|
||||
|
|
@ -218,5 +232,3 @@ public:
|
|||
void add_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin);
|
||||
void remove_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin);
|
||||
};
|
||||
|
||||
#endif // EDITOR_DEBUGGER_NODE_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_DEBUGGER_SERVER_H
|
||||
#define EDITOR_DEBUGGER_SERVER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/debugger/remote_debugger_peer.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
|
|
@ -56,5 +55,3 @@ public:
|
|||
virtual bool is_connection_available() const = 0;
|
||||
virtual Ref<RemoteDebuggerPeer> take_connection() = 0;
|
||||
};
|
||||
|
||||
#endif // EDITOR_DEBUGGER_SERVER_H
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "editor/editor_settings.h"
|
||||
#include "editor/editor_string_names.h"
|
||||
#include "editor/gui/editor_file_dialog.h"
|
||||
#include "editor/gui/editor_toaster.h"
|
||||
#include "editor/scene_tree_dock.h"
|
||||
#include "scene/debugger/scene_debugger.h"
|
||||
#include "scene/gui/texture_rect.h"
|
||||
|
|
@ -44,6 +45,7 @@
|
|||
EditorDebuggerTree::EditorDebuggerTree() {
|
||||
set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
set_allow_rmb_select(true);
|
||||
set_select_mode(SELECT_MULTI);
|
||||
|
||||
// Popup
|
||||
item_menu = memnew(PopupMenu);
|
||||
|
|
@ -54,6 +56,9 @@ EditorDebuggerTree::EditorDebuggerTree() {
|
|||
file_dialog = memnew(EditorFileDialog);
|
||||
file_dialog->connect("file_selected", callable_mp(this, &EditorDebuggerTree::_file_selected));
|
||||
add_child(file_dialog);
|
||||
|
||||
accept = memnew(AcceptDialog);
|
||||
add_child(accept);
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::_notification(int p_what) {
|
||||
|
|
@ -61,7 +66,8 @@ void EditorDebuggerTree::_notification(int p_what) {
|
|||
case NOTIFICATION_POSTINITIALIZE: {
|
||||
set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
|
||||
connect("cell_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_selected));
|
||||
connect("multi_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_selection_changed));
|
||||
connect("nothing_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_nothing_selected));
|
||||
connect("item_collapsed", callable_mp(this, &EditorDebuggerTree::_scene_tree_folded));
|
||||
connect("item_mouse_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_rmb_selected));
|
||||
} break;
|
||||
|
|
@ -73,24 +79,57 @@ void EditorDebuggerTree::_notification(int p_what) {
|
|||
}
|
||||
|
||||
void EditorDebuggerTree::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("object_selected", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::INT, "debugger")));
|
||||
ADD_SIGNAL(MethodInfo("objects_selected", PropertyInfo(Variant::ARRAY, "object_ids"), PropertyInfo(Variant::INT, "debugger")));
|
||||
ADD_SIGNAL(MethodInfo("selection_cleared", PropertyInfo(Variant::INT, "debugger")));
|
||||
ADD_SIGNAL(MethodInfo("save_node", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "filename"), PropertyInfo(Variant::INT, "debugger")));
|
||||
ADD_SIGNAL(MethodInfo("open"));
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::_scene_tree_selected() {
|
||||
if (updating_scene_tree) {
|
||||
void EditorDebuggerTree::_scene_tree_selection_changed(TreeItem *p_item, int p_column, bool p_selected) {
|
||||
if (updating_scene_tree || !p_item) {
|
||||
return;
|
||||
}
|
||||
|
||||
TreeItem *item = get_selected();
|
||||
if (!item) {
|
||||
return;
|
||||
uint64_t id = uint64_t(p_item->get_metadata(0));
|
||||
if (p_selected) {
|
||||
if (inspected_object_ids.size() == (int)EDITOR_GET("debugger/max_node_selection")) {
|
||||
selection_surpassed_limit = true;
|
||||
p_item->deselect(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inspected_object_ids.has(id)) {
|
||||
inspected_object_ids.append(id);
|
||||
}
|
||||
} else if (inspected_object_ids.has(id)) {
|
||||
inspected_object_ids.erase(id);
|
||||
}
|
||||
|
||||
inspected_object_id = uint64_t(item->get_metadata(0));
|
||||
if (!notify_selection_queued) {
|
||||
callable_mp(this, &EditorDebuggerTree::_notify_selection_changed).call_deferred();
|
||||
notify_selection_queued = true;
|
||||
}
|
||||
}
|
||||
|
||||
emit_signal(SNAME("object_selected"), inspected_object_id, debugger_id);
|
||||
void EditorDebuggerTree::_scene_tree_nothing_selected() {
|
||||
deselect_all();
|
||||
inspected_object_ids.clear();
|
||||
emit_signal(SNAME("selection_cleared"), debugger_id);
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::_notify_selection_changed() {
|
||||
notify_selection_queued = false;
|
||||
|
||||
if (inspected_object_ids.is_empty()) {
|
||||
emit_signal(SNAME("selection_cleared"), debugger_id);
|
||||
} else {
|
||||
emit_signal(SNAME("objects_selected"), inspected_object_ids.duplicate(), debugger_id);
|
||||
}
|
||||
|
||||
if (selection_surpassed_limit) {
|
||||
selection_surpassed_limit = false;
|
||||
EditorToaster::get_singleton()->popup_str(vformat(TTR("Some remote nodes were not selected, as the configured maximum selection is %d. This can be changed at \"debugger/max_node_selection\" in the Editor Settings."), EDITOR_GET("debugger/max_node_selection")), EditorToaster::SEVERITY_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::_scene_tree_folded(Object *p_obj) {
|
||||
|
|
@ -124,7 +163,7 @@ void EditorDebuggerTree::_scene_tree_rmb_selected(const Vector2 &p_position, Mou
|
|||
item->select(0);
|
||||
|
||||
item_menu->clear();
|
||||
item_menu->add_icon_item(get_editor_theme_icon(SNAME("CreateNewSceneFrom")), TTR("Save Branch as Scene"), ITEM_MENU_SAVE_REMOTE_NODE);
|
||||
item_menu->add_icon_item(get_editor_theme_icon(SNAME("CreateNewSceneFrom")), TTR("Save Branch as Scene..."), ITEM_MENU_SAVE_REMOTE_NODE);
|
||||
item_menu->add_icon_item(get_editor_theme_icon(SNAME("CopyNodePath")), TTR("Copy Node Path"), ITEM_MENU_COPY_NODE_PATH);
|
||||
item_menu->add_icon_item(get_editor_theme_icon(SNAME("Collapse")), TTR("Expand/Collapse Branch"), ITEM_MENU_EXPAND_COLLAPSE);
|
||||
item_menu->set_position(get_screen_position() + get_local_mouse_position());
|
||||
|
|
@ -152,12 +191,13 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
updating_scene_tree = true;
|
||||
const String last_path = get_selected_path();
|
||||
const String filter = SceneTreeDock::get_singleton()->get_filter();
|
||||
TreeItem *select_item = nullptr;
|
||||
LocalVector<TreeItem *> select_items;
|
||||
bool hide_filtered_out_parents = EDITOR_GET("docks/scene_tree/hide_filtered_out_parents");
|
||||
|
||||
bool should_scroll = scrolling_to_item || filter != last_filter;
|
||||
scrolling_to_item = false;
|
||||
TreeItem *scroll_item = nullptr;
|
||||
TypedArray<uint64_t> ids_present;
|
||||
|
||||
// Nodes are in a flatten list, depth first. Use a stack of parents, avoid recursion.
|
||||
List<ParentItem> parents;
|
||||
|
|
@ -216,9 +256,11 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
}
|
||||
item->set_meta("node_path", current_path + "/" + item->get_text(0));
|
||||
|
||||
// Select previously selected node.
|
||||
// Select previously selected nodes.
|
||||
if (debugger_id == p_debugger) { // Can use remote id.
|
||||
if (node.id == inspected_object_id) {
|
||||
if (inspected_object_ids.has(uint64_t(node.id))) {
|
||||
ids_present.append(node.id);
|
||||
|
||||
if (selection_uncollapse_all) {
|
||||
selection_uncollapse_all = false;
|
||||
|
||||
|
|
@ -228,14 +270,14 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
updating_scene_tree = true;
|
||||
}
|
||||
|
||||
select_item = item;
|
||||
select_items.push_back(item);
|
||||
if (should_scroll) {
|
||||
scroll_item = item;
|
||||
}
|
||||
}
|
||||
} else if (last_path == (String)item->get_meta("node_path")) { // Must use path.
|
||||
updating_scene_tree = false; // Force emission of new selection.
|
||||
select_item = item;
|
||||
updating_scene_tree = false; // Force emission of new selections.
|
||||
select_items.push_back(item);
|
||||
if (should_scroll) {
|
||||
scroll_item = item;
|
||||
}
|
||||
|
|
@ -280,12 +322,12 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
break; // Filter matches, must survive.
|
||||
}
|
||||
|
||||
parent->remove_child(item);
|
||||
memdelete(item);
|
||||
if (select_item == item || scroll_item == item) {
|
||||
select_item = nullptr;
|
||||
if (select_items.has(item) || scroll_item == item) {
|
||||
select_items.resize(select_items.size() - 1);
|
||||
scroll_item = nullptr;
|
||||
}
|
||||
parent->remove_child(item);
|
||||
memdelete(item);
|
||||
|
||||
if (had_siblings) {
|
||||
break; // Parent must survive.
|
||||
|
|
@ -316,18 +358,20 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
|
||||
from->get_parent()->remove_child(from);
|
||||
memdelete(from);
|
||||
if (select_item == from || scroll_item == from) {
|
||||
select_item = nullptr;
|
||||
if (select_items.has(from) || scroll_item == from) {
|
||||
select_items.erase(from);
|
||||
scroll_item = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inspected_object_ids = ids_present;
|
||||
|
||||
debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree.
|
||||
|
||||
if (select_item) {
|
||||
select_item->select(0);
|
||||
for (TreeItem *item : select_items) {
|
||||
item->select(0);
|
||||
}
|
||||
if (scroll_item) {
|
||||
scroll_to_item(scroll_item, false);
|
||||
|
|
@ -337,12 +381,22 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||
updating_scene_tree = false;
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::select_node(ObjectID p_id) {
|
||||
void EditorDebuggerTree::select_nodes(const TypedArray<int64_t> &p_ids) {
|
||||
// Manually select, as the tree control may be out-of-date for some reason (e.g. not shown yet).
|
||||
selection_uncollapse_all = true;
|
||||
inspected_object_id = uint64_t(p_id);
|
||||
inspected_object_ids = p_ids;
|
||||
scrolling_to_item = true;
|
||||
emit_signal(SNAME("object_selected"), inspected_object_id, debugger_id);
|
||||
|
||||
if (!updating_scene_tree) {
|
||||
// Request a tree refresh.
|
||||
EditorDebuggerNode::get_singleton()->request_remote_tree();
|
||||
}
|
||||
// Set the value immediately, so no update flooding happens and causes a crash.
|
||||
updating_scene_tree = true;
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::clear_selection() {
|
||||
inspected_object_ids.clear();
|
||||
|
||||
if (!updating_scene_tree) {
|
||||
// Request a tree refresh.
|
||||
|
|
@ -453,8 +507,11 @@ void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
|
|||
}
|
||||
|
||||
void EditorDebuggerTree::_file_selected(const String &p_file) {
|
||||
if (inspected_object_id.is_null()) {
|
||||
if (inspected_object_ids.size() != 1) {
|
||||
accept->set_text(vformat(TTR("Saving the branch as a scene requires selecting only one node, but you have selected %d nodes."), inspected_object_ids.size()));
|
||||
accept->popup_centered();
|
||||
return;
|
||||
}
|
||||
emit_signal(SNAME("save_node"), inspected_object_id, p_file, debugger_id);
|
||||
|
||||
emit_signal(SNAME("save_node"), inspected_object_ids[0], p_file, debugger_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_DEBUGGER_TREE_H
|
||||
#define EDITOR_DEBUGGER_TREE_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/tree.h"
|
||||
|
||||
class AcceptDialog;
|
||||
class SceneDebuggerTree;
|
||||
class EditorFileDialog;
|
||||
|
||||
|
|
@ -58,18 +58,23 @@ private:
|
|||
ITEM_MENU_EXPAND_COLLAPSE,
|
||||
};
|
||||
|
||||
ObjectID inspected_object_id;
|
||||
TypedArray<uint64_t> inspected_object_ids;
|
||||
int debugger_id = 0;
|
||||
bool updating_scene_tree = false;
|
||||
bool scrolling_to_item = false;
|
||||
bool notify_selection_queued = false;
|
||||
bool selection_surpassed_limit = false;
|
||||
bool selection_uncollapse_all = false;
|
||||
HashSet<ObjectID> unfold_cache;
|
||||
PopupMenu *item_menu = nullptr;
|
||||
EditorFileDialog *file_dialog = nullptr;
|
||||
AcceptDialog *accept = nullptr;
|
||||
String last_filter;
|
||||
|
||||
void _scene_tree_folded(Object *p_obj);
|
||||
void _scene_tree_selected();
|
||||
void _scene_tree_selection_changed(TreeItem *p_item, int p_column, bool p_selected);
|
||||
void _scene_tree_nothing_selected();
|
||||
void _notify_selection_changed();
|
||||
void _scene_tree_rmb_selected(const Vector2 &p_position, MouseButton p_button);
|
||||
void _item_menu_id_pressed(int p_option);
|
||||
void _file_selected(const String &p_file);
|
||||
|
|
@ -90,9 +95,10 @@ public:
|
|||
String get_selected_path();
|
||||
ObjectID get_selected_object();
|
||||
int get_current_debugger(); // Would love to have one tree for every debugger.
|
||||
inline TypedArray<uint64_t> get_selection() const { return inspected_object_ids.duplicate(); }
|
||||
void update_scene_tree(const SceneDebuggerTree *p_tree, int p_debugger);
|
||||
void select_node(ObjectID p_id);
|
||||
void select_nodes(const TypedArray<int64_t> &p_ids);
|
||||
void clear_selection();
|
||||
|
||||
EditorDebuggerTree();
|
||||
};
|
||||
|
||||
#endif // EDITOR_DEBUGGER_TREE_H
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@ void EditorExpressionEvaluator::_clear() {
|
|||
}
|
||||
|
||||
void EditorExpressionEvaluator::_remote_object_selected(ObjectID p_id) {
|
||||
editor_debugger->emit_signal(SNAME("remote_object_requested"), p_id);
|
||||
Array arr = { p_id };
|
||||
editor_debugger->emit_signal(SNAME("remote_objects_requested"), arr);
|
||||
}
|
||||
|
||||
void EditorExpressionEvaluator::_on_expression_input_changed(const String &p_expression) {
|
||||
|
|
@ -109,6 +110,7 @@ EditorExpressionEvaluator::EditorExpressionEvaluator() {
|
|||
expression_input = memnew(LineEdit);
|
||||
expression_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
expression_input->set_placeholder(TTR("Expression to evaluate"));
|
||||
expression_input->set_accessibility_name(TTRC("Expression"));
|
||||
expression_input->set_clear_button_enabled(true);
|
||||
expression_input->connect(SceneStringName(text_submitted), callable_mp(this, &EditorExpressionEvaluator::_evaluate).unbind(1));
|
||||
expression_input->connect(SceneStringName(text_changed), callable_mp(this, &EditorExpressionEvaluator::_on_expression_input_changed));
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_EXPRESSION_EVALUATOR_H
|
||||
#define EDITOR_EXPRESSION_EVALUATOR_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
|
||||
|
|
@ -73,5 +72,3 @@ public:
|
|||
|
||||
EditorExpressionEvaluator();
|
||||
};
|
||||
|
||||
#endif // EDITOR_EXPRESSION_EVALUATOR_H
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ void EditorFileServer::_scan_files_changed(EditorFileSystemDirectory *efd, const
|
|||
uint64_t mt = FileAccess::get_modified_time(remapped_path);
|
||||
_add_file(remapped_path, mt, files_to_send, cached_files);
|
||||
} else if (remap.begins_with("path.")) {
|
||||
String feature = remap.get_slice(".", 1);
|
||||
String feature = remap.get_slicec('.', 1);
|
||||
if (p_tags.has(feature)) {
|
||||
String remapped_path = cf->get_value("remap", remap);
|
||||
uint64_t mt = FileAccess::get_modified_time(remapped_path);
|
||||
|
|
@ -200,7 +200,7 @@ void EditorFileServer::poll() {
|
|||
// Scan files to send.
|
||||
_scan_files_changed(EditorFileSystem::get_singleton()->get_filesystem(), tags, files_to_send, cached_files);
|
||||
// Add forced export files
|
||||
Vector<String> forced_export = EditorExportPlatform::get_forced_export_files();
|
||||
Vector<String> forced_export = EditorExportPlatform::get_forced_export_files(Ref<EditorExportPreset>());
|
||||
for (int i = 0; i < forced_export.size(); i++) {
|
||||
_add_custom_file(forced_export[i], files_to_send, cached_files);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_FILE_SERVER_H
|
||||
#define EDITOR_FILE_SERVER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/tcp_server.h"
|
||||
#include "core/os/thread.h"
|
||||
|
|
@ -55,5 +54,3 @@ public:
|
|||
EditorFileServer();
|
||||
~EditorFileServer();
|
||||
};
|
||||
|
||||
#endif // EDITOR_FILE_SERVER_H
|
||||
|
|
|
|||
|
|
@ -37,8 +37,6 @@
|
|||
#include "editor/themes/editor_theme_manager.h"
|
||||
#include "main/performance.h"
|
||||
|
||||
EditorPerformanceProfiler::Monitor::Monitor() {}
|
||||
|
||||
EditorPerformanceProfiler::Monitor::Monitor(const String &p_name, const String &p_base, int p_frame_index, Performance::MonitorType p_type, TreeItem *p_item) {
|
||||
type = p_type;
|
||||
item = p_item;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_PERFORMANCE_PROFILER_H
|
||||
#define EDITOR_PERFORMANCE_PROFILER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "main/performance.h"
|
||||
|
|
@ -52,7 +51,7 @@ private:
|
|||
Performance::MonitorType type = Performance::MONITOR_TYPE_QUANTITY;
|
||||
int frame_index = 0;
|
||||
|
||||
Monitor();
|
||||
Monitor() {}
|
||||
Monitor(const String &p_name, const String &p_base, int p_frame_index, Performance::MonitorType p_type, TreeItem *p_item);
|
||||
void update_value(float p_value);
|
||||
void reset();
|
||||
|
|
@ -88,5 +87,3 @@ public:
|
|||
List<float> *get_monitor_data(const StringName &p_name);
|
||||
EditorPerformanceProfiler();
|
||||
};
|
||||
|
||||
#endif // EDITOR_PERFORMANCE_PROFILER_H
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ String EditorProfiler::_get_time_as_text(const Metric &m, float p_time, int p_ca
|
|||
|
||||
Color EditorProfiler::_get_color_from_signature(const StringName &p_signature) const {
|
||||
Color bc = get_theme_color(SNAME("error_color"), EditorStringName(Editor));
|
||||
double rot = ABS(double(p_signature.hash()) / double(0x7FFFFFFF));
|
||||
double rot = Math::abs(double(p_signature.hash()) / double(0x7FFFFFFF));
|
||||
Color c;
|
||||
c.set_hsv(rot, bc.get_s(), bc.get_v());
|
||||
return c.lerp(get_theme_color(SNAME("base_color"), EditorStringName(Editor)), 0.07);
|
||||
|
|
@ -694,6 +694,7 @@ EditorProfiler::EditorProfiler() {
|
|||
hb_measure->add_child(memnew(Label(TTR("Measure:"))));
|
||||
|
||||
display_mode = memnew(OptionButton);
|
||||
display_mode->set_accessibility_name(TTRC("Measure"));
|
||||
display_mode->add_item(TTR("Frame Time (ms)"));
|
||||
display_mode->add_item(TTR("Average Time (ms)"));
|
||||
display_mode->add_item(TTR("Frame %"));
|
||||
|
|
@ -709,6 +710,7 @@ EditorProfiler::EditorProfiler() {
|
|||
hb_time->add_child(memnew(Label(TTR("Time:"))));
|
||||
|
||||
display_time = memnew(OptionButton);
|
||||
display_time->set_accessibility_name(TTRC("Time"));
|
||||
// TRANSLATORS: This is an option in the profiler to display the time spent in a function, including the time spent in other functions called by that function.
|
||||
display_time->add_item(TTR("Inclusive"));
|
||||
// TRANSLATORS: This is an option in the profiler to display the time spent in a function, exincluding the time spent in other functions called by that function.
|
||||
|
|
@ -731,6 +733,7 @@ EditorProfiler::EditorProfiler() {
|
|||
hb_frame->add_child(memnew(Label(TTR("Frame #:"))));
|
||||
|
||||
cursor_metric_edit = memnew(SpinBox);
|
||||
cursor_metric_edit->set_accessibility_name(TTRC("Frame"));
|
||||
cursor_metric_edit->set_h_size_flags(SIZE_FILL);
|
||||
cursor_metric_edit->set_value(0);
|
||||
cursor_metric_edit->set_editable(false);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_PROFILER_H
|
||||
#define EDITOR_PROFILER_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
|
|
@ -186,5 +185,3 @@ public:
|
|||
|
||||
EditorProfiler();
|
||||
};
|
||||
|
||||
#endif // EDITOR_PROFILER_H
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ String EditorVisualProfiler::_get_time_as_text(float p_time) {
|
|||
|
||||
Color EditorVisualProfiler::_get_color_from_signature(const StringName &p_signature) const {
|
||||
Color bc = get_theme_color(SNAME("error_color"), EditorStringName(Editor));
|
||||
double rot = ABS(double(p_signature.hash()) / double(0x7FFFFFFF));
|
||||
double rot = Math::abs(double(p_signature.hash()) / double(0x7FFFFFFF));
|
||||
Color c;
|
||||
c.set_hsv(rot, bc.get_s(), bc.get_v());
|
||||
return c.lerp(get_theme_color(SNAME("base_color"), EditorStringName(Editor)), 0.07);
|
||||
|
|
@ -362,7 +362,7 @@ void EditorVisualProfiler::_update_frame(bool p_focus_selected) {
|
|||
stack.push_back(category);
|
||||
categories.push_back(category);
|
||||
|
||||
name = name.substr(1, name.length());
|
||||
name = name.substr(1);
|
||||
|
||||
category->set_text(0, name);
|
||||
category->set_metadata(1, cpu_time);
|
||||
|
|
@ -778,6 +778,7 @@ EditorVisualProfiler::EditorVisualProfiler() {
|
|||
hb_measure->add_child(memnew(Label(TTR("Measure:"))));
|
||||
|
||||
display_mode = memnew(OptionButton);
|
||||
display_mode->set_accessibility_name(TTRC("Measure"));
|
||||
display_mode->add_item(TTR("Frame Time (ms)"));
|
||||
display_mode->add_item(TTR("Frame %"));
|
||||
display_mode->connect(SceneStringName(item_selected), callable_mp(this, &EditorVisualProfiler::_combo_changed));
|
||||
|
|
@ -801,6 +802,7 @@ EditorVisualProfiler::EditorVisualProfiler() {
|
|||
hb_frame->add_child(memnew(Label(TTR("Frame #:"))));
|
||||
|
||||
cursor_metric_edit = memnew(SpinBox);
|
||||
cursor_metric_edit->set_accessibility_name(TTRC("Frame"));
|
||||
cursor_metric_edit->set_h_size_flags(SIZE_FILL);
|
||||
hb_frame->add_child(cursor_metric_edit);
|
||||
cursor_metric_edit->connect(SceneStringName(value_changed), callable_mp(this, &EditorVisualProfiler::_cursor_metric_changed));
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_VISUAL_PROFILER_H
|
||||
#define EDITOR_VISUAL_PROFILER_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
|
|
@ -153,5 +152,3 @@ public:
|
|||
|
||||
EditorVisualProfiler();
|
||||
};
|
||||
|
||||
#endif // EDITOR_VISUAL_PROFILER_H
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -28,17 +28,15 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef SCRIPT_EDITOR_DEBUGGER_H
|
||||
#define SCRIPT_EDITOR_DEBUGGER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/os/os.h"
|
||||
#include "editor/debugger/editor_debugger_inspector.h"
|
||||
#include "editor/debugger/editor_debugger_node.h"
|
||||
#include "editor/debugger/editor_debugger_server.h"
|
||||
#include "scene/gui/button.h"
|
||||
#include "scene/gui/margin_container.h"
|
||||
|
||||
class Button;
|
||||
class Tree;
|
||||
class LineEdit;
|
||||
class TabContainer;
|
||||
|
|
@ -115,6 +113,7 @@ private:
|
|||
int warning_count;
|
||||
|
||||
bool skip_breakpoints_value = false;
|
||||
bool ignore_error_breaks_value = false;
|
||||
Ref<Script> stack_script;
|
||||
|
||||
TabContainer *tabs = nullptr;
|
||||
|
|
@ -122,6 +121,7 @@ private:
|
|||
Label *reason = nullptr;
|
||||
|
||||
Button *skip_breakpoints = nullptr;
|
||||
Button *ignore_error_breaks = nullptr;
|
||||
Button *copy = nullptr;
|
||||
Button *step = nullptr;
|
||||
Button *next = nullptr;
|
||||
|
|
@ -147,7 +147,7 @@ private:
|
|||
Ref<RemoteDebuggerPeer> peer;
|
||||
|
||||
HashMap<NodePath, int> node_path_cache;
|
||||
int last_path_id;
|
||||
int last_path_id = 0;
|
||||
HashMap<String, int> res_path_cache;
|
||||
|
||||
EditorProfiler *profiler = nullptr;
|
||||
|
|
@ -159,7 +159,7 @@ private:
|
|||
bool move_to_foreground = true;
|
||||
bool can_request_idle_draw = false;
|
||||
|
||||
bool live_debug;
|
||||
bool live_debug = true;
|
||||
|
||||
uint64_t debugging_thread_id = Thread::UNASSIGNED_ID;
|
||||
|
||||
|
|
@ -183,16 +183,54 @@ private:
|
|||
|
||||
void _select_thread(int p_index);
|
||||
|
||||
bool debug_mute_audio = false;
|
||||
|
||||
EditorDebuggerNode::CameraOverride camera_override;
|
||||
|
||||
void _stack_dump_frame_selected();
|
||||
|
||||
void _file_selected(const String &p_file);
|
||||
|
||||
/// Message handler function for _parse_message.
|
||||
typedef void (ScriptEditorDebugger::*ParseMessageFunc)(uint64_t p_thread_id, const Array &p_data);
|
||||
static HashMap<String, ParseMessageFunc> parse_message_handlers;
|
||||
static void _init_parse_message_handlers();
|
||||
|
||||
void _msg_debug_enter(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_debug_exit(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_set_pid(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_scene_click_ctrl(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_scene_scene_tree(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_scene_inspect_objects(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_servers_memory_usage(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_servers_drawn(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_stack_dump(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_stack_frame_vars(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_stack_frame_var(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_output(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_performance_profile_frame(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_visual_hardware_info(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_visual_profile_frame(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_error(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_servers_function_signature(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_servers_profile_common(const Array &p_data, const bool p_final);
|
||||
void _msg_servers_profile_frame(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_servers_profile_total(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_request_quit(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_remote_objects_selected(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_remote_nothing_selected(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_remote_selection_invalidated(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_show_selection_limit_warning(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_performance_profile_names(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_filesystem_update_file(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_evaluation_return(uint64_t p_thread_id, const Array &p_data);
|
||||
void _msg_window_title(uint64_t p_thread_id, const Array &p_data);
|
||||
|
||||
void _parse_message(const String &p_msg, uint64_t p_thread_id, const Array &p_data);
|
||||
void _set_reason_text(const String &p_reason, MessageType p_type);
|
||||
void _update_buttons_state();
|
||||
void _remote_object_selected(ObjectID p_object);
|
||||
void _remote_object_edited(ObjectID, const String &p_prop, const Variant &p_value);
|
||||
void _remote_objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field);
|
||||
void _remote_object_property_updated(ObjectID p_id, const String &p_property);
|
||||
|
||||
void _video_mem_request();
|
||||
|
|
@ -216,6 +254,8 @@ private:
|
|||
void _expand_errors_list();
|
||||
void _collapse_errors_list();
|
||||
|
||||
void _vmem_item_activated();
|
||||
|
||||
void _profiler_activate(bool p_enable, int p_profiler);
|
||||
void _profiler_seeked();
|
||||
|
||||
|
|
@ -246,9 +286,10 @@ protected:
|
|||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void request_remote_object(ObjectID p_obj_id);
|
||||
void update_remote_object(ObjectID p_obj_id, const String &p_prop, const Variant &p_value);
|
||||
Object *get_remote_object(ObjectID p_id);
|
||||
void request_remote_objects(const TypedArray<uint64_t> &p_obj_ids, bool p_update_selection = true);
|
||||
void update_remote_object(ObjectID p_obj_id, const String &p_prop, const Variant &p_value, const String &p_field = "");
|
||||
|
||||
void clear_inspector(bool p_send_msg = true);
|
||||
|
||||
// Needed by _live_edit_set, buttons state.
|
||||
void set_editor_remote_tree(const Tree *p_tree) { editor_remote_tree = p_tree; }
|
||||
|
|
@ -262,6 +303,7 @@ public:
|
|||
void stop();
|
||||
|
||||
void debug_skip_breakpoints();
|
||||
void debug_ignore_error_breaks();
|
||||
void debug_copy();
|
||||
|
||||
void debug_next();
|
||||
|
|
@ -299,6 +341,9 @@ public:
|
|||
void live_debug_duplicate_node(const NodePath &p_at, const String &p_new_name);
|
||||
void live_debug_reparent_node(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos);
|
||||
|
||||
bool get_debug_mute_audio() const;
|
||||
void set_debug_mute_audio(bool p_mute);
|
||||
|
||||
EditorDebuggerNode::CameraOverride get_camera_override() const;
|
||||
void set_camera_override(EditorDebuggerNode::CameraOverride p_override);
|
||||
|
||||
|
|
@ -309,7 +354,8 @@ public:
|
|||
void reload_all_scripts();
|
||||
void reload_scripts(const Vector<String> &p_script_paths);
|
||||
|
||||
bool is_skip_breakpoints();
|
||||
bool is_skip_breakpoints() const;
|
||||
bool is_ignore_error_breaks() const;
|
||||
|
||||
virtual Size2 get_minimum_size() const override;
|
||||
|
||||
|
|
@ -324,5 +370,3 @@ public:
|
|||
ScriptEditorDebugger();
|
||||
~ScriptEditorDebugger();
|
||||
};
|
||||
|
||||
#endif // SCRIPT_EDITOR_DEBUGGER_H
|
||||
|
|
|
|||
|
|
@ -317,12 +317,8 @@ void DependencyEditorOwners::_list_rmb_clicked(int p_item, const Vector2 &p_pos,
|
|||
|
||||
void DependencyEditorOwners::_select_file(int p_idx) {
|
||||
String fpath = owners->get_item_text(p_idx);
|
||||
EditorNode::get_singleton()->load_scene_or_resource(fpath);
|
||||
|
||||
if (ResourceLoader::get_resource_type(fpath) == "PackedScene") {
|
||||
EditorNode::get_singleton()->open_request(fpath);
|
||||
} else {
|
||||
EditorNode::get_singleton()->load_resource(fpath);
|
||||
}
|
||||
hide();
|
||||
emit_signal(SceneStringName(confirmed));
|
||||
}
|
||||
|
|
@ -467,17 +463,16 @@ void DependencyRemoveDialog::_find_localization_remaps_of_removed_files(Vector<R
|
|||
p_removed.push_back(dep);
|
||||
}
|
||||
|
||||
Array remap_keys = remaps.keys();
|
||||
for (int j = 0; j < remap_keys.size(); j++) {
|
||||
PackedStringArray remapped_files = remaps[remap_keys[j]];
|
||||
for (int k = 0; k < remapped_files.size(); k++) {
|
||||
int splitter_pos = remapped_files[k].rfind_char(':');
|
||||
String res_path = remapped_files[k].substr(0, splitter_pos);
|
||||
for (const KeyValue<Variant, Variant> &remap_kv : remaps) {
|
||||
PackedStringArray remapped_files = remap_kv.value;
|
||||
for (const String &remapped_file : remapped_files) {
|
||||
int splitter_pos = remapped_file.rfind_char(':');
|
||||
String res_path = remapped_file.substr(0, splitter_pos);
|
||||
if (res_path == path) {
|
||||
String locale_name = remapped_files[k].substr(splitter_pos + 1);
|
||||
String locale_name = remapped_file.substr(splitter_pos + 1);
|
||||
|
||||
RemovedDependency dep;
|
||||
dep.file = vformat(TTR("Localization remap for path '%s' and locale '%s'."), remap_keys[j], locale_name);
|
||||
dep.file = vformat(TTR("Localization remap for path '%s' and locale '%s'."), remap_kv.key, locale_name);
|
||||
dep.file_type = "";
|
||||
dep.dependency = path;
|
||||
dep.dependency_folder = files.value;
|
||||
|
|
@ -589,34 +584,19 @@ void DependencyRemoveDialog::ok_pressed() {
|
|||
}
|
||||
}
|
||||
|
||||
HashMap<String, StringName> setting_path_map;
|
||||
for (const StringName &setting : path_project_settings) {
|
||||
const String path = ResourceUID::ensure_path(GLOBAL_GET(setting));
|
||||
setting_path_map[path] = setting;
|
||||
}
|
||||
|
||||
bool project_settings_modified = false;
|
||||
for (const String &file : files_to_delete) {
|
||||
// If the file we are deleting for e.g. the main scene, default environment,
|
||||
// or audio bus layout, we must clear its definition in Project Settings.
|
||||
if (file == ResourceUID::ensure_path(GLOBAL_GET("application/config/icon"))) {
|
||||
ProjectSettings::get_singleton()->set("application/config/icon", "");
|
||||
project_settings_modified = true;
|
||||
} else if (file == ResourceUID::ensure_path(GLOBAL_GET("application/run/main_scene"))) {
|
||||
ProjectSettings::get_singleton()->set("application/run/main_scene", "");
|
||||
project_settings_modified = true;
|
||||
} else if (file == ResourceUID::ensure_path(GLOBAL_GET("application/boot_splash/image"))) {
|
||||
ProjectSettings::get_singleton()->set("application/boot_splash/image", "");
|
||||
project_settings_modified = true;
|
||||
} else if (file == ResourceUID::ensure_path(GLOBAL_GET("rendering/environment/defaults/default_environment"))) {
|
||||
ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
|
||||
project_settings_modified = true;
|
||||
} else if (file == ResourceUID::ensure_path(GLOBAL_GET("display/mouse_cursor/custom_image"))) {
|
||||
ProjectSettings::get_singleton()->set("display/mouse_cursor/custom_image", "");
|
||||
project_settings_modified = true;
|
||||
} else if (file == ResourceUID::ensure_path(GLOBAL_GET("gui/theme/custom"))) {
|
||||
ProjectSettings::get_singleton()->set("gui/theme/custom", "");
|
||||
project_settings_modified = true;
|
||||
} else if (file == ResourceUID::ensure_path(GLOBAL_GET("gui/theme/custom_font"))) {
|
||||
ProjectSettings::get_singleton()->set("gui/theme/custom_font", "");
|
||||
project_settings_modified = true;
|
||||
} else if (file == ResourceUID::ensure_path(GLOBAL_GET("audio/buses/default_bus_layout"))) {
|
||||
ProjectSettings::get_singleton()->set("audio/buses/default_bus_layout", "");
|
||||
project_settings_modified = true;
|
||||
const StringName *setting_name = setting_path_map.getptr(file);
|
||||
if (setting_name) {
|
||||
ProjectSettings::get_singleton()->set(*setting_name, "");
|
||||
}
|
||||
|
||||
const String path = OS::get_singleton()->get_resource_dir() + file.replace_first("res://", "/");
|
||||
|
|
@ -632,7 +612,7 @@ void DependencyRemoveDialog::ok_pressed() {
|
|||
ProjectSettings::get_singleton()->save();
|
||||
}
|
||||
|
||||
if (dirs_to_delete.size() == 0) {
|
||||
if (dirs_to_delete.is_empty()) {
|
||||
// If we only deleted files we should only need to tell the file system about the files we touched.
|
||||
for (int i = 0; i < files_to_delete.size(); ++i) {
|
||||
EditorFileSystem::get_singleton()->update_file(files_to_delete[i]);
|
||||
|
|
@ -698,6 +678,7 @@ DependencyRemoveDialog::DependencyRemoveDialog() {
|
|||
files_to_delete_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
files_to_delete_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
files_to_delete_list->set_custom_minimum_size(Size2(0, 94) * EDSCALE);
|
||||
files_to_delete_list->set_accessibility_name(TTRC("Files to be Deleted"));
|
||||
vb->add_child(files_to_delete_list);
|
||||
|
||||
vb_owners = memnew(VBoxContainer);
|
||||
|
|
@ -714,14 +695,22 @@ DependencyRemoveDialog::DependencyRemoveDialog() {
|
|||
owners->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
owners->set_hide_root(true);
|
||||
owners->set_custom_minimum_size(Size2(0, 94) * EDSCALE);
|
||||
owners->set_accessibility_name(TTRC("Dependencies"));
|
||||
vb_owners->add_child(owners);
|
||||
owners->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
||||
List<PropertyInfo> property_list;
|
||||
ProjectSettings::get_singleton()->get_property_list(&property_list);
|
||||
for (const PropertyInfo &pi : property_list) {
|
||||
if (pi.type == Variant::STRING && pi.hint == PROPERTY_HINT_FILE) {
|
||||
path_project_settings.push_back(pi.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////
|
||||
|
||||
void DependencyErrorDialog::show(Mode p_mode, const String &p_for_file, const Vector<String> &report) {
|
||||
mode = p_mode;
|
||||
void DependencyErrorDialog::show(const String &p_for_file, const Vector<String> &report) {
|
||||
for_file = p_for_file;
|
||||
set_title(TTR("Error loading:") + " " + p_for_file.get_file());
|
||||
files->clear();
|
||||
|
|
@ -746,14 +735,7 @@ void DependencyErrorDialog::show(Mode p_mode, const String &p_for_file, const Ve
|
|||
}
|
||||
|
||||
void DependencyErrorDialog::ok_pressed() {
|
||||
switch (mode) {
|
||||
case MODE_SCENE:
|
||||
EditorNode::get_singleton()->load_scene(for_file, true);
|
||||
break;
|
||||
case MODE_RESOURCE:
|
||||
EditorNode::get_singleton()->load_resource(for_file, true);
|
||||
break;
|
||||
}
|
||||
EditorNode::get_singleton()->load_scene_or_resource(for_file, true);
|
||||
}
|
||||
|
||||
void DependencyErrorDialog::custom_action(const String &) {
|
||||
|
|
@ -778,8 +760,6 @@ DependencyErrorDialog::DependencyErrorDialog() {
|
|||
vb->add_child(text);
|
||||
text->set_text(TTR("Which action should be taken?"));
|
||||
|
||||
mode = Mode::MODE_RESOURCE;
|
||||
|
||||
fdep = add_button(TTR("Fix Dependencies"), true, "fixdeps");
|
||||
|
||||
set_title(TTR("Errors loading!"));
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEPENDENCY_EDITOR_H
|
||||
#define DEPENDENCY_EDITOR_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
|
|
@ -120,6 +119,8 @@ class DependencyRemoveDialog : public ConfirmationDialog {
|
|||
}
|
||||
};
|
||||
|
||||
LocalVector<StringName> path_project_settings;
|
||||
|
||||
void _find_files_in_removed_folder(EditorFileSystemDirectory *efsd, const String &p_folder);
|
||||
void _find_all_removed_dependencies(EditorFileSystemDirectory *efsd, Vector<RemovedDependency> &p_removed);
|
||||
void _find_localization_remaps_of_removed_files(Vector<RemovedDependency> &p_removed);
|
||||
|
|
@ -138,12 +139,6 @@ public:
|
|||
class DependencyErrorDialog : public ConfirmationDialog {
|
||||
GDCLASS(DependencyErrorDialog, ConfirmationDialog);
|
||||
|
||||
public:
|
||||
enum Mode {
|
||||
MODE_SCENE,
|
||||
MODE_RESOURCE,
|
||||
};
|
||||
|
||||
private:
|
||||
String for_file;
|
||||
Mode mode;
|
||||
|
|
@ -154,7 +149,7 @@ private:
|
|||
void custom_action(const String &) override;
|
||||
|
||||
public:
|
||||
void show(Mode p_mode, const String &p_for_file, const Vector<String> &report);
|
||||
void show(const String &p_for_file, const Vector<String> &report);
|
||||
DependencyErrorDialog();
|
||||
};
|
||||
|
||||
|
|
@ -179,5 +174,3 @@ public:
|
|||
void show();
|
||||
OrphanResourcesDialog();
|
||||
};
|
||||
|
||||
#endif // DEPENDENCY_EDITOR_H
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ DirectoryCreateDialog::DirectoryCreateDialog() {
|
|||
vb->add_child(name_label);
|
||||
|
||||
dir_path = memnew(LineEdit);
|
||||
dir_path->set_accessibility_name(TTRC("Name"));
|
||||
vb->add_child(dir_path);
|
||||
register_text_enter(dir_path);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DIRECTORY_CREATE_DIALOG_H
|
||||
#define DIRECTORY_CREATE_DIALOG_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/dialogs.h"
|
||||
|
||||
|
|
@ -68,5 +67,3 @@ public:
|
|||
|
||||
DirectoryCreateDialog();
|
||||
};
|
||||
|
||||
#endif // DIRECTORY_CREATE_DIALOG_H
|
||||
|
|
|
|||
|
|
@ -368,6 +368,15 @@ void DocTools::remove_doc(const String &p_class_name) {
|
|||
class_list.erase(p_class_name);
|
||||
}
|
||||
|
||||
void DocTools::remove_script_doc_by_path(const String &p_path) {
|
||||
for (KeyValue<String, DocData::ClassDoc> &E : class_list) {
|
||||
if (E.value.is_script_doc && E.value.script_path == p_path) {
|
||||
remove_doc(E.key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DocTools::has_doc(const String &p_class_name) {
|
||||
if (p_class_name.is_empty()) {
|
||||
return false;
|
||||
|
|
@ -385,9 +394,9 @@ static Variant get_documentation_default_value(const StringName &p_class_name, c
|
|||
// Cannot get default value of classes that can't be instantiated
|
||||
List<StringName> inheriting_classes;
|
||||
ClassDB::get_direct_inheriters_from_class(p_class_name, &inheriting_classes);
|
||||
for (List<StringName>::Element *E2 = inheriting_classes.front(); E2; E2 = E2->next()) {
|
||||
if (ClassDB::can_instantiate(E2->get())) {
|
||||
default_value = ClassDB::class_get_default_property_value(E2->get(), p_property_name, &r_default_value_valid);
|
||||
for (const StringName &class_name : inheriting_classes) {
|
||||
if (ClassDB::can_instantiate(class_name)) {
|
||||
default_value = ClassDB::class_get_default_property_value(class_name, p_property_name, &r_default_value_valid);
|
||||
if (r_default_value_valid) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -619,7 +628,7 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
|
|||
// Don't skip parametric setters and getters, i.e. method which require
|
||||
// one or more parameters to define what property should be set or retrieved.
|
||||
// E.g. CPUParticles3D::set_param(Parameter param, float value).
|
||||
if (E.arguments.size() == 0 /* getter */ || (E.arguments.size() == 1 && E.return_val.type == Variant::NIL /* setter */)) {
|
||||
if (E.arguments.is_empty() /* getter */ || (E.arguments.size() == 1 && E.return_val.type == Variant::NIL /* setter */)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -648,11 +657,10 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
|
|||
ClassDB::get_signal_list(name, &signal_list, true);
|
||||
|
||||
if (signal_list.size()) {
|
||||
for (List<MethodInfo>::Element *EV = signal_list.front(); EV; EV = EV->next()) {
|
||||
for (const MethodInfo &mi : signal_list) {
|
||||
DocData::MethodDoc signal;
|
||||
signal.name = EV->get().name;
|
||||
for (List<PropertyInfo>::Element *EA = EV->get().arguments.front(); EA; EA = EA->next()) {
|
||||
const PropertyInfo &arginfo = EA->get();
|
||||
signal.name = mi.name;
|
||||
for (const PropertyInfo &arginfo : mi.arguments) {
|
||||
DocData::ArgumentDoc argument;
|
||||
DocData::argument_doc_from_arginfo(argument, arginfo);
|
||||
|
||||
|
|
@ -844,9 +852,8 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
|
|||
|
||||
method.name = mi.name;
|
||||
|
||||
int j = 0;
|
||||
for (List<PropertyInfo>::ConstIterator itr = mi.arguments.begin(); itr != mi.arguments.end(); ++itr, ++j) {
|
||||
PropertyInfo arginfo = *itr;
|
||||
for (int64_t j = 0; j < mi.arguments.size(); ++j) {
|
||||
const PropertyInfo &arginfo = mi.arguments[j];
|
||||
DocData::ArgumentDoc ad;
|
||||
DocData::argument_doc_from_arginfo(ad, arginfo);
|
||||
ad.name = arginfo.name;
|
||||
|
|
@ -933,7 +940,7 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
|
|||
DocData::ConstantDoc constant;
|
||||
constant.name = E;
|
||||
Variant value = Variant::get_constant_value(Variant::Type(i), E);
|
||||
constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string().replace("\n", " ");
|
||||
constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string().replace_char('\n', ' ');
|
||||
constant.is_value_valid = true;
|
||||
constant.type = Variant::get_type_name(value.get_type());
|
||||
c.constants.push_back(constant);
|
||||
|
|
@ -1057,10 +1064,9 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
|
|||
|
||||
DocData::return_doc_from_retinfo(md, mi.return_val);
|
||||
|
||||
int j = 0;
|
||||
for (List<PropertyInfo>::ConstIterator itr = mi.arguments.begin(); itr != mi.arguments.end(); ++itr, ++j) {
|
||||
for (int64_t j = 0; j < mi.arguments.size(); ++j) {
|
||||
DocData::ArgumentDoc ad;
|
||||
DocData::argument_doc_from_arginfo(ad, *itr);
|
||||
DocData::argument_doc_from_arginfo(ad, mi.arguments[j]);
|
||||
|
||||
int darg_idx = j - (mi.arguments.size() - mi.default_arguments.size());
|
||||
if (darg_idx >= 0) {
|
||||
|
|
@ -1103,12 +1109,11 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
|
|||
|
||||
DocData::return_doc_from_retinfo(atd, ai.return_val);
|
||||
|
||||
int j = 0;
|
||||
for (List<PropertyInfo>::ConstIterator itr = ai.arguments.begin(); itr != ai.arguments.end(); ++itr, ++j) {
|
||||
for (int64_t j = 0; j < ai.arguments.size(); ++j) {
|
||||
DocData::ArgumentDoc ad;
|
||||
DocData::argument_doc_from_arginfo(ad, *itr);
|
||||
DocData::argument_doc_from_arginfo(ad, ai.arguments[j]);
|
||||
|
||||
int darg_idx = j - (ai.arguments.size() - ai.default_arguments.size());
|
||||
int64_t darg_idx = j - (ai.arguments.size() - ai.default_arguments.size());
|
||||
if (darg_idx >= 0) {
|
||||
ad.default_value = DocData::get_default_value_string(ai.default_arguments[darg_idx]);
|
||||
}
|
||||
|
|
@ -1632,7 +1637,7 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
|
|||
}
|
||||
|
||||
Error err;
|
||||
String save_file = save_path.path_join(c.name.replace("\"", "").replace("/", "--") + ".xml");
|
||||
String save_file = save_path.path_join(c.name.remove_char('\"').replace("/", "--") + ".xml");
|
||||
Ref<FileAccess> f = FileAccess::open(save_file, FileAccess::WRITE, &err);
|
||||
|
||||
ERR_CONTINUE_MSG(err != OK, "Can't write doc file: " + save_file + ".");
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DOC_TOOLS_H
|
||||
#define DOC_TOOLS_H
|
||||
#pragma once
|
||||
|
||||
#include "core/doc_data.h"
|
||||
#include "core/templates/rb_set.h"
|
||||
|
|
@ -45,6 +44,7 @@ public:
|
|||
void merge_from(const DocTools &p_data);
|
||||
void add_doc(const DocData::ClassDoc &p_class_doc);
|
||||
void remove_doc(const String &p_class_name);
|
||||
void remove_script_doc_by_path(const String &p_path);
|
||||
bool has_doc(const String &p_class_name);
|
||||
enum GenerateFlags {
|
||||
GENERATE_FLAG_SKIP_BASIC_TYPES = (1 << 0),
|
||||
|
|
@ -58,5 +58,3 @@ public:
|
|||
Error load_compressed(const uint8_t *p_data, int p_compressed_size, int p_uncompressed_size);
|
||||
Error load_xml(const uint8_t *p_data, int p_size);
|
||||
};
|
||||
|
||||
#endif // DOC_TOOLS_H
|
||||
|
|
|
|||
|
|
@ -133,8 +133,8 @@ ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<St
|
|||
|
||||
while (*names_ptr) {
|
||||
const String name = String::utf8(*names_ptr++);
|
||||
const String identifier = name.get_slice("<", 0);
|
||||
const String website = name.get_slice_count("<") == 1 ? "" : name.get_slice("<", 1).trim_suffix(">");
|
||||
const String identifier = name.get_slicec('<', 0);
|
||||
const String website = name.get_slice_count("<") == 1 ? "" : name.get_slicec('<', 1).trim_suffix(">");
|
||||
|
||||
const int name_item_id = il->add_item(identifier, nullptr, false);
|
||||
il->set_item_tooltip_enabled(name_item_id, false);
|
||||
|
|
@ -340,5 +340,3 @@ EditorAbout::EditorAbout() {
|
|||
tpl_ti_all->select(0);
|
||||
_tpl_text->set_text(tpl_ti_all->get_metadata(0));
|
||||
}
|
||||
|
||||
EditorAbout::~EditorAbout() {}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_ABOUT_H
|
||||
#define EDITOR_ABOUT_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/item_list.h"
|
||||
|
|
@ -62,7 +61,4 @@ protected:
|
|||
|
||||
public:
|
||||
EditorAbout();
|
||||
~EditorAbout();
|
||||
};
|
||||
|
||||
#endif // EDITOR_ABOUT_H
|
||||
|
|
|
|||
|
|
@ -684,6 +684,7 @@ EditorAssetInstaller::EditorAssetInstaller() {
|
|||
show_source_files_button = memnew(Button);
|
||||
show_source_files_button->set_toggle_mode(true);
|
||||
show_source_files_button->set_tooltip_text(TTR("Open the list of the asset contents and select which files to install."));
|
||||
show_source_files_button->set_accessibility_name(TTRC("Show Asset Contents"));
|
||||
remapping_tools->add_child(show_source_files_button);
|
||||
show_source_files_button->connect(SceneStringName(toggled), callable_mp(this, &EditorAssetInstaller::_toggle_source_tree).bind(false));
|
||||
|
||||
|
|
@ -708,6 +709,7 @@ EditorAssetInstaller::EditorAssetInstaller() {
|
|||
asset_conflicts_label->set_text(TTR("No files conflict with your project"));
|
||||
remapping_tools->add_child(asset_conflicts_label);
|
||||
asset_conflicts_link = memnew(LinkButton);
|
||||
asset_conflicts_link->set_accessibility_name(TTRC("Show Conflicting Files"));
|
||||
asset_conflicts_link->set_theme_type_variation("HeaderSmallLink");
|
||||
asset_conflicts_link->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
|
||||
asset_conflicts_link->set_tooltip_text(TTR("Show contents of the asset and conflicting files."));
|
||||
|
|
@ -732,6 +734,7 @@ EditorAssetInstaller::EditorAssetInstaller() {
|
|||
source_tree_vb->add_child(source_tree_label);
|
||||
|
||||
source_tree = memnew(Tree);
|
||||
source_tree->set_accessibility_name(TTRC("Source Files"));
|
||||
source_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
source_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
source_tree->connect("item_edited", callable_mp(this, &EditorAssetInstaller::_item_checked_cbk));
|
||||
|
|
@ -748,6 +751,7 @@ EditorAssetInstaller::EditorAssetInstaller() {
|
|||
destination_tree_vb->add_child(destination_tree_label);
|
||||
|
||||
destination_tree = memnew(Tree);
|
||||
destination_tree->set_accessibility_name(TTRC("Destination Files"));
|
||||
destination_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
destination_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
destination_tree->connect("item_edited", callable_mp(this, &EditorAssetInstaller::_item_checked_cbk));
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_ASSET_INSTALLER_H
|
||||
#define EDITOR_ASSET_INSTALLER_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/tree.h"
|
||||
|
|
@ -105,5 +104,3 @@ public:
|
|||
|
||||
EditorAssetInstaller();
|
||||
};
|
||||
|
||||
#endif // EDITOR_ASSET_INSTALLER_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_ATLAS_PACKER_H
|
||||
#define EDITOR_ATLAS_PACKER_H
|
||||
#pragma once
|
||||
|
||||
#include "core/math/vector2.h"
|
||||
#include "core/math/vector2i.h"
|
||||
|
|
@ -68,5 +67,3 @@ private:
|
|||
public:
|
||||
static void chart_pack(Vector<Chart> &charts, int &r_width, int &r_height, int p_atlas_max_size = 2048, int p_cell_resolution = 4);
|
||||
};
|
||||
|
||||
#endif // EDITOR_ATLAS_PACKER_H
|
||||
|
|
|
|||
|
|
@ -130,6 +130,14 @@ void EditorAudioBus::_notification(int p_what) {
|
|||
set_process(true);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_STATIC_TEXT);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, TTR(vformat("The %s is not accessible at this time.", "Audio bus editor")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAW: {
|
||||
if (is_master) {
|
||||
draw_style_box(get_theme_stylebox(SNAME("disabled"), SNAME("Button")), Rect2(Vector2(), get_size()));
|
||||
|
|
@ -583,6 +591,15 @@ void EditorAudioBus::gui_input(const Ref<InputEvent> &p_event) {
|
|||
bus_popup->reset_size();
|
||||
bus_popup->popup();
|
||||
}
|
||||
|
||||
Ref<InputEventKey> k = p_event;
|
||||
if (k.is_valid() && k->is_pressed() && k->is_action("ui_menu", true)) {
|
||||
bus_popup->set_position(get_screen_position());
|
||||
bus_popup->reset_size();
|
||||
bus_popup->popup();
|
||||
|
||||
accept_event();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorAudioBus::_effects_gui_input(Ref<InputEvent> p_event) {
|
||||
|
|
@ -619,7 +636,7 @@ Variant EditorAudioBus::get_drag_data(const Point2 &p_point) {
|
|||
p->set_modulate(Color(1, 1, 1, 0.7));
|
||||
p->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("focus"), SNAME("Button")));
|
||||
p->set_size(get_size());
|
||||
p->set_position(-p_point);
|
||||
p->set_position((p_point == Vector2(Math::INF, Math::INF)) ? Vector2() : -p_point);
|
||||
set_drag_preview(c);
|
||||
Dictionary d;
|
||||
d["type"] = "move_audio_bus";
|
||||
|
|
@ -652,7 +669,7 @@ void EditorAudioBus::drop_data(const Point2 &p_point, const Variant &p_data) {
|
|||
}
|
||||
|
||||
Variant EditorAudioBus::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
|
||||
TreeItem *item = effects->get_item_at_position(p_point);
|
||||
TreeItem *item = (p_point == Vector2(Math::INF, Math::INF)) ? effects->get_selected() : effects->get_item_at_position(p_point);
|
||||
if (!item) {
|
||||
return Variant();
|
||||
}
|
||||
|
|
@ -681,7 +698,7 @@ bool EditorAudioBus::can_drop_data_fw(const Point2 &p_point, const Variant &p_da
|
|||
return false;
|
||||
}
|
||||
|
||||
TreeItem *item = effects->get_item_at_position(p_point);
|
||||
TreeItem *item = (p_point == Vector2(Math::INF, Math::INF)) ? effects->get_selected() : effects->get_item_at_position(p_point);
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -694,11 +711,11 @@ bool EditorAudioBus::can_drop_data_fw(const Point2 &p_point, const Variant &p_da
|
|||
void EditorAudioBus::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
|
||||
Dictionary d = p_data;
|
||||
|
||||
TreeItem *item = effects->get_item_at_position(p_point);
|
||||
TreeItem *item = (p_point == Vector2(Math::INF, Math::INF)) ? effects->get_selected() : effects->get_item_at_position(p_point);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
int pos = effects->get_drop_section_at_position(p_point);
|
||||
int pos = (p_point == Vector2(Math::INF, Math::INF)) ? effects->get_drop_section_at_position(effects->get_item_rect(item).position) : effects->get_drop_section_at_position(p_point);
|
||||
Variant md = item->get_metadata(0);
|
||||
|
||||
int paste_at;
|
||||
|
|
@ -815,6 +832,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
|
|||
set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
|
||||
track_name = memnew(LineEdit);
|
||||
track_name->set_accessibility_name(TTRC("Track Name"));
|
||||
track_name->connect(SceneStringName(text_submitted), callable_mp(this, &EditorAudioBus::_name_changed));
|
||||
track_name->connect(SceneStringName(focus_exited), callable_mp(this, &EditorAudioBus::_name_focus_exit));
|
||||
vb->add_child(track_name);
|
||||
|
|
@ -825,6 +843,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
|
|||
solo->set_theme_type_variation(SceneStringName(FlatButton));
|
||||
solo->set_toggle_mode(true);
|
||||
solo->set_tooltip_text(TTR("Solo"));
|
||||
solo->set_accessibility_name(TTRC("Solo"));
|
||||
solo->set_focus_mode(FOCUS_NONE);
|
||||
solo->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBus::_solo_toggled));
|
||||
hbc->add_child(solo);
|
||||
|
|
@ -832,6 +851,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
|
|||
mute->set_theme_type_variation(SceneStringName(FlatButton));
|
||||
mute->set_toggle_mode(true);
|
||||
mute->set_tooltip_text(TTR("Mute"));
|
||||
mute->set_accessibility_name(TTRC("Mute"));
|
||||
mute->set_focus_mode(FOCUS_NONE);
|
||||
mute->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBus::_mute_toggled));
|
||||
hbc->add_child(mute);
|
||||
|
|
@ -839,6 +859,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
|
|||
bypass->set_theme_type_variation(SceneStringName(FlatButton));
|
||||
bypass->set_toggle_mode(true);
|
||||
bypass->set_tooltip_text(TTR("Bypass"));
|
||||
bypass->set_accessibility_name(TTRC("Bypass"));
|
||||
bypass->set_focus_mode(FOCUS_NONE);
|
||||
bypass->connect(SceneStringName(pressed), callable_mp(this, &EditorAudioBus::_bypass_toggled));
|
||||
hbc->add_child(bypass);
|
||||
|
|
@ -886,6 +907,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
|
|||
slider->set_max(1.0);
|
||||
slider->set_step(0.0001);
|
||||
slider->set_clip_contents(false);
|
||||
slider->set_accessibility_name(TTRC("Volume"));
|
||||
|
||||
audio_value_preview_box = memnew(Panel);
|
||||
slider->add_child(audio_value_preview_box);
|
||||
|
|
@ -922,6 +944,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
|
|||
channel[i].vu_l->set_min(-80);
|
||||
channel[i].vu_l->set_max(24);
|
||||
channel[i].vu_l->set_step(0.1);
|
||||
channel[i].vu_l->set_accessibility_name(vformat(TTR("Channel %d, Left VU"), i));
|
||||
|
||||
channel[i].vu_r = memnew(TextureProgressBar);
|
||||
channel[i].vu_r->set_fill_mode(TextureProgressBar::FILL_BOTTOM_TO_TOP);
|
||||
|
|
@ -929,6 +952,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
|
|||
channel[i].vu_r->set_min(-80);
|
||||
channel[i].vu_r->set_max(24);
|
||||
channel[i].vu_r->set_step(0.1);
|
||||
channel[i].vu_r->set_accessibility_name(vformat(TTR("Channel %d, Right VU"), i));
|
||||
|
||||
channel[i].peak_l = 0.0f;
|
||||
channel[i].peak_r = 0.0f;
|
||||
|
|
@ -944,6 +968,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
|
|||
hb->add_child(scale);
|
||||
|
||||
effects = memnew(Tree);
|
||||
effects->set_accessibility_name(TTRC("Effects"));
|
||||
effects->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
effects->set_hide_root(true);
|
||||
effects->set_custom_minimum_size(Size2(0, 80) * EDSCALE);
|
||||
|
|
@ -963,6 +988,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
|
|||
effects->connect(SceneStringName(gui_input), callable_mp(this, &EditorAudioBus::_effects_gui_input));
|
||||
|
||||
send = memnew(OptionButton);
|
||||
send->set_accessibility_name(TTRC("Send"));
|
||||
send->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
send->set_clip_text(true);
|
||||
send->connect(SceneStringName(item_selected), callable_mp(this, &EditorAudioBus::_send_selected));
|
||||
|
|
@ -974,8 +1000,8 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
|
|||
effect_options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // Don't translate class names.
|
||||
effect_options->connect("index_pressed", callable_mp(this, &EditorAudioBus::_effect_add));
|
||||
add_child(effect_options);
|
||||
List<StringName> effect_list;
|
||||
ClassDB::get_inheriters_from_class("AudioEffect", &effect_list);
|
||||
LocalVector<StringName> effect_list;
|
||||
ClassDB::get_inheriters_from_class("AudioEffect", effect_list);
|
||||
effect_list.sort_custom<StringName::AlphCompare>();
|
||||
for (const StringName &E : effect_list) {
|
||||
if (!ClassDB::can_instantiate(E) || ClassDB::is_virtual(E)) {
|
||||
|
|
@ -992,6 +1018,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
|
|||
bus_options->set_h_size_flags(SIZE_SHRINK_END);
|
||||
bus_options->set_anchor(SIDE_RIGHT, 0.0);
|
||||
bus_options->set_tooltip_text(TTR("Bus Options"));
|
||||
bus_options->set_accessibility_name(TTRC("Bus Options"));
|
||||
hbc->add_child(bus_options);
|
||||
|
||||
bus_popup = bus_options->get_popup();
|
||||
|
|
@ -1050,9 +1077,6 @@ void EditorAudioBusDrop::_bind_methods() {
|
|||
ADD_SIGNAL(MethodInfo("dropped"));
|
||||
}
|
||||
|
||||
EditorAudioBusDrop::EditorAudioBusDrop() {
|
||||
}
|
||||
|
||||
void EditorAudioBuses::_rebuild_buses() {
|
||||
for (int i = bus_hb->get_child_count() - 1; i >= 0; i--) {
|
||||
EditorAudioBus *audio_bus = Object::cast_to<EditorAudioBus>(bus_hb->get_child(i));
|
||||
|
|
@ -1118,9 +1142,8 @@ void EditorAudioBuses::_notification(int p_what) {
|
|||
}
|
||||
}
|
||||
|
||||
AudioServer::get_singleton()->set_edited(false);
|
||||
|
||||
if (edited) {
|
||||
AudioServer::get_singleton()->set_edited(false);
|
||||
save_timer->start();
|
||||
}
|
||||
} break;
|
||||
|
|
@ -1409,9 +1432,6 @@ AudioBusesEditorPlugin::AudioBusesEditorPlugin(EditorAudioBuses *p_node) {
|
|||
audio_bus_editor = p_node;
|
||||
}
|
||||
|
||||
AudioBusesEditorPlugin::~AudioBusesEditorPlugin() {
|
||||
}
|
||||
|
||||
void EditorAudioMeterNotches::add_notch(float p_normalized_offset, float p_db_value, bool p_render_value) {
|
||||
notches.push_back(AudioNotch(p_normalized_offset, p_db_value, p_render_value));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_AUDIO_BUSES_H
|
||||
#define EDITOR_AUDIO_BUSES_H
|
||||
#pragma once
|
||||
|
||||
#include "editor/plugins/editor_plugin.h"
|
||||
#include "scene/gui/box_container.h"
|
||||
|
|
@ -146,9 +145,6 @@ class EditorAudioBusDrop : public Control {
|
|||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
EditorAudioBusDrop();
|
||||
};
|
||||
|
||||
class EditorAudioBuses : public VBoxContainer {
|
||||
|
|
@ -263,9 +259,6 @@ private:
|
|||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
void _draw_audio_notches();
|
||||
|
||||
public:
|
||||
EditorAudioMeterNotches() {}
|
||||
};
|
||||
|
||||
class AudioBusesEditorPlugin : public EditorPlugin {
|
||||
|
|
@ -281,7 +274,4 @@ public:
|
|||
virtual void make_visible(bool p_visible) override;
|
||||
|
||||
AudioBusesEditorPlugin(EditorAudioBuses *p_node);
|
||||
~AudioBusesEditorPlugin();
|
||||
};
|
||||
|
||||
#endif // EDITOR_AUDIO_BUSES_H
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ void EditorAutoloadSettings::_autoload_edited() {
|
|||
|
||||
if (column == 0) {
|
||||
String name = ti->get_text(0);
|
||||
String old_name = selected_autoload.get_slice("/", 1);
|
||||
String old_name = selected_autoload.get_slicec('/', 1);
|
||||
|
||||
if (name == old_name) {
|
||||
return;
|
||||
|
|
@ -242,7 +242,7 @@ void EditorAutoloadSettings::_autoload_edited() {
|
|||
String scr_path = GLOBAL_GET(base);
|
||||
|
||||
if (scr_path.begins_with("*")) {
|
||||
scr_path = scr_path.substr(1, scr_path.length());
|
||||
scr_path = scr_path.substr(1);
|
||||
}
|
||||
|
||||
// Singleton autoloads are represented with a leading "*" in their path.
|
||||
|
|
@ -349,11 +349,7 @@ void EditorAutoloadSettings::_autoload_activated() {
|
|||
}
|
||||
|
||||
void EditorAutoloadSettings::_autoload_open(const String &fpath) {
|
||||
if (ResourceLoader::get_resource_type(fpath) == "PackedScene") {
|
||||
EditorNode::get_singleton()->open_request(fpath);
|
||||
} else {
|
||||
EditorNode::get_singleton()->load_resource(fpath);
|
||||
}
|
||||
EditorNode::get_singleton()->load_scene_or_resource(fpath);
|
||||
ProjectSettingsEditor::get_singleton()->hide();
|
||||
}
|
||||
|
||||
|
|
@ -483,7 +479,7 @@ void EditorAutoloadSettings::update_autoload() {
|
|||
continue;
|
||||
}
|
||||
|
||||
String name = pi.name.get_slice("/", 1);
|
||||
String name = pi.name.get_slicec('/', 1);
|
||||
String scr_path = GLOBAL_GET(pi.name);
|
||||
|
||||
if (name.is_empty()) {
|
||||
|
|
@ -494,7 +490,7 @@ void EditorAutoloadSettings::update_autoload() {
|
|||
info.is_singleton = scr_path.begins_with("*");
|
||||
|
||||
if (info.is_singleton) {
|
||||
scr_path = scr_path.substr(1, scr_path.length());
|
||||
scr_path = scr_path.substr(1);
|
||||
}
|
||||
|
||||
info.name = name;
|
||||
|
|
@ -625,7 +621,7 @@ Variant EditorAutoloadSettings::get_drag_data_fw(const Point2 &p_point, Control
|
|||
next = tree->get_next_selected(next);
|
||||
}
|
||||
|
||||
if (autoloads.size() == 0 || autoloads.size() == autoload_cache.size()) {
|
||||
if (autoloads.is_empty() || autoloads.size() == autoload_cache.size()) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
|
|
@ -663,13 +659,13 @@ bool EditorAutoloadSettings::can_drop_data_fw(const Point2 &p_point, const Varia
|
|||
}
|
||||
|
||||
if (drop_data.has("type")) {
|
||||
TreeItem *ti = tree->get_item_at_position(p_point);
|
||||
TreeItem *ti = (p_point == Vector2(Math::INF, Math::INF)) ? tree->get_selected() : tree->get_item_at_position(p_point);
|
||||
|
||||
if (!ti) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int section = tree->get_drop_section_at_position(p_point);
|
||||
int section = (p_point == Vector2(Math::INF, Math::INF)) ? tree->get_drop_section_at_position(tree->get_item_rect(ti).position) : tree->get_drop_section_at_position(p_point);
|
||||
|
||||
return section >= -1;
|
||||
}
|
||||
|
|
@ -678,13 +674,13 @@ bool EditorAutoloadSettings::can_drop_data_fw(const Point2 &p_point, const Varia
|
|||
}
|
||||
|
||||
void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_control) {
|
||||
TreeItem *ti = tree->get_item_at_position(p_point);
|
||||
TreeItem *ti = (p_point == Vector2(Math::INF, Math::INF)) ? tree->get_selected() : tree->get_item_at_position(p_point);
|
||||
|
||||
if (!ti) {
|
||||
return;
|
||||
}
|
||||
|
||||
int section = tree->get_drop_section_at_position(p_point);
|
||||
int section = (p_point == Vector2(Math::INF, Math::INF)) ? tree->get_drop_section_at_position(tree->get_item_rect(ti).position) : tree->get_drop_section_at_position(p_point);
|
||||
|
||||
if (section < -1) {
|
||||
return;
|
||||
|
|
@ -862,7 +858,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
|
|||
continue;
|
||||
}
|
||||
|
||||
String name = pi.name.get_slice("/", 1);
|
||||
String name = pi.name.get_slicec('/', 1);
|
||||
String scr_path = GLOBAL_GET(pi.name);
|
||||
|
||||
if (name.is_empty()) {
|
||||
|
|
@ -873,7 +869,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
|
|||
info.is_singleton = scr_path.begins_with("*");
|
||||
|
||||
if (info.is_singleton) {
|
||||
scr_path = scr_path.substr(1, scr_path.length());
|
||||
scr_path = scr_path.substr(1);
|
||||
}
|
||||
|
||||
info.name = name;
|
||||
|
|
@ -905,6 +901,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
|
|||
|
||||
autoload_add_path = memnew(LineEdit);
|
||||
hbc->add_child(autoload_add_path);
|
||||
autoload_add_path->set_accessibility_name(TTRC("Autoload Path"));
|
||||
autoload_add_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
autoload_add_path->set_clear_button_enabled(true);
|
||||
autoload_add_path->set_placeholder(vformat(TTR("Set path or press \"%s\" to create a script."), TTR("Add")));
|
||||
|
|
@ -912,6 +909,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
|
|||
|
||||
browse_button = memnew(Button);
|
||||
hbc->add_child(browse_button);
|
||||
browse_button->set_accessibility_name(TTRC("Select Autoload Path"));
|
||||
browse_button->connect(SceneStringName(pressed), callable_mp(this, &EditorAutoloadSettings::_browse_autoload_add_path));
|
||||
|
||||
file_dialog = memnew(EditorFileDialog);
|
||||
|
|
@ -929,6 +927,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
|
|||
hbc->add_child(l);
|
||||
|
||||
autoload_add_name = memnew(LineEdit);
|
||||
autoload_add_name->set_accessibility_name(TTRC("Node Name"));
|
||||
autoload_add_name->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
autoload_add_name->connect(SceneStringName(text_submitted), callable_mp(this, &EditorAutoloadSettings::_autoload_text_submitted));
|
||||
autoload_add_name->connect(SceneStringName(text_changed), callable_mp(this, &EditorAutoloadSettings::_autoload_text_changed));
|
||||
|
|
@ -942,6 +941,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
|
|||
hbc->add_child(add_autoload);
|
||||
|
||||
tree = memnew(Tree);
|
||||
tree->set_accessibility_name(TTRC("Autoloads"));
|
||||
tree->set_hide_root(true);
|
||||
tree->set_select_mode(Tree::SELECT_MULTI);
|
||||
tree->set_allow_reselect(true);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_AUTOLOAD_SETTINGS_H
|
||||
#define EDITOR_AUTOLOAD_SETTINGS_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
|
|
@ -114,5 +113,3 @@ public:
|
|||
EditorAutoloadSettings();
|
||||
~EditorAutoloadSettings();
|
||||
};
|
||||
|
||||
#endif // EDITOR_AUTOLOAD_SETTINGS_H
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ const char *EditorBuildProfile::build_option_identifiers[BUILD_OPTION_MAX] = {
|
|||
"disable_2d_physics",
|
||||
"disable_3d_physics",
|
||||
"disable_navigation",
|
||||
"openxr",
|
||||
"disable_xr",
|
||||
"rendering_device", // FIXME: there's no scons option to disable rendering device
|
||||
"opengl3",
|
||||
"vulkan",
|
||||
|
|
@ -82,7 +82,7 @@ const bool EditorBuildProfile::build_option_disable_values[BUILD_OPTION_MAX] = {
|
|||
true, // PHYSICS_2D
|
||||
true, // PHYSICS_3D
|
||||
true, // NAVIGATION
|
||||
false, // XR
|
||||
true, // XR
|
||||
false, // RENDERING_DEVICE
|
||||
false, // OPENGL
|
||||
false, // VULKAN
|
||||
|
|
@ -297,11 +297,9 @@ Error EditorBuildProfile::load_from_file(const String &p_path) {
|
|||
|
||||
if (data.has("disabled_build_options")) {
|
||||
Dictionary disabled_build_options_arr = data["disabled_build_options"];
|
||||
List<Variant> keys;
|
||||
disabled_build_options_arr.get_key_list(&keys);
|
||||
|
||||
for (const Variant &K : keys) {
|
||||
String key = K;
|
||||
for (const KeyValue<Variant, Variant> &kv : disabled_build_options_arr) {
|
||||
String key = kv.key;
|
||||
|
||||
for (int i = 0; i < BUILD_OPTION_MAX; i++) {
|
||||
String f = build_option_identifiers[i];
|
||||
|
|
@ -810,6 +808,7 @@ EditorBuildProfileManager::EditorBuildProfileManager() {
|
|||
HBoxContainer *path_hbc = memnew(HBoxContainer);
|
||||
profile_path = memnew(LineEdit);
|
||||
path_hbc->add_child(profile_path);
|
||||
profile_path->set_accessibility_name(TTRC("Profile Path"));
|
||||
profile_path->set_editable(true);
|
||||
profile_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
||||
|
|
@ -868,7 +867,7 @@ EditorBuildProfileManager::EditorBuildProfileManager() {
|
|||
import_profile = memnew(EditorFileDialog);
|
||||
add_child(import_profile);
|
||||
import_profile->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
|
||||
import_profile->add_filter("*.build", TTR("Engine Compilation Profile"));
|
||||
import_profile->add_filter("*.gdbuild,*.build", TTR("Engine Compilation Profile"));
|
||||
import_profile->connect("files_selected", callable_mp(this, &EditorBuildProfileManager::_import_profile));
|
||||
import_profile->set_title(TTR("Load Profile"));
|
||||
import_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
|
||||
|
|
@ -876,12 +875,13 @@ EditorBuildProfileManager::EditorBuildProfileManager() {
|
|||
export_profile = memnew(EditorFileDialog);
|
||||
add_child(export_profile);
|
||||
export_profile->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
|
||||
export_profile->add_filter("*.build", TTR("Engine Compilation Profile"));
|
||||
export_profile->add_filter("*.gdbuild,*.build", TTR("Engine Compilation Profile"));
|
||||
export_profile->connect("file_selected", callable_mp(this, &EditorBuildProfileManager::_export_profile));
|
||||
export_profile->set_title(TTR("Export Profile"));
|
||||
export_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
|
||||
|
||||
force_detect_classes = memnew(LineEdit);
|
||||
force_detect_classes->set_accessibility_name(TTRC("Forced Classes"));
|
||||
main_vbc->add_margin_child(TTR("Forced Classes on Detect:"), force_detect_classes);
|
||||
force_detect_classes->connect(SceneStringName(text_changed), callable_mp(this, &EditorBuildProfileManager::_force_detect_classes_changed));
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_BUILD_PROFILE_H
|
||||
#define EDITOR_BUILD_PROFILE_H
|
||||
#pragma once
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "editor/editor_help.h"
|
||||
|
|
@ -185,5 +184,3 @@ public:
|
|||
static EditorBuildProfileManager *get_singleton() { return singleton; }
|
||||
EditorBuildProfileManager();
|
||||
};
|
||||
|
||||
#endif // EDITOR_BUILD_PROFILE_H
|
||||
|
|
|
|||
|
|
@ -2,141 +2,95 @@
|
|||
|
||||
import os
|
||||
import os.path
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import uuid
|
||||
import zlib
|
||||
|
||||
from methods import print_warning
|
||||
import methods
|
||||
|
||||
|
||||
def make_doc_header(target, source, env):
|
||||
dst = str(target[0])
|
||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
||||
buf = ""
|
||||
docbegin = ""
|
||||
docend = ""
|
||||
for src in source:
|
||||
src = str(src)
|
||||
if not src.endswith(".xml"):
|
||||
continue
|
||||
with open(src, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
buf += content
|
||||
buffer = b"".join([methods.get_buffer(src) for src in map(str, source)])
|
||||
decomp_size = len(buffer)
|
||||
buffer = methods.compress_buffer(buffer)
|
||||
|
||||
buf = (docbegin + buf + docend).encode("utf-8")
|
||||
decomp_size = len(buf)
|
||||
|
||||
# Use maximum zlib compression level to further reduce file size
|
||||
# (at the cost of initial build times).
|
||||
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
|
||||
|
||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
||||
g.write("#ifndef _DOC_DATA_RAW_H\n")
|
||||
g.write("#define _DOC_DATA_RAW_H\n")
|
||||
g.write('static const char *_doc_data_hash = "' + str(hash(buf)) + '";\n')
|
||||
g.write("static const int _doc_data_compressed_size = " + str(len(buf)) + ";\n")
|
||||
g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n")
|
||||
g.write("static const unsigned char _doc_data_compressed[] = {\n")
|
||||
for i in range(len(buf)):
|
||||
g.write("\t" + str(buf[i]) + ",\n")
|
||||
g.write("};\n")
|
||||
|
||||
g.write("#endif")
|
||||
with methods.generated_wrapper(str(target[0])) as file:
|
||||
file.write(f"""\
|
||||
inline constexpr const char *_doc_data_hash = "{hash(buffer)}";
|
||||
inline constexpr int _doc_data_compressed_size = {len(buffer)};
|
||||
inline constexpr int _doc_data_uncompressed_size = {decomp_size};
|
||||
inline constexpr const unsigned char _doc_data_compressed[] = {{
|
||||
{methods.format_buffer(buffer, 1)}
|
||||
}};
|
||||
""")
|
||||
|
||||
|
||||
def make_translations_header(target, source, env, category):
|
||||
dst = str(target[0])
|
||||
def make_translations_header(target, source, env):
|
||||
category = os.path.basename(str(target[0])).split("_")[0]
|
||||
sorted_paths = sorted([src.abspath for src in source], key=lambda path: os.path.splitext(os.path.basename(path))[0])
|
||||
|
||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
||||
g.write("#ifndef _{}_TRANSLATIONS_H\n".format(category.upper()))
|
||||
g.write("#define _{}_TRANSLATIONS_H\n".format(category.upper()))
|
||||
xl_names = []
|
||||
msgfmt = env.Detect("msgfmt")
|
||||
if not msgfmt:
|
||||
methods.print_warning("msgfmt not found, using .po files instead of .mo")
|
||||
|
||||
sorted_paths = sorted([str(x) for x in source], key=lambda path: os.path.splitext(os.path.basename(path))[0])
|
||||
|
||||
msgfmt_available = shutil.which("msgfmt") is not None
|
||||
|
||||
if not msgfmt_available:
|
||||
print_warning("msgfmt is not found, using .po files instead of .mo")
|
||||
|
||||
xl_names = []
|
||||
for i in range(len(sorted_paths)):
|
||||
name = os.path.splitext(os.path.basename(sorted_paths[i]))[0]
|
||||
with methods.generated_wrapper(str(target[0])) as file:
|
||||
for path in sorted_paths:
|
||||
name = os.path.splitext(os.path.basename(path))[0]
|
||||
# msgfmt erases non-translated messages, so avoid using it if exporting the POT.
|
||||
if msgfmt_available and name != category:
|
||||
if msgfmt and name != category:
|
||||
mo_path = os.path.join(tempfile.gettempdir(), uuid.uuid4().hex + ".mo")
|
||||
cmd = "msgfmt " + sorted_paths[i] + " --no-hash -o " + mo_path
|
||||
cmd = f"{msgfmt} {path} --no-hash -o {mo_path}"
|
||||
try:
|
||||
subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
|
||||
with open(mo_path, "rb") as f:
|
||||
buf = f.read()
|
||||
buffer = methods.get_buffer(mo_path)
|
||||
except OSError as e:
|
||||
print_warning(
|
||||
methods.print_warning(
|
||||
"msgfmt execution failed, using .po file instead of .mo: path=%r; [%s] %s"
|
||||
% (sorted_paths[i], e.__class__.__name__, e)
|
||||
% (path, e.__class__.__name__, e)
|
||||
)
|
||||
with open(sorted_paths[i], "rb") as f:
|
||||
buf = f.read()
|
||||
buffer = methods.get_buffer(path)
|
||||
finally:
|
||||
try:
|
||||
os.remove(mo_path)
|
||||
if os.path.exists(mo_path):
|
||||
os.remove(mo_path)
|
||||
except OSError as e:
|
||||
# Do not fail the entire build if it cannot delete a temporary file.
|
||||
print_warning(
|
||||
methods.print_warning(
|
||||
"Could not delete temporary .mo file: path=%r; [%s] %s" % (mo_path, e.__class__.__name__, e)
|
||||
)
|
||||
else:
|
||||
with open(sorted_paths[i], "rb") as f:
|
||||
buf = f.read()
|
||||
|
||||
buffer = methods.get_buffer(path)
|
||||
if name == category:
|
||||
name = "source"
|
||||
|
||||
decomp_size = len(buf)
|
||||
# Use maximum zlib compression level to further reduce file size
|
||||
# (at the cost of initial build times).
|
||||
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
|
||||
decomp_size = len(buffer)
|
||||
buffer = methods.compress_buffer(buffer)
|
||||
|
||||
g.write("static const unsigned char _{}_translation_{}_compressed[] = {{\n".format(category, name))
|
||||
for j in range(len(buf)):
|
||||
g.write("\t" + str(buf[j]) + ",\n")
|
||||
file.write(f"""\
|
||||
inline constexpr const unsigned char _{category}_translation_{name}_compressed[] = {{
|
||||
{methods.format_buffer(buffer, 1)}
|
||||
}};
|
||||
|
||||
g.write("};\n")
|
||||
""")
|
||||
|
||||
xl_names.append([name, len(buf), str(decomp_size)])
|
||||
xl_names.append([name, len(buffer), decomp_size])
|
||||
|
||||
file.write(f"""\
|
||||
struct {category.capitalize()}TranslationList {{
|
||||
const char* lang;
|
||||
int comp_size;
|
||||
int uncomp_size;
|
||||
const unsigned char* data;
|
||||
}};
|
||||
|
||||
inline constexpr {category.capitalize()}TranslationList _{category}_translations[] = {{
|
||||
""")
|
||||
|
||||
g.write("struct {}TranslationList {{\n".format(category.capitalize()))
|
||||
g.write("\tconst char* lang;\n")
|
||||
g.write("\tint comp_size;\n")
|
||||
g.write("\tint uncomp_size;\n")
|
||||
g.write("\tconst unsigned char* data;\n")
|
||||
g.write("};\n\n")
|
||||
g.write("static {}TranslationList _{}_translations[] = {{\n".format(category.capitalize(), category))
|
||||
for x in xl_names:
|
||||
g.write(
|
||||
'\t{{ "{}", {}, {}, _{}_translation_{}_compressed }},\n'.format(
|
||||
x[0], str(x[1]), str(x[2]), category, x[0]
|
||||
)
|
||||
)
|
||||
g.write("\t{nullptr, 0, 0, nullptr}\n")
|
||||
g.write("};\n")
|
||||
file.write(f'\t{{ "{x[0]}", {x[1]}, {x[2]}, _{category}_translation_{x[0]}_compressed }},\n')
|
||||
|
||||
g.write("#endif")
|
||||
|
||||
|
||||
def make_editor_translations_header(target, source, env):
|
||||
make_translations_header(target, source, env, "editor")
|
||||
|
||||
|
||||
def make_property_translations_header(target, source, env):
|
||||
make_translations_header(target, source, env, "property")
|
||||
|
||||
|
||||
def make_doc_translations_header(target, source, env):
|
||||
make_translations_header(target, source, env, "doc")
|
||||
|
||||
|
||||
def make_extractable_translations_header(target, source, env):
|
||||
make_translations_header(target, source, env, "extractable")
|
||||
file.write("""\
|
||||
{ nullptr, 0, 0, nullptr },
|
||||
};
|
||||
""")
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ void EditorCommandPalette::_update_command_search(const String &search_text) {
|
|||
|
||||
const int entry_limit = MIN(entries.size(), 300);
|
||||
for (int i = 0; i < entry_limit; i++) {
|
||||
String section_name = entries[i].key_name.get_slice("/", 0);
|
||||
String section_name = entries[i].key_name.get_slicec('/', 0);
|
||||
TreeItem *section;
|
||||
|
||||
if (sections.has(section_name)) {
|
||||
|
|
@ -294,11 +294,10 @@ void EditorCommandPalette::register_shortcuts_as_command() {
|
|||
|
||||
// Load command use history.
|
||||
Dictionary command_history = EditorSettings::get_singleton()->get_project_metadata("command_palette", "command_history", Dictionary());
|
||||
Array history_entries = command_history.keys();
|
||||
for (int i = 0; i < history_entries.size(); i++) {
|
||||
const String &history_key = history_entries[i];
|
||||
for (const KeyValue<Variant, Variant> &history_kv : command_history) {
|
||||
const String &history_key = history_kv.key;
|
||||
if (commands.has(history_key)) {
|
||||
commands[history_key].last_used = command_history[history_key];
|
||||
commands[history_key].last_used = history_kv.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -345,6 +344,7 @@ EditorCommandPalette::EditorCommandPalette() {
|
|||
|
||||
command_search_box = memnew(LineEdit);
|
||||
command_search_box->set_placeholder(TTR("Filter Commands"));
|
||||
command_search_box->set_accessibility_name(TTRC("Filter Commands"));
|
||||
command_search_box->connect(SceneStringName(gui_input), callable_mp(this, &EditorCommandPalette::_sbox_input));
|
||||
command_search_box->connect(SceneStringName(text_changed), callable_mp(this, &EditorCommandPalette::_update_command_search));
|
||||
command_search_box->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_COMMAND_PALETTE_H
|
||||
#define EDITOR_COMMAND_PALETTE_H
|
||||
#pragma once
|
||||
|
||||
#include "core/input/shortcut.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
|
|
@ -103,5 +102,3 @@ public:
|
|||
|
||||
Ref<Shortcut> ED_SHORTCUT_AND_COMMAND(const String &p_path, const String &p_name, Key p_keycode = Key::NONE, String p_command = "");
|
||||
Ref<Shortcut> ED_SHORTCUT_ARRAY_AND_COMMAND(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes, String p_command = "");
|
||||
|
||||
#endif // EDITOR_COMMAND_PALETTE_H
|
||||
|
|
|
|||
|
|
@ -336,12 +336,8 @@ void EditorData::set_editor_plugin_states(const Dictionary &p_states) {
|
|||
return;
|
||||
}
|
||||
|
||||
List<Variant> keys;
|
||||
p_states.get_key_list(&keys);
|
||||
|
||||
List<Variant>::Element *E = keys.front();
|
||||
for (; E; E = E->next()) {
|
||||
String name = E->get();
|
||||
for (const KeyValue<Variant, Variant> &kv : p_states) {
|
||||
String name = kv.key;
|
||||
int idx = -1;
|
||||
for (int i = 0; i < editor_plugins.size(); i++) {
|
||||
if (editor_plugins[i]->get_plugin_name() == name) {
|
||||
|
|
@ -353,7 +349,7 @@ void EditorData::set_editor_plugin_states(const Dictionary &p_states) {
|
|||
if (idx == -1) {
|
||||
continue;
|
||||
}
|
||||
editor_plugins[idx]->set_state(p_states[name]);
|
||||
editor_plugins[idx]->set_state(kv.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -602,8 +598,7 @@ void EditorData::instantiate_object_properties(Object *p_object) {
|
|||
List<PropertyInfo> pinfo;
|
||||
p_object->get_property_list(&pinfo);
|
||||
|
||||
for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
|
||||
PropertyInfo pi = E->get();
|
||||
for (const PropertyInfo &pi : pinfo) {
|
||||
if (pi.type == Variant::OBJECT && pi.usage & PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT) {
|
||||
Object *prop = ClassDB::instantiate(pi.class_name);
|
||||
p_object->set(pi.name, prop);
|
||||
|
|
@ -1071,12 +1066,10 @@ void EditorData::script_class_load_icon_paths() {
|
|||
#ifndef DISABLE_DEPRECATED
|
||||
if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
|
||||
Dictionary d = GLOBAL_GET("_global_script_class_icons");
|
||||
List<Variant> keys;
|
||||
d.get_key_list(&keys);
|
||||
|
||||
for (const Variant &E : keys) {
|
||||
String name = E.operator String();
|
||||
_script_class_icon_paths[name] = d[name];
|
||||
for (const KeyValue<Variant, Variant> &kv : d) {
|
||||
String name = kv.key.operator String();
|
||||
_script_class_icon_paths[name] = kv.value;
|
||||
|
||||
String path = ScriptServer::get_global_class_path(name);
|
||||
script_class_set_name(path, name);
|
||||
|
|
@ -1258,7 +1251,10 @@ void EditorSelection::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("add_node", "node"), &EditorSelection::add_node);
|
||||
ClassDB::bind_method(D_METHOD("remove_node", "node"), &EditorSelection::remove_node);
|
||||
ClassDB::bind_method(D_METHOD("get_selected_nodes"), &EditorSelection::get_selected_nodes);
|
||||
ClassDB::bind_method(D_METHOD("get_transformable_selected_nodes"), &EditorSelection::_get_transformable_selected_nodes);
|
||||
ClassDB::bind_method(D_METHOD("get_top_selected_nodes"), &EditorSelection::get_top_selected_nodes);
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
ClassDB::bind_method(D_METHOD("get_transformable_selected_nodes"), &EditorSelection::get_top_selected_nodes);
|
||||
#endif // DISABLE_DEPRECATED
|
||||
ADD_SIGNAL(MethodInfo("selection_changed"));
|
||||
}
|
||||
|
||||
|
|
@ -1271,7 +1267,7 @@ void EditorSelection::_update_node_list() {
|
|||
return;
|
||||
}
|
||||
|
||||
selected_node_list.clear();
|
||||
top_selected_node_list.clear();
|
||||
|
||||
// If the selection does not have the parent of the selected node, then add the node to the node list.
|
||||
// However, if the parent is already selected, then adding this node is redundant as
|
||||
|
|
@ -1291,7 +1287,7 @@ void EditorSelection::_update_node_list() {
|
|||
if (skip) {
|
||||
continue;
|
||||
}
|
||||
selected_node_list.push_back(E.key);
|
||||
top_selected_node_list.push_back(E.key);
|
||||
}
|
||||
|
||||
node_list_changed = true;
|
||||
|
|
@ -1315,10 +1311,10 @@ void EditorSelection::_emit_change() {
|
|||
emitted = false;
|
||||
}
|
||||
|
||||
TypedArray<Node> EditorSelection::_get_transformable_selected_nodes() {
|
||||
TypedArray<Node> EditorSelection::get_top_selected_nodes() {
|
||||
TypedArray<Node> ret;
|
||||
|
||||
for (const Node *E : selected_node_list) {
|
||||
for (const Node *E : top_selected_node_list) {
|
||||
ret.push_back(E);
|
||||
}
|
||||
|
||||
|
|
@ -1335,13 +1331,13 @@ TypedArray<Node> EditorSelection::get_selected_nodes() {
|
|||
return ret;
|
||||
}
|
||||
|
||||
List<Node *> &EditorSelection::get_selected_node_list() {
|
||||
const List<Node *> &EditorSelection::get_top_selected_node_list() {
|
||||
if (changed) {
|
||||
update();
|
||||
} else {
|
||||
_update_node_list();
|
||||
}
|
||||
return selected_node_list;
|
||||
return top_selected_node_list;
|
||||
}
|
||||
|
||||
List<Node *> EditorSelection::get_full_selected_node_list() {
|
||||
|
|
@ -1362,9 +1358,6 @@ void EditorSelection::clear() {
|
|||
node_list_changed = true;
|
||||
}
|
||||
|
||||
EditorSelection::EditorSelection() {
|
||||
}
|
||||
|
||||
EditorSelection::~EditorSelection() {
|
||||
clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_DATA_H
|
||||
#define EDITOR_DATA_H
|
||||
#pragma once
|
||||
|
||||
#include "core/templates/list.h"
|
||||
#include "scene/resources/texture.h"
|
||||
|
|
@ -287,10 +286,9 @@ class EditorSelection : public Object {
|
|||
|
||||
// Editor plugins which are related to selection.
|
||||
List<Object *> editor_plugins;
|
||||
List<Node *> selected_node_list;
|
||||
List<Node *> top_selected_node_list;
|
||||
|
||||
void _update_node_list();
|
||||
TypedArray<Node> _get_transformable_selected_nodes();
|
||||
void _emit_change();
|
||||
|
||||
protected:
|
||||
|
|
@ -315,18 +313,17 @@ public:
|
|||
void update();
|
||||
void clear();
|
||||
|
||||
// Returns all the selected nodes.
|
||||
TypedArray<Node> get_selected_nodes();
|
||||
// Returns only the top level selected nodes.
|
||||
// That is, if the selection includes some node and a child of that node, only the parent is returned.
|
||||
List<Node *> &get_selected_node_list();
|
||||
const List<Node *> &get_top_selected_node_list();
|
||||
// Same as get_top_selected_node_list but returns a copy in a TypedArray for binding to scripts.
|
||||
TypedArray<Node> get_top_selected_nodes();
|
||||
// Returns all the selected nodes (list version of "get_selected_nodes").
|
||||
List<Node *> get_full_selected_node_list();
|
||||
// Same as get_full_selected_node_list but returns a copy in a TypedArray for binding to scripts.
|
||||
TypedArray<Node> get_selected_nodes();
|
||||
// Returns the map of selected objects and their metadata.
|
||||
HashMap<Node *, Object *> &get_selection() { return selection; }
|
||||
|
||||
EditorSelection();
|
||||
~EditorSelection();
|
||||
};
|
||||
|
||||
#endif // EDITOR_DATA_H
|
||||
|
|
|
|||
|
|
@ -158,17 +158,20 @@ void EditorDockManager::_update_layout() {
|
|||
return;
|
||||
}
|
||||
dock_context_popup->docks_updated();
|
||||
_update_docks_menu();
|
||||
update_docks_menu();
|
||||
EditorNode::get_singleton()->save_editor_layout_delayed();
|
||||
}
|
||||
|
||||
void EditorDockManager::_update_docks_menu() {
|
||||
void EditorDockManager::update_docks_menu() {
|
||||
docks_menu->clear();
|
||||
docks_menu->reset_size();
|
||||
|
||||
const Ref<Texture2D> default_icon = docks_menu->get_editor_theme_icon(SNAME("Window"));
|
||||
const Color closed_icon_color_mod = Color(1, 1, 1, 0.5);
|
||||
|
||||
bool global_menu = !bool(EDITOR_GET("interface/editor/use_embedded_menu")) && NativeMenu::get_singleton()->has_feature(NativeMenu::FEATURE_GLOBAL_MENU);
|
||||
bool dark_mode = DisplayServer::get_singleton()->is_dark_mode_supported() && DisplayServer::get_singleton()->is_dark_mode();
|
||||
|
||||
// Add docks.
|
||||
docks_menu_docks.clear();
|
||||
int id = 0;
|
||||
|
|
@ -182,7 +185,7 @@ void EditorDockManager::_update_docks_menu() {
|
|||
} else {
|
||||
docks_menu->add_item(dock.value.title, id);
|
||||
}
|
||||
const Ref<Texture2D> icon = dock.value.icon_name ? docks_menu->get_editor_theme_icon(dock.value.icon_name) : dock.value.icon;
|
||||
const Ref<Texture2D> icon = dock.value.icon_name ? docks_menu->get_editor_theme_native_menu_icon(dock.value.icon_name, global_menu, dark_mode) : dock.value.icon;
|
||||
docks_menu->set_item_icon(id, icon.is_valid() ? icon : default_icon);
|
||||
if (!dock.value.open) {
|
||||
docks_menu->set_item_icon_modulate(id, closed_icon_color_mod);
|
||||
|
|
@ -613,7 +616,7 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S
|
|||
int ofs = p_layout->get_value(p_section, "dock_hsplit_" + itos(i + 1));
|
||||
hsplits[i]->set_split_offset(ofs * EDSCALE);
|
||||
}
|
||||
_update_docks_menu();
|
||||
update_docks_menu();
|
||||
}
|
||||
|
||||
void EditorDockManager::bottom_dock_show_placement_popup(const Rect2i &p_position, Control *p_dock) {
|
||||
|
|
@ -848,11 +851,13 @@ EditorDockManager::EditorDockManager() {
|
|||
docks_menu = memnew(PopupMenu);
|
||||
docks_menu->set_hide_on_item_selection(false);
|
||||
docks_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorDockManager::_docks_menu_option));
|
||||
EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorDockManager::_update_docks_menu));
|
||||
EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorDockManager::update_docks_menu));
|
||||
}
|
||||
|
||||
void DockContextPopup::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
|
||||
case NOTIFICATION_TRANSLATION_CHANGED:
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
if (make_float_button) {
|
||||
make_float_button->set_button_icon(get_editor_theme_icon(SNAME("MakeFloating")));
|
||||
|
|
@ -1087,6 +1092,7 @@ DockContextPopup::DockContextPopup() {
|
|||
|
||||
HBoxContainer *header_hb = memnew(HBoxContainer);
|
||||
tab_move_left_button = memnew(Button);
|
||||
tab_move_left_button->set_accessibility_name(TTRC("Move Tab Left"));
|
||||
tab_move_left_button->set_flat(true);
|
||||
tab_move_left_button->set_focus_mode(Control::FOCUS_NONE);
|
||||
tab_move_left_button->connect(SceneStringName(pressed), callable_mp(this, &DockContextPopup::_tab_move_left));
|
||||
|
|
@ -1099,6 +1105,7 @@ DockContextPopup::DockContextPopup() {
|
|||
header_hb->add_child(position_label);
|
||||
|
||||
tab_move_right_button = memnew(Button);
|
||||
tab_move_right_button->set_accessibility_name(TTRC("Move Tab Right"));
|
||||
tab_move_right_button->set_flat(true);
|
||||
tab_move_right_button->set_focus_mode(Control::FOCUS_NONE);
|
||||
tab_move_right_button->connect(SceneStringName(pressed), callable_mp(this, &DockContextPopup::_tab_move_right));
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_DOCK_MANAGER_H
|
||||
#define EDITOR_DOCK_MANAGER_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/popup.h"
|
||||
#include "scene/gui/split_container.h"
|
||||
|
|
@ -113,7 +112,6 @@ private:
|
|||
void _dock_container_update_visibility(TabContainer *p_dock_container);
|
||||
void _update_layout();
|
||||
|
||||
void _update_docks_menu();
|
||||
void _docks_menu_option(int p_id);
|
||||
|
||||
void _window_close_request(WindowWrapper *p_wrapper);
|
||||
|
|
@ -133,6 +131,7 @@ private:
|
|||
public:
|
||||
static EditorDockManager *get_singleton() { return singleton; }
|
||||
|
||||
void update_docks_menu();
|
||||
void update_tab_styles();
|
||||
void set_tab_icon_max_width(int p_max_width);
|
||||
|
||||
|
|
@ -207,5 +206,3 @@ public:
|
|||
|
||||
DockContextPopup();
|
||||
};
|
||||
|
||||
#endif // EDITOR_DOCK_MANAGER_H
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ Error EditorFeatureProfile::load_from_file(const String &p_path) {
|
|||
Array disabled_properties_arr = data["disabled_properties"];
|
||||
for (int i = 0; i < disabled_properties_arr.size(); i++) {
|
||||
String s = disabled_properties_arr[i];
|
||||
set_disable_class_property(s.get_slice(":", 0), s.get_slice(":", 1), true);
|
||||
set_disable_class_property(s.get_slicec(':', 0), s.get_slicec(':', 1), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -924,6 +924,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
|
|||
HBoxContainer *name_hbc = memnew(HBoxContainer);
|
||||
current_profile_name = memnew(LineEdit);
|
||||
name_hbc->add_child(current_profile_name);
|
||||
current_profile_name->set_accessibility_name(TTRC("Current Profile"));
|
||||
current_profile_name->set_text(TTR("(none)"));
|
||||
current_profile_name->set_editable(false);
|
||||
current_profile_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
|
@ -938,6 +939,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
|
|||
|
||||
HBoxContainer *profiles_hbc = memnew(HBoxContainer);
|
||||
profile_list = memnew(OptionButton);
|
||||
profile_list->set_accessibility_name(TTRC("Profiles"));
|
||||
profile_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
profile_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
profiles_hbc->add_child(profile_list);
|
||||
|
|
@ -1031,6 +1033,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
|
|||
new_profile_name = memnew(LineEdit);
|
||||
new_profile_vb->add_child(new_profile_name);
|
||||
new_profile_name->set_custom_minimum_size(Size2(300 * EDSCALE, 1));
|
||||
new_profile_name->set_accessibility_name(TTRC("Profile Name"));
|
||||
add_child(new_profile_dialog);
|
||||
new_profile_dialog->connect(SceneStringName(confirmed), callable_mp(this, &EditorFeatureProfileManager::_create_new_profile));
|
||||
new_profile_dialog->register_text_enter(new_profile_name);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_FEATURE_PROFILE_H
|
||||
#define EDITOR_FEATURE_PROFILE_H
|
||||
#pragma once
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "editor/editor_help.h"
|
||||
|
|
@ -185,5 +184,3 @@ public:
|
|||
static EditorFeatureProfileManager *get_singleton() { return singleton; }
|
||||
EditorFeatureProfileManager();
|
||||
};
|
||||
|
||||
#endif // EDITOR_FEATURE_PROFILE_H
|
||||
|
|
|
|||
|
|
@ -447,8 +447,8 @@ void EditorFileSystem::_scan_filesystem() {
|
|||
name = cpath.path_join(name);
|
||||
|
||||
FileCache fc;
|
||||
fc.type = split[1].get_slice("/", 0);
|
||||
fc.resource_script_class = split[1].get_slice("/", 1);
|
||||
fc.type = split[1].get_slicec('/', 0);
|
||||
fc.resource_script_class = split[1].get_slicec('/', 1);
|
||||
fc.uid = split[2].to_int();
|
||||
fc.modification_time = split[3].to_int();
|
||||
fc.import_modification_time = split[4].to_int();
|
||||
|
|
@ -802,7 +802,7 @@ Vector<String> EditorFileSystem::_get_import_dest_paths(const String &p_path) {
|
|||
}
|
||||
|
||||
bool EditorFileSystem::_scan_import_support(const Vector<String> &reimports) {
|
||||
if (import_support_queries.size() == 0) {
|
||||
if (import_support_queries.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
HashMap<String, int> import_support_test;
|
||||
|
|
@ -818,7 +818,7 @@ bool EditorFileSystem::_scan_import_support(const Vector<String> &reimports) {
|
|||
}
|
||||
}
|
||||
|
||||
if (import_support_test.size() == 0) {
|
||||
if (import_support_test.is_empty()) {
|
||||
return false; //well nothing to do
|
||||
}
|
||||
|
||||
|
|
@ -905,7 +905,7 @@ bool EditorFileSystem::_update_scan_actions() {
|
|||
if (existing_id != ResourceUID::INVALID_ID) {
|
||||
const String old_path = ResourceUID::get_singleton()->get_id_path(existing_id);
|
||||
if (old_path != new_file_path && FileAccess::exists(old_path)) {
|
||||
const ResourceUID::ID new_id = ResourceUID::get_singleton()->create_id();
|
||||
const ResourceUID::ID new_id = ResourceUID::get_singleton()->create_id_for_path(new_file_path);
|
||||
ResourceUID::get_singleton()->add_id(new_id, new_file_path);
|
||||
ResourceSaver::set_uid(new_file_path, new_id);
|
||||
WARN_PRINT(vformat("Duplicate UID detected for Resource at \"%s\".\nOld Resource path: \"%s\". The new file UID was changed automatically.", new_file_path, old_path));
|
||||
|
|
@ -913,6 +913,12 @@ bool EditorFileSystem::_update_scan_actions() {
|
|||
// Re-assign the UID to file, just in case it was pulled from cache.
|
||||
ResourceSaver::set_uid(new_file_path, existing_id);
|
||||
}
|
||||
} else if (ResourceLoader::should_create_uid_file(new_file_path)) {
|
||||
Ref<FileAccess> f = FileAccess::open(new_file_path + ".uid", FileAccess::WRITE);
|
||||
if (f.is_valid()) {
|
||||
ia.new_file->uid = ResourceUID::get_singleton()->create_id_for_path(new_file_path);
|
||||
f->store_line(ResourceUID::get_singleton()->id_to_text(ia.new_file->uid));
|
||||
}
|
||||
}
|
||||
|
||||
if (ClassDB::is_parent_class(ia.new_file->type, SNAME("Script"))) {
|
||||
|
|
@ -927,15 +933,16 @@ bool EditorFileSystem::_update_scan_actions() {
|
|||
int idx = ia.dir->find_file_index(ia.file);
|
||||
ERR_CONTINUE(idx == -1);
|
||||
|
||||
String class_name = ia.dir->files[idx]->class_info.name;
|
||||
const String file_path = ia.dir->get_file_path(idx);
|
||||
const String class_name = ia.dir->files[idx]->class_info.name;
|
||||
if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) {
|
||||
_queue_update_script_class(ia.dir->get_file_path(idx), ScriptClassInfoUpdate());
|
||||
_queue_update_script_class(file_path, ScriptClassInfoUpdate());
|
||||
}
|
||||
if (ia.dir->files[idx]->type == SNAME("PackedScene")) {
|
||||
_queue_update_scene_groups(ia.dir->get_file_path(idx));
|
||||
_queue_update_scene_groups(file_path);
|
||||
}
|
||||
|
||||
_delete_internal_files(ia.dir->files[idx]->file);
|
||||
_delete_internal_files(file_path);
|
||||
memdelete(ia.dir->files[idx]);
|
||||
ia.dir->files.remove_at(idx);
|
||||
|
||||
|
|
@ -963,7 +970,7 @@ bool EditorFileSystem::_update_scan_actions() {
|
|||
Vector<String> dependencies = _get_dependencies(full_path);
|
||||
for (const String &dep : dependencies) {
|
||||
const String &dependency_path = dep.contains("::") ? dep.get_slice("::", 0) : dep;
|
||||
if (import_extensions.has(dep.get_extension())) {
|
||||
if (_can_import_file(dep)) {
|
||||
reimports.push_back(dependency_path);
|
||||
}
|
||||
}
|
||||
|
|
@ -1061,6 +1068,19 @@ void EditorFileSystem::scan() {
|
|||
// to be loaded to continue the scan and reimportations.
|
||||
if (first_scan) {
|
||||
_first_scan_filesystem();
|
||||
#ifdef ANDROID_ENABLED
|
||||
const String nomedia_file_path = ProjectSettings::get_singleton()->get_resource_path().path_join(".nomedia");
|
||||
if (!FileAccess::exists(nomedia_file_path)) {
|
||||
// Create a .nomedia file to hide assets from media apps on Android.
|
||||
Ref<FileAccess> f = FileAccess::open(nomedia_file_path, FileAccess::WRITE);
|
||||
if (f.is_null()) {
|
||||
// .nomedia isn't so critical.
|
||||
ERR_PRINT("Couldn't create .nomedia in project path.");
|
||||
} else {
|
||||
f->close();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
_update_extensions();
|
||||
|
|
@ -1145,15 +1165,15 @@ int EditorFileSystem::_scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da)
|
|||
|
||||
int nb_files_total_scan = 0;
|
||||
|
||||
for (List<String>::Element *E = dirs.front(); E; E = E->next()) {
|
||||
if (da->change_dir(E->get()) == OK) {
|
||||
for (const String &dir : dirs) {
|
||||
if (da->change_dir(dir) == OK) {
|
||||
String d = da->get_current_dir();
|
||||
|
||||
if (d == cd || !d.begins_with(cd)) {
|
||||
da->change_dir(cd); //avoid recursion
|
||||
} else {
|
||||
ScannedDirectory *sd = memnew(ScannedDirectory);
|
||||
sd->name = E->get();
|
||||
sd->name = dir;
|
||||
sd->full_path = p_dir->full_path.path_join(sd->name);
|
||||
|
||||
nb_files_total_scan += _scan_new_dir(sd, da);
|
||||
|
|
@ -1163,7 +1183,7 @@ int EditorFileSystem::_scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da)
|
|||
da->change_dir("..");
|
||||
}
|
||||
} else {
|
||||
ERR_PRINT("Cannot go into subdir '" + E->get() + "'.");
|
||||
ERR_PRINT("Cannot go into subdir '" + dir + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1204,7 +1224,7 @@ void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir,
|
|||
FileCache *fc = file_cache.getptr(path);
|
||||
uint64_t mt = FileAccess::get_modified_time(path);
|
||||
|
||||
if (import_extensions.has(ext)) {
|
||||
if (_can_import_file(scan_file)) {
|
||||
//is imported
|
||||
uint64_t import_mt = FileAccess::get_modified_time(path + ".import");
|
||||
|
||||
|
|
@ -1333,7 +1353,7 @@ void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir,
|
|||
Ref<FileAccess> f = FileAccess::open(path + ".uid", FileAccess::WRITE);
|
||||
if (f.is_valid()) {
|
||||
if (fi->uid == ResourceUID::INVALID_ID) {
|
||||
fi->uid = ResourceUID::get_singleton()->create_id();
|
||||
fi->uid = ResourceUID::get_singleton()->create_id_for_path(path);
|
||||
} else {
|
||||
WARN_PRINT(vformat("Missing .uid file for path \"%s\". The file was re-created from cache.", path));
|
||||
}
|
||||
|
|
@ -1494,7 +1514,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanPr
|
|||
scan_actions.push_back(ia);
|
||||
}
|
||||
|
||||
if (import_extensions.has(ext)) {
|
||||
if (_can_import_file(f)) {
|
||||
//if it can be imported, and it was added, it needs to be reimported
|
||||
ItemAction ia;
|
||||
ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT;
|
||||
|
|
@ -1526,7 +1546,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanPr
|
|||
|
||||
String path = cd.path_join(p_dir->files[i]->file);
|
||||
|
||||
if (import_extensions.has(p_dir->files[i]->file.get_extension().to_lower())) {
|
||||
if (_can_import_file(p_dir->files[i]->file)) {
|
||||
// Check here if file must be imported or not.
|
||||
// Same logic as in _process_file_system, the last modifications dates
|
||||
// needs to be trusted to prevent reading all the .import files and the md5
|
||||
|
|
@ -1846,12 +1866,12 @@ bool EditorFileSystem::_find_file(const String &p_file, EditorFileSystemDirector
|
|||
if (!f.begins_with("res://")) {
|
||||
return false;
|
||||
}
|
||||
f = f.substr(6, f.length());
|
||||
f = f.replace("\\", "/");
|
||||
f = f.substr(6);
|
||||
f = f.replace_char('\\', '/');
|
||||
|
||||
Vector<String> path = f.split("/");
|
||||
|
||||
if (path.size() == 0) {
|
||||
if (path.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
String file = path[path.size() - 1];
|
||||
|
|
@ -1972,8 +1992,8 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
f = f.substr(6, f.length());
|
||||
f = f.replace("\\", "/");
|
||||
f = f.substr(6);
|
||||
f = f.replace_char('\\', '/');
|
||||
if (f.is_empty()) {
|
||||
return filesystem;
|
||||
}
|
||||
|
|
@ -1984,7 +2004,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p
|
|||
|
||||
Vector<String> path = f.split("/");
|
||||
|
||||
if (path.size() == 0) {
|
||||
if (path.is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -2171,6 +2191,7 @@ void EditorFileSystem::_update_script_documentation() {
|
|||
|
||||
if (!efd || index < 0) {
|
||||
// The file was removed
|
||||
EditorHelp::remove_script_doc_by_path(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -2188,7 +2209,7 @@ void EditorFileSystem::_update_script_documentation() {
|
|||
scr->reload_from_file();
|
||||
}
|
||||
for (const DocData::ClassDoc &cd : scr->get_documentation()) {
|
||||
EditorHelp::get_doc_data()->add_doc(cd);
|
||||
EditorHelp::add_doc(cd);
|
||||
if (!first_scan) {
|
||||
// Update the documentation in the Script Editor if it is open.
|
||||
ScriptEditor::get_singleton()->update_doc(cd.name);
|
||||
|
|
@ -2421,7 +2442,7 @@ void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
|
|||
if (ResourceLoader::should_create_uid_file(file)) {
|
||||
Ref<FileAccess> f = FileAccess::open(file + ".uid", FileAccess::WRITE);
|
||||
if (f.is_valid()) {
|
||||
const ResourceUID::ID id = ResourceUID::get_singleton()->create_id();
|
||||
const ResourceUID::ID id = ResourceUID::get_singleton()->create_id_for_path(file);
|
||||
ResourceUID::get_singleton()->add_id(id, file);
|
||||
f->store_line(ResourceUID::get_singleton()->id_to_text(id));
|
||||
fi->uid = id;
|
||||
|
|
@ -2609,7 +2630,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
|
|||
}
|
||||
|
||||
if (uid == ResourceUID::INVALID_ID) {
|
||||
uid = ResourceUID::get_singleton()->create_id();
|
||||
uid = ResourceUID::get_singleton()->create_id_for_path(file);
|
||||
}
|
||||
|
||||
f->store_line("uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\""); // Store in readable format.
|
||||
|
|
@ -2799,7 +2820,7 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<Strin
|
|||
|
||||
if (importer.is_null()) {
|
||||
//not found by name, find by extension
|
||||
importer = ResourceFormatImporter::get_singleton()->get_importer_by_extension(p_file.get_extension());
|
||||
importer = ResourceFormatImporter::get_singleton()->get_importer_by_file(p_file);
|
||||
load_default = true;
|
||||
if (importer.is_null()) {
|
||||
ERR_FAIL_V_MSG(ERR_FILE_CANT_OPEN, "BUG: File queued for import, but can't be imported, importer for type '" + importer_name + "' not found.");
|
||||
|
|
@ -2824,16 +2845,14 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<Strin
|
|||
if (load_default && ProjectSettings::get_singleton()->has_setting("importer_defaults/" + importer->get_importer_name())) {
|
||||
//use defaults if exist
|
||||
Dictionary d = GLOBAL_GET("importer_defaults/" + importer->get_importer_name());
|
||||
List<Variant> v;
|
||||
d.get_key_list(&v);
|
||||
|
||||
for (const Variant &E : v) {
|
||||
params[E] = d[E];
|
||||
for (const KeyValue<Variant, Variant> &kv : d) {
|
||||
params[kv.key] = kv.value;
|
||||
}
|
||||
}
|
||||
|
||||
if (uid == ResourceUID::INVALID_ID) {
|
||||
uid = ResourceUID::get_singleton()->create_id();
|
||||
uid = ResourceUID::get_singleton()->create_id_for_path(p_file);
|
||||
}
|
||||
|
||||
//finally, perform import!!
|
||||
|
|
@ -3093,7 +3112,7 @@ void EditorFileSystem::_queue_refresh_filesystem() {
|
|||
|
||||
void EditorFileSystem::_refresh_filesystem() {
|
||||
for (const ObjectID &id : folders_to_sort) {
|
||||
EditorFileSystemDirectory *dir = Object::cast_to<EditorFileSystemDirectory>(ObjectDB::get_instance(id));
|
||||
EditorFileSystemDirectory *dir = ObjectDB::get_instance<EditorFileSystemDirectory>(id);
|
||||
if (dir) {
|
||||
dir->subdirs.sort_custom<DirectoryComparator>();
|
||||
}
|
||||
|
|
@ -3107,8 +3126,11 @@ void EditorFileSystem::_refresh_filesystem() {
|
|||
}
|
||||
|
||||
void EditorFileSystem::_reimport_thread(uint32_t p_index, ImportThreadData *p_import_data) {
|
||||
ResourceLoader::set_is_import_thread(true);
|
||||
int file_idx = p_import_data->reimport_from + int(p_index);
|
||||
_reimport_file(p_import_data->reimport_files[file_idx].path);
|
||||
ResourceLoader::set_is_import_thread(false);
|
||||
|
||||
p_import_data->imported_sem->post();
|
||||
}
|
||||
|
||||
|
|
@ -3437,7 +3459,7 @@ Error EditorFileSystem::make_dir_recursive(const String &p_path, const String &p
|
|||
ERR_FAIL_NULL_V(parent, ERR_FILE_NOT_FOUND);
|
||||
folders_to_sort.insert(parent->get_instance_id());
|
||||
|
||||
const PackedStringArray folders = p_path.trim_prefix(path).trim_suffix("/").split("/");
|
||||
const PackedStringArray folders = p_path.trim_prefix(path).split("/", false);
|
||||
for (const String &folder : folders) {
|
||||
const int current = parent->find_dir_index(folder);
|
||||
if (current > -1) {
|
||||
|
|
@ -3519,14 +3541,14 @@ ResourceUID::ID EditorFileSystem::_resource_saver_get_resource_id_for_path(const
|
|||
}
|
||||
|
||||
if (p_generate) {
|
||||
return ResourceUID::get_singleton()->create_id(); // Just create a new one, we will be notified of save anyway and fetch the right UID at that time, to keep things simple.
|
||||
return ResourceUID::get_singleton()->create_id_for_path(p_path); // Just create a new one, we will be notified of save anyway and fetch the right UID at that time, to keep things simple.
|
||||
} else {
|
||||
return ResourceUID::INVALID_ID;
|
||||
}
|
||||
} else if (fs->files[cpos]->uid != ResourceUID::INVALID_ID) {
|
||||
return fs->files[cpos]->uid;
|
||||
} else if (p_generate) {
|
||||
return ResourceUID::get_singleton()->create_id(); // Just create a new one, we will be notified of save anyway and fetch the right UID at that time, to keep things simple.
|
||||
return ResourceUID::get_singleton()->create_id_for_path(p_path); // Just create a new one, we will be notified of save anyway and fetch the right UID at that time, to keep things simple.
|
||||
} else {
|
||||
return ResourceUID::INVALID_ID;
|
||||
}
|
||||
|
|
@ -3604,10 +3626,20 @@ void EditorFileSystem::_update_extensions() {
|
|||
extensionsl.clear();
|
||||
ResourceFormatImporter::get_singleton()->get_recognized_extensions(&extensionsl);
|
||||
for (const String &E : extensionsl) {
|
||||
import_extensions.insert(E);
|
||||
import_extensions.insert(!E.begins_with(".") ? "." + E : E);
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorFileSystem::_can_import_file(const String &p_file) {
|
||||
for (const String &F : import_extensions) {
|
||||
if (p_file.right(F.length()).nocasecmp_to(F) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditorFileSystem::add_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query) {
|
||||
ERR_FAIL_COND(import_support_queries.has(p_query));
|
||||
import_support_queries.push_back(p_query);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_FILE_SYSTEM_H
|
||||
#define EDITOR_FILE_SYSTEM_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/io/resource_importer.h"
|
||||
|
|
@ -280,6 +279,7 @@ class EditorFileSystem : public Node {
|
|||
|
||||
bool _test_for_reimport(const String &p_path, const String &p_expected_import_md5);
|
||||
bool _is_test_for_reimport_needed(const String &p_path, uint64_t p_last_modification_time, uint64_t p_modification_time, uint64_t p_last_import_modification_time, uint64_t p_import_modification_time, const Vector<String> &p_import_dest_paths);
|
||||
bool _can_import_file(const String &p_path);
|
||||
Vector<String> _get_import_dest_paths(const String &p_path);
|
||||
|
||||
bool reimport_on_missing_imported_files;
|
||||
|
|
@ -424,5 +424,3 @@ public:
|
|||
EditorFileSystem();
|
||||
~EditorFileSystem();
|
||||
};
|
||||
|
||||
#endif // EDITOR_FILE_SYSTEM_H
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ void EditorFolding::_set_unfolds(Object *p_object, const Vector<String> &p_unfol
|
|||
const String *r = p_unfolds.ptr();
|
||||
p_object->editor_clear_section_folding();
|
||||
for (int i = 0; i < uc; i++) {
|
||||
p_object->editor_set_section_unfold(r[i], true);
|
||||
p_object->editor_set_section_unfold(r[i], true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -294,6 +294,3 @@ void EditorFolding::unfold_scene(Node *p_scene) {
|
|||
HashSet<Ref<Resource>> resources;
|
||||
_do_node_unfolds(p_scene, p_scene, resources);
|
||||
}
|
||||
|
||||
EditorFolding::EditorFolding() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_FOLDING_H
|
||||
#define EDITOR_FOLDING_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/main/node.h"
|
||||
|
||||
|
|
@ -52,8 +51,4 @@ public:
|
|||
void unfold_scene(Node *p_scene);
|
||||
|
||||
bool has_folding_data(const String &p_path);
|
||||
|
||||
EditorFolding();
|
||||
};
|
||||
|
||||
#endif // EDITOR_FOLDING_H
|
||||
|
|
|
|||
|
|
@ -38,8 +38,9 @@
|
|||
#include "core/object/script_language.h"
|
||||
#include "core/os/keyboard.h"
|
||||
#include "core/string/string_builder.h"
|
||||
#include "core/version_generated.gen.h"
|
||||
#include "core/version.h"
|
||||
#include "editor/doc_data_compressed.gen.h"
|
||||
#include "editor/editor_file_system.h"
|
||||
#include "editor/editor_main_screen.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_paths.h"
|
||||
|
|
@ -66,7 +67,7 @@
|
|||
#include "modules/mono/csharp_script.h"
|
||||
#endif
|
||||
|
||||
#define CONTRIBUTE_URL vformat("%s/contributing/documentation/updating_the_class_reference.html", VERSION_DOCS_URL)
|
||||
#define CONTRIBUTE_URL vformat("%s/contributing/documentation/updating_the_class_reference.html", GODOT_VERSION_DOCS_URL)
|
||||
|
||||
#ifdef MODULE_MONO_ENABLED
|
||||
// Sync with the types mentioned in https://docs.godotengine.org/en/stable/tutorials/scripting/c_sharp/c_sharp_differences.html
|
||||
|
|
@ -102,7 +103,8 @@ const Vector<String> classes_with_csharp_differences = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static const String nbsp = String::chr(160);
|
||||
static const char32_t nbsp_chr = 160;
|
||||
static const String nbsp = String::chr(nbsp_chr);
|
||||
static const String nbsp_equal_nbsp = nbsp + "=" + nbsp;
|
||||
static const String colon_nbsp = ":" + nbsp;
|
||||
|
||||
|
|
@ -120,7 +122,7 @@ const Vector<String> packed_array_types = {
|
|||
};
|
||||
|
||||
static String _replace_nbsp_with_space(const String &p_string) {
|
||||
return p_string.replace(nbsp, " ");
|
||||
return p_string.replace_char(nbsp_chr, ' ');
|
||||
}
|
||||
|
||||
static String _fix_constant(const String &p_constant) {
|
||||
|
|
@ -192,37 +194,6 @@ static String _contextualize_class_specifier(const String &p_class_specifier, co
|
|||
|
||||
/// EditorHelp ///
|
||||
|
||||
// TODO: This is sometimes used directly as `doc->something`, other times as `EditorHelp::get_doc_data()`, which is thread-safe.
|
||||
// Might this be a problem?
|
||||
DocTools *EditorHelp::doc = nullptr;
|
||||
DocTools *EditorHelp::ext_doc = nullptr;
|
||||
|
||||
int EditorHelp::doc_generation_count = 0;
|
||||
String EditorHelp::doc_version_hash;
|
||||
Thread EditorHelp::worker_thread;
|
||||
|
||||
static bool _attempt_doc_load(const String &p_class) {
|
||||
// Docgen always happens in the outer-most class: it also generates docs for inner classes.
|
||||
const String outer_class = p_class.get_slicec('.', 0);
|
||||
if (!ScriptServer::is_global_class(outer_class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// `ResourceLoader` is used in order to have a script-agnostic way to load scripts.
|
||||
// This forces GDScript to compile the code, which is unnecessary for docgen, but it's a good compromise right now.
|
||||
const Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(outer_class), outer_class);
|
||||
if (script.is_valid()) {
|
||||
const Vector<DocData::ClassDoc> docs = script->get_documentation();
|
||||
for (int j = 0; j < docs.size(); j++) {
|
||||
const DocData::ClassDoc &doc = docs.get(j);
|
||||
EditorHelp::get_doc_data()->add_doc(doc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditorHelp::_update_theme_item_cache() {
|
||||
VBoxContainer::_update_theme_item_cache();
|
||||
|
||||
|
|
@ -705,8 +676,7 @@ void EditorHelp::_pop_code_font() {
|
|||
}
|
||||
|
||||
Error EditorHelp::_goto_desc(const String &p_class) {
|
||||
// If class doesn't have docs listed, attempt on-demand docgen
|
||||
if (!doc->class_list.has(p_class) && !_attempt_doc_load(p_class)) {
|
||||
if (!doc->class_list.has(p_class)) {
|
||||
return ERR_DOES_NOT_EXIST;
|
||||
}
|
||||
|
||||
|
|
@ -1127,7 +1097,7 @@ void EditorHelp::_update_doc() {
|
|||
class_desc->add_newline();
|
||||
class_desc->add_newline();
|
||||
|
||||
const String &csharp_differences_url = vformat("%s/tutorials/scripting/c_sharp/c_sharp_differences.html", VERSION_DOCS_URL);
|
||||
const String &csharp_differences_url = vformat("%s/tutorials/scripting/c_sharp/c_sharp_differences.html", GODOT_VERSION_DOCS_URL);
|
||||
|
||||
class_desc->push_indent(1);
|
||||
_push_normal_font();
|
||||
|
|
@ -1704,8 +1674,8 @@ void EditorHelp::_update_doc() {
|
|||
|
||||
for (KeyValue<String, Vector<DocData::ConstantDoc>> &E : enums) {
|
||||
String key = E.key;
|
||||
if ((key.get_slice_count(".") > 1) && (key.get_slice(".", 0) == edited_class)) {
|
||||
key = key.get_slice(".", 1);
|
||||
if ((key.get_slice_count(".") > 1) && (key.get_slicec('.', 0) == edited_class)) {
|
||||
key = key.get_slicec('.', 1);
|
||||
}
|
||||
if (cd.enums.has(key)) {
|
||||
const bool is_documented = cd.enums[key].is_deprecated || cd.enums[key].is_experimental || !cd.enums[key].description.strip_edges().is_empty();
|
||||
|
|
@ -1906,7 +1876,7 @@ void EditorHelp::_update_doc() {
|
|||
_push_code_font();
|
||||
|
||||
if (constant.value.begins_with("Color(") && constant.value.ends_with(")")) {
|
||||
String stripped = constant.value.replace(" ", "").replace("Color(", "").replace(")", "");
|
||||
String stripped = constant.value.remove_char(' ').replace("Color(", "").remove_char(')');
|
||||
PackedFloat64Array color = stripped.split_floats(",");
|
||||
if (color.size() >= 3) {
|
||||
class_desc->push_color(Color(color[0], color[1], color[2]));
|
||||
|
|
@ -2334,11 +2304,11 @@ void EditorHelp::_request_help(const String &p_string) {
|
|||
}
|
||||
|
||||
void EditorHelp::_help_callback(const String &p_topic) {
|
||||
String what = p_topic.get_slice(":", 0);
|
||||
String clss = p_topic.get_slice(":", 1);
|
||||
String what = p_topic.get_slicec(':', 0);
|
||||
String clss = p_topic.get_slicec(':', 1);
|
||||
String name;
|
||||
if (p_topic.get_slice_count(":") == 3) {
|
||||
name = p_topic.get_slice(":", 2);
|
||||
name = p_topic.get_slicec(':', 2);
|
||||
}
|
||||
|
||||
_request_help(clss); // First go to class.
|
||||
|
|
@ -2403,12 +2373,10 @@ void EditorHelp::_help_callback(const String &p_topic) {
|
|||
}
|
||||
|
||||
static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, const Control *p_owner_node, const String &p_class) {
|
||||
const DocTools *doc = EditorHelp::get_doc_data();
|
||||
|
||||
bool is_native = false;
|
||||
{
|
||||
const HashMap<String, DocData::ClassDoc>::ConstIterator E = doc->class_list.find(p_class);
|
||||
if (E && !E->value.is_script_doc) {
|
||||
const DocData::ClassDoc *E = EditorHelp::get_doc(p_class);
|
||||
if (E && !E->is_script_doc) {
|
||||
is_native = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2439,7 +2407,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, const C
|
|||
const Color kbd_bg_color = p_owner_node->get_theme_color(SNAME("kbd_bg_color"), SNAME("EditorHelp"));
|
||||
const Color param_bg_color = p_owner_node->get_theme_color(SNAME("param_bg_color"), SNAME("EditorHelp"));
|
||||
|
||||
String bbcode = p_bbcode.dedent().replace("\t", "").replace("\r", "").strip_edges();
|
||||
String bbcode = p_bbcode.dedent().remove_chars("\t\r").strip_edges();
|
||||
|
||||
// Select the correct code examples.
|
||||
switch ((int)EDITOR_GET("text_editor/help/class_reference_examples")) {
|
||||
|
|
@ -2517,7 +2485,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, const C
|
|||
int brk_end = bbcode.find_char(']', brk_pos + 1);
|
||||
|
||||
if (brk_end == -1) {
|
||||
p_rt->add_text(bbcode.substr(brk_pos, bbcode.length() - brk_pos).replace("\n", "\n\n"));
|
||||
p_rt->add_text(bbcode.substr(brk_pos).replace("\n", "\n\n"));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2622,7 +2590,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, const C
|
|||
p_rt->pop(); // font
|
||||
|
||||
pos = brk_end + 1;
|
||||
} else if (doc->class_list.has(tag)) {
|
||||
} else if (EditorHelp::has_doc(tag)) {
|
||||
// Use a monospace font for class reference tags such as [Node2D] or [SceneTree].
|
||||
|
||||
p_rt->push_font(doc_code_font);
|
||||
|
|
@ -2902,9 +2870,9 @@ void EditorHelp::_add_text(const String &p_bbcode) {
|
|||
_add_text_to_rt(p_bbcode, class_desc, this, edited_class);
|
||||
}
|
||||
|
||||
void EditorHelp::_wait_for_thread() {
|
||||
if (worker_thread.is_started()) {
|
||||
worker_thread.wait_to_finish();
|
||||
void EditorHelp::_wait_for_thread(Thread &p_thread) {
|
||||
if (p_thread.is_started()) {
|
||||
p_thread.wait_to_finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2914,7 +2882,53 @@ void EditorHelp::_compute_doc_version_hash() {
|
|||
}
|
||||
|
||||
String EditorHelp::get_cache_full_path() {
|
||||
return EditorPaths::get_singleton()->get_cache_dir().path_join(vformat("editor_doc_cache-%d.%d.res", VERSION_MAJOR, VERSION_MINOR));
|
||||
return EditorPaths::get_singleton()->get_cache_dir().path_join(vformat("editor_doc_cache-%d.%d.res", GODOT_VERSION_MAJOR, GODOT_VERSION_MINOR));
|
||||
}
|
||||
|
||||
String EditorHelp::get_script_doc_cache_full_path() {
|
||||
return EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_script_doc_cache.res");
|
||||
}
|
||||
|
||||
DocTools *EditorHelp::get_doc_data() {
|
||||
_wait_for_thread();
|
||||
return doc;
|
||||
}
|
||||
|
||||
bool EditorHelp::has_doc(const String &p_class_name) {
|
||||
return get_doc(p_class_name) != nullptr;
|
||||
}
|
||||
|
||||
DocData::ClassDoc *EditorHelp::get_doc(const String &p_class_name) {
|
||||
return get_doc_data()->class_list.getptr(p_class_name);
|
||||
}
|
||||
|
||||
void EditorHelp::add_doc(const DocData::ClassDoc &p_class_doc) {
|
||||
if (!_script_docs_loaded.is_set()) {
|
||||
_docs_to_add.push_back(p_class_doc);
|
||||
return;
|
||||
}
|
||||
|
||||
get_doc_data()->add_doc(p_class_doc);
|
||||
}
|
||||
|
||||
void EditorHelp::remove_doc(const String &p_class_name) {
|
||||
if (!_script_docs_loaded.is_set()) {
|
||||
_docs_to_remove.push_back(p_class_name);
|
||||
return;
|
||||
}
|
||||
|
||||
DocTools *dt = get_doc_data();
|
||||
if (dt->has_doc(p_class_name)) {
|
||||
dt->remove_doc(p_class_name);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorHelp::remove_script_doc_by_path(const String &p_path) {
|
||||
if (!_script_docs_loaded.is_set()) {
|
||||
_docs_to_remove_by_path.push_back(p_path);
|
||||
return;
|
||||
}
|
||||
get_doc_data()->remove_script_doc_by_path(p_path);
|
||||
}
|
||||
|
||||
void EditorHelp::load_xml_buffer(const uint8_t *p_buffer, int p_size) {
|
||||
|
|
@ -2935,23 +2949,26 @@ void EditorHelp::remove_class(const String &p_class) {
|
|||
}
|
||||
|
||||
if (doc && doc->has_doc(p_class)) {
|
||||
doc->remove_doc(p_class);
|
||||
remove_doc(p_class);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorHelp::_load_doc_thread(void *p_udata) {
|
||||
bool use_script_cache = (bool)p_udata;
|
||||
Ref<Resource> cache_res = ResourceLoader::load(get_cache_full_path());
|
||||
if (cache_res.is_valid() && cache_res->get_meta("version_hash", "") == doc_version_hash) {
|
||||
Array classes = cache_res->get_meta("classes", Array());
|
||||
for (int i = 0; i < classes.size(); i++) {
|
||||
doc->add_doc(DocData::ClassDoc::from_dict(classes[i]));
|
||||
}
|
||||
|
||||
if (use_script_cache) {
|
||||
callable_mp_static(&EditorHelp::load_script_doc_cache).call_deferred();
|
||||
}
|
||||
// Extensions' docs are not cached. Generate them now (on the main thread).
|
||||
callable_mp_static(&EditorHelp::_gen_extensions_docs).call_deferred();
|
||||
} else {
|
||||
// We have to go back to the main thread to start from scratch, bypassing any possibly existing cache.
|
||||
callable_mp_static(&EditorHelp::generate_doc).call_deferred(false);
|
||||
callable_mp_static(&EditorHelp::generate_doc).call_deferred(false, use_script_cache);
|
||||
}
|
||||
|
||||
OS::get_singleton()->benchmark_end_measure("EditorHelp", vformat("Generate Documentation (Run %d)", doc_generation_count));
|
||||
|
|
@ -2981,6 +2998,12 @@ void EditorHelp::_gen_doc_thread(void *p_udata) {
|
|||
ERR_PRINT("Cannot save editor help cache (" + get_cache_full_path() + ").");
|
||||
}
|
||||
|
||||
// Load script docs after native ones are cached so native cache doesn't contain script docs.
|
||||
bool use_script_cache = (bool)p_udata;
|
||||
if (use_script_cache) {
|
||||
callable_mp_static(&EditorHelp::load_script_doc_cache).call_deferred();
|
||||
}
|
||||
|
||||
OS::get_singleton()->benchmark_end_measure("EditorHelp", vformat("Generate Documentation (Run %d)", doc_generation_count));
|
||||
}
|
||||
|
||||
|
|
@ -2992,8 +3015,166 @@ void EditorHelp::_gen_extensions_docs() {
|
|||
doc->merge_from(*ext_doc);
|
||||
}
|
||||
}
|
||||
static void _load_script_doc_cache(bool p_changes) {
|
||||
EditorHelp::load_script_doc_cache();
|
||||
}
|
||||
|
||||
void EditorHelp::generate_doc(bool p_use_cache) {
|
||||
void EditorHelp::load_script_doc_cache() {
|
||||
if (!ProjectSettings::get_singleton()->is_project_loaded()) {
|
||||
print_verbose("Skipping loading script doc cache since no project is open.");
|
||||
return;
|
||||
}
|
||||
|
||||
_wait_for_thread();
|
||||
|
||||
if (!ResourceLoader::exists(get_script_doc_cache_full_path())) {
|
||||
print_verbose("Script documentation cache not found. Regenerating it may take a while for projects with many scripts.");
|
||||
regenerate_script_doc_cache();
|
||||
return;
|
||||
}
|
||||
|
||||
if (EditorFileSystem::get_singleton()->is_scanning()) {
|
||||
// This is assuming EditorFileSystem is performing first scan. We must wait until it is done.
|
||||
EditorFileSystem::get_singleton()->connect(SNAME("sources_changed"), callable_mp_static(_load_script_doc_cache), CONNECT_ONE_SHOT);
|
||||
return;
|
||||
}
|
||||
|
||||
worker_thread.start(_load_script_doc_cache_thread, nullptr);
|
||||
}
|
||||
|
||||
void EditorHelp::_process_postponed_docs() {
|
||||
for (const String &class_name : _docs_to_remove) {
|
||||
doc->remove_doc(class_name);
|
||||
}
|
||||
for (const String &path : _docs_to_remove_by_path) {
|
||||
doc->remove_script_doc_by_path(path);
|
||||
}
|
||||
for (const DocData::ClassDoc &cd : _docs_to_add) {
|
||||
doc->add_doc(cd);
|
||||
}
|
||||
_docs_to_add.clear();
|
||||
_docs_to_remove.clear();
|
||||
_docs_to_remove_by_path.clear();
|
||||
}
|
||||
|
||||
void EditorHelp::_load_script_doc_cache_thread(void *p_udata) {
|
||||
ERR_FAIL_COND_MSG(!ProjectSettings::get_singleton()->is_project_loaded(), "Error: cannot load script doc cache without a project.");
|
||||
ERR_FAIL_COND_MSG(!ResourceLoader::exists(get_script_doc_cache_full_path()), "Error: cannot load script doc cache from inexistent file.");
|
||||
|
||||
Ref<Resource> script_doc_cache_res = ResourceLoader::load(get_script_doc_cache_full_path(), "", ResourceFormatLoader::CACHE_MODE_IGNORE);
|
||||
if (script_doc_cache_res.is_null()) {
|
||||
print_verbose("Script doc cache is corrupted. Regenerating it instead.");
|
||||
_delete_script_doc_cache();
|
||||
callable_mp_static(EditorHelp::regenerate_script_doc_cache).call_deferred();
|
||||
return;
|
||||
}
|
||||
|
||||
Array classes = script_doc_cache_res->get_meta("classes", Array());
|
||||
for (const Dictionary dict : classes) {
|
||||
doc->add_doc(DocData::ClassDoc::from_dict(dict));
|
||||
}
|
||||
|
||||
// Protect from race condition in other threads reading / this thread writing to _docs_to_add/remove/etc.
|
||||
_script_docs_loaded.set();
|
||||
|
||||
// Deal with docs likely added from EditorFileSystem's scans while the cache was loading in EditorHelp::worker_thread.
|
||||
_process_postponed_docs();
|
||||
|
||||
// Always delete the doc cache after successful load since most uses of editor will change a script, invalidating cache.
|
||||
_delete_script_doc_cache();
|
||||
}
|
||||
|
||||
// Helper method to deal with "sources_changed" signal having a parameter.
|
||||
static void _regenerate_script_doc_cache(bool p_changes) {
|
||||
EditorHelp::regenerate_script_doc_cache();
|
||||
}
|
||||
|
||||
void EditorHelp::regenerate_script_doc_cache() {
|
||||
if (EditorFileSystem::get_singleton()->is_scanning()) {
|
||||
// Wait until EditorFileSystem scanning is complete to use updated filesystem structure.
|
||||
EditorFileSystem::get_singleton()->connect(SNAME("sources_changed"), callable_mp_static(_regenerate_script_doc_cache), CONNECT_ONE_SHOT);
|
||||
return;
|
||||
}
|
||||
|
||||
_wait_for_thread(worker_thread);
|
||||
_wait_for_thread(loader_thread);
|
||||
loader_thread.start(_regen_script_doc_thread, EditorFileSystem::get_singleton()->get_filesystem());
|
||||
}
|
||||
|
||||
// Runs on worker_thread since it writes to DocData.
|
||||
void EditorHelp::_finish_regen_script_doc_thread(void *p_udata) {
|
||||
loader_thread.wait_to_finish();
|
||||
_process_postponed_docs();
|
||||
_script_docs_loaded.set();
|
||||
|
||||
OS::get_singleton()->benchmark_end_measure("EditorHelp", "Generate Script Documentation");
|
||||
}
|
||||
|
||||
// Runs on loader_thread since _reload_scripts_documentation calls ResourceLoader::load().
|
||||
// Avoids deadlocks of worker_thread needing main thread for load task dispatching, but main thread waiting on worker_thread.
|
||||
void EditorHelp::_regen_script_doc_thread(void *p_udata) {
|
||||
OS::get_singleton()->benchmark_begin_measure("EditorHelp", "Generate Script Documentation");
|
||||
|
||||
EditorFileSystemDirectory *dir = static_cast<EditorFileSystemDirectory *>(p_udata);
|
||||
_script_docs_loaded.set_to(false);
|
||||
|
||||
// Ignore changes from filesystem scan since script docs will be now.
|
||||
_docs_to_add.clear();
|
||||
_docs_to_remove.clear();
|
||||
_docs_to_remove_by_path.clear();
|
||||
|
||||
_reload_scripts_documentation(dir);
|
||||
|
||||
// All ResourceLoader::load() calls are done, so we can no longer deadlock with main thread.
|
||||
// Switch to back to worker_thread from loader_thread to resynchronize access to DocData.
|
||||
worker_thread.start(_finish_regen_script_doc_thread, nullptr);
|
||||
}
|
||||
|
||||
void EditorHelp::_reload_scripts_documentation(EditorFileSystemDirectory *p_dir) {
|
||||
// Recursively force compile all scripts, which should generate their documentation.
|
||||
for (int i = 0; i < p_dir->get_subdir_count(); i++) {
|
||||
_reload_scripts_documentation(p_dir->get_subdir(i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_dir->get_file_count(); i++) {
|
||||
if (ClassDB::is_parent_class(p_dir->get_file_type(i), SNAME("Script"))) {
|
||||
Ref<Script> scr = ResourceLoader::load(p_dir->get_file_path(i));
|
||||
if (scr.is_valid()) {
|
||||
for (const DocData::ClassDoc &cd : scr->get_documentation()) {
|
||||
_docs_to_add.push_back(cd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorHelp::_delete_script_doc_cache() {
|
||||
if (FileAccess::exists(get_script_doc_cache_full_path())) {
|
||||
DirAccess::remove_file_or_error(ProjectSettings::get_singleton()->globalize_path(get_script_doc_cache_full_path()));
|
||||
}
|
||||
}
|
||||
|
||||
void EditorHelp::save_script_doc_cache() {
|
||||
if (!_script_docs_loaded.is_set()) {
|
||||
print_verbose("Script docs haven't been properly loaded or regenerated, so don't save them to disk.");
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<Resource> cache_res;
|
||||
cache_res.instantiate();
|
||||
Array classes;
|
||||
for (const KeyValue<String, DocData::ClassDoc> &E : doc->class_list) {
|
||||
if (E.value.is_script_doc) {
|
||||
classes.push_back(DocData::ClassDoc::to_dict(E.value));
|
||||
}
|
||||
}
|
||||
|
||||
cache_res->set_meta("classes", classes);
|
||||
Error err = ResourceSaver::save(cache_res, get_script_doc_cache_full_path(), ResourceSaver::FLAG_COMPRESS);
|
||||
ERR_FAIL_COND_MSG(err != OK, vformat("Cannot save script documentation cache in %s.", get_script_doc_cache_full_path()));
|
||||
}
|
||||
|
||||
void EditorHelp::generate_doc(bool p_use_cache, bool p_use_script_cache) {
|
||||
doc_generation_count++;
|
||||
OS::get_singleton()->benchmark_begin_measure("EditorHelp", vformat("Generate Documentation (Run %d)", doc_generation_count));
|
||||
|
||||
|
|
@ -3009,17 +3190,17 @@ void EditorHelp::generate_doc(bool p_use_cache) {
|
|||
}
|
||||
|
||||
if (p_use_cache && FileAccess::exists(get_cache_full_path())) {
|
||||
worker_thread.start(_load_doc_thread, nullptr);
|
||||
worker_thread.start(_load_doc_thread, (void *)p_use_script_cache);
|
||||
} else {
|
||||
print_verbose("Regenerating editor help cache");
|
||||
doc->generate();
|
||||
worker_thread.start(_gen_doc_thread, nullptr);
|
||||
worker_thread.start(_gen_doc_thread, (void *)p_use_script_cache);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorHelp::_toggle_scripts_pressed() {
|
||||
ScriptEditor::get_singleton()->toggle_scripts_panel();
|
||||
update_toggle_scripts_button();
|
||||
void EditorHelp::_toggle_files_pressed() {
|
||||
ScriptEditor::get_singleton()->toggle_files_panel();
|
||||
update_toggle_files_button();
|
||||
}
|
||||
|
||||
void EditorHelp::_notification(int p_what) {
|
||||
|
|
@ -3053,11 +3234,13 @@ void EditorHelp::_notification(int p_what) {
|
|||
if (is_inside_tree()) {
|
||||
_class_desc_resized(true);
|
||||
}
|
||||
update_toggle_scripts_button();
|
||||
update_toggle_files_button();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
|
||||
case NOTIFICATION_TRANSLATION_CHANGED:
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
update_toggle_scripts_button();
|
||||
update_toggle_files_button();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
|
@ -3126,13 +3309,13 @@ void EditorHelp::set_scroll(int p_scroll) {
|
|||
class_desc->get_v_scroll_bar()->set_value(p_scroll);
|
||||
}
|
||||
|
||||
void EditorHelp::update_toggle_scripts_button() {
|
||||
void EditorHelp::update_toggle_files_button() {
|
||||
if (is_layout_rtl()) {
|
||||
toggle_scripts_button->set_button_icon(get_editor_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Forward") : SNAME("Back")));
|
||||
toggle_files_button->set_button_icon(get_editor_theme_icon(ScriptEditor::get_singleton()->is_files_panel_toggled() ? SNAME("Forward") : SNAME("Back")));
|
||||
} else {
|
||||
toggle_scripts_button->set_button_icon(get_editor_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward")));
|
||||
toggle_files_button->set_button_icon(get_editor_theme_icon(ScriptEditor::get_singleton()->is_files_panel_toggled() ? SNAME("Back") : SNAME("Forward")));
|
||||
}
|
||||
toggle_scripts_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
|
||||
toggle_files_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Files Panel"), ED_GET_SHORTCUT("script_editor/toggle_files_panel")->get_as_text()));
|
||||
}
|
||||
|
||||
void EditorHelp::_bind_methods() {
|
||||
|
|
@ -3175,10 +3358,11 @@ EditorHelp::EditorHelp() {
|
|||
status_bar->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
status_bar->set_custom_minimum_size(Size2(0, 24 * EDSCALE));
|
||||
|
||||
toggle_scripts_button = memnew(Button);
|
||||
toggle_scripts_button->set_flat(true);
|
||||
toggle_scripts_button->connect(SceneStringName(pressed), callable_mp(this, &EditorHelp::_toggle_scripts_pressed));
|
||||
status_bar->add_child(toggle_scripts_button);
|
||||
toggle_files_button = memnew(Button);
|
||||
toggle_files_button->set_accessibility_name(TTRC("Scripts"));
|
||||
toggle_files_button->set_flat(true);
|
||||
toggle_files_button->connect(SceneStringName(pressed), callable_mp(this, &EditorHelp::_toggle_files_pressed));
|
||||
status_bar->add_child(toggle_files_button);
|
||||
|
||||
class_desc->set_selection_enabled(true);
|
||||
class_desc->set_context_menu_enabled(true);
|
||||
|
|
@ -3187,14 +3371,6 @@ EditorHelp::EditorHelp() {
|
|||
class_desc->hide();
|
||||
}
|
||||
|
||||
EditorHelp::~EditorHelp() {
|
||||
}
|
||||
|
||||
DocTools *EditorHelp::get_doc_data() {
|
||||
_wait_for_thread();
|
||||
return doc;
|
||||
}
|
||||
|
||||
/// EditorHelpBit ///
|
||||
|
||||
#define HANDLE_DOC(m_string) ((is_native ? DTR(m_string) : (m_string)).strip_edges())
|
||||
|
|
@ -3206,13 +3382,13 @@ EditorHelpBit::HelpData EditorHelpBit::_get_class_help_data(const StringName &p_
|
|||
|
||||
HelpData result;
|
||||
|
||||
const HashMap<String, DocData::ClassDoc>::ConstIterator E = EditorHelp::get_doc_data()->class_list.find(p_class_name);
|
||||
if (E) {
|
||||
const DocData::ClassDoc *class_doc = EditorHelp::get_doc(p_class_name);
|
||||
if (class_doc) {
|
||||
// Non-native class shouldn't be cached, nor translated.
|
||||
const bool is_native = !E->value.is_script_doc;
|
||||
const bool is_native = !class_doc->is_script_doc;
|
||||
|
||||
const String brief_description = HANDLE_DOC(E->value.brief_description);
|
||||
const String long_description = HANDLE_DOC(E->value.description);
|
||||
const String brief_description = HANDLE_DOC(class_doc->brief_description);
|
||||
const String long_description = HANDLE_DOC(class_doc->description);
|
||||
|
||||
if (!brief_description.is_empty()) {
|
||||
result.description += "[b]" + brief_description + "[/b]";
|
||||
|
|
@ -3223,18 +3399,18 @@ EditorHelpBit::HelpData EditorHelpBit::_get_class_help_data(const StringName &p_
|
|||
}
|
||||
result.description += long_description;
|
||||
}
|
||||
if (E->value.is_deprecated) {
|
||||
if (E->value.deprecated_message.is_empty()) {
|
||||
if (class_doc->is_deprecated) {
|
||||
if (class_doc->deprecated_message.is_empty()) {
|
||||
result.deprecated_message = TTR("This class may be changed or removed in future versions.");
|
||||
} else {
|
||||
result.deprecated_message = HANDLE_DOC(E->value.deprecated_message);
|
||||
result.deprecated_message = HANDLE_DOC(class_doc->deprecated_message);
|
||||
}
|
||||
}
|
||||
if (E->value.is_experimental) {
|
||||
if (E->value.experimental_message.is_empty()) {
|
||||
if (class_doc->is_experimental) {
|
||||
if (class_doc->experimental_message.is_empty()) {
|
||||
result.experimental_message = TTR("This class may be changed or removed in future versions.");
|
||||
} else {
|
||||
result.experimental_message = HANDLE_DOC(E->value.experimental_message);
|
||||
result.experimental_message = HANDLE_DOC(class_doc->experimental_message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3253,13 +3429,12 @@ EditorHelpBit::HelpData EditorHelpBit::_get_enum_help_data(const StringName &p_c
|
|||
|
||||
HelpData result;
|
||||
|
||||
const DocTools *dd = EditorHelp::get_doc_data();
|
||||
const HashMap<String, DocData::ClassDoc>::ConstIterator E = dd->class_list.find(p_class_name);
|
||||
if (E) {
|
||||
const DocData::ClassDoc *class_doc = EditorHelp::get_doc(p_class_name);
|
||||
if (class_doc) {
|
||||
// Non-native enums shouldn't be cached, nor translated.
|
||||
const bool is_native = !E->value.is_script_doc;
|
||||
const bool is_native = !class_doc->is_script_doc;
|
||||
|
||||
for (const KeyValue<String, DocData::EnumDoc> &kv : E->value.enums) {
|
||||
for (const KeyValue<String, DocData::EnumDoc> &kv : class_doc->enums) {
|
||||
const StringName enum_name = kv.key;
|
||||
const DocData::EnumDoc &enum_doc = kv.value;
|
||||
|
||||
|
|
@ -3304,13 +3479,12 @@ EditorHelpBit::HelpData EditorHelpBit::_get_constant_help_data(const StringName
|
|||
|
||||
HelpData result;
|
||||
|
||||
const DocTools *dd = EditorHelp::get_doc_data();
|
||||
const HashMap<String, DocData::ClassDoc>::ConstIterator E = dd->class_list.find(p_class_name);
|
||||
if (E) {
|
||||
const DocData::ClassDoc *class_doc = EditorHelp::get_doc(p_class_name);
|
||||
if (class_doc) {
|
||||
// Non-native constants shouldn't be cached, nor translated.
|
||||
const bool is_native = !E->value.is_script_doc;
|
||||
const bool is_native = !class_doc->is_script_doc;
|
||||
|
||||
for (const DocData::ConstantDoc &constant : E->value.constants) {
|
||||
for (const DocData::ConstantDoc &constant : class_doc->constants) {
|
||||
HelpData current;
|
||||
current.description = HANDLE_DOC(constant.description);
|
||||
if (constant.is_deprecated) {
|
||||
|
|
@ -3356,13 +3530,12 @@ EditorHelpBit::HelpData EditorHelpBit::_get_property_help_data(const StringName
|
|||
|
||||
HelpData result;
|
||||
|
||||
const DocTools *dd = EditorHelp::get_doc_data();
|
||||
const HashMap<String, DocData::ClassDoc>::ConstIterator E = dd->class_list.find(p_class_name);
|
||||
if (E) {
|
||||
const DocData::ClassDoc *class_doc = EditorHelp::get_doc(p_class_name);
|
||||
if (class_doc) {
|
||||
// Non-native properties shouldn't be cached, nor translated.
|
||||
const bool is_native = !E->value.is_script_doc;
|
||||
const bool is_native = !class_doc->is_script_doc;
|
||||
|
||||
for (const DocData::PropertyDoc &property : E->value.properties) {
|
||||
for (const DocData::PropertyDoc &property : class_doc->properties) {
|
||||
HelpData current;
|
||||
current.description = HANDLE_DOC(property.description);
|
||||
if (property.is_deprecated) {
|
||||
|
|
@ -3397,10 +3570,10 @@ EditorHelpBit::HelpData EditorHelpBit::_get_property_help_data(const StringName
|
|||
|
||||
if (!enum_class_name.is_empty() && !enum_name.is_empty()) {
|
||||
// Classes can use enums from other classes, so check from which it came.
|
||||
const HashMap<String, DocData::ClassDoc>::ConstIterator enum_class = dd->class_list.find(enum_class_name);
|
||||
const DocData::ClassDoc *enum_class = EditorHelp::get_doc(enum_class_name);
|
||||
if (enum_class) {
|
||||
const String enum_prefix = EditorPropertyNameProcessor::get_singleton()->process_name(enum_name, EditorPropertyNameProcessor::STYLE_CAPITALIZED) + " ";
|
||||
for (DocData::ConstantDoc constant : enum_class->value.constants) {
|
||||
for (DocData::ConstantDoc constant : enum_class->constants) {
|
||||
// Don't display `_MAX` enum value descriptions, as these are never exposed in the inspector.
|
||||
if (constant.enumeration == enum_name && !constant.name.ends_with("_MAX")) {
|
||||
// Prettify the enum value display, so that "<ENUM_NAME>_<ITEM>" becomes "Item".
|
||||
|
|
@ -3441,13 +3614,12 @@ EditorHelpBit::HelpData EditorHelpBit::_get_theme_item_help_data(const StringNam
|
|||
HelpData result;
|
||||
|
||||
bool found = false;
|
||||
const DocTools *dd = EditorHelp::get_doc_data();
|
||||
HashMap<String, DocData::ClassDoc>::ConstIterator E = dd->class_list.find(p_class_name);
|
||||
while (E) {
|
||||
DocData::ClassDoc *class_doc = EditorHelp::get_doc(p_class_name);
|
||||
while (class_doc) {
|
||||
// Non-native theme items shouldn't be cached, nor translated.
|
||||
const bool is_native = !E->value.is_script_doc;
|
||||
const bool is_native = !class_doc->is_script_doc;
|
||||
|
||||
for (const DocData::ThemeItemDoc &theme_item : E->value.theme_properties) {
|
||||
for (const DocData::ThemeItemDoc &theme_item : class_doc->theme_properties) {
|
||||
HelpData current;
|
||||
current.description = HANDLE_DOC(theme_item.description);
|
||||
if (theme_item.is_deprecated) {
|
||||
|
|
@ -3481,12 +3653,12 @@ EditorHelpBit::HelpData EditorHelpBit::_get_theme_item_help_data(const StringNam
|
|||
}
|
||||
}
|
||||
|
||||
if (found || E->value.inherits.is_empty()) {
|
||||
if (found || class_doc->inherits.is_empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for inherited theme items.
|
||||
E = dd->class_list.find(E->value.inherits);
|
||||
class_doc = EditorHelp::get_doc(class_doc->inherits);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -3499,12 +3671,12 @@ EditorHelpBit::HelpData EditorHelpBit::_get_method_help_data(const StringName &p
|
|||
|
||||
HelpData result;
|
||||
|
||||
const HashMap<String, DocData::ClassDoc>::ConstIterator E = EditorHelp::get_doc_data()->class_list.find(p_class_name);
|
||||
if (E) {
|
||||
const DocData::ClassDoc *class_doc = EditorHelp::get_doc(p_class_name);
|
||||
if (class_doc) {
|
||||
// Non-native methods shouldn't be cached, nor translated.
|
||||
const bool is_native = !E->value.is_script_doc;
|
||||
const bool is_native = !class_doc->is_script_doc;
|
||||
|
||||
for (const DocData::MethodDoc &method : E->value.methods) {
|
||||
for (const DocData::MethodDoc &method : class_doc->methods) {
|
||||
HelpData current;
|
||||
current.description = HANDLE_DOC(method.description);
|
||||
if (method.is_deprecated) {
|
||||
|
|
@ -3552,12 +3724,12 @@ EditorHelpBit::HelpData EditorHelpBit::_get_signal_help_data(const StringName &p
|
|||
|
||||
HelpData result;
|
||||
|
||||
const HashMap<String, DocData::ClassDoc>::ConstIterator E = EditorHelp::get_doc_data()->class_list.find(p_class_name);
|
||||
if (E) {
|
||||
const DocData::ClassDoc *class_doc = EditorHelp::get_doc(p_class_name);
|
||||
if (class_doc) {
|
||||
// Non-native signals shouldn't be cached, nor translated.
|
||||
const bool is_native = !E->value.is_script_doc;
|
||||
const bool is_native = !class_doc->is_script_doc;
|
||||
|
||||
for (const DocData::MethodDoc &signal : E->value.signals) {
|
||||
for (const DocData::MethodDoc &signal : class_doc->signals) {
|
||||
HelpData current;
|
||||
current.description = HANDLE_DOC(signal.description);
|
||||
if (signal.is_deprecated) {
|
||||
|
|
@ -3604,12 +3776,12 @@ EditorHelpBit::HelpData EditorHelpBit::_get_annotation_help_data(const StringNam
|
|||
|
||||
HelpData result;
|
||||
|
||||
const HashMap<String, DocData::ClassDoc>::ConstIterator E = EditorHelp::get_doc_data()->class_list.find(p_class_name);
|
||||
if (E) {
|
||||
const DocData::ClassDoc *class_doc = EditorHelp::get_doc(p_class_name);
|
||||
if (class_doc) {
|
||||
// Non-native annotations shouldn't be cached, nor translated.
|
||||
const bool is_native = !E->value.is_script_doc;
|
||||
const bool is_native = !class_doc->is_script_doc;
|
||||
|
||||
for (const DocData::MethodDoc &annotation : E->value.annotations) {
|
||||
for (const DocData::MethodDoc &annotation : class_doc->annotations) {
|
||||
HelpData current;
|
||||
current.description = HANDLE_DOC(annotation.description);
|
||||
if (annotation.is_deprecated) {
|
||||
|
|
@ -3699,8 +3871,7 @@ void EditorHelpBit::_update_labels() {
|
|||
// Nothing to do.
|
||||
} break;
|
||||
case SYMBOL_HINT_INHERITANCE: {
|
||||
const HashMap<String, DocData::ClassDoc> &class_list = EditorHelp::get_doc_data()->class_list;
|
||||
const DocData::ClassDoc *class_doc = class_list.getptr(symbol_class_name);
|
||||
const DocData::ClassDoc *class_doc = EditorHelp::get_doc(symbol_class_name);
|
||||
String inherits = class_doc ? class_doc->inherits : String();
|
||||
|
||||
if (!inherits.is_empty()) {
|
||||
|
|
@ -3714,7 +3885,7 @@ void EditorHelpBit::_update_labels() {
|
|||
|
||||
_add_type_to_title({ inherits, String(), false });
|
||||
|
||||
const DocData::ClassDoc *base_class_doc = class_list.getptr(inherits);
|
||||
const DocData::ClassDoc *base_class_doc = EditorHelp::get_doc(inherits);
|
||||
inherits = base_class_doc ? base_class_doc->inherits : String();
|
||||
}
|
||||
|
||||
|
|
@ -3989,11 +4160,7 @@ void EditorHelpBit::_meta_clicked(const String &p_select) {
|
|||
String path = ProjectSettings::get_singleton()->globalize_path(p_select.trim_prefix("open-file:"));
|
||||
OS::get_singleton()->shell_show_in_file_manager(path, true);
|
||||
} else if (p_select.begins_with("open-res:")) {
|
||||
if (help_data.doc_type.type == "PackedScene") {
|
||||
EditorNode::get_singleton()->load_scene(p_select.trim_prefix("open-res:"));
|
||||
} else {
|
||||
EditorNode::get_singleton()->load_resource(p_select.trim_prefix("open-res:"));
|
||||
}
|
||||
EditorNode::get_singleton()->load_scene_or_resource(p_select.trim_prefix("open-res:"));
|
||||
} else if (p_select.begins_with("show:")) {
|
||||
FileSystemDock::get_singleton()->navigate_to_path(p_select.trim_prefix("show:"));
|
||||
} else if (p_select.begins_with("http:") || p_select.begins_with("https:")) {
|
||||
|
|
@ -4390,7 +4557,7 @@ void EditorHelpBitTooltip::popup_under_cursor() {
|
|||
// When `FLAG_POPUP` is false, it prevents the editor from losing focus when displaying the tooltip.
|
||||
// This way, clicks and double-clicks are still available outside the tooltip.
|
||||
set_flag(Window::FLAG_POPUP, false);
|
||||
set_flag(Window::FLAG_NO_FOCUS, true);
|
||||
set_flag(Window::FLAG_NO_FOCUS, !is_embedded());
|
||||
popup(r);
|
||||
}
|
||||
|
||||
|
|
@ -4410,7 +4577,6 @@ EditorHelpBitTooltip::EditorHelpBitTooltip(Control *p_target) {
|
|||
set_process_internal(true);
|
||||
}
|
||||
|
||||
#if defined(MODULE_GDSCRIPT_ENABLED) || defined(MODULE_MONO_ENABLED)
|
||||
/// EditorHelpHighlighter ///
|
||||
|
||||
EditorHelpHighlighter *EditorHelpHighlighter::singleton = nullptr;
|
||||
|
|
@ -4576,12 +4742,11 @@ EditorHelpHighlighter::~EditorHelpHighlighter() {
|
|||
#endif
|
||||
}
|
||||
|
||||
#endif // defined(MODULE_GDSCRIPT_ENABLED) || defined(MODULE_MONO_ENABLED)
|
||||
|
||||
/// FindBar ///
|
||||
|
||||
FindBar::FindBar() {
|
||||
search_text = memnew(LineEdit);
|
||||
search_text->set_accessibility_name(TTRC("Search help"));
|
||||
add_child(search_text);
|
||||
search_text->set_keep_editing_on_text_submit(true);
|
||||
search_text->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
|
||||
|
|
@ -4594,12 +4759,14 @@ FindBar::FindBar() {
|
|||
matches_label->hide();
|
||||
|
||||
find_prev = memnew(Button);
|
||||
find_prev->set_accessibility_name(TTRC("Find Previous"));
|
||||
find_prev->set_flat(true);
|
||||
add_child(find_prev);
|
||||
find_prev->set_focus_mode(FOCUS_NONE);
|
||||
find_prev->connect(SceneStringName(pressed), callable_mp(this, &FindBar::search_prev));
|
||||
|
||||
find_next = memnew(Button);
|
||||
find_next->set_accessibility_name(TTRC("Find Next"));
|
||||
find_next->set_flat(true);
|
||||
add_child(find_next);
|
||||
find_next->set_focus_mode(FOCUS_NONE);
|
||||
|
|
@ -4611,6 +4778,7 @@ FindBar::FindBar() {
|
|||
|
||||
hide_button = memnew(TextureButton);
|
||||
add_child(hide_button);
|
||||
hide_button->set_accessibility_name(TTRC("Hide"));
|
||||
hide_button->set_focus_mode(FOCUS_NONE);
|
||||
hide_button->set_ignore_texture_size(true);
|
||||
hide_button->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_HELP_H
|
||||
#define EDITOR_HELP_H
|
||||
#pragma once
|
||||
|
||||
#include "core/os/thread.h"
|
||||
#include "editor/doc_tools.h"
|
||||
|
|
@ -41,8 +40,6 @@
|
|||
#include "scene/gui/text_edit.h"
|
||||
#include "scene/main/timer.h"
|
||||
|
||||
#include "modules/modules_enabled.gen.h" // For gdscript, mono.
|
||||
|
||||
class FindBar : public HBoxContainer {
|
||||
GDCLASS(FindBar, HBoxContainer);
|
||||
|
||||
|
|
@ -83,6 +80,8 @@ public:
|
|||
FindBar();
|
||||
};
|
||||
|
||||
class EditorFileSystemDirectory;
|
||||
|
||||
class EditorHelp : public VBoxContainer {
|
||||
GDCLASS(EditorHelp, VBoxContainer);
|
||||
|
||||
|
|
@ -112,14 +111,14 @@ class EditorHelp : public VBoxContainer {
|
|||
|
||||
RichTextLabel *class_desc = nullptr;
|
||||
HSplitContainer *h_split = nullptr;
|
||||
static DocTools *doc;
|
||||
static DocTools *ext_doc;
|
||||
inline static DocTools *doc = nullptr;
|
||||
inline static DocTools *ext_doc = nullptr;
|
||||
|
||||
ConfirmationDialog *search_dialog = nullptr;
|
||||
LineEdit *search = nullptr;
|
||||
FindBar *find_bar = nullptr;
|
||||
HBoxContainer *status_bar = nullptr;
|
||||
Button *toggle_scripts_button = nullptr;
|
||||
Button *toggle_files_button = nullptr;
|
||||
|
||||
String base_path;
|
||||
|
||||
|
|
@ -186,16 +185,28 @@ class EditorHelp : public VBoxContainer {
|
|||
void _request_help(const String &p_string);
|
||||
void _search(bool p_search_previous = false);
|
||||
|
||||
void _toggle_scripts_pressed();
|
||||
void _toggle_files_pressed();
|
||||
|
||||
static int doc_generation_count;
|
||||
static String doc_version_hash;
|
||||
static Thread worker_thread;
|
||||
inline static int doc_generation_count = 0;
|
||||
inline static String doc_version_hash;
|
||||
inline static Thread worker_thread;
|
||||
inline static Thread loader_thread; // Only load scripts here to avoid deadlocking with main thread.
|
||||
|
||||
static void _wait_for_thread();
|
||||
inline static SafeFlag _script_docs_loaded = SafeFlag(false);
|
||||
inline static LocalVector<DocData::ClassDoc> _docs_to_add;
|
||||
inline static LocalVector<String> _docs_to_remove;
|
||||
inline static LocalVector<String> _docs_to_remove_by_path;
|
||||
|
||||
static void _wait_for_thread(Thread &p_thread = worker_thread);
|
||||
static void _load_doc_thread(void *p_udata);
|
||||
static void _gen_doc_thread(void *p_udata);
|
||||
static void _gen_extensions_docs();
|
||||
static void _process_postponed_docs();
|
||||
static void _load_script_doc_cache_thread(void *p_udata);
|
||||
static void _regen_script_doc_thread(void *p_udata);
|
||||
static void _finish_regen_script_doc_thread(void *p_udata);
|
||||
static void _reload_scripts_documentation(EditorFileSystemDirectory *p_dir);
|
||||
static void _delete_script_doc_cache();
|
||||
static void _compute_doc_version_hash();
|
||||
|
||||
struct PropertyCompare {
|
||||
|
|
@ -215,10 +226,23 @@ protected:
|
|||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static void generate_doc(bool p_use_cache = true);
|
||||
static DocTools *get_doc_data();
|
||||
static void generate_doc(bool p_use_cache = true, bool p_use_script_cache = true);
|
||||
static void cleanup_doc();
|
||||
static void load_script_doc_cache();
|
||||
static void regenerate_script_doc_cache();
|
||||
static void save_script_doc_cache();
|
||||
static String get_cache_full_path();
|
||||
static String get_script_doc_cache_full_path();
|
||||
|
||||
// Adding scripts to DocData directly may make script doc cache inconsistent. Use methods below when adding script docs.
|
||||
// Usage during startup can also cause deadlocks.
|
||||
static DocTools *get_doc_data();
|
||||
// Method forwarding to underlying DocTools to keep script doc cache consistent.
|
||||
static DocData::ClassDoc *get_doc(const String &p_class_name);
|
||||
static void add_doc(const DocData::ClassDoc &p_class_doc);
|
||||
static void remove_doc(const String &p_class_name);
|
||||
static void remove_script_doc_by_path(const String &p_path);
|
||||
static bool has_doc(const String &p_class_name);
|
||||
|
||||
static void load_xml_buffer(const uint8_t *p_buffer, int p_size);
|
||||
static void remove_class(const String &p_class);
|
||||
|
|
@ -240,12 +264,11 @@ public:
|
|||
int get_scroll() const;
|
||||
void set_scroll(int p_scroll);
|
||||
|
||||
void update_toggle_scripts_button();
|
||||
void update_toggle_files_button();
|
||||
|
||||
static void init_gdext_pointers();
|
||||
|
||||
EditorHelp();
|
||||
~EditorHelp();
|
||||
};
|
||||
|
||||
class EditorHelpBit : public VBoxContainer {
|
||||
|
|
@ -361,7 +384,6 @@ public:
|
|||
EditorHelpBitTooltip(Control *p_target);
|
||||
};
|
||||
|
||||
#if defined(MODULE_GDSCRIPT_ENABLED) || defined(MODULE_MONO_ENABLED)
|
||||
class EditorSyntaxHighlighter;
|
||||
|
||||
class EditorHelpHighlighter {
|
||||
|
|
@ -396,6 +418,3 @@ public:
|
|||
EditorHelpHighlighter();
|
||||
virtual ~EditorHelpHighlighter();
|
||||
};
|
||||
#endif // defined(MODULE_GDSCRIPT_ENABLED) || defined(MODULE_MONO_ENABLED)
|
||||
|
||||
#endif // EDITOR_HELP_H
|
||||
|
|
|
|||
|
|
@ -328,6 +328,7 @@ EditorHelpSearch::EditorHelpSearch() {
|
|||
vbox->add_child(hbox);
|
||||
|
||||
search_box = memnew(LineEdit);
|
||||
search_box->set_accessibility_name(TTRC("Search"));
|
||||
search_box->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
|
||||
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
search_box->set_clear_button_enabled(true);
|
||||
|
|
@ -339,6 +340,7 @@ EditorHelpSearch::EditorHelpSearch() {
|
|||
case_sensitive_button = memnew(Button);
|
||||
case_sensitive_button->set_theme_type_variation(SceneStringName(FlatButton));
|
||||
case_sensitive_button->set_tooltip_text(TTR("Case Sensitive"));
|
||||
case_sensitive_button->set_accessibility_name(TTRC("Case Sensitive"));
|
||||
case_sensitive_button->connect(SceneStringName(pressed), callable_mp(this, &EditorHelpSearch::_update_results));
|
||||
case_sensitive_button->set_toggle_mode(true);
|
||||
case_sensitive_button->set_focus_mode(Control::FOCUS_NONE);
|
||||
|
|
@ -347,6 +349,7 @@ EditorHelpSearch::EditorHelpSearch() {
|
|||
hierarchy_button = memnew(Button);
|
||||
hierarchy_button->set_theme_type_variation(SceneStringName(FlatButton));
|
||||
hierarchy_button->set_tooltip_text(TTR("Show Hierarchy"));
|
||||
hierarchy_button->set_accessibility_name(TTRC("Show Hierarchy"));
|
||||
hierarchy_button->connect(SceneStringName(pressed), callable_mp(this, &EditorHelpSearch::_update_results));
|
||||
hierarchy_button->set_toggle_mode(true);
|
||||
hierarchy_button->set_pressed(true);
|
||||
|
|
@ -354,6 +357,7 @@ EditorHelpSearch::EditorHelpSearch() {
|
|||
hbox->add_child(hierarchy_button);
|
||||
|
||||
filter_combo = memnew(OptionButton);
|
||||
filter_combo->set_accessibility_name(TTRC("Filter"));
|
||||
filter_combo->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
|
||||
filter_combo->set_stretch_ratio(0); // Fixed width.
|
||||
filter_combo->add_item(TTR("Display All"), SEARCH_ALL);
|
||||
|
|
@ -372,6 +376,7 @@ EditorHelpSearch::EditorHelpSearch() {
|
|||
|
||||
// Create the results tree.
|
||||
results_tree = memnew(Tree);
|
||||
results_tree->set_accessibility_name(TTRC("Search Results"));
|
||||
results_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
results_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
results_tree->set_columns(2);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_HELP_SEARCH_H
|
||||
#define EDITOR_HELP_SEARCH_H
|
||||
#pragma once
|
||||
|
||||
#include "editor/plugins/editor_plugin.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
|
|
@ -212,5 +211,3 @@ public:
|
|||
|
||||
Runner(Control *p_icon_service, Tree *p_results_tree, TreeCache *p_tree_cache, const String &p_term, int p_search_flags);
|
||||
};
|
||||
|
||||
#endif // EDITOR_HELP_SEARCH_H
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "core/os/keyboard.h"
|
||||
#include "editor/add_metadata_dialog.h"
|
||||
#include "editor/debugger/editor_debugger_inspector.h"
|
||||
#include "editor/doc_tools.h"
|
||||
#include "editor/editor_feature_profile.h"
|
||||
#include "editor/editor_main_screen.h"
|
||||
|
|
@ -252,6 +253,25 @@ void EditorProperty::emit_changed(const StringName &p_property, const Variant &p
|
|||
|
||||
void EditorProperty::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_BUTTON);
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_name(ae, vformat(TTR("Property: %s"), label));
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, vformat(TTR("Property: %s"), label));
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_popup_type(ae, DisplayServer::AccessibilityPopupType::POPUP_MENU);
|
||||
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SHOW_CONTEXT_MENU, callable_mp(this, &EditorProperty::_accessibility_action_menu));
|
||||
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_CLICK, callable_mp(this, &EditorProperty::_accessibility_action_click));
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_flag(ae, DisplayServer::AccessibilityFlags::FLAG_READONLY, read_only);
|
||||
if (checkable) {
|
||||
DisplayServer::get_singleton()->accessibility_update_set_checked(ae, checked);
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SORT_CHILDREN: {
|
||||
Size2 size = get_size();
|
||||
Rect2 rect;
|
||||
|
|
@ -578,6 +598,12 @@ void EditorProperty::_notification(int p_what) {
|
|||
}
|
||||
} break;
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
EditorInspector *inspector = get_parent_inspector();
|
||||
if (inspector) {
|
||||
inspector = inspector->get_root_inspector();
|
||||
}
|
||||
set_shortcut_context(inspector);
|
||||
|
||||
if (has_borders) {
|
||||
get_parent()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorProperty::_update_property_bg));
|
||||
_update_property_bg();
|
||||
|
|
@ -617,6 +643,16 @@ StringName EditorProperty::get_edited_property() const {
|
|||
return property;
|
||||
}
|
||||
|
||||
Variant EditorProperty::get_edited_property_display_value() const {
|
||||
ERR_FAIL_NULL_V(object, Variant());
|
||||
Control *control = Object::cast_to<Control>(object);
|
||||
if (checkable && !checked && control && String(property).begins_with("theme_override_")) {
|
||||
return control->get_used_theme_item(property);
|
||||
} else {
|
||||
return get_edited_property_value();
|
||||
}
|
||||
}
|
||||
|
||||
EditorInspector *EditorProperty::get_parent_inspector() const {
|
||||
Node *parent = get_parent();
|
||||
while (parent) {
|
||||
|
|
@ -769,9 +805,7 @@ bool EditorProperty::use_keying_next() const {
|
|||
List<PropertyInfo> plist;
|
||||
object->get_property_list(&plist, true);
|
||||
|
||||
for (List<PropertyInfo>::Element *I = plist.front(); I; I = I->next()) {
|
||||
PropertyInfo &p = I->get();
|
||||
|
||||
for (const PropertyInfo &p : plist) {
|
||||
if (p.name == property) {
|
||||
return (p.usage & PROPERTY_USAGE_KEYING_INCREMENTS);
|
||||
}
|
||||
|
|
@ -918,6 +952,9 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
|
|||
|
||||
if (me.is_valid()) {
|
||||
Vector2 mpos = me->get_position();
|
||||
if (bottom_child_rect.has_point(mpos)) {
|
||||
return; // Makes child EditorProperties behave like sibling nodes when handling mouse events.
|
||||
}
|
||||
if (is_layout_rtl()) {
|
||||
mpos.x = get_size().x - mpos.x;
|
||||
}
|
||||
|
|
@ -1013,6 +1050,22 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
}
|
||||
|
||||
void EditorProperty::_accessibility_action_click(const Variant &p_data) {
|
||||
select();
|
||||
if (checkable) {
|
||||
checked = !checked;
|
||||
queue_redraw();
|
||||
emit_signal(SNAME("property_checked"), property, checked);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorProperty::_accessibility_action_menu(const Variant &p_data) {
|
||||
_update_popup();
|
||||
menu->set_position(get_screen_position());
|
||||
menu->reset_size();
|
||||
menu->popup();
|
||||
}
|
||||
|
||||
void EditorProperty::shortcut_input(const Ref<InputEvent> &p_event) {
|
||||
if (!selected || !p_event->is_pressed()) {
|
||||
return;
|
||||
|
|
@ -1250,6 +1303,19 @@ void EditorProperty::menu_option(int p_option) {
|
|||
emit_signal(SNAME("property_pinned"), property, !pinned);
|
||||
queue_redraw();
|
||||
} break;
|
||||
case MENU_DELETE: {
|
||||
accept_event();
|
||||
emit_signal(SNAME("property_deleted"), property);
|
||||
} break;
|
||||
case MENU_REVERT_VALUE: {
|
||||
accept_event();
|
||||
get_viewport()->gui_release_focus();
|
||||
bool is_valid_revert = false;
|
||||
Variant revert_value = EditorPropertyRevert::get_property_revert_value(object, property, &is_valid_revert);
|
||||
ERR_FAIL_COND(!is_valid_revert);
|
||||
emit_changed(_get_revert_property(), revert_value);
|
||||
update_property();
|
||||
} break;
|
||||
case MENU_OPEN_DOCUMENTATION: {
|
||||
ScriptEditor::get_singleton()->goto_help(doc_path);
|
||||
EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_SCRIPT);
|
||||
|
|
@ -1343,6 +1409,8 @@ void EditorProperty::_bind_methods() {
|
|||
}
|
||||
|
||||
EditorProperty::EditorProperty() {
|
||||
set_focus_mode(FOCUS_ACCESSIBILITY);
|
||||
|
||||
object = nullptr;
|
||||
split_ratio = 0.5;
|
||||
text_size = 0;
|
||||
|
|
@ -1377,6 +1445,7 @@ void EditorProperty::_update_popup() {
|
|||
menu->add_icon_item(get_editor_theme_icon(SNAME("Unfavorite")), TTR("Unfavorite Property"), MENU_FAVORITE_PROPERTY);
|
||||
menu->set_item_tooltip(menu->get_item_index(MENU_FAVORITE_PROPERTY), TTR("Make this property be put back at its original place."));
|
||||
} else {
|
||||
// TRANSLATORS: This is a menu item to add a property to the favorites.
|
||||
menu->add_icon_item(get_editor_theme_icon(SNAME("Favorites")), TTR("Favorite Property"), MENU_FAVORITE_PROPERTY);
|
||||
menu->set_item_tooltip(menu->get_item_index(MENU_FAVORITE_PROPERTY), TTR("Make this property be placed at the top for all objects of this class."));
|
||||
}
|
||||
|
|
@ -1392,7 +1461,15 @@ void EditorProperty::_update_popup() {
|
|||
}
|
||||
menu->set_item_tooltip(menu->get_item_index(MENU_PIN_VALUE), TTR("Pinning a value forces it to be saved even if it's equal to the default."));
|
||||
}
|
||||
|
||||
if (deletable || can_revert) {
|
||||
menu->add_separator();
|
||||
if (deletable) {
|
||||
menu->add_icon_item(get_editor_theme_icon(SNAME("Remove")), TTR("Delete Property"), MENU_PIN_VALUE);
|
||||
}
|
||||
if (can_revert) {
|
||||
menu->add_icon_item(get_editor_theme_icon(SNAME("Reload")), TTR("Revert Value"), MENU_REVERT_VALUE);
|
||||
}
|
||||
}
|
||||
if (!doc_path.is_empty()) {
|
||||
menu->add_separator();
|
||||
menu->add_icon_item(get_editor_theme_icon(SNAME("Help")), TTR("Open Documentation"), MENU_OPEN_DOCUMENTATION);
|
||||
|
|
@ -1471,6 +1548,19 @@ void EditorInspectorPlugin::_bind_methods() {
|
|||
|
||||
void EditorInspectorCategory::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_BUTTON);
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_name(ae, vformat(TTR("Category: %s"), label));
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, vformat(TTR("Category: %s"), label));
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_popup_type(ae, DisplayServer::AccessibilityPopupType::POPUP_MENU);
|
||||
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SHOW_CONTEXT_MENU, callable_mp(this, &EditorInspectorCategory::_accessibility_action_menu));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
if (menu) {
|
||||
if (is_favorite) {
|
||||
|
|
@ -1524,6 +1614,22 @@ void EditorInspectorCategory::_notification(int p_what) {
|
|||
}
|
||||
}
|
||||
|
||||
void EditorInspectorCategory::_accessibility_action_menu(const Variant &p_data) {
|
||||
if (!is_favorite) {
|
||||
if (!menu) {
|
||||
menu = memnew(PopupMenu);
|
||||
menu->add_icon_item(get_editor_theme_icon(SNAME("Help")), TTR("Open Documentation"), MENU_OPEN_DOCS);
|
||||
add_child(menu);
|
||||
menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorInspectorCategory::_handle_menu_option));
|
||||
}
|
||||
menu->set_item_disabled(menu->get_item_index(MENU_OPEN_DOCS), !EditorHelp::get_doc_data()->class_list.has(doc_class_name));
|
||||
}
|
||||
|
||||
menu->set_position(get_screen_position());
|
||||
menu->reset_size();
|
||||
menu->popup();
|
||||
}
|
||||
|
||||
Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) const {
|
||||
// If it's not a doc tooltip, fallback to the default one.
|
||||
if (doc_class_name.is_empty()) {
|
||||
|
|
@ -1594,6 +1700,10 @@ void EditorInspectorCategory::gui_input(const Ref<InputEvent> &p_event) {
|
|||
menu->popup();
|
||||
}
|
||||
|
||||
EditorInspectorCategory::EditorInspectorCategory() {
|
||||
set_focus_mode(FOCUS_ACCESSIBILITY);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////
|
||||
|
||||
|
|
@ -1637,10 +1747,24 @@ int EditorInspectorSection::_get_header_height() {
|
|||
|
||||
void EditorInspectorSection::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_BUTTON);
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_name(ae, vformat(TTR("Section: %s"), label));
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, vformat(TTR("Section: %s"), label));
|
||||
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_COLLAPSE, callable_mp(this, &EditorInspectorSection::_accessibility_action_collapse));
|
||||
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_EXPAND, callable_mp(this, &EditorInspectorSection::_accessibility_action_expand));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
update_minimum_size();
|
||||
bg_color = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor));
|
||||
bg_color.a /= level;
|
||||
int separation = get_theme_constant(SNAME("v_separation"), SNAME("EditorInspector"));
|
||||
vbox->add_theme_constant_override(SNAME("separation"), separation);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SORT_CHILDREN: {
|
||||
|
|
@ -1864,6 +1988,20 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) {
|
|||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventKey> k = p_event;
|
||||
if (k.is_valid() && k->is_pressed()) {
|
||||
if (k->is_action("ui_accept", true)) {
|
||||
accept_event();
|
||||
|
||||
bool should_unfold = !object->editor_is_section_unfolded(section);
|
||||
if (should_unfold) {
|
||||
unfold();
|
||||
} else {
|
||||
fold();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventMouseButton> mb = p_event;
|
||||
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
|
||||
if (object->editor_is_section_unfolded(section)) {
|
||||
|
|
@ -1885,6 +2023,15 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) {
|
|||
} else if (mb.is_valid() && !mb->is_pressed()) {
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
Ref<InputEventMouseMotion> mm = p_event;
|
||||
if (mm.is_valid()) {
|
||||
int header_height = _get_header_height();
|
||||
Vector2 previous = mm->get_position() - mm->get_relative();
|
||||
if ((mm->get_position().y >= header_height) != (previous.y >= header_height)) {
|
||||
queue_redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String EditorInspectorSection::get_section() const {
|
||||
|
|
@ -1895,6 +2042,14 @@ VBoxContainer *EditorInspectorSection::get_vbox() {
|
|||
return vbox;
|
||||
}
|
||||
|
||||
void EditorInspectorSection::_accessibility_action_collapse(const Variant &p_data) {
|
||||
fold();
|
||||
}
|
||||
|
||||
void EditorInspectorSection::_accessibility_action_expand(const Variant &p_data) {
|
||||
unfold();
|
||||
}
|
||||
|
||||
void EditorInspectorSection::unfold() {
|
||||
if (!foldable) {
|
||||
return;
|
||||
|
|
@ -1926,6 +2081,12 @@ void EditorInspectorSection::set_bg_color(const Color &p_bg_color) {
|
|||
queue_redraw();
|
||||
}
|
||||
|
||||
void EditorInspectorSection::reset_timer() {
|
||||
if (dropping_for_unfold && !dropping_unfold_timer->is_stopped()) {
|
||||
dropping_unfold_timer->start();
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorInspectorSection::has_revertable_properties() const {
|
||||
return !revertable_properties.is_empty();
|
||||
}
|
||||
|
|
@ -1950,6 +2111,8 @@ void EditorInspectorSection::_bind_methods() {
|
|||
}
|
||||
|
||||
EditorInspectorSection::EditorInspectorSection() {
|
||||
set_focus_mode(FOCUS_ACCESSIBILITY);
|
||||
|
||||
vbox = memnew(VBoxContainer);
|
||||
|
||||
dropping_unfold_timer = memnew(Timer);
|
||||
|
|
@ -2063,6 +2226,18 @@ void EditorInspectorArray::_panel_draw(int p_index) {
|
|||
}
|
||||
}
|
||||
|
||||
void EditorInspectorArray::_panel_gui_focus(int p_index) {
|
||||
array_elements[p_index].panel->queue_redraw();
|
||||
selected = p_index;
|
||||
}
|
||||
|
||||
void EditorInspectorArray::_panel_gui_unfocus(int p_index) {
|
||||
array_elements[p_index].panel->queue_redraw();
|
||||
if (selected == p_index) {
|
||||
selected = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int p_index) {
|
||||
ERR_FAIL_INDEX(p_index, (int)array_elements.size());
|
||||
|
||||
|
|
@ -2087,13 +2262,22 @@ void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int p_index
|
|||
popup_array_index_pressed = begin_array_index + p_index;
|
||||
rmb_popup->set_item_disabled(OPTION_MOVE_UP, popup_array_index_pressed == 0);
|
||||
rmb_popup->set_item_disabled(OPTION_MOVE_DOWN, popup_array_index_pressed == count - 1);
|
||||
rmb_popup->set_position(get_screen_position() + mb->get_position());
|
||||
rmb_popup->set_position(array_elements[p_index].panel->get_screen_position() + mb->get_position());
|
||||
rmb_popup->reset_size();
|
||||
rmb_popup->popup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorInspectorArray::show_menu(int p_index, const Vector2 &p_offset) {
|
||||
popup_array_index_pressed = begin_array_index + p_index;
|
||||
rmb_popup->set_item_disabled(OPTION_MOVE_UP, popup_array_index_pressed == 0);
|
||||
rmb_popup->set_item_disabled(OPTION_MOVE_DOWN, popup_array_index_pressed == count - 1);
|
||||
rmb_popup->set_position(get_screen_position() + p_offset);
|
||||
rmb_popup->reset_size();
|
||||
rmb_popup->popup();
|
||||
}
|
||||
|
||||
void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
|
||||
String action_name;
|
||||
if (p_element_index < 0) {
|
||||
|
|
@ -2193,10 +2377,8 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
|
|||
undo_redo->add_undo_property(object, count_property, properties_as_array.size());
|
||||
for (int i = 0; i < (int)properties_as_array.size(); i++) {
|
||||
Dictionary d = Dictionary(properties_as_array[i]);
|
||||
Array keys = d.keys();
|
||||
for (int j = 0; j < keys.size(); j++) {
|
||||
String key = keys[j];
|
||||
undo_redo->add_undo_property(object, vformat(key, i), d[key]);
|
||||
for (const KeyValue<Variant, Variant> &kv : d) {
|
||||
undo_redo->add_undo_property(object, vformat(kv.key, i), kv.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2216,10 +2398,8 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
|
|||
undo_redo->add_do_property(object, count_property, properties_as_array.size());
|
||||
for (int i = 0; i < (int)properties_as_array.size(); i++) {
|
||||
Dictionary d = properties_as_array[i];
|
||||
Array keys = d.keys();
|
||||
for (int j = 0; j < keys.size(); j++) {
|
||||
String key = keys[j];
|
||||
undo_redo->add_do_property(object, vformat(key, i), d[key]);
|
||||
for (const KeyValue<Variant, Variant> &kv : d) {
|
||||
undo_redo->add_do_property(object, vformat(kv.key, i), kv.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2270,10 +2450,8 @@ void EditorInspectorArray::_clear_array() {
|
|||
undo_redo->add_undo_property(object, count_property, count);
|
||||
for (int i = 0; i < (int)properties_as_array.size(); i++) {
|
||||
Dictionary d = Dictionary(properties_as_array[i]);
|
||||
Array keys = d.keys();
|
||||
for (int j = 0; j < keys.size(); j++) {
|
||||
String key = keys[j];
|
||||
undo_redo->add_undo_property(object, vformat(key, i), d[key]);
|
||||
for (const KeyValue<Variant, Variant> &kv : d) {
|
||||
undo_redo->add_undo_property(object, vformat(kv.key, i), kv.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2335,10 +2513,8 @@ void EditorInspectorArray::_resize_array(int p_size) {
|
|||
undo_redo->add_undo_property(object, count_property, count);
|
||||
for (int i = count - 1; i > p_size - 1; i--) {
|
||||
Dictionary d = Dictionary(properties_as_array[i]);
|
||||
Array keys = d.keys();
|
||||
for (int j = 0; j < keys.size(); j++) {
|
||||
String key = keys[j];
|
||||
undo_redo->add_undo_property(object, vformat(key, i), d[key]);
|
||||
for (const KeyValue<Variant, Variant> &kv : d) {
|
||||
undo_redo->add_undo_property(object, vformat(kv.key, i), kv.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2462,16 +2638,20 @@ void EditorInspectorArray::_setup() {
|
|||
ArrayElement &ae = array_elements[i];
|
||||
|
||||
// Panel and its hbox.
|
||||
ae.panel = memnew(PanelContainer);
|
||||
ae.panel = memnew(ArrayPanelContainer);
|
||||
ae.panel->set_focus_mode(FOCUS_ALL);
|
||||
ae.panel->set_mouse_filter(MOUSE_FILTER_PASS);
|
||||
SET_DRAG_FORWARDING_GCD(ae.panel, EditorInspectorArray);
|
||||
|
||||
int element_position = begin_array_index + i;
|
||||
String ae_name = vformat(TTR("Element %d: %s%d*"), element_position, array_element_prefix, element_position);
|
||||
|
||||
ae.panel->set_meta("index", element_position);
|
||||
ae.panel->set_tooltip_text(vformat(TTR("Element %d: %s%d*"), element_position, array_element_prefix, element_position));
|
||||
ae.panel->connect(SceneStringName(focus_entered), callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw));
|
||||
ae.panel->connect(SceneStringName(focus_exited), callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw));
|
||||
ae.panel->set_meta("name", ae_name);
|
||||
ae.panel->set_meta("element", this);
|
||||
ae.panel->set_tooltip_text(ae_name);
|
||||
ae.panel->connect(SceneStringName(focus_entered), callable_mp(this, &EditorInspectorArray::_panel_gui_focus).bind(i));
|
||||
ae.panel->connect(SceneStringName(focus_exited), callable_mp(this, &EditorInspectorArray::_panel_gui_unfocus).bind(i));
|
||||
ae.panel->connect(SceneStringName(draw), callable_mp(this, &EditorInspectorArray::_panel_draw).bind(i));
|
||||
ae.panel->connect(SceneStringName(gui_input), callable_mp(this, &EditorInspectorArray::_panel_gui_input).bind(i));
|
||||
ae.panel->add_theme_style_override(SceneStringName(panel), i % 2 ? odd_style : even_style);
|
||||
|
|
@ -2504,6 +2684,7 @@ void EditorInspectorArray::_setup() {
|
|||
|
||||
if (element_position > 0) {
|
||||
ae.move_up = memnew(Button);
|
||||
ae.move_up->set_accessibility_name(TTRC("Move Up"));
|
||||
ae.move_up->set_button_icon(get_editor_theme_icon(SNAME("MoveUp")));
|
||||
ae.move_up->connect(SceneStringName(pressed), callable_mp(this, &EditorInspectorArray::_move_element).bind(element_position, element_position - 1));
|
||||
move_vbox->add_child(ae.move_up);
|
||||
|
|
@ -2520,6 +2701,7 @@ void EditorInspectorArray::_setup() {
|
|||
|
||||
if (element_position < count - 1) {
|
||||
ae.move_down = memnew(Button);
|
||||
ae.move_down->set_accessibility_name(TTRC("Move Down"));
|
||||
ae.move_down->set_button_icon(get_editor_theme_icon(SNAME("MoveDown")));
|
||||
ae.move_down->connect(SceneStringName(pressed), callable_mp(this, &EditorInspectorArray::_move_element).bind(element_position, element_position + 2));
|
||||
move_vbox->add_child(ae.move_down);
|
||||
|
|
@ -2544,6 +2726,7 @@ void EditorInspectorArray::_setup() {
|
|||
|
||||
if (!unresizable) {
|
||||
ae.erase = memnew(Button);
|
||||
ae.erase->set_accessibility_name(TTRC("Remove"));
|
||||
ae.erase->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
|
||||
ae.erase->set_v_size_flags(SIZE_SHRINK_CENTER);
|
||||
ae.erase->connect(SceneStringName(pressed), callable_mp(this, &EditorInspectorArray::_remove_item).bind(element_position));
|
||||
|
|
@ -2584,7 +2767,7 @@ void EditorInspectorArray::drop_data_fw(const Point2 &p_point, const Variant &p_
|
|||
Dictionary dict = p_data;
|
||||
|
||||
int to_drop = dict["index"];
|
||||
int drop_position = _drop_position();
|
||||
int drop_position = (p_point == Vector2(Math::INF, Math::INF)) ? selected : _drop_position();
|
||||
if (drop_position < 0) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -2602,7 +2785,7 @@ bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant
|
|||
return false;
|
||||
}
|
||||
Dictionary dict = p_data;
|
||||
int drop_position = _drop_position();
|
||||
int drop_position = (p_point == Vector2(Math::INF, Math::INF)) ? selected : _drop_position();
|
||||
if (!dict.has("type") || dict["type"] != "property_array_element" || String(dict["property_array_prefix"]) != array_element_prefix || drop_position < 0) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2614,8 +2797,45 @@ bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant
|
|||
return drop_array_index != moved_array_index && drop_array_index - 1 != moved_array_index;
|
||||
}
|
||||
|
||||
void ArrayPanelContainer::_accessibility_action_menu(const Variant &p_data) {
|
||||
EditorInspectorArray *el = Object::cast_to<EditorInspectorArray>(get_meta("element"));
|
||||
if (el) {
|
||||
int index = get_meta("index");
|
||||
el->show_menu(index, Vector2());
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayPanelContainer::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_BUTTON);
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_name(ae, get_meta("text"));
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, get_meta("text"));
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_popup_type(ae, DisplayServer::AccessibilityPopupType::POPUP_MENU);
|
||||
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SHOW_CONTEXT_MENU, callable_mp(this, &ArrayPanelContainer::_accessibility_action_menu));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayPanelContainer::ArrayPanelContainer() {
|
||||
set_focus_mode(FOCUS_ACCESSIBILITY);
|
||||
}
|
||||
|
||||
void EditorInspectorArray::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_name(ae, vformat(TTR("Array: %s"), get_label()));
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, vformat(TTR("Array: %s"), get_label()));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_ENTER_TREE:
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
Color color = get_theme_color(SNAME("dark_color_1"), EditorStringName(Editor));
|
||||
|
|
@ -2715,12 +2935,11 @@ VBoxContainer *EditorInspectorArray::get_vbox(int p_index) {
|
|||
EditorInspectorArray::EditorInspectorArray(bool p_read_only) {
|
||||
read_only = p_read_only;
|
||||
|
||||
set_mouse_filter(Control::MOUSE_FILTER_STOP);
|
||||
|
||||
odd_style.instantiate();
|
||||
even_style.instantiate();
|
||||
|
||||
rmb_popup = memnew(PopupMenu);
|
||||
rmb_popup->set_accessibility_name(TTRC("Move"));
|
||||
rmb_popup->add_item(TTR("Move Up"), OPTION_MOVE_UP);
|
||||
rmb_popup->add_item(TTR("Move Down"), OPTION_MOVE_DOWN);
|
||||
rmb_popup->add_separator();
|
||||
|
|
@ -2758,6 +2977,7 @@ EditorInspectorArray::EditorInspectorArray(bool p_read_only) {
|
|||
resize_dialog->add_child(resize_dialog_vbox);
|
||||
|
||||
new_size_spin_box = memnew(SpinBox);
|
||||
new_size_spin_box->set_accessibility_name(TTRC("Size"));
|
||||
new_size_spin_box->set_max(16384);
|
||||
new_size_spin_box->connect(SceneStringName(value_changed), callable_mp(this, &EditorInspectorArray::_new_size_spin_box_value_changed));
|
||||
new_size_spin_box->get_line_edit()->connect(SceneStringName(text_submitted), callable_mp(this, &EditorInspectorArray::_new_size_spin_box_text_submitted));
|
||||
|
|
@ -2833,16 +3053,19 @@ EditorPaginator::EditorPaginator() {
|
|||
set_alignment(ALIGNMENT_CENTER);
|
||||
|
||||
first_page_button = memnew(Button);
|
||||
first_page_button->set_accessibility_name(TTRC("First Page"));
|
||||
first_page_button->set_flat(true);
|
||||
first_page_button->connect(SceneStringName(pressed), callable_mp(this, &EditorPaginator::_first_page_button_pressed));
|
||||
add_child(first_page_button);
|
||||
|
||||
prev_page_button = memnew(Button);
|
||||
prev_page_button->set_accessibility_name(TTRC("Previuos Page"));
|
||||
prev_page_button->set_flat(true);
|
||||
prev_page_button->connect(SceneStringName(pressed), callable_mp(this, &EditorPaginator::_prev_page_button_pressed));
|
||||
add_child(prev_page_button);
|
||||
|
||||
page_line_edit = memnew(LineEdit);
|
||||
page_line_edit->set_accessibility_name(TTRC("Page"));
|
||||
page_line_edit->connect(SceneStringName(text_submitted), callable_mp(this, &EditorPaginator::_page_line_edit_text_submitted));
|
||||
page_line_edit->add_theme_constant_override("minimum_character_width", 2);
|
||||
add_child(page_line_edit);
|
||||
|
|
@ -2851,11 +3074,13 @@ EditorPaginator::EditorPaginator() {
|
|||
add_child(page_count_label);
|
||||
|
||||
next_page_button = memnew(Button);
|
||||
prev_page_button->set_accessibility_name(TTRC("Next Page"));
|
||||
next_page_button->set_flat(true);
|
||||
next_page_button->connect(SceneStringName(pressed), callable_mp(this, &EditorPaginator::_next_page_button_pressed));
|
||||
add_child(next_page_button);
|
||||
|
||||
last_page_button = memnew(Button);
|
||||
last_page_button->set_accessibility_name(TTRC("Last Page"));
|
||||
last_page_button->set_flat(true);
|
||||
last_page_button->connect(SceneStringName(pressed), callable_mp(this, &EditorPaginator::_last_page_button_pressed));
|
||||
add_child(last_page_button);
|
||||
|
|
@ -2968,7 +3193,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorIn
|
|||
ep->connect("property_pinned", callable_mp(this, &EditorInspector::_property_pinned));
|
||||
ep->connect("selected", callable_mp(this, &EditorInspector::_property_selected));
|
||||
ep->connect("multiple_properties_changed", callable_mp(this, &EditorInspector::_multiple_properties_changed));
|
||||
ep->connect("resource_selected", callable_mp(this, &EditorInspector::_resource_selected), CONNECT_DEFERRED);
|
||||
ep->connect("resource_selected", callable_mp(get_root_inspector(), &EditorInspector::_resource_selected), CONNECT_DEFERRED);
|
||||
ep->connect("object_id_selected", callable_mp(this, &EditorInspector::_object_id_selected), CONNECT_DEFERRED);
|
||||
|
||||
if (F.properties.size()) {
|
||||
|
|
@ -3040,15 +3265,21 @@ bool EditorInspector::_is_property_disabled_by_feature_profile(const StringName
|
|||
}
|
||||
|
||||
void EditorInspector::update_tree() {
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool root_inspector_was_following_focus = get_root_inspector()->is_following_focus();
|
||||
if (root_inspector_was_following_focus) {
|
||||
// Temporarily disable focus following on the root inspector to avoid jumping while the inspector is updating.
|
||||
get_root_inspector()->set_follow_focus(false);
|
||||
}
|
||||
|
||||
// Store currently selected and focused elements to restore after the update.
|
||||
// TODO: Can be useful to store more context for the focusable, such as the caret position in LineEdit.
|
||||
StringName current_selected = property_selected;
|
||||
int current_focusable = -1;
|
||||
|
||||
// Temporarily disable focus following on the root inspector to avoid jumping while the inspector is updating.
|
||||
bool was_following = get_root_inspector()->is_following_focus();
|
||||
get_root_inspector()->set_follow_focus(false);
|
||||
|
||||
if (property_focusable != -1) {
|
||||
// Check that focusable is actually focusable.
|
||||
bool restore_focus = false;
|
||||
|
|
@ -3070,14 +3301,9 @@ void EditorInspector::update_tree() {
|
|||
}
|
||||
}
|
||||
|
||||
// Only hide plugins if we are not editing any object.
|
||||
// This should be handled outside of the update_tree call anyway (see EditorInspector::edit), but might as well keep it safe.
|
||||
_clear(!object);
|
||||
|
||||
if (!object) {
|
||||
get_root_inspector()->set_follow_focus(was_following);
|
||||
return;
|
||||
}
|
||||
// The call here is for the edited object that has not changed, but the tree needs to be updated (for example, the object's property list has been modified).
|
||||
// Since the edited object has not changed, there is no need to hide the plugin at this time.
|
||||
_clear(false);
|
||||
|
||||
List<Ref<EditorInspectorPlugin>> valid_plugins;
|
||||
|
||||
|
|
@ -3132,13 +3358,14 @@ void EditorInspector::update_tree() {
|
|||
Color sscolor = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor));
|
||||
bool sub_inspectors_enabled = EDITOR_GET("interface/inspector/open_resources_in_current_inspector");
|
||||
|
||||
// Get the lists of editors to add the beginning.
|
||||
for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
|
||||
ped->parse_begin(object);
|
||||
_parse_added_editors(begin_vbox, nullptr, ped);
|
||||
}
|
||||
if (begin_vbox->get_child_count()) {
|
||||
if (!valid_plugins.is_empty()) {
|
||||
begin_vbox->show();
|
||||
|
||||
// Get the lists of editors to add the beginning.
|
||||
for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
|
||||
ped->parse_begin(object);
|
||||
_parse_added_editors(begin_vbox, nullptr, ped);
|
||||
}
|
||||
}
|
||||
|
||||
StringName doc_name;
|
||||
|
|
@ -3440,6 +3667,8 @@ void EditorInspector::update_tree() {
|
|||
// Recreate the category vbox if it was reset.
|
||||
if (category_vbox == nullptr) {
|
||||
category_vbox = memnew(VBoxContainer);
|
||||
int separation = get_theme_constant(SNAME("v_separation"), SNAME("EditorInspector"));
|
||||
category_vbox->add_theme_constant_override(SNAME("separation"), separation);
|
||||
category_vbox->hide();
|
||||
main_vbox->add_child(category_vbox);
|
||||
}
|
||||
|
|
@ -3467,6 +3696,7 @@ void EditorInspector::update_tree() {
|
|||
if (!vbox_per_path[root_vbox].has(acc_path)) {
|
||||
// If the section does not exists, create it.
|
||||
EditorInspectorSection *section = memnew(EditorInspectorSection);
|
||||
get_root_inspector()->get_v_scroll_bar()->connect(SceneStringName(value_changed), callable_mp(section, &EditorInspectorSection::reset_timer).unbind(1));
|
||||
current_vbox->add_child(section);
|
||||
sections.push_back(section);
|
||||
|
||||
|
|
@ -3535,9 +3765,9 @@ void EditorInspector::update_tree() {
|
|||
String swap_method;
|
||||
for (int i = (p.type == Variant::NIL ? 1 : 2); i < class_name_components.size(); i++) {
|
||||
if (class_name_components[i].begins_with("page_size") && class_name_components[i].get_slice_count("=") == 2) {
|
||||
page_size = class_name_components[i].get_slice("=", 1).to_int();
|
||||
page_size = class_name_components[i].get_slicec('=', 1).to_int();
|
||||
} else if (class_name_components[i].begins_with("add_button_text") && class_name_components[i].get_slice_count("=") == 2) {
|
||||
add_button_text = class_name_components[i].get_slice("=", 1).strip_edges();
|
||||
add_button_text = class_name_components[i].get_slicec('=', 1).strip_edges();
|
||||
} else if (class_name_components[i] == "static") {
|
||||
movable = false;
|
||||
} else if (class_name_components[i] == "const") {
|
||||
|
|
@ -3547,7 +3777,7 @@ void EditorInspector::update_tree() {
|
|||
} else if (class_name_components[i] == "unfoldable") {
|
||||
foldable = false;
|
||||
} else if (class_name_components[i].begins_with("swap_method") && class_name_components[i].get_slice_count("=") == 2) {
|
||||
swap_method = class_name_components[i].get_slice("=", 1).strip_edges();
|
||||
swap_method = class_name_components[i].get_slicec('=', 1).strip_edges();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3807,7 +4037,7 @@ void EditorInspector::update_tree() {
|
|||
ep->connect("property_pinned", callable_mp(this, &EditorInspector::_property_pinned));
|
||||
ep->connect("selected", callable_mp(this, &EditorInspector::_property_selected));
|
||||
ep->connect("multiple_properties_changed", callable_mp(this, &EditorInspector::_multiple_properties_changed));
|
||||
ep->connect("resource_selected", callable_mp(this, &EditorInspector::_resource_selected), CONNECT_DEFERRED);
|
||||
ep->connect("resource_selected", callable_mp(get_root_inspector(), &EditorInspector::_resource_selected), CONNECT_DEFERRED);
|
||||
ep->connect("object_id_selected", callable_mp(this, &EditorInspector::_object_id_selected), CONNECT_DEFERRED);
|
||||
|
||||
if (use_doc_hints) {
|
||||
|
|
@ -3867,6 +4097,7 @@ void EditorInspector::update_tree() {
|
|||
}
|
||||
|
||||
EditorInspectorSection *section = memnew(EditorInspectorSection);
|
||||
get_root_inspector()->get_v_scroll_bar()->connect(SceneStringName(value_changed), callable_mp(section, &EditorInspectorSection::reset_timer).unbind(1));
|
||||
favorites_groups_vbox->add_child(section);
|
||||
parent_vbox = section->get_vbox();
|
||||
section->setup("", section_name, object, sscolor, false);
|
||||
|
|
@ -3886,6 +4117,7 @@ void EditorInspector::update_tree() {
|
|||
}
|
||||
|
||||
EditorInspectorSection *section = memnew(EditorInspectorSection);
|
||||
get_root_inspector()->get_v_scroll_bar()->connect(SceneStringName(value_changed), callable_mp(section, &EditorInspectorSection::reset_timer).unbind(1));
|
||||
vbox->add_child(section);
|
||||
vbox = section->get_vbox();
|
||||
section->setup("", section_name, object, sscolor, false);
|
||||
|
|
@ -3918,8 +4150,9 @@ void EditorInspector::update_tree() {
|
|||
}
|
||||
|
||||
// Clean up empty sections.
|
||||
for (List<EditorInspectorSection *>::Element *I = sections.back(); I; I = I->prev()) {
|
||||
for (List<EditorInspectorSection *>::Element *I = sections.back(); I;) {
|
||||
EditorInspectorSection *section = I->get();
|
||||
I = I->prev(); // Note: Advance before erasing element.
|
||||
if (section->get_vbox()->get_child_count() == 0) {
|
||||
sections.erase(section);
|
||||
vbox_per_path[main_vbox].erase(section->get_section());
|
||||
|
|
@ -3954,7 +4187,9 @@ void EditorInspector::update_tree() {
|
|||
EditorNode::get_singleton()->hide_unused_editors();
|
||||
}
|
||||
|
||||
get_root_inspector()->set_follow_focus(was_following);
|
||||
if (root_inspector_was_following_focus) {
|
||||
get_root_inspector()->set_follow_focus(true);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorInspector::update_property(const String &p_prop) {
|
||||
|
|
@ -4271,6 +4506,10 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
|
|||
Object::cast_to<MultiNodeEdit>(object)->set_property_field(p_name, p_value, p_changed_field);
|
||||
_edit_request_change(object, p_name);
|
||||
emit_signal(_prop_edited, p_name);
|
||||
} else if (Object::cast_to<EditorDebuggerRemoteObjects>(object)) {
|
||||
Object::cast_to<EditorDebuggerRemoteObjects>(object)->set_property_field(p_name, p_value, p_changed_field);
|
||||
_edit_request_change(object, p_name);
|
||||
emit_signal(_prop_edited, p_name);
|
||||
} else {
|
||||
undo_redo->create_action(vformat(TTR("Set %s"), p_name), UndoRedo::MERGE_ENDS);
|
||||
undo_redo->add_do_property(object, p_name, p_value);
|
||||
|
|
@ -4450,13 +4689,26 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) {
|
|||
_edit_set(p_path, Variant(), false, "");
|
||||
} else {
|
||||
Variant to_create;
|
||||
List<PropertyInfo> pinfo;
|
||||
object->get_property_list(&pinfo);
|
||||
for (const PropertyInfo &E : pinfo) {
|
||||
if (E.name == p_path) {
|
||||
Callable::CallError ce;
|
||||
Variant::construct(E.type, to_create, nullptr, 0, ce);
|
||||
break;
|
||||
Control *control = Object::cast_to<Control>(object);
|
||||
bool skip = false;
|
||||
if (control && p_path.begins_with("theme_override_")) {
|
||||
to_create = control->get_used_theme_item(p_path);
|
||||
Ref<Resource> resource = to_create;
|
||||
if (resource.is_valid()) {
|
||||
to_create = resource->duplicate();
|
||||
}
|
||||
skip = true;
|
||||
}
|
||||
|
||||
if (!skip) {
|
||||
List<PropertyInfo> pinfo;
|
||||
object->get_property_list(&pinfo);
|
||||
for (const PropertyInfo &E : pinfo) {
|
||||
if (E.name == p_path) {
|
||||
Callable::CallError ce;
|
||||
Variant::construct(E.type, to_create, nullptr, 0, ce);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_edit_set(p_path, to_create, false, "");
|
||||
|
|
@ -4528,14 +4780,6 @@ void EditorInspector::_node_removed(Node *p_node) {
|
|||
}
|
||||
}
|
||||
|
||||
void EditorInspector::_gui_focus_changed(Control *p_control) {
|
||||
if (!is_visible_in_tree() && !is_following_focus()) {
|
||||
return;
|
||||
}
|
||||
// Don't follow focus when the inspector nor any of its children is focused. Prevents potential jumping when gaining focus.
|
||||
set_follow_focus(has_focus() || child_has_focus());
|
||||
}
|
||||
|
||||
void EditorInspector::_update_current_favorites() {
|
||||
current_favorites.clear();
|
||||
if (!can_favorite) {
|
||||
|
|
@ -4608,7 +4852,7 @@ void EditorInspector::_set_property_favorited(const String &p_path, bool p_favor
|
|||
|
||||
String theme_property;
|
||||
if (p_path.begins_with("theme_override_")) {
|
||||
theme_property = p_path.get_slice("/", 1);
|
||||
theme_property = p_path.get_slicec('/', 1);
|
||||
}
|
||||
|
||||
while (!validate_name.is_empty()) {
|
||||
|
|
@ -4712,9 +4956,25 @@ void EditorInspector::_clear_current_favorites() {
|
|||
update_tree();
|
||||
}
|
||||
|
||||
void EditorInspector::_update_theme() {
|
||||
updating_theme = true;
|
||||
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
|
||||
updating_theme = false;
|
||||
}
|
||||
|
||||
void EditorInspector::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_TRANSLATION_CHANGED: {
|
||||
if (property_name_style == EditorPropertyNameProcessor::STYLE_LOCALIZED) {
|
||||
update_tree_pending = true;
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
if (updating_theme) {
|
||||
break;
|
||||
}
|
||||
|
||||
favorites_category->icon = get_editor_theme_icon(SNAME("Favorites"));
|
||||
|
||||
int separation = get_theme_constant(SNAME("v_separation"), SNAME("EditorInspector"));
|
||||
|
|
@ -4729,14 +4989,15 @@ void EditorInspector::_notification(int p_what) {
|
|||
ERR_FAIL_NULL(EditorFeatureProfileManager::get_singleton());
|
||||
EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &EditorInspector::_feature_profile_changed));
|
||||
set_process(is_visible_in_tree());
|
||||
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
|
||||
get_parent()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorInspector::_update_theme));
|
||||
_update_theme();
|
||||
if (!is_sub_inspector()) {
|
||||
get_tree()->connect("node_removed", callable_mp(this, &EditorInspector::_node_removed));
|
||||
}
|
||||
} break;
|
||||
|
||||
Viewport *viewport = get_viewport();
|
||||
ERR_FAIL_NULL(viewport);
|
||||
viewport->connect("gui_focus_changed", callable_mp(this, &EditorInspector::_gui_focus_changed));
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
get_parent()->disconnect(SceneStringName(theme_changed), callable_mp(this, &EditorInspector::_update_theme));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_PREDELETE: {
|
||||
|
|
@ -4798,25 +5059,20 @@ void EditorInspector::_notification(int p_what) {
|
|||
} break;
|
||||
|
||||
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
|
||||
bool needs_update = false;
|
||||
if (!is_sub_inspector() && EditorThemeManager::is_generated_theme_outdated()) {
|
||||
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
|
||||
_update_theme();
|
||||
}
|
||||
|
||||
if (use_settings_name_style && EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/localize_settings")) {
|
||||
EditorPropertyNameProcessor::Style style = EditorPropertyNameProcessor::get_settings_style();
|
||||
if (property_name_style != style) {
|
||||
property_name_style = style;
|
||||
needs_update = true;
|
||||
update_tree_pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/inspector")) {
|
||||
needs_update = true;
|
||||
}
|
||||
|
||||
if (needs_update) {
|
||||
update_tree();
|
||||
update_tree_pending = true;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
|
@ -4975,6 +5231,7 @@ EditorInspector::EditorInspector() {
|
|||
base_vbox->add_child(main_vbox);
|
||||
|
||||
set_horizontal_scroll_mode(SCROLL_MODE_DISABLED);
|
||||
set_follow_focus(true);
|
||||
|
||||
changing = 0;
|
||||
search_box = nullptr;
|
||||
|
|
@ -5001,4 +5258,5 @@ EditorInspector::EditorInspector() {
|
|||
set_property_name_style(EditorPropertyNameProcessor::get_singleton()->get_settings_style());
|
||||
|
||||
set_draw_focus_border(true);
|
||||
set_scroll_on_drag_hover(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_INSPECTOR_H
|
||||
#define EDITOR_INSPECTOR_H
|
||||
#pragma once
|
||||
|
||||
#include "editor/add_metadata_dialog.h"
|
||||
#include "editor_property_name_processor.h"
|
||||
|
|
@ -67,6 +66,8 @@ public:
|
|||
MENU_COPY_PROPERTY_PATH,
|
||||
MENU_FAVORITE_PROPERTY,
|
||||
MENU_PIN_VALUE,
|
||||
MENU_DELETE,
|
||||
MENU_REVERT_VALUE,
|
||||
MENU_OPEN_DOCUMENTATION,
|
||||
};
|
||||
|
||||
|
|
@ -159,6 +160,9 @@ protected:
|
|||
|
||||
void _update_property_bg();
|
||||
|
||||
void _accessibility_action_menu(const Variant &p_data);
|
||||
void _accessibility_action_click(const Variant &p_data);
|
||||
|
||||
public:
|
||||
void emit_changed(const StringName &p_property, const Variant &p_value, const StringName &p_field = StringName(), bool p_changing = false);
|
||||
|
||||
|
|
@ -184,6 +188,7 @@ public:
|
|||
ERR_FAIL_NULL_V(object, Variant());
|
||||
return object->get(property);
|
||||
}
|
||||
Variant get_edited_property_display_value() const;
|
||||
EditorInspector *get_parent_inspector() const;
|
||||
|
||||
void set_doc_path(const String &p_doc_path);
|
||||
|
|
@ -314,11 +319,15 @@ protected:
|
|||
void _notification(int p_what);
|
||||
virtual void gui_input(const Ref<InputEvent> &p_event) override;
|
||||
|
||||
void _accessibility_action_menu(const Variant &p_data);
|
||||
|
||||
public:
|
||||
void set_as_favorite(EditorInspector *p_for_inspector);
|
||||
|
||||
virtual Size2 get_minimum_size() const override;
|
||||
virtual Control *make_custom_tooltip(const String &p_text) const override;
|
||||
|
||||
EditorInspectorCategory();
|
||||
};
|
||||
|
||||
class EditorInspectorSection : public Container {
|
||||
|
|
@ -349,15 +358,20 @@ protected:
|
|||
static void _bind_methods();
|
||||
virtual void gui_input(const Ref<InputEvent> &p_event) override;
|
||||
|
||||
void _accessibility_action_collapse(const Variant &p_data);
|
||||
void _accessibility_action_expand(const Variant &p_data);
|
||||
|
||||
public:
|
||||
virtual Size2 get_minimum_size() const override;
|
||||
|
||||
void setup(const String &p_section, const String &p_label, Object *p_object, const Color &p_bg_color, bool p_foldable, int p_indent_depth = 0, int p_level = 1);
|
||||
String get_section() const;
|
||||
String get_label() const { return label; }
|
||||
VBoxContainer *get_vbox();
|
||||
void unfold();
|
||||
void fold();
|
||||
void set_bg_color(const Color &p_bg_color);
|
||||
void reset_timer();
|
||||
|
||||
bool has_revertable_properties() const;
|
||||
void property_can_revert_changed(const String &p_path, bool p_can_revert);
|
||||
|
|
@ -366,6 +380,18 @@ public:
|
|||
~EditorInspectorSection();
|
||||
};
|
||||
|
||||
class ArrayPanelContainer : public PanelContainer {
|
||||
GDCLASS(ArrayPanelContainer, PanelContainer);
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
void _accessibility_action_menu(const Variant &p_data);
|
||||
|
||||
public:
|
||||
ArrayPanelContainer();
|
||||
};
|
||||
|
||||
class EditorInspectorArray : public EditorInspectorSection {
|
||||
GDCLASS(EditorInspectorArray, EditorInspectorSection);
|
||||
|
||||
|
|
@ -379,6 +405,7 @@ class EditorInspectorArray : public EditorInspectorSection {
|
|||
String swap_method;
|
||||
|
||||
int count = 0;
|
||||
int selected = -1;
|
||||
|
||||
VBoxContainer *elements_vbox = nullptr;
|
||||
|
||||
|
|
@ -442,6 +469,8 @@ class EditorInspectorArray : public EditorInspectorSection {
|
|||
|
||||
void _panel_draw(int p_index);
|
||||
void _panel_gui_input(Ref<InputEvent> p_event, int p_index);
|
||||
void _panel_gui_focus(int p_index);
|
||||
void _panel_gui_unfocus(int p_index);
|
||||
void _move_element(int p_element_index, int p_to_pos);
|
||||
void _clear_array();
|
||||
void _resize_array(int p_size);
|
||||
|
|
@ -470,6 +499,8 @@ public:
|
|||
void setup_with_count_property(Object *p_object, const String &p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_is_const = false, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = "");
|
||||
VBoxContainer *get_vbox(int p_index);
|
||||
|
||||
void show_menu(int p_index, const Vector2 &p_offset);
|
||||
|
||||
EditorInspectorArray(bool p_read_only);
|
||||
};
|
||||
|
||||
|
|
@ -568,6 +599,8 @@ class EditorInspector : public ScrollContainer {
|
|||
int property_focusable;
|
||||
int update_scroll_request;
|
||||
|
||||
bool updating_theme = false;
|
||||
|
||||
struct DocCacheInfo {
|
||||
String doc_path;
|
||||
String theme_item_name;
|
||||
|
|
@ -605,8 +638,9 @@ class EditorInspector : public ScrollContainer {
|
|||
void _set_property_favorited(const String &p_path, bool p_favorited);
|
||||
void _clear_current_favorites();
|
||||
|
||||
void _update_theme();
|
||||
|
||||
void _node_removed(Node *p_node);
|
||||
void _gui_focus_changed(Control *p_control);
|
||||
|
||||
HashMap<StringName, int> per_array_page;
|
||||
void _page_change_request(int p_new_page, const StringName &p_array_prefix);
|
||||
|
|
@ -706,5 +740,3 @@ public:
|
|||
|
||||
EditorInspector();
|
||||
};
|
||||
|
||||
#endif // EDITOR_INSPECTOR_H
|
||||
|
|
|
|||
|
|
@ -186,8 +186,8 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh
|
|||
Vector3 ofs = aabb.get_center();
|
||||
aabb.position -= ofs;
|
||||
Transform3D xform;
|
||||
xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI / 6);
|
||||
xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI / 6) * xform.basis;
|
||||
xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math::PI / 6);
|
||||
xform.basis = Basis().rotated(Vector3(1, 0, 0), Math::PI / 6) * xform.basis;
|
||||
AABB rot_aabb = xform.xform(aabb);
|
||||
float m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5;
|
||||
if (m == 0) {
|
||||
|
|
@ -282,8 +282,8 @@ void EditorInterface::make_scene_preview(const String &p_path, Node *p_scene, in
|
|||
Vector3 center = scene_aabb.get_center();
|
||||
float camera_size = scene_aabb.get_longest_axis_size();
|
||||
|
||||
const float cam_rot_x = -Math_PI / 4;
|
||||
const float cam_rot_y = -Math_PI / 4;
|
||||
const float cam_rot_x = -Math::PI / 4;
|
||||
const float cam_rot_y = -Math::PI / 4;
|
||||
|
||||
camera->set_orthogonal(camera_size * 2.0, 0.0001, camera_size * 2.0);
|
||||
|
||||
|
|
@ -295,8 +295,8 @@ void EditorInterface::make_scene_preview(const String &p_path, Node *p_scene, in
|
|||
camera->set_transform(xf);
|
||||
|
||||
Transform3D xform;
|
||||
xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI / 6);
|
||||
xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI / 6) * xform.basis;
|
||||
xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math::PI / 6);
|
||||
xform.basis = Basis().rotated(Vector3(1, 0, 0), Math::PI / 6) * xform.basis;
|
||||
|
||||
light->set_transform(xform * Transform3D().looking_at(Vector3(-2, -1, -1), Vector3(0, 1, 0)));
|
||||
light2->set_transform(xform * Transform3D().looking_at(Vector3(+1, -1, -2), Vector3(0, 1, 0)));
|
||||
|
|
@ -647,8 +647,7 @@ void EditorInterface::open_scene_from_path(const String &scene_path, bool p_set_
|
|||
if (EditorNode::get_singleton()->is_changing_scene()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EditorNode::get_singleton()->open_request(scene_path, p_set_inherited);
|
||||
EditorNode::get_singleton()->load_scene(scene_path, false, p_set_inherited);
|
||||
}
|
||||
|
||||
void EditorInterface::reload_scene_from_path(const String &scene_path) {
|
||||
|
|
@ -667,12 +666,24 @@ PackedStringArray EditorInterface::get_open_scenes() const {
|
|||
PackedStringArray ret;
|
||||
Vector<EditorData::EditedScene> scenes = EditorNode::get_editor_data().get_edited_scenes();
|
||||
|
||||
int scns_amount = scenes.size();
|
||||
for (int idx_scn = 0; idx_scn < scns_amount; idx_scn++) {
|
||||
if (scenes[idx_scn].root == nullptr) {
|
||||
for (EditorData::EditedScene &edited_scene : scenes) {
|
||||
if (edited_scene.root == nullptr) {
|
||||
continue;
|
||||
}
|
||||
ret.push_back(scenes[idx_scn].root->get_scene_file_path());
|
||||
ret.push_back(edited_scene.root->get_scene_file_path());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
TypedArray<Node> EditorInterface::get_open_scene_roots() const {
|
||||
TypedArray<Node> ret;
|
||||
Vector<EditorData::EditedScene> scenes = EditorNode::get_editor_data().get_edited_scenes();
|
||||
|
||||
for (EditorData::EditedScene &edited_scene : scenes) {
|
||||
if (edited_scene.root == nullptr) {
|
||||
continue;
|
||||
}
|
||||
ret.push_back(edited_scene.root);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -736,12 +747,11 @@ bool EditorInterface::is_movie_maker_enabled() const {
|
|||
return EditorRunBar::get_singleton()->is_movie_maker_enabled();
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void EditorInterface::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
|
||||
const String pf = p_function;
|
||||
if (p_idx == 0) {
|
||||
if (pf == "set_main_screen_editor") {
|
||||
for (String E : { "\"2D\"", "\"3D\"", "\"Script\"", "\"AssetLib\"" }) {
|
||||
for (String E : { "\"2D\"", "\"3D\"", "\"Script\"", "\"Game\"", "\"AssetLib\"" }) {
|
||||
r_options->push_back(E);
|
||||
}
|
||||
} else if (pf == "get_editor_viewport_3d") {
|
||||
|
|
@ -752,7 +762,6 @@ void EditorInterface::get_argument_options(const StringName &p_function, int p_i
|
|||
}
|
||||
Object::get_argument_options(p_function, p_idx, r_options);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Base.
|
||||
|
||||
|
|
@ -830,6 +839,7 @@ void EditorInterface::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("reload_scene_from_path", "scene_filepath"), &EditorInterface::reload_scene_from_path);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_open_scenes"), &EditorInterface::get_open_scenes);
|
||||
ClassDB::bind_method(D_METHOD("get_open_scene_roots"), &EditorInterface::get_open_scene_roots);
|
||||
ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &EditorInterface::get_edited_scene_root);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("save_scene"), &EditorInterface::save_scene);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_INTERFACE_H
|
||||
#define EDITOR_INTERFACE_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/resource.h"
|
||||
#include "core/object/class_db.h"
|
||||
|
|
@ -171,6 +170,7 @@ public:
|
|||
void reload_scene_from_path(const String &scene_path);
|
||||
|
||||
PackedStringArray get_open_scenes() const;
|
||||
TypedArray<Node> get_open_scene_roots() const;
|
||||
Node *get_edited_scene_root() const;
|
||||
|
||||
Error save_scene();
|
||||
|
|
@ -190,9 +190,7 @@ public:
|
|||
void set_movie_maker_enabled(bool p_enabled);
|
||||
bool is_movie_maker_enabled() const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
|
||||
#endif
|
||||
|
||||
// Base.
|
||||
static void create();
|
||||
|
|
@ -200,5 +198,3 @@ public:
|
|||
|
||||
EditorInterface();
|
||||
};
|
||||
|
||||
#endif // EDITOR_INTERFACE_H
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ EditorLayoutsDialog::EditorLayoutsDialog() {
|
|||
name = memnew(LineEdit);
|
||||
makevb->add_child(name);
|
||||
name->set_placeholder(TTR("Or enter new layout name"));
|
||||
name->set_accessibility_name(TTRC("Layout Name"));
|
||||
name->set_offset(SIDE_TOP, 5);
|
||||
name->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5);
|
||||
name->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_LAYOUTS_DIALOG_H
|
||||
#define EDITOR_LAYOUTS_DIALOG_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/dialogs.h"
|
||||
|
||||
|
|
@ -57,5 +56,3 @@ public:
|
|||
|
||||
void set_name_line_enabled(bool p_enabled);
|
||||
};
|
||||
|
||||
#endif // EDITOR_LAYOUTS_DIALOG_H
|
||||
|
|
|
|||
|
|
@ -396,6 +396,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
|
|||
HBoxContainer *hb_filter = memnew(HBoxContainer);
|
||||
{
|
||||
filter_mode = memnew(OptionButton);
|
||||
filter_mode->set_accessibility_name(TTRC("Locale Filter"));
|
||||
filter_mode->add_item(TTR("Show All Locales"), SHOW_ALL_LOCALES);
|
||||
filter_mode->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
filter_mode->add_item(TTR("Show Selected Locales Only"), SHOW_ONLY_SELECTED_LOCALES);
|
||||
|
|
@ -434,6 +435,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
|
|||
}
|
||||
{
|
||||
lang_list = memnew(Tree);
|
||||
lang_list->set_accessibility_name(TTRC("Language"));
|
||||
lang_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
lang_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
lang_list->connect("cell_selected", callable_mp(this, &EditorLocaleDialog::_item_selected));
|
||||
|
|
@ -454,6 +456,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
|
|||
}
|
||||
{
|
||||
script_list = memnew(Tree);
|
||||
script_list->set_accessibility_name(TTR("Script", "Locale"));
|
||||
script_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
script_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
script_list->connect("cell_selected", callable_mp(this, &EditorLocaleDialog::_item_selected));
|
||||
|
|
@ -473,6 +476,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
|
|||
}
|
||||
{
|
||||
cnt_list = memnew(Tree);
|
||||
cnt_list->set_accessibility_name(TTRC("Country"));
|
||||
cnt_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
cnt_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
cnt_list->connect("cell_selected", callable_mp(this, &EditorLocaleDialog::_item_selected));
|
||||
|
|
@ -499,7 +503,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
|
|||
{
|
||||
lang_code = memnew(LineEdit);
|
||||
lang_code->set_max_length(3);
|
||||
lang_code->set_tooltip_text("Language");
|
||||
lang_code->set_accessibility_name("Language");
|
||||
vb_language->add_child(lang_code);
|
||||
}
|
||||
hb_locale->add_child(vb_language);
|
||||
|
|
@ -516,7 +520,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
|
|||
{
|
||||
script_code = memnew(LineEdit);
|
||||
script_code->set_max_length(4);
|
||||
script_code->set_tooltip_text("Script");
|
||||
script_code->set_accessibility_name("Script");
|
||||
vb_script->add_child(script_code);
|
||||
}
|
||||
hb_locale->add_child(vb_script);
|
||||
|
|
@ -549,7 +553,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
|
|||
variant_code = memnew(LineEdit);
|
||||
variant_code->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
variant_code->set_placeholder("Variant");
|
||||
variant_code->set_tooltip_text("Variant");
|
||||
variant_code->set_accessibility_name("Variant");
|
||||
vb_variant->add_child(variant_code);
|
||||
}
|
||||
hb_locale->add_child(vb_variant);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_LOCALE_DIALOG_H
|
||||
#define EDITOR_LOCALE_DIALOG_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/dialogs.h"
|
||||
|
||||
|
|
@ -85,5 +84,3 @@ public:
|
|||
void set_locale(const String &p_locale);
|
||||
void popup_locale_dialog();
|
||||
};
|
||||
|
||||
#endif // EDITOR_LOCALE_DIALOG_H
|
||||
|
|
|
|||
|
|
@ -466,6 +466,7 @@ EditorLog::EditorLog() {
|
|||
search_box = memnew(LineEdit);
|
||||
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
search_box->set_placeholder(TTR("Filter Messages"));
|
||||
search_box->set_accessibility_name(TTRC("Filter Messages"));
|
||||
search_box->set_clear_button_enabled(true);
|
||||
search_box->set_visible(true);
|
||||
search_box->connect(SceneStringName(text_changed), callable_mp(this, &EditorLog::_search_changed));
|
||||
|
|
@ -481,6 +482,7 @@ EditorLog::EditorLog() {
|
|||
|
||||
// Clear.
|
||||
clear_button = memnew(Button);
|
||||
clear_button->set_accessibility_name(TTRC("Clear Log"));
|
||||
clear_button->set_theme_type_variation(SceneStringName(FlatButton));
|
||||
clear_button->set_focus_mode(FOCUS_NONE);
|
||||
clear_button->set_shortcut(ED_SHORTCUT("editor/clear_output", TTRC("Clear Output"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::K));
|
||||
|
|
@ -489,6 +491,7 @@ EditorLog::EditorLog() {
|
|||
|
||||
// Copy.
|
||||
copy_button = memnew(Button);
|
||||
copy_button->set_accessibility_name(TTRC("Copy Selection"));
|
||||
copy_button->set_theme_type_variation(SceneStringName(FlatButton));
|
||||
copy_button->set_focus_mode(FOCUS_NONE);
|
||||
copy_button->set_shortcut(ED_SHORTCUT("editor/copy_output", TTRC("Copy Selection"), KeyModifierMask::CMD_OR_CTRL | Key::C));
|
||||
|
|
@ -509,6 +512,7 @@ EditorLog::EditorLog() {
|
|||
collapse_button->set_theme_type_variation(SceneStringName(FlatButton));
|
||||
collapse_button->set_focus_mode(FOCUS_NONE);
|
||||
collapse_button->set_tooltip_text(TTR("Collapse duplicate messages into one log entry. Shows number of occurrences."));
|
||||
collapse_button->set_accessibility_name(TTRC("Collapse Duplicate Messages"));
|
||||
collapse_button->set_toggle_mode(true);
|
||||
collapse_button->set_pressed(false);
|
||||
collapse_button->connect(SceneStringName(toggled), callable_mp(this, &EditorLog::_set_collapse));
|
||||
|
|
@ -516,6 +520,7 @@ EditorLog::EditorLog() {
|
|||
|
||||
// Show Search.
|
||||
show_search_button = memnew(Button);
|
||||
show_search_button->set_accessibility_name(TTRC("Show Search"));
|
||||
show_search_button->set_theme_type_variation(SceneStringName(FlatButton));
|
||||
show_search_button->set_focus_mode(FOCUS_NONE);
|
||||
show_search_button->set_toggle_mode(true);
|
||||
|
|
@ -529,27 +534,27 @@ EditorLog::EditorLog() {
|
|||
vb_right->add_child(memnew(HSeparator));
|
||||
|
||||
LogFilter *std_filter = memnew(LogFilter(MSG_TYPE_STD));
|
||||
std_filter->initialize_button(TTR("Toggle visibility of standard output messages."), callable_mp(this, &EditorLog::_set_filter_active));
|
||||
std_filter->initialize_button(TTRC("Standard Messages"), TTRC("Toggle visibility of standard output messages."), callable_mp(this, &EditorLog::_set_filter_active));
|
||||
vb_right->add_child(std_filter->toggle_button);
|
||||
type_filter_map.insert(MSG_TYPE_STD, std_filter);
|
||||
type_filter_map.insert(MSG_TYPE_STD_RICH, std_filter);
|
||||
|
||||
LogFilter *error_filter = memnew(LogFilter(MSG_TYPE_ERROR));
|
||||
error_filter->initialize_button(TTR("Toggle visibility of errors."), callable_mp(this, &EditorLog::_set_filter_active));
|
||||
error_filter->initialize_button(TTRC("Errors"), TTRC("Toggle visibility of errors."), callable_mp(this, &EditorLog::_set_filter_active));
|
||||
vb_right->add_child(error_filter->toggle_button);
|
||||
type_filter_map.insert(MSG_TYPE_ERROR, error_filter);
|
||||
|
||||
LogFilter *warning_filter = memnew(LogFilter(MSG_TYPE_WARNING));
|
||||
warning_filter->initialize_button(TTR("Toggle visibility of warnings."), callable_mp(this, &EditorLog::_set_filter_active));
|
||||
warning_filter->initialize_button(TTRC("Warnings"), TTRC("Toggle visibility of warnings."), callable_mp(this, &EditorLog::_set_filter_active));
|
||||
vb_right->add_child(warning_filter->toggle_button);
|
||||
type_filter_map.insert(MSG_TYPE_WARNING, warning_filter);
|
||||
|
||||
LogFilter *editor_filter = memnew(LogFilter(MSG_TYPE_EDITOR));
|
||||
editor_filter->initialize_button(TTR("Toggle visibility of editor messages."), callable_mp(this, &EditorLog::_set_filter_active));
|
||||
editor_filter->initialize_button(TTRC("Editor Messages"), TTRC("Toggle visibility of editor messages."), callable_mp(this, &EditorLog::_set_filter_active));
|
||||
vb_right->add_child(editor_filter->toggle_button);
|
||||
type_filter_map.insert(MSG_TYPE_EDITOR, editor_filter);
|
||||
|
||||
add_message(VERSION_FULL_NAME " (c) 2007-present Juan Linietsky, Ariel Manzur & Godot Contributors.");
|
||||
add_message(GODOT_VERSION_FULL_NAME " (c) 2007-present Juan Linietsky, Ariel Manzur & Godot Contributors.");
|
||||
|
||||
eh.errfunc = _error_handler;
|
||||
eh.userdata = this;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_LOG_H
|
||||
#define EDITOR_LOG_H
|
||||
#pragma once
|
||||
|
||||
#include "core/os/thread.h"
|
||||
#include "scene/gui/box_container.h"
|
||||
|
|
@ -88,12 +87,13 @@ private:
|
|||
MessageType type;
|
||||
Button *toggle_button = nullptr;
|
||||
|
||||
void initialize_button(const String &p_tooltip, Callable p_toggled_callback) {
|
||||
void initialize_button(const String &p_name, const String &p_tooltip, Callable p_toggled_callback) {
|
||||
toggle_button = memnew(Button);
|
||||
toggle_button->set_toggle_mode(true);
|
||||
toggle_button->set_pressed(true);
|
||||
toggle_button->set_text(itos(message_count));
|
||||
toggle_button->set_tooltip_text(TTR(p_tooltip));
|
||||
toggle_button->set_accessibility_name(TTRGET(p_name));
|
||||
toggle_button->set_tooltip_text(TTRGET(p_tooltip));
|
||||
toggle_button->set_focus_mode(FOCUS_NONE);
|
||||
// When toggled call the callback and pass the MessageType this button is for.
|
||||
toggle_button->connect(SceneStringName(toggled), p_toggled_callback.bind(type));
|
||||
|
|
@ -191,5 +191,3 @@ public:
|
|||
};
|
||||
|
||||
VARIANT_ENUM_CAST(EditorLog::MessageType);
|
||||
|
||||
#endif // EDITOR_LOG_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_MAIN_SCREEN_H
|
||||
#define EDITOR_MAIN_SCREEN_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/panel_container.h"
|
||||
|
||||
|
|
@ -90,5 +89,3 @@ public:
|
|||
|
||||
EditorMainScreen();
|
||||
};
|
||||
|
||||
#endif // EDITOR_MAIN_SCREEN_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_NATIVE_SHADER_SOURCE_VISUALIZER_H
|
||||
#define EDITOR_NATIVE_SHADER_SOURCE_VISUALIZER_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/tab_container.h"
|
||||
|
|
@ -49,5 +48,3 @@ protected:
|
|||
public:
|
||||
EditorNativeShaderSourceVisualizer();
|
||||
};
|
||||
|
||||
#endif // EDITOR_NATIVE_SHADER_SOURCE_VISUALIZER_H
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_NODE_H
|
||||
#define EDITOR_NODE_H
|
||||
#pragma once
|
||||
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
|
|
@ -98,10 +97,7 @@ class ProgressDialog;
|
|||
class ProjectExportDialog;
|
||||
class ProjectSettingsEditor;
|
||||
class SceneImportSettingsDialog;
|
||||
class SurfaceUpgradeTool;
|
||||
class SurfaceUpgradeDialog;
|
||||
class UIDUpgradeTool;
|
||||
class UIDUpgradeDialog;
|
||||
class ProjectUpgradeTool;
|
||||
|
||||
struct EditorProgress {
|
||||
String task;
|
||||
|
|
@ -121,6 +117,7 @@ public:
|
|||
SCENE_NAME_CASING_PASCAL_CASE,
|
||||
SCENE_NAME_CASING_SNAKE_CASE,
|
||||
SCENE_NAME_CASING_KEBAB_CASE,
|
||||
SCENE_NAME_CASING_CAMEL_CASE,
|
||||
};
|
||||
|
||||
enum ActionOnPlay {
|
||||
|
|
@ -144,6 +141,7 @@ public:
|
|||
FILE_SAVE_SCENE,
|
||||
FILE_SAVE_AS_SCENE,
|
||||
FILE_SAVE_ALL_SCENES,
|
||||
FILE_MULTI_SAVE_AS_SCENE,
|
||||
FILE_QUICK_OPEN,
|
||||
FILE_QUICK_OPEN_SCENE,
|
||||
FILE_QUICK_OPEN_SCRIPT,
|
||||
|
|
@ -167,8 +165,7 @@ public:
|
|||
|
||||
TOOLS_ORPHAN_RESOURCES,
|
||||
TOOLS_BUILD_PROFILE_MANAGER,
|
||||
TOOLS_SURFACE_UPGRADE,
|
||||
TOOLS_UID_UPGRADE,
|
||||
TOOLS_PROJECT_UPGRADE,
|
||||
TOOLS_CUSTOM,
|
||||
|
||||
VCS_METADATA,
|
||||
|
|
@ -227,7 +224,6 @@ public:
|
|||
|
||||
private:
|
||||
friend class EditorSceneTabs;
|
||||
friend class SurfaceUpgradeTool;
|
||||
|
||||
enum {
|
||||
MAX_INIT_CALLBACKS = 128,
|
||||
|
|
@ -301,6 +297,7 @@ private:
|
|||
|
||||
int tab_closing_idx = 0;
|
||||
List<String> tabs_to_close;
|
||||
List<int> scenes_to_save_as;
|
||||
int tab_closing_menu_option = -1;
|
||||
|
||||
bool exiting = false;
|
||||
|
|
@ -351,14 +348,16 @@ private:
|
|||
|
||||
PopupMenu *recent_scenes = nullptr;
|
||||
String _recent_scene;
|
||||
List<String> previous_scenes;
|
||||
List<String> prev_closed_scenes;
|
||||
String defer_load_scene;
|
||||
Node *_last_instantiated_scene = nullptr;
|
||||
|
||||
ConfirmationDialog *confirmation = nullptr;
|
||||
Button *confirmation_button = nullptr;
|
||||
ConfirmationDialog *save_confirmation = nullptr;
|
||||
ConfirmationDialog *import_confirmation = nullptr;
|
||||
ConfirmationDialog *pick_main_scene = nullptr;
|
||||
ConfirmationDialog *open_project_settings = nullptr;
|
||||
Button *select_current_scene_button = nullptr;
|
||||
AcceptDialog *accept = nullptr;
|
||||
AcceptDialog *save_accept = nullptr;
|
||||
|
|
@ -387,6 +386,7 @@ private:
|
|||
EditorFileDialog *file_export_lib = nullptr;
|
||||
EditorFileDialog *file_script = nullptr;
|
||||
EditorFileDialog *file_android_build_source = nullptr;
|
||||
EditorFileDialog *file_pack_zip = nullptr;
|
||||
String current_path;
|
||||
MenuButton *update_spinner = nullptr;
|
||||
|
||||
|
|
@ -414,15 +414,15 @@ private:
|
|||
|
||||
Tree *disk_changed_list = nullptr;
|
||||
ConfirmationDialog *disk_changed = nullptr;
|
||||
ConfirmationDialog *project_data_missing = nullptr;
|
||||
|
||||
bool scene_distraction_free = false;
|
||||
bool script_distraction_free = false;
|
||||
|
||||
bool changing_scene = false;
|
||||
bool cmdline_export_mode = false;
|
||||
bool cmdline_mode = false;
|
||||
bool convert_old = false;
|
||||
bool immediate_dialog_confirmed = false;
|
||||
bool opening_prev = false;
|
||||
bool restoring_scenes = false;
|
||||
bool unsaved_cache = true;
|
||||
|
||||
|
|
@ -461,16 +461,8 @@ private:
|
|||
|
||||
HashMap<String, Ref<Texture2D>> icon_type_cache;
|
||||
|
||||
SurfaceUpgradeTool *surface_upgrade_tool = nullptr;
|
||||
SurfaceUpgradeDialog *surface_upgrade_dialog = nullptr;
|
||||
|
||||
bool run_surface_upgrade_tool = false;
|
||||
|
||||
UIDUpgradeTool *uid_upgrade_tool = nullptr;
|
||||
UIDUpgradeDialog *uid_upgrade_dialog = nullptr;
|
||||
|
||||
bool run_uid_upgrade_tool = false;
|
||||
bool should_prompt_uid_upgrade_tool = false;
|
||||
ProjectUpgradeTool *project_upgrade_tool = nullptr;
|
||||
bool run_project_upgrade_tool = false;
|
||||
|
||||
bool was_window_windowed_last = false;
|
||||
|
||||
|
|
@ -537,7 +529,6 @@ private:
|
|||
void _tool_menu_option(int p_idx);
|
||||
void _export_as_menu_option(int p_idx);
|
||||
void _update_file_menu_opened();
|
||||
void _update_file_menu_closed();
|
||||
void _palette_quick_open_dialog();
|
||||
|
||||
void _remove_plugin_from_enabled(const String &p_name);
|
||||
|
|
@ -587,9 +578,12 @@ private:
|
|||
void _project_run_started();
|
||||
void _project_run_stopped();
|
||||
|
||||
void _update_prev_closed_scenes(const String &p_scene_path, bool p_add_scene);
|
||||
|
||||
void _add_to_recent_scenes(const String &p_scene);
|
||||
void _update_recent_scenes();
|
||||
void _open_recent_scene(int p_idx);
|
||||
|
||||
void _dropped_files(const Vector<String> &p_files);
|
||||
void _add_dropped_files_recursive(const Vector<String> &p_files, String to_path);
|
||||
|
||||
|
|
@ -615,6 +609,7 @@ private:
|
|||
bool _find_and_save_edited_subresources(Object *obj, HashMap<Ref<Resource>, bool> &processed, int32_t flags);
|
||||
void _save_edited_subresources(Node *scene, HashMap<Ref<Resource>, bool> &processed, int32_t flags);
|
||||
void _mark_unsaved_scenes();
|
||||
bool _is_scene_unsaved(int p_idx);
|
||||
|
||||
void _find_node_types(Node *p_node, int &count_2d, int &count_3d);
|
||||
void _save_scene_with_preview(String p_file, int p_idx = -1);
|
||||
|
|
@ -623,6 +618,7 @@ private:
|
|||
bool _find_scene_in_use(Node *p_node, const String &p_path) const;
|
||||
|
||||
void _proceed_closing_scene_tabs();
|
||||
void _proceed_save_asing_scene_tabs();
|
||||
bool _is_closing_editor() const;
|
||||
void _restart_editor(bool p_goto_project_manager = false);
|
||||
|
||||
|
|
@ -662,6 +658,7 @@ private:
|
|||
bool _is_class_editor_disabled_by_feature_profile(const StringName &p_class);
|
||||
|
||||
Ref<Texture2D> _get_class_or_script_icon(const String &p_class, const String &p_script_path, const String &p_fallback = "Object", bool p_fallback_script_to_theme = false);
|
||||
Ref<Texture2D> _get_editor_theme_native_menu_icon(const StringName &p_name, bool p_global_menu, bool p_dark_mode) const;
|
||||
|
||||
void _pick_main_scene_custom_action(const String &p_custom_action_name);
|
||||
|
||||
|
|
@ -678,6 +675,8 @@ private:
|
|||
|
||||
void _execute_upgrades();
|
||||
|
||||
bool _is_project_data_missing();
|
||||
|
||||
protected:
|
||||
friend class FileSystemDock;
|
||||
|
||||
|
|
@ -744,7 +743,7 @@ public:
|
|||
ProjectSettingsEditor *get_project_settings() { return project_settings_editor; }
|
||||
|
||||
void trigger_menu_option(int p_option, bool p_confirmed);
|
||||
bool has_previous_scenes() const;
|
||||
bool has_previous_closed_scenes() const;
|
||||
|
||||
void new_inherited_scene() { _menu_option_confirm(FILE_NEW_INHERITED_SCENE, false); }
|
||||
|
||||
|
|
@ -778,7 +777,6 @@ public:
|
|||
void replace_resources_in_scenes(
|
||||
const Vector<Ref<Resource>> &p_source_resources,
|
||||
const Vector<Ref<Resource>> &p_target_resource);
|
||||
void open_request(const String &p_path, bool p_set_inherited = false);
|
||||
void edit_foreign_resource(Ref<Resource> p_resource);
|
||||
|
||||
bool is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_resources_are_writable = false);
|
||||
|
|
@ -797,6 +795,7 @@ public:
|
|||
int new_scene();
|
||||
Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_force_open_imported = false, bool p_silent_change_tab = false);
|
||||
Error load_resource(const String &p_resource, bool p_ignore_broken_deps = false);
|
||||
Error load_scene_or_resource(const String &p_file, bool p_ignore_broken_deps = false, bool p_change_scene_tab_if_already_open = true);
|
||||
|
||||
HashMap<StringName, Variant> get_modified_properties_for_node(Node *p_node, bool p_node_references_only);
|
||||
HashMap<StringName, Variant> get_modified_properties_reference_to_nodes(Node *p_node, List<Node *> &p_nodes_referenced_by);
|
||||
|
|
@ -966,6 +965,7 @@ public:
|
|||
Vector<Ref<EditorResourceConversionPlugin>> find_resource_conversion_plugin_for_type_name(const String &p_type);
|
||||
|
||||
bool ensure_main_scene(bool p_from_native);
|
||||
bool validate_custom_directory();
|
||||
};
|
||||
|
||||
class EditorPluginList : public Object {
|
||||
|
|
@ -993,9 +993,6 @@ public:
|
|||
void remove_plugin(EditorPlugin *p_plugin);
|
||||
void clear();
|
||||
bool is_empty();
|
||||
|
||||
EditorPluginList();
|
||||
~EditorPluginList();
|
||||
};
|
||||
|
||||
struct EditorProgressBG {
|
||||
|
|
@ -1007,5 +1004,3 @@ struct EditorProgressBG {
|
|||
}
|
||||
~EditorProgressBG() { EditorNode::progress_end_task_bg(task); }
|
||||
};
|
||||
|
||||
#endif // EDITOR_NODE_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_PATHS_H
|
||||
#define EDITOR_PATHS_H
|
||||
#pragma once
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/object/object.h"
|
||||
|
|
@ -84,5 +83,3 @@ public:
|
|||
|
||||
EditorPaths();
|
||||
};
|
||||
|
||||
#endif // EDITOR_PATHS_H
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ EditorPropertyMultilineText::EditorPropertyMultilineText(bool p_expression) {
|
|||
hb->add_child(text);
|
||||
text->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
open_big_text = memnew(Button);
|
||||
open_big_text->set_accessibility_name(TTRC("Open Text Edit Dialog"));
|
||||
open_big_text->set_flat(true);
|
||||
open_big_text->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyMultilineText::_open_big_text));
|
||||
hb->add_child(open_big_text);
|
||||
|
|
@ -373,6 +374,7 @@ EditorPropertyTextEnum::EditorPropertyTextEnum() {
|
|||
hb->add_child(edit_custom_layout);
|
||||
|
||||
option_button = memnew(OptionButton);
|
||||
option_button->set_accessibility_name(TTRC("Enum Options"));
|
||||
option_button->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
option_button->set_clip_text(true);
|
||||
option_button->set_flat(true);
|
||||
|
|
@ -381,22 +383,26 @@ EditorPropertyTextEnum::EditorPropertyTextEnum() {
|
|||
option_button->connect(SceneStringName(item_selected), callable_mp(this, &EditorPropertyTextEnum::_option_selected));
|
||||
|
||||
edit_button = memnew(Button);
|
||||
edit_button->set_accessibility_name(TTRC("Edit"));
|
||||
edit_button->set_flat(true);
|
||||
edit_button->hide();
|
||||
default_layout->add_child(edit_button);
|
||||
edit_button->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyTextEnum::_edit_custom_value));
|
||||
|
||||
custom_value_edit = memnew(LineEdit);
|
||||
custom_value_edit->set_accessibility_name(TTRC("Custom Value"));
|
||||
custom_value_edit->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
edit_custom_layout->add_child(custom_value_edit);
|
||||
custom_value_edit->connect(SceneStringName(text_submitted), callable_mp(this, &EditorPropertyTextEnum::_custom_value_submitted));
|
||||
|
||||
accept_button = memnew(Button);
|
||||
accept_button->set_accessibility_name(TTRC("Accept Custom Value Edit"));
|
||||
accept_button->set_flat(true);
|
||||
edit_custom_layout->add_child(accept_button);
|
||||
accept_button->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyTextEnum::_custom_value_accepted));
|
||||
|
||||
cancel_button = memnew(Button);
|
||||
cancel_button->set_accessibility_name(TTRC("Cancel Custom Value Edit"));
|
||||
cancel_button->set_flat(true);
|
||||
edit_custom_layout->add_child(cancel_button);
|
||||
cancel_button->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyTextEnum::_custom_value_canceled));
|
||||
|
|
@ -453,12 +459,14 @@ EditorPropertyLocale::EditorPropertyLocale() {
|
|||
HBoxContainer *locale_hb = memnew(HBoxContainer);
|
||||
add_child(locale_hb);
|
||||
locale = memnew(LineEdit);
|
||||
locale->set_accessibility_name(TTRC("Locale"));
|
||||
locale_hb->add_child(locale);
|
||||
locale->connect(SceneStringName(text_submitted), callable_mp(this, &EditorPropertyLocale::_locale_selected));
|
||||
locale->connect(SceneStringName(focus_exited), callable_mp(this, &EditorPropertyLocale::_locale_focus_exited));
|
||||
locale->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
|
||||
locale_edit = memnew(Button);
|
||||
locale_edit->set_accessibility_name(TTRC("Edit"));
|
||||
locale_edit->set_clip_text(true);
|
||||
locale_hb->add_child(locale_edit);
|
||||
add_focusable(locale);
|
||||
|
|
@ -573,7 +581,7 @@ void EditorPropertyPath::_drop_data_fw(const Point2 &p_point, const Variant &p_d
|
|||
return;
|
||||
}
|
||||
const Vector<String> filesPaths = drag_data["files"];
|
||||
if (filesPaths.size() == 0) {
|
||||
if (filesPaths.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -589,12 +597,12 @@ bool EditorPropertyPath::_can_drop_data_fw(const Point2 &p_point, const Variant
|
|||
return false;
|
||||
}
|
||||
const Vector<String> filesPaths = drag_data["files"];
|
||||
if (filesPaths.size() == 0) {
|
||||
if (filesPaths.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const String &extension : extensions) {
|
||||
if (filesPaths[0].ends_with(extension.substr(1, extension.size() - 1))) {
|
||||
if (filesPaths[0].ends_with(extension.substr(1))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -606,6 +614,7 @@ EditorPropertyPath::EditorPropertyPath() {
|
|||
HBoxContainer *path_hb = memnew(HBoxContainer);
|
||||
add_child(path_hb);
|
||||
path = memnew(LineEdit);
|
||||
path->set_accessibility_name(TTRC("Path"));
|
||||
SET_DRAG_FORWARDING_CDU(path, EditorPropertyPath);
|
||||
path->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
|
||||
path_hb->add_child(path);
|
||||
|
|
@ -614,6 +623,7 @@ EditorPropertyPath::EditorPropertyPath() {
|
|||
path->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
|
||||
path_edit = memnew(Button);
|
||||
path_edit->set_accessibility_name(TTRC("Edit"));
|
||||
path_edit->set_clip_text(true);
|
||||
path_hb->add_child(path_edit);
|
||||
add_focusable(path);
|
||||
|
|
@ -993,6 +1003,15 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) {
|
|||
|
||||
void EditorPropertyLayersGrid::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
|
||||
RID ae = get_accessibility_element();
|
||||
ERR_FAIL_COND(ae.is_null());
|
||||
|
||||
//TODO
|
||||
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_STATIC_TEXT);
|
||||
DisplayServer::get_singleton()->accessibility_update_set_value(ae, TTR(vformat("The %s is not accessible at this time.", "Layers grid property editor")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAW: {
|
||||
Size2 grid_size = get_grid_size();
|
||||
grid_size.x = get_size().x;
|
||||
|
|
@ -1300,6 +1319,7 @@ EditorPropertyLayers::EditorPropertyLayers() {
|
|||
hb->add_child(grid);
|
||||
|
||||
button = memnew(TextureButton);
|
||||
button->set_accessibility_name(TTRC("Layers"));
|
||||
button->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED);
|
||||
button->set_toggle_mode(true);
|
||||
button->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyLayers::_button_pressed));
|
||||
|
|
@ -1326,7 +1346,7 @@ void EditorPropertyInteger::_value_changed(int64_t val) {
|
|||
}
|
||||
|
||||
void EditorPropertyInteger::update_property() {
|
||||
int64_t val = get_edited_property_value();
|
||||
int64_t val = get_edited_property_display_value();
|
||||
spin->set_value_no_signal(val);
|
||||
#ifdef DEBUG_ENABLED
|
||||
// If spin (currently EditorSplinSlider : Range) is changed so that it can use int64_t, then the below warning wouldn't be a problem.
|
||||
|
|
@ -1391,6 +1411,7 @@ void EditorPropertyObjectID::setup(const String &p_base_type) {
|
|||
|
||||
EditorPropertyObjectID::EditorPropertyObjectID() {
|
||||
edit = memnew(Button);
|
||||
edit->set_accessibility_name(TTRC("Edit"));
|
||||
add_child(edit);
|
||||
add_focusable(edit);
|
||||
edit->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
|
||||
|
|
@ -1416,6 +1437,7 @@ void EditorPropertySignal::update_property() {
|
|||
|
||||
EditorPropertySignal::EditorPropertySignal() {
|
||||
edit = memnew(Button);
|
||||
edit->set_accessibility_name(TTRC("Edit"));
|
||||
add_child(edit);
|
||||
add_focusable(edit);
|
||||
edit->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertySignal::_edit_pressed));
|
||||
|
|
@ -1435,6 +1457,7 @@ void EditorPropertyCallable::update_property() {
|
|||
|
||||
EditorPropertyCallable::EditorPropertyCallable() {
|
||||
edit = memnew(Button);
|
||||
edit->set_accessibility_name(TTRC("Edit"));
|
||||
add_child(edit);
|
||||
add_focusable(edit);
|
||||
}
|
||||
|
|
@ -1766,6 +1789,7 @@ EditorPropertyRect2::EditorPropertyRect2(bool p_force_wide) {
|
|||
for (int i = 0; i < 4; i++) {
|
||||
spin[i] = memnew(EditorSpinSlider);
|
||||
spin[i]->set_label(desc[i]);
|
||||
spin[i]->set_accessibility_name(desc[i]);
|
||||
spin[i]->set_flat(true);
|
||||
|
||||
if (grid) {
|
||||
|
|
@ -1860,6 +1884,7 @@ EditorPropertyRect2i::EditorPropertyRect2i(bool p_force_wide) {
|
|||
for (int i = 0; i < 4; i++) {
|
||||
spin[i] = memnew(EditorSpinSlider);
|
||||
spin[i]->set_label(desc[i]);
|
||||
spin[i]->set_accessibility_name(desc[i]);
|
||||
spin[i]->set_flat(true);
|
||||
|
||||
if (grid) {
|
||||
|
|
@ -1951,6 +1976,7 @@ EditorPropertyPlane::EditorPropertyPlane(bool p_force_wide) {
|
|||
spin[i] = memnew(EditorSpinSlider);
|
||||
spin[i]->set_flat(true);
|
||||
spin[i]->set_label(desc[i]);
|
||||
spin[i]->set_accessibility_name(desc[i]);
|
||||
bc->add_child(spin[i]);
|
||||
add_focusable(spin[i]);
|
||||
spin[i]->connect(SceneStringName(value_changed), callable_mp(this, &EditorPropertyPlane::_value_changed).bind(desc[i]));
|
||||
|
|
@ -2121,6 +2147,7 @@ EditorPropertyQuaternion::EditorPropertyQuaternion() {
|
|||
spin[i] = memnew(EditorSpinSlider);
|
||||
spin[i]->set_flat(true);
|
||||
spin[i]->set_label(desc[i]);
|
||||
spin[i]->set_accessibility_name(desc[i]);
|
||||
default_layout->add_child(spin[i]);
|
||||
add_focusable(spin[i]);
|
||||
spin[i]->connect(SceneStringName(value_changed), callable_mp(this, &EditorPropertyQuaternion::_value_changed).bind(desc[i]));
|
||||
|
|
@ -2148,6 +2175,7 @@ EditorPropertyQuaternion::EditorPropertyQuaternion() {
|
|||
euler[i] = memnew(EditorSpinSlider);
|
||||
euler[i]->set_flat(true);
|
||||
euler[i]->set_label(desc[i]);
|
||||
euler[i]->set_accessibility_name(vformat(TTR("Temporary Euler %s"), desc[i]));
|
||||
edit_custom_layout->add_child(euler[i]);
|
||||
add_focusable(euler[i]);
|
||||
euler[i]->connect(SceneStringName(value_changed), callable_mp(this, &EditorPropertyQuaternion::_custom_value_changed));
|
||||
|
|
@ -2157,6 +2185,7 @@ EditorPropertyQuaternion::EditorPropertyQuaternion() {
|
|||
}
|
||||
|
||||
edit_button = memnew(Button);
|
||||
edit_button->set_accessibility_name(TTRC("Edit"));
|
||||
edit_button->set_flat(true);
|
||||
edit_button->set_toggle_mode(true);
|
||||
default_layout->add_child(edit_button);
|
||||
|
|
@ -2231,6 +2260,7 @@ EditorPropertyAABB::EditorPropertyAABB() {
|
|||
for (int i = 0; i < 6; i++) {
|
||||
spin[i] = memnew(EditorSpinSlider);
|
||||
spin[i]->set_label(desc[i]);
|
||||
spin[i]->set_accessibility_name(desc[i]);
|
||||
spin[i]->set_flat(true);
|
||||
|
||||
g->add_child(spin[i]);
|
||||
|
|
@ -2311,6 +2341,7 @@ EditorPropertyTransform2D::EditorPropertyTransform2D(bool p_include_origin) {
|
|||
for (int i = 0; i < 6; i++) {
|
||||
spin[i] = memnew(EditorSpinSlider);
|
||||
spin[i]->set_label(desc[i]);
|
||||
spin[i]->set_accessibility_name(desc[i]);
|
||||
spin[i]->set_flat(true);
|
||||
if (p_include_origin || i % 3 != 2) {
|
||||
g->add_child(spin[i]);
|
||||
|
|
@ -2393,6 +2424,7 @@ EditorPropertyBasis::EditorPropertyBasis() {
|
|||
for (int i = 0; i < 9; i++) {
|
||||
spin[i] = memnew(EditorSpinSlider);
|
||||
spin[i]->set_label(desc[i]);
|
||||
spin[i]->set_accessibility_name(desc[i]);
|
||||
spin[i]->set_flat(true);
|
||||
g->add_child(spin[i]);
|
||||
spin[i]->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
|
|
@ -2482,6 +2514,7 @@ EditorPropertyTransform3D::EditorPropertyTransform3D() {
|
|||
for (int i = 0; i < 12; i++) {
|
||||
spin[i] = memnew(EditorSpinSlider);
|
||||
spin[i]->set_label(desc[i]);
|
||||
spin[i]->set_accessibility_name(desc[i]);
|
||||
spin[i]->set_flat(true);
|
||||
g->add_child(spin[i]);
|
||||
spin[i]->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
|
|
@ -2579,6 +2612,7 @@ EditorPropertyProjection::EditorPropertyProjection() {
|
|||
for (int i = 0; i < 16; i++) {
|
||||
spin[i] = memnew(EditorSpinSlider);
|
||||
spin[i]->set_label(desc[i]);
|
||||
spin[i]->set_accessibility_name(desc[i]);
|
||||
spin[i]->set_flat(true);
|
||||
g->add_child(spin[i]);
|
||||
spin[i]->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
|
|
@ -2635,7 +2669,7 @@ void EditorPropertyColor::_notification(int p_what) {
|
|||
}
|
||||
|
||||
void EditorPropertyColor::update_property() {
|
||||
picker->set_pick_color(get_edited_property_value());
|
||||
picker->set_pick_color(get_edited_property_display_value());
|
||||
const Color color = picker->get_pick_color();
|
||||
|
||||
// Add a tooltip to display each channel's values without having to click the ColorPickerButton
|
||||
|
|
@ -2732,6 +2766,13 @@ void EditorPropertyNodePath::_node_assign() {
|
|||
scene_tree->popup_scenetree_dialog(n, get_base_node());
|
||||
}
|
||||
|
||||
void EditorPropertyNodePath::_assign_draw() {
|
||||
if (dropping) {
|
||||
Color color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
|
||||
assign->draw_rect(Rect2(Point2(), assign->get_size()), color, false);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorPropertyNodePath::_update_menu() {
|
||||
const NodePath &np = _get_node_path();
|
||||
|
||||
|
|
@ -2909,6 +2950,20 @@ void EditorPropertyNodePath::_notification(int p_what) {
|
|||
menu->get_popup()->set_item_icon(ACTION_EDIT, get_editor_theme_icon(SNAME("Edit")));
|
||||
menu->get_popup()->set_item_icon(ACTION_SELECT, get_editor_theme_icon(SNAME("ExternalLink")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAG_BEGIN: {
|
||||
if (!is_read_only() && is_drop_valid(get_viewport()->gui_get_drag_data())) {
|
||||
dropping = true;
|
||||
assign->queue_redraw();
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAG_END: {
|
||||
if (dropping) {
|
||||
dropping = false;
|
||||
assign->queue_redraw();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2943,12 +2998,14 @@ EditorPropertyNodePath::EditorPropertyNodePath() {
|
|||
hbc->add_theme_constant_override("separation", 0);
|
||||
add_child(hbc);
|
||||
assign = memnew(Button);
|
||||
assign->set_accessibility_name(TTRC("Assign Node"));
|
||||
assign->set_flat(true);
|
||||
assign->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
assign->set_clip_text(true);
|
||||
assign->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
assign->set_expand_icon(true);
|
||||
assign->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyNodePath::_node_assign));
|
||||
assign->connect(SceneStringName(draw), callable_mp(this, &EditorPropertyNodePath::_assign_draw));
|
||||
SET_DRAG_FORWARDING_CD(assign, EditorPropertyNodePath);
|
||||
hbc->add_child(assign);
|
||||
|
||||
|
|
@ -2964,6 +3021,7 @@ EditorPropertyNodePath::EditorPropertyNodePath() {
|
|||
menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyNodePath::_menu_option));
|
||||
|
||||
edit = memnew(LineEdit);
|
||||
edit->set_accessibility_name(TTRC("Node Path"));
|
||||
edit->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
edit->hide();
|
||||
edit->connect(SceneStringName(focus_exited), callable_mp(this, &EditorPropertyNodePath::_accept_text));
|
||||
|
|
@ -3015,7 +3073,7 @@ void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource,
|
|||
bool unfold = !get_edited_object()->editor_is_section_unfolded(get_edited_property());
|
||||
get_edited_object()->editor_set_section_unfold(get_edited_property(), unfold);
|
||||
update_property();
|
||||
} else {
|
||||
} else if (!is_checkable() || is_checked()) {
|
||||
emit_signal(SNAME("resource_selected"), get_edited_property(), p_resource);
|
||||
}
|
||||
}
|
||||
|
|
@ -3036,15 +3094,14 @@ static bool _find_recursive_resources(const Variant &v, HashSet<Resource *> &res
|
|||
} break;
|
||||
case Variant::DICTIONARY: {
|
||||
Dictionary d = v;
|
||||
List<Variant> keys;
|
||||
d.get_key_list(&keys);
|
||||
for (const Variant &k : keys) {
|
||||
for (const KeyValue<Variant, Variant> &kv : d) {
|
||||
const Variant &k = kv.key;
|
||||
const Variant &v2 = kv.value;
|
||||
if (k.get_type() == Variant::ARRAY || k.get_type() == Variant::DICTIONARY || k.get_type() == Variant::OBJECT) {
|
||||
if (_find_recursive_resources(k, resources_found)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Variant v2 = d[k];
|
||||
if (v2.get_type() == Variant::ARRAY || v2.get_type() == Variant::DICTIONARY || v2.get_type() == Variant::OBJECT) {
|
||||
if (_find_recursive_resources(v2, resources_found)) {
|
||||
return true;
|
||||
|
|
@ -3228,8 +3285,9 @@ void EditorPropertyResource::_viewport_selected(const NodePath &p_path) {
|
|||
return;
|
||||
}
|
||||
|
||||
Ref<ViewportTexture> vt;
|
||||
vt.instantiate();
|
||||
Ref<ViewportTexture> vt = get_edited_property_value();
|
||||
ERR_FAIL_COND(vt.is_null());
|
||||
|
||||
vt->set_viewport_path_in_scene(get_tree()->get_edited_scene_root()->get_path_to(to_node));
|
||||
|
||||
emit_changed(get_edited_property(), vt);
|
||||
|
|
@ -3276,7 +3334,7 @@ void EditorPropertyResource::setup(Object *p_object, const String &p_path, const
|
|||
}
|
||||
|
||||
void EditorPropertyResource::update_property() {
|
||||
Ref<Resource> res = get_edited_property_value();
|
||||
Ref<Resource> res = get_edited_property_display_value();
|
||||
|
||||
if (use_sub_inspector) {
|
||||
if (res.is_valid() != resource_picker->is_toggle_mode()) {
|
||||
|
|
@ -3303,11 +3361,11 @@ void EditorPropertyResource::update_property() {
|
|||
sub_inspector->set_use_folding(is_using_folding());
|
||||
|
||||
sub_inspector->set_draw_focus_border(false);
|
||||
sub_inspector->set_focus_mode(FocusMode::FOCUS_NONE);
|
||||
|
||||
sub_inspector->set_use_filter(use_filter);
|
||||
sub_inspector->register_text_enter(parent_inspector->search_box);
|
||||
|
||||
sub_inspector->set_mouse_filter(MOUSE_FILTER_STOP);
|
||||
add_child(sub_inspector);
|
||||
set_bottom_editor(sub_inspector);
|
||||
|
||||
|
|
@ -3328,6 +3386,8 @@ void EditorPropertyResource::update_property() {
|
|||
}
|
||||
}
|
||||
|
||||
sub_inspector->set_read_only(is_checkable() && !is_checked());
|
||||
|
||||
if (res.ptr() != sub_inspector->get_edited_object()) {
|
||||
sub_inspector->edit(res.ptr());
|
||||
_update_property_bg();
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_PROPERTIES_H
|
||||
#define EDITOR_PROPERTIES_H
|
||||
#pragma once
|
||||
|
||||
#include "editor/editor_inspector.h"
|
||||
|
||||
|
|
@ -629,10 +628,12 @@ class EditorPropertyNodePath : public EditorProperty {
|
|||
SceneTreeDialog *scene_tree = nullptr;
|
||||
bool use_path_from_scene_root = false;
|
||||
bool editing_node = false;
|
||||
bool dropping = false;
|
||||
|
||||
Vector<StringName> valid_types;
|
||||
void _node_selected(const NodePath &p_path, bool p_absolute = true);
|
||||
void _node_assign();
|
||||
void _assign_draw();
|
||||
Node *get_base_node();
|
||||
void _update_menu();
|
||||
void _menu_option(int p_idx);
|
||||
|
|
@ -723,5 +724,3 @@ public:
|
|||
|
||||
static EditorProperty *get_editor_for_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide = false);
|
||||
};
|
||||
|
||||
#endif // EDITOR_PROPERTIES_H
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "core/input/input.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "editor/editor_file_system.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_properties.h"
|
||||
#include "editor/editor_properties_vector.h"
|
||||
#include "editor/editor_settings.h"
|
||||
|
|
@ -52,9 +53,9 @@ bool EditorPropertyArrayObject::_set(const StringName &p_name, const Variant &p_
|
|||
|
||||
int index;
|
||||
if (name.begins_with("metadata/")) {
|
||||
index = name.get_slice("/", 2).to_int();
|
||||
index = name.get_slicec('/', 2).to_int();
|
||||
} else {
|
||||
index = name.get_slice("/", 1).to_int();
|
||||
index = name.get_slicec('/', 1).to_int();
|
||||
}
|
||||
|
||||
array.set(index, p_value);
|
||||
|
|
@ -70,9 +71,9 @@ bool EditorPropertyArrayObject::_get(const StringName &p_name, Variant &r_ret) c
|
|||
|
||||
int index;
|
||||
if (name.begins_with("metadata/")) {
|
||||
index = name.get_slice("/", 2).to_int();
|
||||
index = name.get_slicec('/', 2).to_int();
|
||||
} else {
|
||||
index = name.get_slice("/", 1).to_int();
|
||||
index = name.get_slicec('/', 1).to_int();
|
||||
}
|
||||
|
||||
bool valid;
|
||||
|
|
@ -93,9 +94,6 @@ Variant EditorPropertyArrayObject::get_array() {
|
|||
return array;
|
||||
}
|
||||
|
||||
EditorPropertyArrayObject::EditorPropertyArrayObject() {
|
||||
}
|
||||
|
||||
///////////////////
|
||||
|
||||
bool EditorPropertyDictionaryObject::_set(const StringName &p_name, const Variant &p_value) {
|
||||
|
|
@ -232,9 +230,6 @@ String EditorPropertyDictionaryObject::get_label_for_index(int p_index) {
|
|||
}
|
||||
}
|
||||
|
||||
EditorPropertyDictionaryObject::EditorPropertyDictionaryObject() {
|
||||
}
|
||||
|
||||
///////////////////// ARRAY ///////////////////////////
|
||||
|
||||
void EditorPropertyArray::initialize_array(Variant &p_array) {
|
||||
|
|
@ -263,7 +258,7 @@ void EditorPropertyArray::_property_changed(const String &p_property, Variant p_
|
|||
p_value = Variant(); // `EditorResourcePicker` resets to `Ref<Resource>()`. See GH-82716.
|
||||
}
|
||||
|
||||
int index = p_property.get_slice("/", 1).to_int();
|
||||
int index = p_property.get_slicec('/', 1).to_int();
|
||||
|
||||
Variant array = object->get_array().duplicate();
|
||||
array.set(index, p_value);
|
||||
|
|
@ -310,6 +305,7 @@ void EditorPropertyArray::_create_new_property_slot() {
|
|||
HBoxContainer *hbox = memnew(HBoxContainer);
|
||||
|
||||
Button *reorder_button = memnew(Button);
|
||||
reorder_button->set_accessibility_name(TTRC("Reorder"));
|
||||
reorder_button->set_button_icon(get_editor_theme_icon(SNAME("TripleBar")));
|
||||
reorder_button->set_default_cursor_shape(Control::CURSOR_MOVE);
|
||||
reorder_button->set_disabled(is_read_only());
|
||||
|
|
@ -325,12 +321,14 @@ void EditorPropertyArray::_create_new_property_slot() {
|
|||
|
||||
if (is_untyped_array) {
|
||||
Button *edit_btn = memnew(Button);
|
||||
edit_btn->set_accessibility_name(TTRC("Edit"));
|
||||
edit_btn->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
|
||||
edit_btn->set_disabled(is_read_only());
|
||||
edit_btn->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyArray::_change_type).bind(edit_btn, idx));
|
||||
hbox->add_child(edit_btn);
|
||||
} else {
|
||||
Button *remove_btn = memnew(Button);
|
||||
remove_btn->set_accessibility_name(TTRC("Remove"));
|
||||
remove_btn->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
|
||||
remove_btn->set_disabled(is_read_only());
|
||||
remove_btn->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyArray::_remove_pressed).bind(idx));
|
||||
|
|
@ -401,7 +399,7 @@ void EditorPropertyArray::update_property() {
|
|||
}
|
||||
|
||||
if (preview_value) {
|
||||
String ctr_str = array.get_construct_string().trim_prefix(array_type_name + "(").trim_suffix(")").replace("\n", "");
|
||||
String ctr_str = array.get_construct_string().trim_prefix(array_type_name + "(").trim_suffix(")").remove_char('\n');
|
||||
if (array_type == Variant::ARRAY && subtype != Variant::NIL) {
|
||||
int type_end = ctr_str.find("](");
|
||||
if (type_end > 0) {
|
||||
|
|
@ -430,7 +428,6 @@ void EditorPropertyArray::update_property() {
|
|||
|
||||
if (!container) {
|
||||
container = memnew(PanelContainer);
|
||||
container->set_mouse_filter(MOUSE_FILTER_STOP);
|
||||
add_child(container);
|
||||
set_bottom_editor(container);
|
||||
|
||||
|
|
@ -450,6 +447,7 @@ void EditorPropertyArray::update_property() {
|
|||
size_slider->set_editing_integer(true);
|
||||
size_slider->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
size_slider->set_read_only(is_read_only());
|
||||
size_slider->set_accessibility_name(TTRC("Size"));
|
||||
size_slider->connect(SceneStringName(value_changed), callable_mp(this, &EditorPropertyArray::_length_changed));
|
||||
hbox->add_child(size_slider);
|
||||
|
||||
|
|
@ -460,7 +458,10 @@ void EditorPropertyArray::update_property() {
|
|||
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Element"));
|
||||
button_add_item->set_button_icon(get_editor_theme_icon(SNAME("Add")));
|
||||
button_add_item->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyArray::_add_element));
|
||||
button_add_item->connect(SceneStringName(draw), callable_mp(this, &EditorPropertyArray::_button_add_item_draw));
|
||||
SET_DRAG_FORWARDING_CD(button_add_item, EditorPropertyArray);
|
||||
button_add_item->set_disabled(is_read_only());
|
||||
button_add_item->set_accessibility_name(TTRC("Add"));
|
||||
vbox->add_child(button_add_item);
|
||||
|
||||
paginator = memnew(EditorPaginator);
|
||||
|
|
@ -551,6 +552,13 @@ void EditorPropertyArray::_button_draw() {
|
|||
}
|
||||
}
|
||||
|
||||
void EditorPropertyArray::_button_add_item_draw() {
|
||||
if (dropping) {
|
||||
Color color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
|
||||
button_add_item->draw_rect(Rect2(Point2(), button_add_item->get_size()), color, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
|
||||
if (is_read_only()) {
|
||||
return false;
|
||||
|
|
@ -570,14 +578,19 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
|
|||
if (drop_type == "files") {
|
||||
PackedStringArray files = drag_data["files"];
|
||||
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
const String &file = files[i];
|
||||
String ftype = EditorFileSystem::get_singleton()->get_file_type(file);
|
||||
for (const String &file : files) {
|
||||
int idx_in_dir;
|
||||
EditorFileSystemDirectory const *dir = EditorFileSystem::get_singleton()->find_file(file, &idx_in_dir);
|
||||
if (!dir) {
|
||||
return false;
|
||||
}
|
||||
StringName ftype = dir->get_file_type(idx_in_dir);
|
||||
String script_class = dir->get_file_resource_script_class(idx_in_dir);
|
||||
|
||||
for (int j = 0; j < allowed_type.get_slice_count(","); j++) {
|
||||
String at = allowed_type.get_slice(",", j).strip_edges();
|
||||
for (String at : allowed_type.split(",", false)) {
|
||||
at = at.strip_edges();
|
||||
// Fail if one of the files is not of allowed type.
|
||||
if (!ClassDB::is_parent_class(ftype, at)) {
|
||||
if (!ClassDB::is_parent_class(ftype, at) && !EditorNode::get_editor_data().script_class_is_parent(script_class, at)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -587,6 +600,28 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (drop_type == "resource") {
|
||||
Ref<Resource> res = drag_data["resource"];
|
||||
if (res.is_null()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String res_type = res->get_class();
|
||||
StringName script_class;
|
||||
if (res->get_script()) {
|
||||
script_class = EditorNode::get_singleton()->get_object_custom_type_name(res->get_script());
|
||||
}
|
||||
|
||||
for (String at : allowed_type.split(",", false)) {
|
||||
at = at.strip_edges();
|
||||
if (ClassDB::is_parent_class(res_type, at) || EditorNode::get_editor_data().script_class_is_parent(script_class, at)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (drop_type == "nodes") {
|
||||
Array node_paths = drag_data["nodes"];
|
||||
|
||||
|
|
@ -595,8 +630,8 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
|
|||
if (subtype_hint_string == "NodePath") {
|
||||
return true;
|
||||
} else {
|
||||
for (int j = 0; j < subtype_hint_string.get_slice_count(","); j++) {
|
||||
String ast = subtype_hint_string.get_slice(",", j).strip_edges();
|
||||
for (String ast : subtype_hint_string.split(",", false)) {
|
||||
ast = ast.strip_edges();
|
||||
allowed_subtype_array.append(ast);
|
||||
}
|
||||
}
|
||||
|
|
@ -609,7 +644,8 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
|
|||
ERR_FAIL_NULL_V_MSG(dropped_node, false, "Could not get the dropped node by its path.");
|
||||
|
||||
if (allowed_type != "NodePath") {
|
||||
if (!ClassDB::is_parent_class(dropped_node->get_class_name(), allowed_type)) {
|
||||
if (!ClassDB::is_parent_class(dropped_node->get_class_name(), allowed_type) &&
|
||||
!EditorNode::get_singleton()->is_object_of_custom_type(dropped_node, allowed_type)) {
|
||||
// Fail if one of the nodes is not of allowed type.
|
||||
return false;
|
||||
}
|
||||
|
|
@ -620,7 +656,8 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
|
|||
if (!allowed_subtype_array.has(dropped_node->get_class_name())) {
|
||||
// The dropped node type was not found in the allowed subtype array, we must check if it inherits one of them.
|
||||
for (const String &ast : allowed_subtype_array) {
|
||||
if (ClassDB::is_parent_class(dropped_node->get_class_name(), ast)) {
|
||||
if (ClassDB::is_parent_class(dropped_node->get_class_name(), ast) ||
|
||||
EditorNode::get_singleton()->is_object_of_custom_type(dropped_node, ast)) {
|
||||
is_drop_allowed = true;
|
||||
break;
|
||||
} else {
|
||||
|
|
@ -645,8 +682,6 @@ bool EditorPropertyArray::can_drop_data_fw(const Point2 &p_point, const Variant
|
|||
}
|
||||
|
||||
void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
|
||||
ERR_FAIL_COND(!_is_drop_valid(p_data));
|
||||
|
||||
Dictionary drag_data = p_data;
|
||||
const String drop_type = drag_data.get("type", "");
|
||||
Variant array = object->get_array();
|
||||
|
|
@ -674,6 +709,16 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d
|
|||
emit_changed(get_edited_property(), array);
|
||||
}
|
||||
|
||||
if (drop_type == "resource") {
|
||||
Ref<Resource> res = drag_data["resource"];
|
||||
|
||||
if (res.is_valid()) {
|
||||
array.call("push_back", res);
|
||||
|
||||
emit_changed(get_edited_property(), array);
|
||||
}
|
||||
}
|
||||
|
||||
if (drop_type == "nodes") {
|
||||
Array node_paths = drag_data["nodes"];
|
||||
Node *base_node = get_base_node();
|
||||
|
|
@ -729,6 +774,9 @@ void EditorPropertyArray::_notification(int p_what) {
|
|||
if (_is_drop_valid(get_viewport()->gui_get_drag_data())) {
|
||||
dropping = true;
|
||||
edit->queue_redraw();
|
||||
if (button_add_item) {
|
||||
button_add_item->queue_redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
|
@ -737,6 +785,9 @@ void EditorPropertyArray::_notification(int p_what) {
|
|||
if (dropping) {
|
||||
dropping = false;
|
||||
edit->queue_redraw();
|
||||
if (button_add_item) {
|
||||
button_add_item->queue_redraw();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
|
@ -808,11 +859,11 @@ void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint
|
|||
String subtype_string = p_hint_string.substr(0, hint_subtype_separator);
|
||||
int slash_pos = subtype_string.find_char('/');
|
||||
if (slash_pos >= 0) {
|
||||
subtype_hint = PropertyHint(subtype_string.substr(slash_pos + 1, subtype_string.size() - slash_pos - 1).to_int());
|
||||
subtype_hint = PropertyHint(subtype_string.substr(slash_pos + 1).to_int());
|
||||
subtype_string = subtype_string.substr(0, slash_pos);
|
||||
}
|
||||
|
||||
subtype_hint_string = p_hint_string.substr(hint_subtype_separator + 1, p_hint_string.size() - hint_subtype_separator - 1);
|
||||
subtype_hint_string = p_hint_string.substr(hint_subtype_separator + 1);
|
||||
subtype = Variant::Type(subtype_string.to_int());
|
||||
}
|
||||
}
|
||||
|
|
@ -839,7 +890,7 @@ void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_eve
|
|||
}
|
||||
|
||||
float required_y_distance = 20.0f * EDSCALE;
|
||||
if (ABS(reorder_mouse_y_delta) > required_y_distance) {
|
||||
if (Math::abs(reorder_mouse_y_delta) > required_y_distance) {
|
||||
int direction = reorder_mouse_y_delta > 0.0f ? 1 : -1;
|
||||
reorder_mouse_y_delta -= required_y_distance * direction;
|
||||
|
||||
|
|
@ -851,8 +902,12 @@ void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_eve
|
|||
// Automatically move to the next/previous page.
|
||||
_page_changed(page_index + direction);
|
||||
}
|
||||
// Ensure the moving element is visible.
|
||||
InspectorDock::get_inspector_singleton()->ensure_control_visible(reorder_slot.container);
|
||||
// Ensure the moving element is visible in the root inspector.
|
||||
EditorInspector *parent_inspector = get_parent_inspector();
|
||||
if (parent_inspector) {
|
||||
// Defer to prevent moving elements from not displaying properly, especially near borders.
|
||||
callable_mp((ScrollContainer *)parent_inspector->get_root_inspector(), &ScrollContainer::ensure_control_visible).call_deferred(reorder_slot.container);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -905,6 +960,7 @@ EditorPropertyArray::EditorPropertyArray() {
|
|||
page_length = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page"));
|
||||
|
||||
edit = memnew(Button);
|
||||
edit->set_accessibility_name(TTRC("Edit"));
|
||||
edit->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
edit->set_clip_text(true);
|
||||
edit->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyArray::_edit_pressed));
|
||||
|
|
@ -1018,12 +1074,14 @@ void EditorPropertyDictionary::_create_new_property_slot(int p_idx) {
|
|||
|
||||
if (is_untyped_dict) {
|
||||
Button *edit_btn = memnew(Button);
|
||||
edit_btn->set_accessibility_name(TTRC("Edit"));
|
||||
edit_btn->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
|
||||
edit_btn->set_disabled(is_read_only());
|
||||
edit_btn->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyDictionary::_change_type).bind(edit_btn, slots.size()));
|
||||
hbox->add_child(edit_btn);
|
||||
} else if (p_idx >= 0) {
|
||||
Button *remove_btn = memnew(Button);
|
||||
remove_btn->set_accessibility_name(TTRC("Remove"));
|
||||
remove_btn->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
|
||||
remove_btn->set_disabled(is_read_only());
|
||||
remove_btn->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyDictionary::_remove_pressed).bind(slots.size()));
|
||||
|
|
@ -1091,11 +1149,11 @@ void EditorPropertyDictionary::setup(PropertyHint p_hint, const String &p_hint_s
|
|||
String key_subtype_string = key.substr(0, hint_key_subtype_separator);
|
||||
int slash_pos = key_subtype_string.find_char('/');
|
||||
if (slash_pos >= 0) {
|
||||
key_subtype_hint = PropertyHint(key_subtype_string.substr(slash_pos + 1, key_subtype_string.size() - slash_pos - 1).to_int());
|
||||
key_subtype_hint = PropertyHint(key_subtype_string.substr(slash_pos + 1).to_int());
|
||||
key_subtype_string = key_subtype_string.substr(0, slash_pos);
|
||||
}
|
||||
|
||||
key_subtype_hint_string = key.substr(hint_key_subtype_separator + 1, key.size() - hint_key_subtype_separator - 1);
|
||||
key_subtype_hint_string = key.substr(hint_key_subtype_separator + 1);
|
||||
key_subtype = Variant::Type(key_subtype_string.to_int());
|
||||
|
||||
Variant new_key = object->get_new_item_key();
|
||||
|
|
@ -1110,11 +1168,11 @@ void EditorPropertyDictionary::setup(PropertyHint p_hint, const String &p_hint_s
|
|||
String value_subtype_string = value.substr(0, hint_value_subtype_separator);
|
||||
int slash_pos = value_subtype_string.find_char('/');
|
||||
if (slash_pos >= 0) {
|
||||
value_subtype_hint = PropertyHint(value_subtype_string.substr(slash_pos + 1, value_subtype_string.size() - slash_pos - 1).to_int());
|
||||
value_subtype_hint = PropertyHint(value_subtype_string.substr(slash_pos + 1).to_int());
|
||||
value_subtype_string = value_subtype_string.substr(0, slash_pos);
|
||||
}
|
||||
|
||||
value_subtype_hint_string = value.substr(hint_value_subtype_separator + 1, value.size() - hint_value_subtype_separator - 1);
|
||||
value_subtype_hint_string = value.substr(hint_value_subtype_separator + 1);
|
||||
value_subtype = Variant::Type(value_subtype_string.to_int());
|
||||
|
||||
Variant new_value = object->get_new_item_value();
|
||||
|
|
@ -1179,7 +1237,7 @@ void EditorPropertyDictionary::update_property() {
|
|||
object->set_dict(updated_val);
|
||||
|
||||
if (preview_value) {
|
||||
String ctr_str = updated_val.get_construct_string().replace("\n", "");
|
||||
String ctr_str = updated_val.get_construct_string().remove_char('\n');
|
||||
if (key_subtype != Variant::NIL || value_subtype != Variant::NIL) {
|
||||
int type_end = ctr_str.find("](");
|
||||
if (type_end > 0) {
|
||||
|
|
@ -1208,7 +1266,6 @@ void EditorPropertyDictionary::update_property() {
|
|||
|
||||
if (!container) {
|
||||
container = memnew(PanelContainer);
|
||||
container->set_mouse_filter(MOUSE_FILTER_STOP);
|
||||
add_child(container);
|
||||
set_bottom_editor(container);
|
||||
|
||||
|
|
@ -1239,6 +1296,7 @@ void EditorPropertyDictionary::update_property() {
|
|||
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Key/Value Pair"));
|
||||
button_add_item->set_button_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons)));
|
||||
button_add_item->set_disabled(is_read_only());
|
||||
button_add_item->set_accessibility_name(TTRC("Add"));
|
||||
button_add_item->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyDictionary::_add_key_value));
|
||||
add_vbox->add_child(button_add_item);
|
||||
}
|
||||
|
|
@ -1302,7 +1360,14 @@ void EditorPropertyDictionary::update_property() {
|
|||
|
||||
Variant value;
|
||||
object->get_by_property_name(slot.prop_name, value);
|
||||
Variant::Type value_type = value.get_type();
|
||||
|
||||
Variant::Type value_type;
|
||||
|
||||
if (dict.is_typed_value() && slot.prop_key) {
|
||||
value_type = value_subtype;
|
||||
} else {
|
||||
value_type = value.get_type();
|
||||
}
|
||||
|
||||
// Check if the editor property needs to be updated.
|
||||
bool value_as_id = Object::cast_to<EncodedObjectAsID>(value);
|
||||
|
|
@ -1433,6 +1498,7 @@ EditorPropertyDictionary::EditorPropertyDictionary() {
|
|||
page_length = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page"));
|
||||
|
||||
edit = memnew(Button);
|
||||
edit->set_accessibility_name(TTRC("Edit"));
|
||||
edit->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
edit->set_clip_text(true);
|
||||
edit->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyDictionary::_edit_pressed));
|
||||
|
|
@ -1462,7 +1528,7 @@ EditorPropertyDictionary::EditorPropertyDictionary() {
|
|||
|
||||
void EditorPropertyLocalizableString::_property_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) {
|
||||
if (p_property.begins_with("indices")) {
|
||||
int index = p_property.get_slice("/", 1).to_int();
|
||||
int index = p_property.get_slicec('/', 1).to_int();
|
||||
|
||||
Dictionary dict = object->get_dict().duplicate();
|
||||
Variant key = dict.get_key_at_index(index);
|
||||
|
|
@ -1588,6 +1654,7 @@ void EditorPropertyLocalizableString::update_property() {
|
|||
hbox->add_child(prop);
|
||||
prop->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
Button *edit_btn = memnew(Button);
|
||||
edit_btn->set_accessibility_name(TTRC("Remove Translation"));
|
||||
edit_btn->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
|
||||
hbox->add_child(edit_btn);
|
||||
edit_btn->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyLocalizableString::_remove_item).bind(edit_btn, remove_index));
|
||||
|
|
@ -1597,6 +1664,7 @@ void EditorPropertyLocalizableString::update_property() {
|
|||
|
||||
if (page_index == max_page) {
|
||||
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Translation"));
|
||||
button_add_item->set_accessibility_name(TTRC("Add Translation"));
|
||||
button_add_item->set_button_icon(get_editor_theme_icon(SNAME("Add")));
|
||||
button_add_item->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyLocalizableString::_add_locale_popup));
|
||||
property_vbox->add_child(button_add_item);
|
||||
|
|
@ -1653,6 +1721,7 @@ EditorPropertyLocalizableString::EditorPropertyLocalizableString() {
|
|||
page_length = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page"));
|
||||
|
||||
edit = memnew(Button);
|
||||
edit->set_accessibility_name(TTRC("Edit"));
|
||||
edit->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
edit->set_clip_text(true);
|
||||
edit->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyLocalizableString::_edit_pressed));
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_PROPERTIES_ARRAY_DICT_H
|
||||
#define EDITOR_PROPERTIES_ARRAY_DICT_H
|
||||
#pragma once
|
||||
|
||||
#include "editor/editor_inspector.h"
|
||||
#include "editor/editor_locale_dialog.h"
|
||||
|
|
@ -54,8 +53,6 @@ public:
|
|||
|
||||
void set_array(const Variant &p_array);
|
||||
Variant get_array();
|
||||
|
||||
EditorPropertyArrayObject();
|
||||
};
|
||||
|
||||
class EditorPropertyDictionaryObject : public RefCounted {
|
||||
|
|
@ -89,8 +86,6 @@ public:
|
|||
String get_label_for_index(int p_index);
|
||||
String get_property_name_for_index(int p_index);
|
||||
String get_key_name_for_index(int p_index);
|
||||
|
||||
EditorPropertyDictionaryObject();
|
||||
};
|
||||
|
||||
class EditorPropertyArray : public EditorProperty {
|
||||
|
|
@ -164,6 +159,7 @@ protected:
|
|||
virtual void _remove_pressed(int p_index);
|
||||
|
||||
virtual void _button_draw();
|
||||
virtual void _button_add_item_draw();
|
||||
virtual bool _is_drop_valid(const Dictionary &p_drag_data) const;
|
||||
virtual bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
|
||||
virtual void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
|
||||
|
|
@ -305,5 +301,3 @@ public:
|
|||
virtual void update_property() override;
|
||||
EditorPropertyLocalizableString();
|
||||
};
|
||||
|
||||
#endif // EDITOR_PROPERTIES_ARRAY_DICT_H
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ EditorPropertyVectorN::EditorPropertyVectorN(Variant::Type p_type, bool p_force_
|
|||
bc->add_child(spin[i]);
|
||||
spin[i]->set_flat(true);
|
||||
spin[i]->set_label(String(COMPONENT_LABELS[i]));
|
||||
spin[i]->set_accessibility_name(String(COMPONENT_LABELS[i]));
|
||||
if (horizontal) {
|
||||
spin[i]->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
}
|
||||
|
|
@ -238,6 +239,7 @@ EditorPropertyVectorN::EditorPropertyVectorN(Variant::Type p_type, bool p_force_
|
|||
linked->set_toggle_mode(true);
|
||||
linked->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED);
|
||||
linked->set_tooltip_text(TTR("Lock/Unlock Component Ratio"));
|
||||
linked->set_accessibility_name(TTRC("Lock/Unlock Component Ratio"));
|
||||
linked->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyVectorN::_update_ratio));
|
||||
linked->connect(SceneStringName(toggled), callable_mp(this, &EditorPropertyVectorN::_store_link));
|
||||
hb->add_child(linked);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_PROPERTIES_VECTOR_H
|
||||
#define EDITOR_PROPERTIES_VECTOR_H
|
||||
#pragma once
|
||||
|
||||
#include "editor/editor_inspector.h"
|
||||
|
||||
|
|
@ -107,5 +106,3 @@ class EditorPropertyVector4i : public EditorPropertyVectorN {
|
|||
public:
|
||||
EditorPropertyVector4i(bool p_force_wide = false);
|
||||
};
|
||||
|
||||
#endif // EDITOR_PROPERTIES_VECTOR_H
|
||||
|
|
|
|||
|
|
@ -59,11 +59,7 @@ EditorPropertyNameProcessor::Style EditorPropertyNameProcessor::get_tooltip_styl
|
|||
}
|
||||
|
||||
bool EditorPropertyNameProcessor::is_localization_available() {
|
||||
if (!EditorSettings::get_singleton()) {
|
||||
return false;
|
||||
}
|
||||
const Vector<String> forbidden = String("en").split(",");
|
||||
return !forbidden.has(EDITOR_GET("interface/editor/editor_language"));
|
||||
return EditorSettings::get_singleton() && EDITOR_GET("interface/editor/editor_language") != "en";
|
||||
}
|
||||
|
||||
String EditorPropertyNameProcessor::_capitalize_name(const String &p_name) const {
|
||||
|
|
@ -300,6 +296,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
|
|||
capitalize_string_remaps["us"] = U"(µs)"; // Unit.
|
||||
capitalize_string_remaps["usb"] = "USB";
|
||||
capitalize_string_remaps["usec"] = U"(µsec)"; // Unit.
|
||||
capitalize_string_remaps["uid"] = "UID";
|
||||
capitalize_string_remaps["uuid"] = "UUID";
|
||||
capitalize_string_remaps["uv"] = "UV";
|
||||
capitalize_string_remaps["uv1"] = "UV1";
|
||||
|
|
@ -314,6 +311,8 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
|
|||
capitalize_string_remaps["webrtc"] = "WebRTC";
|
||||
capitalize_string_remaps["websocket"] = "WebSocket";
|
||||
capitalize_string_remaps["wine"] = "wine";
|
||||
capitalize_string_remaps["wintab"] = "WinTab";
|
||||
capitalize_string_remaps["winink"] = "Windows Ink";
|
||||
capitalize_string_remaps["wifi"] = "Wi-Fi";
|
||||
capitalize_string_remaps["x86"] = "x86";
|
||||
capitalize_string_remaps["x86_32"] = "x86_32";
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef EDITOR_PROPERTY_NAME_PROCESSOR_H
|
||||
#define EDITOR_PROPERTY_NAME_PROCESSOR_H
|
||||
#pragma once
|
||||
|
||||
#include "scene/main/node.h"
|
||||
|
||||
|
|
@ -76,5 +75,3 @@ public:
|
|||
EditorPropertyNameProcessor();
|
||||
~EditorPropertyNameProcessor();
|
||||
};
|
||||
|
||||
#endif // EDITOR_PROPERTY_NAME_PROCESSOR_H
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue