/* SPDX-FileCopyrightText: 2024 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup edinterface */ #include "BKE_context.hh" #include "BLI_array.hh" #include "BLI_string_ref.hh" #include "RNA_access.hh" #include "UI_interface.hh" #include "interface_intern.hh" using blender::StringRefNull; static void handle_layer_buttons(bContext *C, void *arg1, void *arg2) { uiBut *but = static_cast(arg1); const int cur = POINTER_AS_INT(arg2); wmWindow *win = CTX_wm_window(C); const bool shift = win->eventstate->modifier & KM_SHIFT; if (!shift) { const int tot = RNA_property_array_length(&but->rnapoin, but->rnaprop); BLI_assert(cur < tot); blender::Array value_array(tot); value_array.fill(false); value_array[cur] = true; /* Normally clicking only selects one layer */ RNA_property_boolean_set_array(&but->rnapoin, but->rnaprop, value_array.data()); } /* view3d layer change should update depsgraph (invisible object changed maybe) */ /* see `view3d_header.cc` */ } void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const StringRefNull propname, PointerRNA *used_ptr, const char *used_propname, int active_layer) { const int cols_per_group = 5; PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str()); if (!prop) { RNA_warning( "layers property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str()); return; } /* the number of layers determines the way we group them * - we want 2 rows only (for now) * - The number of columns (cols) is the total number of buttons per row the 'remainder' * is added to this, as it will be ok to have first row slightly wider if need be. * - For now, only split into groups if group will have at least 5 items. */ const int layers = RNA_property_array_length(ptr, prop); const int cols = (layers / 2) + (layers % 2); const int groups = ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group); PropertyRNA *used_prop = nullptr; if (used_ptr && used_propname) { used_prop = RNA_struct_find_property(used_ptr, used_propname); if (!used_prop) { RNA_warning("used layers property not found: %s.%s", RNA_struct_identifier(ptr->type), used_propname); return; } if (RNA_property_array_length(used_ptr, used_prop) < layers) { used_prop = nullptr; } } /* layers are laid out going across rows, with the columns being divided into groups */ for (int group = 0; group < groups; group++) { uiLayout *uCol = uiLayoutColumn(layout, true); for (int row = 0; row < 2; row++) { uiLayout *uRow = uiLayoutRow(uCol, true); uiBlock *block = uiLayoutGetBlock(uRow); int layer = groups * cols_per_group * row + cols_per_group * group; /* add layers as toggle buts */ for (int col = 0; (col < cols_per_group) && (layer < layers); col++, layer++) { int icon = 0; const int butlay = 1 << layer; if (active_layer & butlay) { icon = ICON_LAYER_ACTIVE; } else if (used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer)) { icon = ICON_LAYER_USED; } uiBut *but = uiDefAutoButR( block, ptr, prop, layer, "", icon, 0, 0, UI_UNIT_X / 2, UI_UNIT_Y / 2); UI_but_func_set(but, handle_layer_buttons, but, POINTER_FROM_INT(layer)); but->type = UI_BTYPE_TOGGLE; } } } }