mirror of
https://github.com/godotengine/godot.git
synced 2024-11-10 14:12:51 +00:00
Add support for internal nodes
This commit is contained in:
parent
d04aa9a114
commit
a913ae8d56
@ -109,9 +109,11 @@
|
||||
<return type="void" />
|
||||
<argument index="0" name="node" type="Node" />
|
||||
<argument index="1" name="legible_unique_name" type="bool" default="false" />
|
||||
<argument index="2" name="internal" type="int" enum="Node.InternalMode" default="0" />
|
||||
<description>
|
||||
Adds a child node. Nodes can have any number of children, but every child must have a unique name. Child nodes are automatically deleted when the parent node is deleted, so an entire scene can be removed by deleting its topmost node.
|
||||
If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instantiated instead of its type.
|
||||
If [code]internal[/code] is different than [constant INTERNAL_MODE_DISABLED], the child will be added as internal node. Such nodes are ignored by methods like [method get_children], unless their parameter [code]include_internal[/code] is [code]true[/code].The intended usage is to hide the internal nodes from the user, so the user won't accidentally delete or modify them. Used by some GUI nodes, e.g. [ColorPicker]. See [enum InternalMode] for available modes.
|
||||
[b]Note:[/b] If the child node already has a parent, the function will fail. Use [method remove_child] first to remove the node from its current parent. For example:
|
||||
[codeblocks]
|
||||
[gdscript]
|
||||
@ -141,6 +143,7 @@
|
||||
Adds a [code]sibling[/code] node to current's node parent, at the same level as that node, right below it.
|
||||
If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instantiated instead of its type.
|
||||
Use [method add_child] instead of this method if you don't need the child node to be added below a specific node in the list of children.
|
||||
[b]Note:[/b] If this node is internal, the new sibling will be internal too (see [code]internal[/code] parameter in [method add_child]).
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_to_group">
|
||||
@ -200,22 +203,28 @@
|
||||
<method name="get_child" qualifiers="const">
|
||||
<return type="Node" />
|
||||
<argument index="0" name="idx" type="int" />
|
||||
<argument index="1" name="include_internal" type="bool" default="false" />
|
||||
<description>
|
||||
Returns a child node by its index (see [method get_child_count]). This method is often used for iterating all children of a node.
|
||||
Negative indices access the children from the last one.
|
||||
If [code]include_internal[/code] is [code]true[/code], internal children are skipped (see [code]internal[/code] parameter in [method add_child]).
|
||||
To access a child node via its name, use [method get_node].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_child_count" qualifiers="const">
|
||||
<return type="int" />
|
||||
<argument index="0" name="include_internal" type="bool" default="false" />
|
||||
<description>
|
||||
Returns the number of child nodes.
|
||||
If [code]include_internal[/code] is [code]false[/code], internal children aren't counted (see [code]internal[/code] parameter in [method add_child]).
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_children" qualifiers="const">
|
||||
<return type="Node[]" />
|
||||
<argument index="0" name="include_internal" type="bool" default="false" />
|
||||
<description>
|
||||
Returns an array of references to node's children.
|
||||
If [code]include_internal[/code] is [code]false[/code], the returned array won't include internal children (see [code]internal[/code] parameter in [method add_child]).
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_editor_description" qualifiers="const">
|
||||
@ -231,8 +240,10 @@
|
||||
</method>
|
||||
<method name="get_index" qualifiers="const">
|
||||
<return type="int" />
|
||||
<argument index="0" name="include_internal" type="bool" default="false" />
|
||||
<description>
|
||||
Returns the node's order in the scene tree branch. For example, if called on the first child node the position is [code]0[/code].
|
||||
If [code]include_internal[/code] is [code]false[/code], the index won't take internal children into account, i.e. first non-internal child will have index of 0 (see [code]internal[/code] parameter in [method add_child]).
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_network_master" qualifiers="const">
|
||||
@ -460,6 +471,7 @@
|
||||
<argument index="1" name="to_position" type="int" />
|
||||
<description>
|
||||
Moves a child node to a different position (order) among the other children. Since calls, signals, etc are performed by tree order, changing the order of children nodes may be useful.
|
||||
[b]Note:[/b] Internal children can only be moved within their expected "internal range" (see [code]internal[/code] parameter in [method add_child]).
|
||||
</description>
|
||||
</method>
|
||||
<method name="print_stray_nodes">
|
||||
@ -888,5 +900,14 @@
|
||||
Duplicate using instancing.
|
||||
An instance stays linked to the original so when the original changes, the instance changes too.
|
||||
</constant>
|
||||
<constant name="INTERNAL_MODE_DISABLED" value="0" enum="InternalMode">
|
||||
Node will not be internal.
|
||||
</constant>
|
||||
<constant name="INTERNAL_MODE_FRONT" value="1" enum="InternalMode">
|
||||
Node will be placed at the front of parent's node list, before any non-internal sibling.
|
||||
</constant>
|
||||
<constant name="INTERNAL_MODE_BACK" value="2" enum="InternalMode">
|
||||
Node will be placed at the back of parent's node list, after any non-internal sibling.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
@ -351,11 +351,11 @@ MarginContainer *VBoxContainer::add_margin_child(const String &p_label, Control
|
||||
Label *l = memnew(Label);
|
||||
l->set_theme_type_variation("HeaderSmall");
|
||||
l->set_text(p_label);
|
||||
add_child(l);
|
||||
add_child(l, false, INTERNAL_MODE_FRONT);
|
||||
MarginContainer *mc = memnew(MarginContainer);
|
||||
mc->add_theme_constant_override("margin_left", 0);
|
||||
mc->add_child(p_control);
|
||||
add_child(mc);
|
||||
add_child(mc, false, INTERNAL_MODE_FRONT);
|
||||
if (p_expand) {
|
||||
mc->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
}
|
||||
|
@ -1139,7 +1139,7 @@ void ColorPicker::_bind_methods() {
|
||||
ColorPicker::ColorPicker() :
|
||||
BoxContainer(true) {
|
||||
HBoxContainer *hb_edit = memnew(HBoxContainer);
|
||||
add_child(hb_edit);
|
||||
add_child(hb_edit, false, INTERNAL_MODE_FRONT);
|
||||
hb_edit->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
|
||||
hb_edit->add_child(uv_edit);
|
||||
@ -1151,7 +1151,7 @@ ColorPicker::ColorPicker() :
|
||||
uv_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, uv_edit));
|
||||
|
||||
HBoxContainer *hb_smpl = memnew(HBoxContainer);
|
||||
add_child(hb_smpl);
|
||||
add_child(hb_smpl, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
hb_smpl->add_child(sample);
|
||||
sample->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
@ -1165,12 +1165,12 @@ ColorPicker::ColorPicker() :
|
||||
btn_pick->connect("pressed", callable_mp(this, &ColorPicker::_screen_pick_pressed));
|
||||
|
||||
VBoxContainer *vbl = memnew(VBoxContainer);
|
||||
add_child(vbl);
|
||||
add_child(vbl, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
add_child(memnew(HSeparator));
|
||||
add_child(memnew(HSeparator), false, INTERNAL_MODE_FRONT);
|
||||
|
||||
VBoxContainer *vbr = memnew(VBoxContainer);
|
||||
add_child(vbr);
|
||||
add_child(vbr, false, INTERNAL_MODE_FRONT);
|
||||
vbr->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@ -1273,11 +1273,11 @@ ColorPicker::ColorPicker() :
|
||||
|
||||
set_pick_color(Color(1, 1, 1));
|
||||
|
||||
add_child(preset_separator);
|
||||
add_child(preset_separator, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
preset_container->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
preset_container->set_columns(preset_column_count);
|
||||
add_child(preset_container);
|
||||
add_child(preset_container, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
btn_add_preset->set_icon_align(Button::ALIGN_CENTER);
|
||||
btn_add_preset->set_tooltip(RTR("Add current color as a preset."));
|
||||
@ -1405,7 +1405,7 @@ void ColorPickerButton::_update_picker() {
|
||||
picker = memnew(ColorPicker);
|
||||
picker->set_anchors_and_offsets_preset(PRESET_WIDE);
|
||||
popup->add_child(picker);
|
||||
add_child(popup);
|
||||
add_child(popup, false, INTERNAL_MODE_FRONT);
|
||||
picker->connect("color_changed", callable_mp(this, &ColorPickerButton::_color_changed));
|
||||
popup->connect("about_to_popup", callable_mp(this, &ColorPickerButton::_about_to_popup));
|
||||
popup->connect("popup_hide", callable_mp(this, &ColorPickerButton::_modal_closed));
|
||||
|
@ -319,7 +319,7 @@ AcceptDialog::AcceptDialog() {
|
||||
set_clamp_to_embedder(true);
|
||||
|
||||
bg = memnew(Panel);
|
||||
add_child(bg);
|
||||
add_child(bg, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
hbc = memnew(HBoxContainer);
|
||||
|
||||
@ -331,9 +331,9 @@ AcceptDialog::AcceptDialog() {
|
||||
label->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END);
|
||||
label->set_begin(Point2(margin, margin));
|
||||
label->set_end(Point2(-margin, -button_margin - 10));
|
||||
add_child(label);
|
||||
add_child(label, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
add_child(hbc);
|
||||
add_child(hbc, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
hbc->add_spacer();
|
||||
ok = memnew(Button);
|
||||
|
@ -924,7 +924,7 @@ FileDialog::FileDialog() {
|
||||
show_hidden_files = default_show_hidden_files;
|
||||
|
||||
vbox = memnew(VBoxContainer);
|
||||
add_child(vbox);
|
||||
add_child(vbox, false, INTERNAL_MODE_FRONT);
|
||||
vbox->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed));
|
||||
|
||||
mode = FILE_MODE_SAVE_FILE;
|
||||
@ -1023,8 +1023,7 @@ FileDialog::FileDialog() {
|
||||
filter->connect("item_selected", callable_mp(this, &FileDialog::_filter_selected));
|
||||
|
||||
confirm_save = memnew(ConfirmationDialog);
|
||||
// confirm_save->set_as_top_level(true);
|
||||
add_child(confirm_save);
|
||||
add_child(confirm_save, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
confirm_save->connect("confirmed", callable_mp(this, &FileDialog::_save_confirm_pressed));
|
||||
|
||||
@ -1036,16 +1035,16 @@ FileDialog::FileDialog() {
|
||||
makedirname = memnew(LineEdit);
|
||||
makedirname->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE);
|
||||
makevb->add_margin_child(TTRC("Name:"), makedirname);
|
||||
add_child(makedialog);
|
||||
add_child(makedialog, false, INTERNAL_MODE_FRONT);
|
||||
makedialog->register_text_enter(makedirname);
|
||||
makedialog->connect("confirmed", callable_mp(this, &FileDialog::_make_dir_confirm));
|
||||
mkdirerr = memnew(AcceptDialog);
|
||||
mkdirerr->set_text(TTRC("Could not create folder."));
|
||||
add_child(mkdirerr);
|
||||
add_child(mkdirerr, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
exterr = memnew(AcceptDialog);
|
||||
exterr->set_text(TTRC("Must use a valid extension."));
|
||||
add_child(exterr);
|
||||
add_child(exterr, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
update_filters();
|
||||
update_dir();
|
||||
|
@ -48,7 +48,7 @@ GradientEdit::GradientEdit() {
|
||||
picker = memnew(ColorPicker);
|
||||
popup->add_child(picker);
|
||||
|
||||
add_child(popup);
|
||||
add_child(popup, false, INTERNAL_MODE_FRONT);
|
||||
}
|
||||
|
||||
int GradientEdit::_get_point_from_pos(int x) {
|
||||
|
@ -366,7 +366,6 @@ void GraphEdit::_graph_node_raised(Node *p_gn) {
|
||||
}
|
||||
|
||||
move_child(connections_layer, first_not_comment);
|
||||
top_layer->raise();
|
||||
emit_signal(SNAME("node_selected"), p_gn);
|
||||
}
|
||||
|
||||
@ -2246,14 +2245,14 @@ GraphEdit::GraphEdit() {
|
||||
zoom_max = (1 * Math::pow(zoom_step, 4));
|
||||
|
||||
top_layer = memnew(GraphEditFilter(this));
|
||||
add_child(top_layer);
|
||||
add_child(top_layer, false, INTERNAL_MODE_BACK);
|
||||
top_layer->set_mouse_filter(MOUSE_FILTER_PASS);
|
||||
top_layer->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
|
||||
top_layer->connect("draw", callable_mp(this, &GraphEdit::_top_layer_draw));
|
||||
top_layer->connect("gui_input", callable_mp(this, &GraphEdit::_top_layer_input));
|
||||
|
||||
connections_layer = memnew(Control);
|
||||
add_child(connections_layer);
|
||||
add_child(connections_layer, false, INTERNAL_MODE_FRONT);
|
||||
connections_layer->connect("draw", callable_mp(this, &GraphEdit::_connections_layer_draw));
|
||||
connections_layer->set_name("CLAYER");
|
||||
connections_layer->set_disable_visibility_clip(true); // so it can draw freely and be offset
|
||||
|
@ -1656,7 +1656,7 @@ void ItemList::_bind_methods() {
|
||||
|
||||
ItemList::ItemList() {
|
||||
scroll_bar = memnew(VScrollBar);
|
||||
add_child(scroll_bar);
|
||||
add_child(scroll_bar, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
scroll_bar->connect("value_changed", callable_mp(this, &ItemList::_scroll_changed));
|
||||
|
||||
|
@ -2220,7 +2220,7 @@ void LineEdit::_bind_methods() {
|
||||
void LineEdit::_ensure_menu() {
|
||||
if (!menu) {
|
||||
menu = memnew(PopupMenu);
|
||||
add_child(menu);
|
||||
add_child(menu, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
menu_dir = memnew(PopupMenu);
|
||||
menu_dir->set_name("DirMenu");
|
||||
@ -2305,7 +2305,7 @@ LineEdit::LineEdit() {
|
||||
set_mouse_filter(MOUSE_FILTER_STOP);
|
||||
|
||||
caret_blink_timer = memnew(Timer);
|
||||
add_child(caret_blink_timer);
|
||||
add_child(caret_blink_timer, false, INTERNAL_MODE_FRONT);
|
||||
caret_blink_timer->set_wait_time(0.65);
|
||||
caret_blink_timer->connect("timeout", callable_mp(this, &LineEdit::_toggle_draw_caret));
|
||||
set_caret_blink_enabled(false);
|
||||
|
@ -172,7 +172,7 @@ MenuButton::MenuButton() {
|
||||
|
||||
popup = memnew(PopupMenu);
|
||||
popup->hide();
|
||||
add_child(popup);
|
||||
add_child(popup, false, INTERNAL_MODE_FRONT);
|
||||
popup->connect("about_to_popup", callable_mp(this, &MenuButton::_popup_visibility_changed), varray(true));
|
||||
popup->connect("popup_hide", callable_mp(this, &MenuButton::_popup_visibility_changed), varray(false));
|
||||
}
|
||||
|
@ -351,7 +351,7 @@ OptionButton::OptionButton() {
|
||||
|
||||
popup = memnew(PopupMenu);
|
||||
popup->hide();
|
||||
add_child(popup);
|
||||
add_child(popup, false, INTERNAL_MODE_FRONT);
|
||||
popup->connect("index_pressed", callable_mp(this, &OptionButton::_selected));
|
||||
popup->connect("id_focused", callable_mp(this, &OptionButton::_focused));
|
||||
popup->connect("popup_hide", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(false));
|
||||
|
@ -255,5 +255,5 @@ void PopupPanel::_notification(int p_what) {
|
||||
|
||||
PopupPanel::PopupPanel() {
|
||||
panel = memnew(Panel);
|
||||
add_child(panel);
|
||||
add_child(panel, false, INTERNAL_MODE_FRONT);
|
||||
}
|
||||
|
@ -1689,7 +1689,7 @@ PopupMenu::PopupMenu() {
|
||||
// Margin Container
|
||||
margin_container = memnew(MarginContainer);
|
||||
margin_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
|
||||
add_child(margin_container);
|
||||
add_child(margin_container, false, INTERNAL_MODE_FRONT);
|
||||
margin_container->connect("draw", callable_mp(this, &PopupMenu::_draw_background));
|
||||
|
||||
// Scroll Container
|
||||
@ -1703,7 +1703,7 @@ PopupMenu::PopupMenu() {
|
||||
control->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
|
||||
control->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
scroll_container->add_child(control);
|
||||
scroll_container->add_child(control, false, INTERNAL_MODE_FRONT);
|
||||
control->connect("draw", callable_mp(this, &PopupMenu::_draw_items));
|
||||
|
||||
connect("window_input", callable_mp(this, &PopupMenu::gui_input));
|
||||
@ -1712,13 +1712,13 @@ PopupMenu::PopupMenu() {
|
||||
submenu_timer->set_wait_time(0.3);
|
||||
submenu_timer->set_one_shot(true);
|
||||
submenu_timer->connect("timeout", callable_mp(this, &PopupMenu::_submenu_timeout));
|
||||
add_child(submenu_timer);
|
||||
add_child(submenu_timer, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
minimum_lifetime_timer = memnew(Timer);
|
||||
minimum_lifetime_timer->set_wait_time(0.3);
|
||||
minimum_lifetime_timer->set_one_shot(true);
|
||||
minimum_lifetime_timer->connect("timeout", callable_mp(this, &PopupMenu::_minimum_lifetime_timeout));
|
||||
add_child(minimum_lifetime_timer);
|
||||
add_child(minimum_lifetime_timer, false, INTERNAL_MODE_FRONT);
|
||||
}
|
||||
|
||||
PopupMenu::~PopupMenu() {
|
||||
|
@ -4361,7 +4361,7 @@ RichTextLabel::RichTextLabel() {
|
||||
current_frame = main;
|
||||
|
||||
vscroll = memnew(VScrollBar);
|
||||
add_child(vscroll);
|
||||
add_child(vscroll, false, INTERNAL_MODE_FRONT);
|
||||
vscroll->set_drag_node(String(".."));
|
||||
vscroll->set_step(1);
|
||||
vscroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0);
|
||||
|
@ -228,9 +228,6 @@ void ScrollContainer::_update_scrollbar_position() {
|
||||
v_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0);
|
||||
v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0);
|
||||
|
||||
h_scroll->raise();
|
||||
v_scroll->raise();
|
||||
|
||||
_updating_scrollbars = false;
|
||||
}
|
||||
|
||||
@ -618,12 +615,12 @@ void ScrollContainer::_bind_methods() {
|
||||
ScrollContainer::ScrollContainer() {
|
||||
h_scroll = memnew(HScrollBar);
|
||||
h_scroll->set_name("_h_scroll");
|
||||
add_child(h_scroll);
|
||||
add_child(h_scroll, false, INTERNAL_MODE_BACK);
|
||||
h_scroll->connect("value_changed", callable_mp(this, &ScrollContainer::_scroll_moved));
|
||||
|
||||
v_scroll = memnew(VScrollBar);
|
||||
v_scroll->set_name("_v_scroll");
|
||||
add_child(v_scroll);
|
||||
add_child(v_scroll, false, INTERNAL_MODE_BACK);
|
||||
v_scroll->connect("value_changed", callable_mp(this, &ScrollContainer::_scroll_moved));
|
||||
|
||||
deadzone = GLOBAL_GET("gui/common/default_scroll_deadzone");
|
||||
|
@ -278,7 +278,7 @@ void SpinBox::_bind_methods() {
|
||||
|
||||
SpinBox::SpinBox() {
|
||||
line_edit = memnew(LineEdit);
|
||||
add_child(line_edit);
|
||||
add_child(line_edit, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
line_edit->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
|
||||
line_edit->set_mouse_filter(MOUSE_FILTER_PASS);
|
||||
@ -291,5 +291,5 @@ SpinBox::SpinBox() {
|
||||
|
||||
range_click_timer = memnew(Timer);
|
||||
range_click_timer->connect("timeout", callable_mp(this, &SpinBox::_range_click_timeout));
|
||||
add_child(range_click_timer);
|
||||
add_child(range_click_timer, false, INTERNAL_MODE_FRONT);
|
||||
}
|
||||
|
@ -905,7 +905,7 @@ void TabContainer::drop_data(const Point2 &p_point, const Variant &p_data) {
|
||||
if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) {
|
||||
Control *moving_tabc = from_tabc->get_tab_control(tab_from_id);
|
||||
from_tabc->remove_child(moving_tabc);
|
||||
add_child(moving_tabc);
|
||||
add_child(moving_tabc, false, INTERNAL_MODE_FRONT);
|
||||
if (hover_now < 0) {
|
||||
hover_now = get_tab_count() - 1;
|
||||
}
|
||||
|
@ -5004,7 +5004,7 @@ void TextEdit::_paste_internal() {
|
||||
void TextEdit::_generate_context_menu() {
|
||||
if (!menu) {
|
||||
menu = memnew(PopupMenu);
|
||||
add_child(menu);
|
||||
add_child(menu, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
menu_dir = memnew(PopupMenu);
|
||||
menu_dir->set_name("DirMenu");
|
||||
@ -5012,7 +5012,7 @@ void TextEdit::_generate_context_menu() {
|
||||
menu_dir->add_radio_check_item(RTR("Auto-detect direction"), MENU_DIR_AUTO);
|
||||
menu_dir->add_radio_check_item(RTR("Left-to-right"), MENU_DIR_LTR);
|
||||
menu_dir->add_radio_check_item(RTR("Right-to-left"), MENU_DIR_RTL);
|
||||
menu->add_child(menu_dir);
|
||||
menu->add_child(menu_dir, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
menu_ctl = memnew(PopupMenu);
|
||||
menu_ctl->set_name("CTLMenu");
|
||||
@ -5034,7 +5034,7 @@ void TextEdit::_generate_context_menu() {
|
||||
menu_ctl->add_item(RTR("Zero width non-joiner (ZWNJ)"), MENU_INSERT_ZWNJ);
|
||||
menu_ctl->add_item(RTR("Word joiner (WJ)"), MENU_INSERT_WJ);
|
||||
menu_ctl->add_item(RTR("Soft hyphen (SHY)"), MENU_INSERT_SHY);
|
||||
menu->add_child(menu_ctl);
|
||||
menu->add_child(menu_ctl, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
menu->connect("id_pressed", callable_mp(this, &TextEdit::menu_option));
|
||||
menu_dir->connect("id_pressed", callable_mp(this, &TextEdit::menu_option));
|
||||
@ -5948,8 +5948,8 @@ TextEdit::TextEdit() {
|
||||
h_scroll = memnew(HScrollBar);
|
||||
v_scroll = memnew(VScrollBar);
|
||||
|
||||
add_child(h_scroll);
|
||||
add_child(v_scroll);
|
||||
add_child(h_scroll, false, INTERNAL_MODE_FRONT);
|
||||
add_child(v_scroll, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
h_scroll->connect("value_changed", callable_mp(this, &TextEdit::_scroll_moved));
|
||||
v_scroll->connect("value_changed", callable_mp(this, &TextEdit::_scroll_moved));
|
||||
@ -5958,19 +5958,19 @@ TextEdit::TextEdit() {
|
||||
|
||||
/* Caret. */
|
||||
caret_blink_timer = memnew(Timer);
|
||||
add_child(caret_blink_timer);
|
||||
add_child(caret_blink_timer, false, INTERNAL_MODE_FRONT);
|
||||
caret_blink_timer->set_wait_time(0.65);
|
||||
caret_blink_timer->connect("timeout", callable_mp(this, &TextEdit::_toggle_draw_caret));
|
||||
set_caret_blink_enabled(false);
|
||||
|
||||
/* Selection. */
|
||||
click_select_held = memnew(Timer);
|
||||
add_child(click_select_held);
|
||||
add_child(click_select_held, false, INTERNAL_MODE_FRONT);
|
||||
click_select_held->set_wait_time(0.05);
|
||||
click_select_held->connect("timeout", callable_mp(this, &TextEdit::_click_selection_held));
|
||||
|
||||
idle_detect = memnew(Timer);
|
||||
add_child(idle_detect);
|
||||
add_child(idle_detect, false, INTERNAL_MODE_FRONT);
|
||||
idle_detect->set_one_shot(true);
|
||||
idle_detect->set_wait_time(GLOBAL_GET("gui/timers/text_edit_idle_detect_sec"));
|
||||
idle_detect->connect("timeout", callable_mp(this, &TextEdit::_push_current_op));
|
||||
|
@ -4795,12 +4795,11 @@ Tree::Tree() {
|
||||
|
||||
popup_menu = memnew(PopupMenu);
|
||||
popup_menu->hide();
|
||||
add_child(popup_menu);
|
||||
// popup_menu->set_as_top_level(true);
|
||||
add_child(popup_menu, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
popup_editor = memnew(Popup);
|
||||
popup_editor->set_wrap_controls(true);
|
||||
add_child(popup_editor);
|
||||
add_child(popup_editor, false, INTERNAL_MODE_FRONT);
|
||||
popup_editor_vb = memnew(VBoxContainer);
|
||||
popup_editor->add_child(popup_editor_vb);
|
||||
popup_editor_vb->add_theme_constant_override("separation", 0);
|
||||
@ -4818,12 +4817,12 @@ Tree::Tree() {
|
||||
h_scroll = memnew(HScrollBar);
|
||||
v_scroll = memnew(VScrollBar);
|
||||
|
||||
add_child(h_scroll);
|
||||
add_child(v_scroll);
|
||||
add_child(h_scroll, false, INTERNAL_MODE_FRONT);
|
||||
add_child(v_scroll, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
range_click_timer = memnew(Timer);
|
||||
range_click_timer->connect("timeout", callable_mp(this, &Tree::_range_click_timeout));
|
||||
add_child(range_click_timer);
|
||||
add_child(range_click_timer, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
h_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved));
|
||||
v_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved));
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
VARIANT_ENUM_CAST(Node::ProcessMode);
|
||||
VARIANT_ENUM_CAST(Node::InternalMode);
|
||||
|
||||
int Node::orphan_node_count = 0;
|
||||
|
||||
@ -291,14 +292,40 @@ void Node::_propagate_exit_tree() {
|
||||
|
||||
void Node::move_child(Node *p_child, int p_pos) {
|
||||
ERR_FAIL_NULL(p_child);
|
||||
ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1, vformat("Invalid new child position: %d.", p_pos));
|
||||
ERR_FAIL_COND_MSG(p_child->data.parent != this, "Child is not a child of this node.");
|
||||
|
||||
// We need to check whether node is internal and move it only in the relevant node range.
|
||||
if (p_child->_is_internal_front()) {
|
||||
ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_front, vformat("Invalid new child position: %d. Child is internal.", p_pos));
|
||||
_move_child(p_child, p_pos);
|
||||
} else if (p_child->_is_internal_back()) {
|
||||
ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_back, vformat("Invalid new child position: %d. Child is internal.", p_pos));
|
||||
_move_child(p_child, data.children.size() - data.internal_children_back + p_pos);
|
||||
} else {
|
||||
ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child position: %d.", p_pos));
|
||||
_move_child(p_child, p_pos + data.internal_children_front);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
|
||||
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup).");
|
||||
|
||||
// Specifying one place beyond the end
|
||||
// means the same as moving to the last position
|
||||
if (p_pos == data.children.size()) {
|
||||
p_pos--;
|
||||
if (!p_ignore_end) { // p_ignore_end is a little hack to make back internal children work properly.
|
||||
if (p_child->_is_internal_front()) {
|
||||
if (p_pos == data.internal_children_front) {
|
||||
p_pos--;
|
||||
}
|
||||
} else if (p_child->_is_internal_back()) {
|
||||
if (p_pos == data.children.size()) {
|
||||
p_pos--;
|
||||
}
|
||||
} else {
|
||||
if (p_pos == data.children.size() - data.internal_children_back) {
|
||||
p_pos--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p_child->data.pos == p_pos) {
|
||||
@ -339,7 +366,14 @@ void Node::raise() {
|
||||
return;
|
||||
}
|
||||
|
||||
data.parent->move_child(this, data.parent->data.children.size() - 1);
|
||||
// Internal children move within a different index range.
|
||||
if (_is_internal_front()) {
|
||||
data.parent->move_child(this, data.parent->data.internal_children_front - 1);
|
||||
} else if (_is_internal_back()) {
|
||||
data.parent->move_child(this, data.parent->data.internal_children_back - 1);
|
||||
} else {
|
||||
data.parent->move_child(this, data.parent->get_child_count(false) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::add_child_notify(Node *p_child) {
|
||||
@ -1058,6 +1092,10 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
|
||||
p_child->data.pos = data.children.size();
|
||||
data.children.push_back(p_child);
|
||||
p_child->data.parent = this;
|
||||
|
||||
if (data.internal_children_back > 0) {
|
||||
_move_child(p_child, data.children.size() - data.internal_children_back - 1);
|
||||
}
|
||||
p_child->notification(NOTIFICATION_PARENTED);
|
||||
|
||||
if (data.tree) {
|
||||
@ -1070,7 +1108,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
|
||||
add_child_notify(p_child);
|
||||
}
|
||||
|
||||
void Node::add_child(Node *p_child, bool p_legible_unique_name) {
|
||||
void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_internal) {
|
||||
ERR_FAIL_NULL(p_child);
|
||||
ERR_FAIL_COND_MSG(p_child == this, vformat("Can't add child '%s' to itself.", p_child->get_name())); // adding to itself!
|
||||
ERR_FAIL_COND_MSG(p_child->data.parent, vformat("Can't add child '%s' to '%s', already has a parent '%s'.", p_child->get_name(), get_name(), p_child->data.parent->get_name())); //Fail if node has a parent
|
||||
@ -1079,19 +1117,35 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name) {
|
||||
#endif
|
||||
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_node() failed. Consider using call_deferred(\"add_child\", child) instead.");
|
||||
|
||||
/* Validate name */
|
||||
_validate_child_name(p_child, p_legible_unique_name);
|
||||
|
||||
_add_child_nocheck(p_child, p_child->data.name);
|
||||
|
||||
if (p_internal == INTERNAL_MODE_FRONT) {
|
||||
_move_child(p_child, data.internal_children_front);
|
||||
data.internal_children_front++;
|
||||
} else if (p_internal == INTERNAL_MODE_BACK) {
|
||||
if (data.internal_children_back > 0) {
|
||||
_move_child(p_child, data.children.size() - 1, true);
|
||||
}
|
||||
data.internal_children_back++;
|
||||
}
|
||||
}
|
||||
|
||||
void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) {
|
||||
ERR_FAIL_NULL(p_sibling);
|
||||
ERR_FAIL_NULL(data.parent);
|
||||
ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself!
|
||||
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_sibling() failed. Consider using call_deferred(\"add_sibling\", sibling) instead.");
|
||||
|
||||
get_parent()->add_child(p_sibling, p_legible_unique_name);
|
||||
get_parent()->move_child(p_sibling, this->get_index() + 1);
|
||||
InternalMode internal = INTERNAL_MODE_DISABLED;
|
||||
if (_is_internal_front()) { // The sibling will have the same internal status.
|
||||
internal = INTERNAL_MODE_FRONT;
|
||||
} else if (_is_internal_back()) {
|
||||
internal = INTERNAL_MODE_BACK;
|
||||
}
|
||||
|
||||
data.parent->add_child(p_sibling, p_legible_unique_name, internal);
|
||||
data.parent->_move_child(p_sibling, get_index() + 1);
|
||||
}
|
||||
|
||||
void Node::_propagate_validate_owner() {
|
||||
@ -1145,7 +1199,12 @@ void Node::remove_child(Node *p_child) {
|
||||
ERR_FAIL_COND_MSG(idx == -1, vformat("Cannot remove child node '%s' as it is not a child of this node.", p_child->get_name()));
|
||||
//ERR_FAIL_COND( p_child->data.blocked > 0 );
|
||||
|
||||
//if (data.scene) { does not matter
|
||||
// If internal child, update the counter.
|
||||
if (p_child->_is_internal_front()) {
|
||||
data.internal_children_front--;
|
||||
} else if (p_child->_is_internal_back()) {
|
||||
data.internal_children_back--;
|
||||
}
|
||||
|
||||
p_child->_set_tree(nullptr);
|
||||
//}
|
||||
@ -1175,17 +1234,29 @@ void Node::remove_child(Node *p_child) {
|
||||
}
|
||||
}
|
||||
|
||||
int Node::get_child_count() const {
|
||||
return data.children.size();
|
||||
int Node::get_child_count(bool p_include_internal) const {
|
||||
if (p_include_internal) {
|
||||
return data.children.size();
|
||||
} else {
|
||||
return data.children.size() - data.internal_children_front - data.internal_children_back;
|
||||
}
|
||||
}
|
||||
|
||||
Node *Node::get_child(int p_index) const {
|
||||
if (p_index < 0) {
|
||||
p_index += data.children.size();
|
||||
Node *Node::get_child(int p_index, bool p_include_internal) const {
|
||||
if (p_include_internal) {
|
||||
if (p_index < 0) {
|
||||
p_index += data.children.size();
|
||||
}
|
||||
ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr);
|
||||
return data.children[p_index];
|
||||
} else {
|
||||
if (p_index < 0) {
|
||||
p_index += data.children.size() - data.internal_children_front - data.internal_children_back;
|
||||
}
|
||||
ERR_FAIL_INDEX_V(p_index, data.children.size() - data.internal_children_front - data.internal_children_back, nullptr);
|
||||
p_index += data.internal_children_front;
|
||||
return data.children[p_index];
|
||||
}
|
||||
ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr);
|
||||
|
||||
return data.children[p_index];
|
||||
}
|
||||
|
||||
Node *Node::_get_child_by_name(const StringName &p_name) const {
|
||||
@ -1717,7 +1788,13 @@ void Node::_propagate_replace_owner(Node *p_owner, Node *p_by_owner) {
|
||||
data.blocked--;
|
||||
}
|
||||
|
||||
int Node::get_index() const {
|
||||
int Node::get_index(bool p_include_internal) const {
|
||||
// p_include_internal = false doesn't make sense if the node is internal.
|
||||
ERR_FAIL_COND_V_MSG(!p_include_internal && (_is_internal_front() || _is_internal_back()), -1, "Node is internal. Can't get index with 'include_internal' being false.");
|
||||
|
||||
if (data.parent && !p_include_internal) {
|
||||
return data.pos - data.parent->data.internal_children_front;
|
||||
}
|
||||
return data.pos;
|
||||
}
|
||||
|
||||
@ -2429,12 +2506,12 @@ void Node::queue_delete() {
|
||||
}
|
||||
}
|
||||
|
||||
TypedArray<Node> Node::_get_children() const {
|
||||
TypedArray<Node> Node::_get_children(bool p_include_internal) const {
|
||||
TypedArray<Node> arr;
|
||||
int cc = get_child_count();
|
||||
int cc = get_child_count(p_include_internal);
|
||||
arr.resize(cc);
|
||||
for (int i = 0; i < cc; i++) {
|
||||
arr[i] = get_child(i);
|
||||
arr[i] = get_child(i, p_include_internal);
|
||||
}
|
||||
|
||||
return arr;
|
||||
@ -2581,11 +2658,11 @@ void Node::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_name", "name"), &Node::set_name);
|
||||
ClassDB::bind_method(D_METHOD("get_name"), &Node::get_name);
|
||||
ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name"), &Node::add_child, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("remove_child", "node"), &Node::remove_child);
|
||||
ClassDB::bind_method(D_METHOD("get_child_count"), &Node::get_child_count);
|
||||
ClassDB::bind_method(D_METHOD("get_children"), &Node::_get_children);
|
||||
ClassDB::bind_method(D_METHOD("get_child", "idx"), &Node::get_child);
|
||||
ClassDB::bind_method(D_METHOD("get_child_count", "include_internal"), &Node::get_child_count, DEFVAL(false)); // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript.
|
||||
ClassDB::bind_method(D_METHOD("get_children", "include_internal"), &Node::_get_children, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("get_child", "idx", "include_internal"), &Node::get_child, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("has_node", "path"), &Node::has_node);
|
||||
ClassDB::bind_method(D_METHOD("get_node", "path"), &Node::get_node);
|
||||
ClassDB::bind_method(D_METHOD("get_node_or_null", "path"), &Node::get_node_or_null);
|
||||
@ -2609,7 +2686,7 @@ void Node::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_owner", "owner"), &Node::set_owner);
|
||||
ClassDB::bind_method(D_METHOD("get_owner"), &Node::get_owner);
|
||||
ClassDB::bind_method(D_METHOD("remove_and_skip"), &Node::remove_and_skip);
|
||||
ClassDB::bind_method(D_METHOD("get_index"), &Node::get_index);
|
||||
ClassDB::bind_method(D_METHOD("get_index", "include_internal"), &Node::get_index, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("print_tree"), &Node::print_tree);
|
||||
ClassDB::bind_method(D_METHOD("print_tree_pretty"), &Node::print_tree_pretty);
|
||||
ClassDB::bind_method(D_METHOD("set_filename", "filename"), &Node::set_filename);
|
||||
@ -2747,6 +2824,10 @@ void Node::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(DUPLICATE_SCRIPTS);
|
||||
BIND_ENUM_CONSTANT(DUPLICATE_USE_INSTANCING);
|
||||
|
||||
BIND_ENUM_CONSTANT(INTERNAL_MODE_DISABLED);
|
||||
BIND_ENUM_CONSTANT(INTERNAL_MODE_FRONT);
|
||||
BIND_ENUM_CONSTANT(INTERNAL_MODE_BACK);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("ready"));
|
||||
ADD_SIGNAL(MethodInfo("renamed"));
|
||||
ADD_SIGNAL(MethodInfo("tree_entered"));
|
||||
|
@ -73,6 +73,12 @@ public:
|
||||
NAME_CASING_SNAKE_CASE
|
||||
};
|
||||
|
||||
enum InternalMode {
|
||||
INTERNAL_MODE_DISABLED,
|
||||
INTERNAL_MODE_FRONT,
|
||||
INTERNAL_MODE_BACK,
|
||||
};
|
||||
|
||||
struct Comparator {
|
||||
bool operator()(const Node *p_a, const Node *p_b) const { return p_b->is_greater_than(p_a); }
|
||||
};
|
||||
@ -97,6 +103,8 @@ private:
|
||||
Node *parent = nullptr;
|
||||
Node *owner = nullptr;
|
||||
Vector<Node *> children;
|
||||
int internal_children_front = 0;
|
||||
int internal_children_back = 0;
|
||||
int pos = -1;
|
||||
int depth = -1;
|
||||
int blocked = 0; // Safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed.
|
||||
@ -172,12 +180,15 @@ private:
|
||||
void _duplicate_signals(const Node *p_original, Node *p_copy) const;
|
||||
Node *_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap = nullptr) const;
|
||||
|
||||
TypedArray<Node> _get_children() const;
|
||||
TypedArray<Node> _get_children(bool p_include_internal = true) const;
|
||||
Array _get_groups() const;
|
||||
|
||||
Variant _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||
Variant _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||
|
||||
_FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.pos < data.parent->data.internal_children_front; }
|
||||
_FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.pos >= data.parent->data.children.size() - data.parent->data.internal_children_back; }
|
||||
|
||||
friend class SceneTree;
|
||||
|
||||
void _set_tree(SceneTree *p_tree);
|
||||
@ -284,12 +295,12 @@ public:
|
||||
StringName get_name() const;
|
||||
void set_name(const String &p_name);
|
||||
|
||||
void add_child(Node *p_child, bool p_legible_unique_name = false);
|
||||
void add_child(Node *p_child, bool p_legible_unique_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED);
|
||||
void add_sibling(Node *p_sibling, bool p_legible_unique_name = false);
|
||||
void remove_child(Node *p_child);
|
||||
|
||||
int get_child_count() const;
|
||||
Node *get_child(int p_index) const;
|
||||
int get_child_count(bool p_include_internal = true) const;
|
||||
Node *get_child(int p_index, bool p_include_internal = true) const;
|
||||
bool has_node(const NodePath &p_path) const;
|
||||
Node *get_node(const NodePath &p_path) const;
|
||||
Node *get_node_or_null(const NodePath &p_path) const;
|
||||
@ -327,6 +338,7 @@ public:
|
||||
int get_persistent_group_count() const;
|
||||
|
||||
void move_child(Node *p_child, int p_pos);
|
||||
void _move_child(Node *p_child, int p_pos, bool p_ignore_end = false);
|
||||
void raise();
|
||||
|
||||
void set_owner(Node *p_owner);
|
||||
@ -334,7 +346,7 @@ public:
|
||||
void get_owned_by(Node *p_by, List<Node *> *p_owned);
|
||||
|
||||
void remove_and_skip();
|
||||
int get_index() const;
|
||||
int get_index(bool p_include_internal = true) const;
|
||||
|
||||
Ref<Tween> create_tween();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user