diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 4649a133fd72..7ac7ccbe87ba 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -665,9 +665,45 @@ Optional name for the 2D physics layer 20. + + Optional name for the 2D physics layer 21. + + + Optional name for the 2D physics layer 22. + + + Optional name for the 2D physics layer 23. + + + Optional name for the 2D physics layer 24. + + + Optional name for the 2D physics layer 25. + + + Optional name for the 2D physics layer 26. + + + Optional name for the 2D physics layer 27. + + + Optional name for the 2D physics layer 28. + + + Optional name for the 2D physics layer 29. + Optional name for the 2D physics layer 3. + + Optional name for the 2D physics layer 30. + + + Optional name for the 2D physics layer 31. + + + Optional name for the 2D physics layer 32. + Optional name for the 2D physics layer 4. @@ -785,9 +821,45 @@ Optional name for the 3D physics layer 20. + + Optional name for the 3D physics layer 21. + + + Optional name for the 3D physics layer 22. + + + Optional name for the 3D physics layer 23. + + + Optional name for the 3D physics layer 24. + + + Optional name for the 3D physics layer 25. + + + Optional name for the 3D physics layer 26. + + + Optional name for the 3D physics layer 27. + + + Optional name for the 3D physics layer 28. + + + Optional name for the 3D physics layer 29. + Optional name for the 3D physics layer 3. + + Optional name for the 3D physics layer 30. + + + Optional name for the 3D physics layer 31. + + + Optional name for the 3D physics layer 32. + Optional name for the 3D physics layer 4. diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index f448354749ac..3585dc577fb0 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -579,16 +579,38 @@ EditorPropertyFlags::EditorPropertyFlags() { class EditorPropertyLayersGrid : public Control { GDCLASS(EditorPropertyLayersGrid, Control); -public: - uint32_t value; +private: Vector flag_rects; + Rect2 expand_rect; + bool expand_hovered = false; + bool expanded = false; + int expansion_rows = 0; + int hovered_index = -1; + + Size2 get_grid_size() const { + Ref font = get_font("font", "Label"); + return Size2(0, font->get_height() * 3); + } + +public: + uint32_t value = 0; + int layer_group_size = 0; + int layer_count = 0; Vector names; Vector tooltips; - int hovered_index; virtual Size2 get_minimum_size() const { - Ref font = get_font("font", "Label"); - return Vector2(0, font->get_height() * 2); + Size2 min_size = get_grid_size(); + + // Add extra rows when expanded. + if (expanded) { + const int bsize = (min_size.height * 80 / 100) / 2; + for (int i = 0; i < expansion_rows; ++i) { + min_size.y += 2 * (bsize + 1) + 3; + } + } + + return min_size; } virtual String get_tooltip(const Point2 &p_pos) const { @@ -599,80 +621,198 @@ class EditorPropertyLayersGrid : public Control { } return String(); } + void _gui_input(const Ref &p_ev) { const Ref mm = p_ev; - if (mm.is_valid()) { - for (int i = 0; i < flag_rects.size(); i++) { - if (flag_rects[i].has_point(mm->get_position())) { - // Used to highlight the hovered flag in the layers grid. - hovered_index = i; - update(); - break; + bool expand_was_hovered = expand_hovered; + expand_hovered = expand_rect.has_point(mm->get_position()); + if (expand_hovered != expand_was_hovered) { + update(); + } + + if (!expand_hovered) { + for (int i = 0; i < flag_rects.size(); i++) { + if (flag_rects[i].has_point(mm->get_position())) { + // Used to highlight the hovered flag in the layers grid. + hovered_index = i; + update(); + return; + } } } + + // Remove highlight when no square is hovered. + if (hovered_index != -1) { + hovered_index = -1; + update(); + } + + return; } const Ref mb = p_ev; + if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { + if (hovered_index >= 0) { + // Toggle the flag. + // We base our choice on the hovered flag, so that it always matches the hovered flag. + if (value & (1 << hovered_index)) { + value &= ~(1 << hovered_index); + } else { + value |= (1 << hovered_index); + } - if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed() && hovered_index >= 0) { - // Toggle the flag. - // We base our choice on the hovered flag, so that it always matches the hovered flag. - if (value & (1 << hovered_index)) { - value &= ~(1 << hovered_index); - } else { - value |= (1 << hovered_index); + emit_signal("flag_changed", value); + update(); + } else if (expand_hovered) { + expanded = !expanded; + minimum_size_changed(); + update(); } - - emit_signal("flag_changed", value); - update(); } } void _notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { - Rect2 rect; - rect.size = get_size(); + Size2 grid_size = get_grid_size(); + grid_size.x = get_size().x; + flag_rects.clear(); - const int bsize = (rect.size.height * 80 / 100) / 2; + int prev_expansion_rows = expansion_rows; + expansion_rows = 0; + + const int bsize = (grid_size.height * 80 / 100) / 2; const int h = bsize * 2 + 1; - const int vofs = (rect.size.height - h) / 2; Color color = get_color("highlight_color", "Editor"); - for (int i = 0; i < 2; i++) { - Point2 ofs(4, vofs); - if (i == 1) { + + Color text_color = get_color("font_color", "Editor"); + text_color.a *= 0.5; + + Color text_color_on = get_color("dark_color_3", "Editor"); + text_color_on.a *= 0.8; + + const int vofs = (grid_size.height - h) / 2; + + int layer_index = 0; + int block_index = 0; + + Point2 arrow_pos; + + Point2 block_ofs(4, vofs); + + while (true) { + Point2 ofs = block_ofs; + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < layer_group_size; j++) { + const bool on = value & (1 << layer_index); + Rect2 rect2 = Rect2(ofs, Size2(bsize, bsize)); + + color.a = on ? 0.6 : 0.2; + if (layer_index == hovered_index) { + // Add visual feedback when hovering a flag. + color.a += 0.15; + } + + draw_rect(rect2, color); + flag_rects.push_back(rect2); + + Ref font = get_font("font", "Label"); + Vector2 offset; + if (layer_index + 1 > 9) { + // Offset for double digit numbers. + offset.x = rect2.size.x * 0.1; + } else { + offset.x = rect2.size.x * 0.3; + } + offset.y = rect2.size.y * 0.75; + + draw_string(font, rect2.position + offset, itos(layer_index + 1), on ? text_color_on : text_color); + + ofs.x += bsize + 1; + + ++layer_index; + } + + ofs.x = block_ofs.x; ofs.y += bsize + 1; } - ofs += rect.position; - for (int j = 0; j < 10; j++) { - Point2 o = ofs + Point2(j * (bsize + 1), 0); - if (j >= 5) { - o.x += 1; + if (layer_index >= layer_count) { + if (!flag_rects.empty() && (expansion_rows == 0)) { + const Rect2 &last_rect = flag_rects[flag_rects.size() - 1]; + arrow_pos = last_rect.position + last_rect.size; } + break; + } - const int idx = i * 10 + j; - const bool on = value & (1 << idx); - Rect2 rect2 = Rect2(o, Size2(bsize, bsize)); + int block_size_x = layer_group_size * (bsize + 1); + block_ofs.x += block_size_x + 3; - color.a = on ? 0.6 : 0.2; - if (idx == hovered_index) { - // Add visual feedback when hovering a flag. - color.a += 0.15; + if (block_ofs.x + block_size_x + 12 > grid_size.width) { + // Keep last valid cell position for the expansion icon. + if (!flag_rects.empty() && (expansion_rows == 0)) { + const Rect2 &last_rect = flag_rects[flag_rects.size() - 1]; + arrow_pos = last_rect.position + last_rect.size; + } + ++expansion_rows; + + if (expanded) { + // Expand grid to next line. + block_ofs.x = 4; + block_ofs.y += 2 * (bsize + 1) + 3; + } else { + // Skip remaining blocks. + break; } - - draw_rect(rect2, color); - flag_rects.push_back(rect2); } + + ++block_index; + } + + if ((expansion_rows != prev_expansion_rows) && expanded) { + minimum_size_changed(); + } + + if ((expansion_rows == 0) && (layer_index == layer_count)) { + // Whole grid was drawn, no need for expansion icon. + break; } + + Ref arrow = get_icon("arrow", "Tree"); + ERR_FAIL_COND(arrow.is_null()); + + Color arrow_color = get_color("highlight_color", "Editor"); + arrow_color.a = expand_hovered ? 1.0 : 0.6; + + arrow_pos.x += 2.0; + arrow_pos.y -= arrow->get_height(); + + Rect2 arrow_draw_rect(arrow_pos, arrow->get_size()); + expand_rect = arrow_draw_rect; + if (expanded) { + arrow_draw_rect.size.y *= -1.0; // Flip arrow vertically when expanded. + } + + RID ci = get_canvas_item(); + arrow->draw_rect(ci, arrow_draw_rect, false, arrow_color); + } break; + case NOTIFICATION_MOUSE_EXIT: { - hovered_index = -1; - update(); + if (expand_hovered) { + expand_hovered = false; + update(); + } + if (hovered_index != -1) { + hovered_index = -1; + update(); + } } break; + default: break; } @@ -687,12 +827,8 @@ class EditorPropertyLayersGrid : public Control { ClassDB::bind_method(D_METHOD("_gui_input"), &EditorPropertyLayersGrid::_gui_input); ADD_SIGNAL(MethodInfo("flag_changed", PropertyInfo(Variant::INT, "flag"))); } - - EditorPropertyLayersGrid() { - value = 0; - hovered_index = -1; // Nothing is hovered. - } }; + void EditorPropertyLayers::_grid_changed(uint32_t p_grid) { emit_changed(get_edited_property(), p_grid); } @@ -705,24 +841,37 @@ void EditorPropertyLayers::update_property() { void EditorPropertyLayers::setup(LayerType p_layer_type) { String basename; + int layer_group_size = 0; + int layer_count = 0; switch (p_layer_type) { - case LAYER_RENDER_2D: + case LAYER_RENDER_2D: { basename = "layer_names/2d_render"; - break; - case LAYER_PHYSICS_2D: + layer_group_size = 5; + layer_count = 20; + } break; + + case LAYER_PHYSICS_2D: { basename = "layer_names/2d_physics"; - break; - case LAYER_RENDER_3D: + layer_group_size = 4; + layer_count = 32; + } break; + + case LAYER_RENDER_3D: { basename = "layer_names/3d_render"; - break; - case LAYER_PHYSICS_3D: + layer_group_size = 5; + layer_count = 20; + } break; + + case LAYER_PHYSICS_3D: { basename = "layer_names/3d_physics"; - break; + layer_group_size = 4; + layer_count = 32; + } break; } Vector names; Vector tooltips; - for (int i = 0; i < 20; i++) { + for (int i = 0; i < layer_count; i++) { String name; if (ProjectSettings::get_singleton()->has_setting(basename + "/layer_" + itos(i + 1))) { @@ -739,12 +888,17 @@ void EditorPropertyLayers::setup(LayerType p_layer_type) { grid->names = names; grid->tooltips = tooltips; + grid->layer_group_size = layer_group_size; + grid->layer_count = layer_count; } void EditorPropertyLayers::_button_pressed() { + int layer_count = grid->layer_count; + int layer_group_size = grid->layer_group_size; + layers->clear(); - for (int i = 0; i < 20; i++) { - if (i == 5 || i == 10 || i == 15) { + for (int i = 0; i < layer_count; i++) { + if ((i != 0) && ((i % layer_group_size) == 0)) { layers->add_separator(); } layers->add_check_item(grid->names[i], i); @@ -778,17 +932,21 @@ void EditorPropertyLayers::_bind_methods() { EditorPropertyLayers::EditorPropertyLayers() { HBoxContainer *hb = memnew(HBoxContainer); + hb->set_clip_contents(true); add_child(hb); grid = memnew(EditorPropertyLayersGrid); grid->connect("flag_changed", this, "_grid_changed"); grid->set_h_size_flags(SIZE_EXPAND_FILL); hb->add_child(grid); + button = memnew(Button); button->set_toggle_mode(true); button->set_text("..."); button->connect("pressed", this, "_button_pressed"); hb->add_child(button); + set_bottom_editor(hb); + layers = memnew(PopupMenu); add_child(layers); layers->set_hide_on_checkable_item_selection(false); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 19b84a27d636..4c0ae2fc8881 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -745,8 +745,11 @@ void register_scene_types() { for (int i = 0; i < 20; i++) { GLOBAL_DEF("layer_names/2d_render/layer_" + itos(i + 1), ""); - GLOBAL_DEF("layer_names/2d_physics/layer_" + itos(i + 1), ""); GLOBAL_DEF("layer_names/3d_render/layer_" + itos(i + 1), ""); + } + + for (int i = 0; i < 32; i++) { + GLOBAL_DEF("layer_names/2d_physics/layer_" + itos(i + 1), ""); GLOBAL_DEF("layer_names/3d_physics/layer_" + itos(i + 1), ""); }