Blender V4.5
interface_template_list.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cstdlib>
11#include <cstring>
12
13#include "BLI_fnmatch.h"
14#include "BLI_function_ref.hh"
15#include "BLI_listbase.h"
16#include "BLI_math_base.h"
17#include "BLI_string.h"
18#include "BLI_string_ref.hh"
19#include "BLI_utildefines.h"
20#include "BLI_vector.hh"
21
22#include "BKE_screen.hh"
23
24#include "BLT_translation.hh"
25
26#include "ED_screen.hh"
27
28#include "MEM_guardedalloc.h"
29
30#include "RNA_access.hh"
31#include "RNA_prototypes.hh"
32
33#include "UI_interface.hh"
34#include "UI_view2d.hh"
35
36#include "WM_api.hh"
37
38#include "interface_intern.hh"
39
40using namespace blender;
41
52
53 /* Index as stored in the input property. I.e. the index before sorting. */
55};
56
65
71 /* Index of the active item following visual order. I.e. unlike
72 * TemplateListInputData.active_item_idx, this is the index after sorting. */
74};
75
84
86 int visual_items; /* Visual number of items (i.e. number of items we have room to display). */
87 int start_idx; /* Index of first item to display. */
88 int end_idx; /* Index of last item to display + 1. */
89};
90
91static void uilist_draw_item_default(uiList *ui_list,
92 const bContext * /*C*/,
93 uiLayout *layout,
94 PointerRNA * /*dataptr*/,
95 PointerRNA *itemptr,
96 int icon,
97 PointerRNA * /*active_dataptr*/,
98 const char * /*active_propname*/,
99 int /*index*/,
100 int /*flt_flag*/)
101{
102 PropertyRNA *nameprop = RNA_struct_name_property(itemptr->type);
103
104 /* Simplest one! */
105 switch (ui_list->layout_type) {
107 layout->label("", icon);
108 break;
111 default:
112 if (nameprop) {
113 layout->prop(itemptr, nameprop, RNA_NO_INDEX, 0, UI_ITEM_R_NO_BG, "", icon);
114 }
115 else {
116 layout->label("", icon);
117 }
118 break;
119 }
120}
121
122static void uilist_draw_filter_default(uiList *ui_list, const bContext * /*C*/, uiLayout *layout)
123{
124 PointerRNA listptr = RNA_pointer_create_discrete(nullptr, &RNA_UIList, ui_list);
125
126 uiLayout *row = &layout->row(false);
127
128 uiLayout *subrow = &row->row(true);
129 subrow->prop(&listptr, "filter_name", UI_ITEM_NONE, "", ICON_NONE);
130 subrow->prop(&listptr,
131 "use_filter_invert",
133 "",
134 ICON_ARROW_LEFTRIGHT);
135
136 if ((ui_list->filter_sort_flag & UILST_FLT_SORT_LOCK) == 0) {
137 subrow = &row->row(true);
138 subrow->prop(
139 &listptr, "use_filter_sort_alpha", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
140 subrow->prop(&listptr,
141 "use_filter_sort_reverse",
143 "",
144 (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) ? ICON_SORT_DESC :
145 ICON_SORT_ASC);
146 }
147}
148
150{
151 const char *filter_raw = list.filter_byname;
152
153 if (filter_raw[0]) {
154 const size_t slen = strlen(filter_raw);
155
156 /* Implicitly add heading/trailing wildcards if needed. */
157 if (slen + 3 <= sizeof(storage_.filter_buff)) {
158 filter_ = storage_.filter_buff;
159 }
160 else {
161 filter_ = storage_.filter_dyn = MEM_malloc_arrayN<char>((slen + 3), "filter_dyn");
162 }
163 BLI_strncpy_ensure_pad(filter_, filter_raw, '*', slen + 3);
164 }
165}
166
168{
169 MEM_SAFE_FREE(storage_.filter_dyn);
170}
171
173 StringRefNull name,
174 int /*index*/)
175{
176 if (!filter_) {
178 }
179
180 /* Use `fnmatch` for shell-style globing.
181 * - Case-insensitive.
182 * - Don't handle escape characters as "special" characters are not expected in names.
183 * Unlike shell input - `\` should be treated like any other character.
184 */
185 const int fn_flag = FNM_CASEFOLD | FNM_NOESCAPE;
186 if (fnmatch(filter_, name.c_str(), fn_flag) == 0) {
188 }
190}
191
196
197static int cmpstringp(const void *p1, const void *p2)
198{
199 /* Case-insensitive comparison. */
200 return BLI_strcasecmp(((StringCmp *)p1)->name, ((StringCmp *)p2)->name);
201}
202
204 const bContext * /*C*/,
205 uiListItemFilterFn item_filter_fn,
206 PointerRNA *dataptr,
207 const char *propname,
208 uiListItemGetNameFn get_name_fn)
209{
210 uiListDyn *dyn_data = ui_list->dyn_data;
211 PropertyRNA *prop = RNA_struct_find_property(dataptr, propname);
212
213 const bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0;
214 const bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_ALPHA) &&
216 const int len = RNA_property_collection_length(dataptr, prop);
217
218 dyn_data->items_shown = dyn_data->items_len = len;
219
220 if (len && (order_by_name || item_filter_fn)) {
221 StringCmp *names = nullptr;
222 int order_idx = 0, i = 0;
223
224 if (order_by_name) {
225 names = MEM_calloc_arrayN<StringCmp>(len, "StringCmp");
226 }
227
228 if (item_filter_fn) {
229 dyn_data->items_filter_flags = MEM_calloc_arrayN<int>(len, "items_filter_flags");
230 dyn_data->items_shown = 0;
231 }
232
233 RNA_PROP_BEGIN (dataptr, itemptr, prop) {
234 bool do_order = false;
235
236 char *namebuf;
237 if (get_name_fn) {
238 namebuf = BLI_strdup(get_name_fn(itemptr, i).c_str());
239 }
240 else {
241 namebuf = RNA_struct_name_get_alloc(&itemptr, nullptr, 0, nullptr);
242 }
243
244 const char *name = namebuf ? namebuf : "";
245
246 if (item_filter_fn) {
247 const eUIListFilterResult filter_result = item_filter_fn(itemptr, name, i);
248
249 if (filter_result == UI_LIST_ITEM_NEVER_SHOW) {
251 }
252 else if (filter_result == UI_LIST_ITEM_FILTER_MATCHES) {
253 if (!filter_exclude) {
255 dyn_data->items_shown++;
256 do_order = order_by_name;
257 }
258 // printf("%s: '%s' matches '%s'\n", __func__, name, filter);
259 }
260 else if (filter_exclude) {
262 dyn_data->items_shown++;
263 do_order = order_by_name;
264 }
265 }
266 else {
267 do_order = order_by_name;
268 }
269
270 if (do_order) {
271 names[order_idx].org_idx = order_idx;
272 STRNCPY(names[order_idx++].name, name);
273 }
274
275 /* free name */
276 if (namebuf) {
277 MEM_freeN(namebuf);
278 }
279 i++;
280 }
282
283 if (order_by_name) {
284 int new_idx;
285 /* NOTE: order_idx equals either to ui_list->items_len if no filtering done,
286 * or to ui_list->items_shown if filter is enabled,
287 * or to (ui_list->items_len - ui_list->items_shown) if filtered items are excluded.
288 * This way, we only sort items we actually intend to draw!
289 */
290 qsort(names, order_idx, sizeof(StringCmp), cmpstringp);
291
292 dyn_data->items_filter_neworder = MEM_malloc_arrayN<int>(order_idx, "items_filter_neworder");
293 for (new_idx = 0; new_idx < order_idx; new_idx++) {
294 dyn_data->items_filter_neworder[names[new_idx].org_idx] = new_idx;
295 }
296 }
297
298 if (names) {
299 MEM_freeN(names);
300 }
301 }
302}
303
304bool UI_list_item_index_is_filtered_visible(const uiList *ui_list, const int item_idx)
305{
306 const uiListDyn *dyn_data = ui_list->dyn_data;
307
308 if (!dyn_data->items_filter_flags) {
309 /* If there are no filter flags to check, always consider all items visible. */
310 return true;
311 }
312
313 if (dyn_data->items_filter_flags[item_idx] & UILST_FLT_ITEM_NEVER_SHOW) {
314 return false;
315 }
316
317 return (dyn_data->items_filter_flags[item_idx] & UILST_FLT_ITEM);
318}
319
324 const bContext *C,
325 PointerRNA *dataptr,
326 const char *propname)
327{
328 if (ui_list->filter_byname[0]) {
329 uiListNameFilter name_filter(*ui_list);
330 UI_list_filter_and_sort_items(ui_list, C, name_filter, dataptr, propname);
331 }
332 /* Optimization: Skip filtering entirely when there is no filter string set. */
333 else {
334 UI_list_filter_and_sort_items(ui_list, C, nullptr, dataptr, propname);
335 }
336}
337
338static void uilist_free_dyn_data(uiList *ui_list)
339{
340 uiListDyn *dyn_data = ui_list->dyn_data;
341 if (!dyn_data) {
342 return;
343 }
344
345 if (dyn_data->custom_activate_opptr) {
347 MEM_delete(dyn_data->custom_activate_opptr);
348 }
349 if (dyn_data->custom_drag_opptr) {
351 MEM_delete(dyn_data->custom_drag_opptr);
352 }
353
356 MEM_SAFE_FREE(dyn_data->customdata);
357}
358
365static bool ui_template_list_data_retrieve(const StringRef listtype_name,
366 const char *list_id,
367 PointerRNA *dataptr,
368 const StringRefNull propname,
369 PointerRNA *active_dataptr,
370 const StringRefNull active_propname,
371 const char *item_dyntip_propname,
372 TemplateListInputData *r_input_data,
373 uiListType **r_list_type)
374{
375 *r_input_data = {};
376
377 /* Forbid default UI_UL_DEFAULT_CLASS_NAME list class without a custom list_id! */
378 if ((UI_UL_DEFAULT_CLASS_NAME == listtype_name) && !(list_id && list_id[0])) {
379 RNA_warning("template_list using default '%s' UIList class must provide a custom list_id",
381 return false;
382 }
383
384 if (!active_dataptr->data) {
385 RNA_warning("No active data");
386 return false;
387 }
388
389 r_input_data->dataptr = *dataptr;
390 if (dataptr->data) {
391 r_input_data->prop = RNA_struct_find_property(dataptr, propname.c_str());
392 if (!r_input_data->prop) {
394 "Property not found: %s.%s", RNA_struct_identifier(dataptr->type), propname.c_str());
395 return false;
396 }
397 }
398
399 r_input_data->active_dataptr = *active_dataptr;
400 r_input_data->activeprop = RNA_struct_find_property(active_dataptr, active_propname.c_str());
401 if (!r_input_data->activeprop) {
402 RNA_warning("Property not found: %s.%s",
403 RNA_struct_identifier(active_dataptr->type),
404 active_propname.c_str());
405 return false;
406 }
407
408 if (r_input_data->prop) {
409 const PropertyType type = RNA_property_type(r_input_data->prop);
410 if (type != PROP_COLLECTION) {
411 RNA_warning("Expected a collection data property");
412 return false;
413 }
414 }
415
416 const PropertyType activetype = RNA_property_type(r_input_data->activeprop);
417 if (activetype != PROP_INT) {
418 RNA_warning("Expected an integer active data property");
419 return false;
420 }
421
422 /* Find the uiList type. */
423 if (!(*r_list_type = WM_uilisttype_find(listtype_name, false))) {
424 RNA_warning("List type %s not found", std::string(listtype_name).c_str());
425 return false;
426 }
427
428 r_input_data->active_item_idx = RNA_property_int_get(&r_input_data->active_dataptr,
429 r_input_data->activeprop);
430 r_input_data->item_dyntip_propname = item_dyntip_propname;
431
432 return true;
433}
434
436 PropertyRNA *list_prop,
437 const uiList *ui_list,
438 int activei,
439 TemplateListItems *r_items)
440{
441 const uiListDyn *dyn_data = ui_list->dyn_data;
442 const bool order_reverse = (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) != 0;
443 int i = 0;
444 int reorder_i = 0;
445 bool activei_mapping_pending = true;
446
447 RNA_PROP_BEGIN (list_ptr, itemptr, list_prop) {
449 int new_order_idx;
450 if (dyn_data->items_filter_neworder) {
451 new_order_idx = dyn_data->items_filter_neworder[reorder_i++];
452 new_order_idx = order_reverse ? dyn_data->items_shown - new_order_idx - 1 : new_order_idx;
453 }
454 else {
455 new_order_idx = order_reverse ? dyn_data->items_shown - ++reorder_i : reorder_i++;
456 }
457 // printf("%s: ii: %d\n", __func__, ii);
458 r_items->item_vec[new_order_idx].item = itemptr;
459 r_items->item_vec[new_order_idx].org_idx = i;
460 r_items->item_vec[new_order_idx].flt_flag = dyn_data->items_filter_flags ?
461 dyn_data->items_filter_flags[i] :
462 0;
463
464 if (activei_mapping_pending && activei == i) {
465 activei = new_order_idx;
466 /* So that we do not map again activei! */
467 activei_mapping_pending = false;
468 }
469#if 0 /* For now, do not alter active element, even if it will be hidden... */
470 else if (activei < i) {
471 /* We do not want an active but invisible item!
472 * Only exception is when all items are filtered out...
473 */
474 if (prev_order_idx >= 0) {
475 activei = prev_order_idx;
476 RNA_property_int_set(active_dataptr, activeprop, prev_i);
477 }
478 else {
479 activei = new_order_idx;
480 RNA_property_int_set(active_dataptr, activeprop, i);
481 }
482 }
483 prev_i = i;
484 prev_ii = new_order_idx;
485#endif
486 }
487 i++;
488 }
490
491 /* If mapping is still pending, no active item was found. Mark as invalid (-1) */
492 r_items->active_item_idx = activei_mapping_pending ? -1 : activei;
493}
494
499 uiList *ui_list,
500 TemplateListInputData *input_data,
501 const uiListFilterItemsFunc filter_items_fn,
502 TemplateListItems *r_items)
503{
504 uiListDyn *dyn_data = ui_list->dyn_data;
505
506 /* Filter list items! (not for compact layout, though) */
507 if (input_data->dataptr.data && input_data->prop) {
508 int items_shown;
509#if 0
510 int prev_ii = -1, prev_i;
511#endif
512
513 if (ui_list->layout_type == UILST_LAYOUT_COMPACT) {
515 &input_data->dataptr, input_data->prop);
516 }
517 else {
518 // printf("%s: filtering...\n", __func__);
519 filter_items_fn(ui_list, C, &input_data->dataptr, RNA_property_identifier(input_data->prop));
520 // printf("%s: filtering done.\n", __func__);
521 }
522
523 items_shown = dyn_data->items_shown;
524 if (items_shown >= 0) {
525 r_items->item_vec.resize(items_shown);
526 // printf("%s: items shown: %d.\n", __func__, items_shown);
527
529 &input_data->dataptr, input_data->prop, ui_list, input_data->active_item_idx, r_items);
530 }
531 }
532}
533
534static void uilist_prepare(uiList *ui_list,
535 const TemplateListItems *items,
536 const TemplateListLayoutDrawData *layout_data,
537 TemplateListVisualInfo *r_visual_info)
538{
539 uiListDyn *dyn_data = ui_list->dyn_data;
540 const bool use_auto_size = (ui_list->list_grip <
541 (layout_data->rows - UI_LIST_AUTO_SIZE_THRESHOLD));
542
543 int actual_rows = layout_data->rows;
544 int actual_maxrows = layout_data->maxrows;
545 int columns = layout_data->columns;
546
547 /* default rows */
548 if (actual_rows <= 0) {
549 actual_rows = 5;
550 }
551 dyn_data->visual_height_min = actual_rows;
552 if (actual_maxrows < actual_rows) {
553 actual_maxrows = max_ii(actual_rows, 5);
554 }
555 if (columns <= 0) {
556 columns = 9;
557 }
558
559 int activei_row;
560 if (columns > 1) {
561 dyn_data->height = int(ceil(double(items->item_vec.size()) / double(columns)));
562 activei_row = int(floor(double(items->active_item_idx) / double(columns)));
563 }
564 else {
565 dyn_data->height = items->item_vec.size();
566 activei_row = items->active_item_idx;
567 }
568
569 dyn_data->columns = columns;
570
571 if (!use_auto_size) {
572 /* No auto-size, yet we clamp at min size! */
573 actual_rows = max_ii(ui_list->list_grip, actual_rows);
574 }
575 else if ((actual_rows != actual_maxrows) && (dyn_data->height > actual_rows)) {
576 /* Expand size if needed and possible. */
577 actual_rows = min_ii(dyn_data->height, actual_maxrows);
578 }
579
580 /* If list length changes or list is tagged to check this,
581 * and active is out of view, scroll to it. */
582 if ((ui_list->list_last_len != items->item_vec.size()) ||
584 {
585 if (activei_row < ui_list->list_scroll) {
586 ui_list->list_scroll = activei_row;
587 }
588 else if (activei_row >= ui_list->list_scroll + actual_rows) {
589 ui_list->list_scroll = activei_row - actual_rows + 1;
590 }
592 }
593
594 const int max_scroll = max_ii(0, dyn_data->height - actual_rows);
595 CLAMP(ui_list->list_scroll, 0, max_scroll);
596 ui_list->list_last_len = items->item_vec.size();
597 dyn_data->visual_height = actual_rows;
598 r_visual_info->visual_items = actual_rows * columns;
599 r_visual_info->start_idx = ui_list->list_scroll * columns;
600 r_visual_info->end_idx = min_ii(r_visual_info->start_idx + actual_rows * columns,
601 items->item_vec.size());
602}
603
604static void uilist_resize_update(bContext *C, uiList *ui_list)
605{
606 uiListDyn *dyn_data = ui_list->dyn_data;
607
608 /* This way we get diff in number of additional items to show (positive) or hide (negative). */
609 const int diff = round_fl_to_int(float(dyn_data->resize - dyn_data->resize_prev) /
610 float(UI_UNIT_Y));
611
612 if (diff != 0) {
613 ui_list->list_grip += diff;
614 dyn_data->resize_prev += diff * UI_UNIT_Y;
616 }
617
618 /* In case uilist is in popup, we need special refreshing */
620}
621
622static void *uilist_item_use_dynamic_tooltip(PointerRNA *itemptr, const char *propname)
623{
624 if (propname && propname[0] && itemptr && itemptr->data) {
625 PropertyRNA *prop = RNA_struct_find_property(itemptr, propname);
626
627 if (prop && (RNA_property_type(prop) == PROP_STRING)) {
628 return RNA_property_string_get_alloc(itemptr, prop, nullptr, 0, nullptr);
629 }
630 }
631 return nullptr;
632}
633
634static std::string uilist_item_tooltip_func(bContext * /*C*/, void *argN, const StringRef tip)
635{
636 char *dyn_tooltip = static_cast<char *>(argN);
637 std::string tooltip_string = dyn_tooltip;
638 if (!tip.is_empty()) {
639 tooltip_string += '\n';
640 tooltip_string += tip;
641 }
642 return tooltip_string;
643}
644
649 uiListType *ui_list_type,
650 const char *list_id,
651 int layout_type,
652 bool sort_reverse,
653 bool sort_lock)
654{
655 /* Allows to work in popups. */
656 ARegion *region = CTX_wm_region_popup(C);
657 if (region == nullptr) {
658 region = CTX_wm_region(C);
659 }
660
661 /* Find or add the uiList to the current Region. */
662
663 char full_list_id[UI_MAX_NAME_STR];
664 WM_uilisttype_to_full_list_id(ui_list_type, list_id, full_list_id);
665
666 uiList *ui_list = static_cast<uiList *>(
667 BLI_findstring(&region->ui_lists, full_list_id, offsetof(uiList, list_id)));
668
669 if (!ui_list) {
670 ui_list = MEM_callocN<uiList>("uiList");
671 STRNCPY(ui_list->list_id, full_list_id);
672 BLI_addtail(&region->ui_lists, ui_list);
673 ui_list->list_grip = -UI_LIST_AUTO_SIZE_THRESHOLD; /* Force auto size by default. */
674 if (sort_reverse) {
676 }
677 if (sort_lock) {
679 }
680 }
681
682 if (!ui_list->dyn_data) {
683 ui_list->dyn_data = MEM_callocN<uiListDyn>("uiList.dyn_data");
684 }
685 uiListDyn *dyn_data = ui_list->dyn_data;
686 /* Note that this isn't a `uiListType` callback, it's stored in the runtime list data. Otherwise
687 * the runtime data could leak when the type is unregistered (e.g. on "Reload Scripts"). */
689
690 /* Because we can't actually pass type across save&load... */
691 ui_list->type = ui_list_type;
692 ui_list->layout_type = layout_type;
693
694 /* Reset filtering data. */
697 dyn_data->items_len = dyn_data->items_shown = -1;
698
699 return ui_list;
700}
701
703 uiList *ui_list,
704 uiLayout *layout,
705 TemplateListInputData *input_data,
706 TemplateListItems *items,
707 const TemplateListLayoutDrawData *layout_data,
708 const enum uiTemplateListFlags flags)
709{
710 uiListDyn *dyn_data = ui_list->dyn_data;
711 const char *active_propname = RNA_property_identifier(input_data->activeprop);
712
713 uiLayout *glob = nullptr, *box, *row, *col, *subrow, *sub, *overlap;
714 char numstr[32];
715 int rnaicon = ICON_NONE, icon = ICON_NONE;
716 uiBut *but;
717
718 uiBlock *block = uiLayoutGetBlock(layout);
719
720 /* get icon */
721 if (input_data->dataptr.data && input_data->prop) {
722 StructRNA *ptype = RNA_property_pointer_type(&input_data->dataptr, input_data->prop);
723 rnaicon = RNA_struct_ui_icon(ptype);
724 }
725
726 TemplateListVisualInfo visual_info;
727 switch (ui_list->layout_type) {
729 /* layout */
730 box = &layout->list_box(ui_list, &input_data->active_dataptr, input_data->activeprop);
731 glob = &box->column(true);
732 row = &glob->row(false);
733 col = &row->column(true);
734
735 TemplateListLayoutDrawData adjusted_layout_data = *layout_data;
736 adjusted_layout_data.columns = 1;
737 /* init numbers */
738 uilist_prepare(ui_list, items, &adjusted_layout_data, &visual_info);
739
740 int i = 0;
741 if (input_data->dataptr.data && input_data->prop) {
742
743 const bool editable = (RNA_property_flag(input_data->prop) & PROP_EDITABLE);
744
745 /* create list items */
746 for (i = visual_info.start_idx; i < visual_info.end_idx; i++) {
747 PointerRNA *itemptr = &items->item_vec[i].item;
748 void *dyntip_data;
749 const int org_i = items->item_vec[i].org_idx;
750 const int flt_flag = items->item_vec[i].flt_flag;
751 uiBlock *subblock = uiLayoutGetBlock(col);
752
753 overlap = &col->overlap();
754
756
757 /* list item behind label & other buttons */
758 overlap->row(false);
759
760 but = uiDefButR_prop(subblock,
762 0,
763 "",
764 0,
765 0,
766 UI_UNIT_X * 10,
767 UI_UNIT_Y,
768 &input_data->active_dataptr,
769 input_data->activeprop,
770 0,
771 0,
772 org_i,
773 editable ? TIP_("Select List Item "
774 "(Double click to rename)") :
775 TIP_("Select List Item"));
776
777 if ((dyntip_data = uilist_item_use_dynamic_tooltip(itemptr,
778 input_data->item_dyntip_propname)))
779 {
781 }
782
783 uiLayout *item_row = &overlap->row(true);
784
786
787 sub = &item_row->row(false);
788 icon = UI_icon_from_rnaptr(C, itemptr, rnaicon, false);
789 if (icon == ICON_DOT) {
790 icon = ICON_NONE;
791 }
792 layout_data->draw_item(ui_list,
793 C,
794 sub,
795 &input_data->dataptr,
796 itemptr,
797 icon,
798 &input_data->active_dataptr,
799 active_propname,
800 org_i,
801 flt_flag);
802
803 /* Items should be able to set context pointers for the layout. But the list-row button
804 * swallows events, so it needs the context storage too for handlers to see it. */
806
807 /* If we are "drawing" active item, set all labels as active. */
808 if (i == items->active_item_idx) {
810 }
811
814 }
815 }
816
817 /* add dummy buttons to fill space */
818 for (; i < visual_info.start_idx + visual_info.visual_items; i++) {
819 col->label("", ICON_NONE);
820 }
821
822 /* Add scroll-bar. */
823 if (items->item_vec.size() > visual_info.visual_items) {
824 row->column(false);
825 but = uiDefButI(block,
827 0,
828 "",
829 0,
830 0,
832 UI_UNIT_Y * dyn_data->visual_height,
833 &ui_list->list_scroll,
834 0,
835 dyn_data->height - dyn_data->visual_height,
836 "");
837 uiButScrollBar *but_scroll = reinterpret_cast<uiButScrollBar *>(but);
838 but_scroll->visual_height = dyn_data->visual_height;
839 }
840 break;
841 }
843 row = &layout->row(true);
844
845 if ((input_data->dataptr.data && input_data->prop) && (dyn_data->items_shown > 0) &&
846 (items->active_item_idx >= 0) && (items->active_item_idx < dyn_data->items_shown))
847 {
848 PointerRNA *itemptr = &items->item_vec[items->active_item_idx].item;
849 const int org_i = items->item_vec[items->active_item_idx].org_idx;
850
851 icon = UI_icon_from_rnaptr(C, itemptr, rnaicon, false);
852 if (icon == ICON_DOT) {
853 icon = ICON_NONE;
854 }
855 layout_data->draw_item(ui_list,
856 C,
857 row,
858 &input_data->dataptr,
859 itemptr,
860 icon,
861 &input_data->active_dataptr,
862 active_propname,
863 org_i,
864 0);
865 }
866 /* if list is empty, add in dummy button */
867 else {
868 row->label("", ICON_NONE);
869 }
870
871 /* next/prev button */
872 SNPRINTF(numstr, "%d :", dyn_data->items_shown);
873 but = uiDefIconTextButR_prop(block,
875 0,
876 ICON_NONE,
877 numstr,
878 0,
879 0,
880 UI_UNIT_X * 5,
881 UI_UNIT_Y,
882 &input_data->active_dataptr,
883 input_data->activeprop,
884 0,
885 0,
886 0,
887 "");
888 if (dyn_data->items_shown == 0) {
890 }
891 break;
892 case UILST_LAYOUT_GRID: {
893 box = &layout->list_box(ui_list, &input_data->active_dataptr, input_data->activeprop);
894 glob = &box->column(true);
895 row = &glob->row(false);
896 col = &row->column(true);
897 subrow = nullptr; /* Quite gcc warning! */
898
899 uilist_prepare(ui_list, items, layout_data, &visual_info);
900
901 int i = 0;
902 if (input_data->dataptr.data && input_data->prop) {
903 /* create list items */
904 for (i = visual_info.start_idx; i < visual_info.end_idx; i++) {
905 PointerRNA *itemptr = &items->item_vec[i].item;
906 const int org_i = items->item_vec[i].org_idx;
907 const int flt_flag = items->item_vec[i].flt_flag;
908
909 /* create button */
910 if (!(i % layout_data->columns)) {
911 subrow = &col->row(false);
912 }
913
914 uiBlock *subblock = uiLayoutGetBlock(subrow);
915 overlap = &subrow->overlap();
916
918
919 /* list item behind label & other buttons */
920 overlap->row(false);
921
922 but = uiDefButR_prop(subblock,
924 0,
925 "",
926 0,
927 0,
928 UI_UNIT_X * 10,
929 UI_UNIT_Y,
930 &input_data->active_dataptr,
931 input_data->activeprop,
932 0,
933 0,
934 org_i,
935 std::nullopt);
937
938 sub = &overlap->row(false);
939
940 icon = UI_icon_from_rnaptr(C, itemptr, rnaicon, false);
941 layout_data->draw_item(ui_list,
942 C,
943 sub,
944 &input_data->dataptr,
945 itemptr,
946 icon,
947 &input_data->active_dataptr,
948 active_propname,
949 org_i,
950 flt_flag);
951
952 /* If we are "drawing" active item, set all labels as active. */
953 if (i == items->active_item_idx) {
955 }
956
958 }
959 }
960
961 /* add dummy buttons to fill space */
962 for (; i < visual_info.start_idx + visual_info.visual_items; i++) {
963 if (!(i % layout_data->columns)) {
964 subrow = &col->row(false);
965 }
966 subrow->label("", ICON_NONE);
967 }
968
969 /* Add scroll-bar. */
970 if (items->item_vec.size() > visual_info.visual_items) {
971 /* col = */ row->column(false);
972 but = uiDefButI(block,
974 0,
975 "",
976 0,
977 0,
979 UI_UNIT_Y * dyn_data->visual_height,
980 &ui_list->list_scroll,
981 0,
982 dyn_data->height - dyn_data->visual_height,
983 "");
984 uiButScrollBar *but_scroll = reinterpret_cast<uiButScrollBar *>(but);
985 but_scroll->visual_height = dyn_data->visual_height;
986 }
987 break;
988 }
990 box = &layout->list_box(ui_list, &input_data->active_dataptr, input_data->activeprop);
991 /* For grip button. */
992 glob = &box->column(true);
993 /* For scroll-bar. */
994 row = &glob->row(false);
995
996 const bool show_names = (flags & UI_TEMPLATE_LIST_NO_NAMES) == 0;
997
998 const int size_x = UI_preview_tile_size_x();
999 const int size_y = show_names ? UI_preview_tile_size_y() : UI_preview_tile_size_y_no_label();
1000
1001 const int cols_per_row = std::max(int((uiLayoutGetWidth(box) - V2D_SCROLL_WIDTH) / size_x),
1002 1);
1003 uiLayout *grid = &row->grid_flow(true, cols_per_row, true, true, true);
1004
1005 TemplateListLayoutDrawData adjusted_layout_data = *layout_data;
1006 adjusted_layout_data.columns = cols_per_row;
1007 uilist_prepare(ui_list, items, &adjusted_layout_data, &visual_info);
1008
1009 if (input_data->dataptr.data && input_data->prop) {
1010 /* create list items */
1011 for (int i = visual_info.start_idx; i < visual_info.end_idx; i++) {
1012 PointerRNA *itemptr = &items->item_vec[i].item;
1013 const int org_i = items->item_vec[i].org_idx;
1014 const int flt_flag = items->item_vec[i].flt_flag;
1015
1016 overlap = &grid->overlap();
1017 col = &overlap->column(false);
1018
1019 uiBlock *subblock = uiLayoutGetBlock(col);
1021
1022 but = uiDefButR_prop(subblock,
1024 0,
1025 "",
1026 0,
1027 0,
1028 size_x,
1029 size_y,
1030 &input_data->active_dataptr,
1031 input_data->activeprop,
1032 0,
1033 0,
1034 org_i,
1035 std::nullopt);
1037
1038 col = &overlap->column(false);
1039
1040 icon = UI_icon_from_rnaptr(C, itemptr, rnaicon, false);
1041 layout_data->draw_item(ui_list,
1042 C,
1043 col,
1044 &input_data->dataptr,
1045 itemptr,
1046 icon,
1047 &input_data->active_dataptr,
1048 active_propname,
1049 org_i,
1050 flt_flag);
1051
1052 /* Items should be able to set context pointers for the layout. But the list-row button
1053 * swallows events, so it needs the context storage too for handlers to see it. */
1055
1056 /* If we are "drawing" active item, set all labels as active. */
1057 if (i == items->active_item_idx) {
1059 }
1060
1062 }
1063 }
1064
1065 if (items->item_vec.size() > visual_info.visual_items) {
1066 /* col = */ row->column(false);
1067 but = uiDefButI(block,
1069 0,
1070 "",
1071 0,
1072 0,
1074 size_y * dyn_data->visual_height,
1075 &ui_list->list_scroll,
1076 0,
1077 dyn_data->height - dyn_data->visual_height,
1078 "");
1079 uiButScrollBar *but_scroll = reinterpret_cast<uiButScrollBar *>(but);
1080 but_scroll->visual_height = dyn_data->visual_height;
1081 }
1082 break;
1083 }
1084
1085 const bool add_filters_but = (flags & UI_TEMPLATE_LIST_NO_FILTER_OPTIONS) == 0;
1086 if (glob && add_filters_but) {
1087 const bool add_grip_but = (flags & UI_TEMPLATE_LIST_NO_GRIP) == 0;
1088
1089 /* About #UI_BTYPE_GRIP drag-resize:
1090 * We can't directly use results from a grip button, since we have a
1091 * rather complex behavior here (sizing by discrete steps and, overall, auto-size feature).
1092 * Since we *never* know whether we are grip-resizing or not
1093 * (because there is no callback for when a button enters/leaves its "edit mode"),
1094 * we use the fact that grip-controlled value (dyn_data->resize) is completely handled
1095 * by the grip during the grab resize, so settings its value here has no effect at all.
1096 *
1097 * It is only meaningful when we are not resizing,
1098 * in which case this gives us the correct "init drag" value.
1099 * Note we cannot affect `dyn_data->resize_prev here`,
1100 * since this value is not controlled by the grip!
1101 */
1102 dyn_data->resize = dyn_data->resize_prev +
1103 (dyn_data->visual_height - ui_list->list_grip) * UI_UNIT_Y;
1104
1105 row = &glob->row(true);
1106 uiBlock *subblock = uiLayoutGetBlock(row);
1108
1109 if (ui_list->filter_flag & UILST_FLT_SHOW) {
1110 but = uiDefIconButBitI(subblock,
1113 0,
1114 ICON_DISCLOSURE_TRI_DOWN,
1115 0,
1116 0,
1117 UI_UNIT_X,
1118 UI_UNIT_Y * 0.5f,
1119 &(ui_list->filter_flag),
1120 0,
1121 0,
1122 TIP_("Hide filtering options"));
1123 UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */
1124
1125 if (add_grip_but) {
1126 but = uiDefIconButI(subblock,
1128 0,
1129 ICON_GRIP,
1130 0,
1131 0,
1132 UI_UNIT_X * 10.0f,
1133 UI_UNIT_Y * 0.5f,
1134 &dyn_data->resize,
1135 0.0,
1136 0.0,
1137 "");
1138 UI_but_func_set(but, [ui_list](bContext &C) { uilist_resize_update(&C, ui_list); });
1139 }
1140
1142
1143 col = &glob->column(false);
1144 subblock = uiLayoutGetBlock(col);
1145 uiDefBut(subblock,
1147 0,
1148 "",
1149 0,
1150 0,
1151 UI_UNIT_X,
1152 UI_UNIT_Y * 0.05f,
1153 nullptr,
1154 0.0,
1155 0.0,
1156 "");
1157
1158 layout_data->draw_filter(ui_list, C, col);
1159 }
1160 else {
1161 but = uiDefIconButBitI(subblock,
1164 0,
1165 ICON_DISCLOSURE_TRI_RIGHT,
1166 0,
1167 0,
1168 UI_UNIT_X,
1169 UI_UNIT_Y * 0.5f,
1170 &(ui_list->filter_flag),
1171 0,
1172 0,
1173 TIP_("Show filtering options"));
1174 UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */
1175
1176 if (add_grip_but) {
1177 but = uiDefIconButI(subblock,
1179 0,
1180 ICON_GRIP,
1181 0,
1182 0,
1183 UI_UNIT_X * 10.0f,
1184 UI_UNIT_Y * 0.5f,
1185 &dyn_data->resize,
1186 0.0,
1187 0.0,
1188 "");
1189 UI_but_func_set(but, [ui_list](bContext &C) { uilist_resize_update(&C, ui_list); });
1190 }
1191
1193 }
1194 }
1195}
1196
1198 const bContext *C,
1199 const char *listtype_name,
1200 const char *list_id,
1201 PointerRNA *dataptr,
1202 const StringRefNull propname,
1203 PointerRNA *active_dataptr,
1204 const StringRefNull active_propname,
1205 const char *item_dyntip_propname,
1206 int rows,
1207 int maxrows,
1208 int layout_type,
1209 int columns,
1210 enum uiTemplateListFlags flags,
1211 void *customdata)
1212{
1213 TemplateListInputData input_data = {};
1214 uiListType *ui_list_type;
1215 if (!ui_template_list_data_retrieve(listtype_name,
1216 list_id,
1217 dataptr,
1218 propname,
1219 active_dataptr,
1220 active_propname,
1221 item_dyntip_propname,
1222 &input_data,
1223 &ui_list_type))
1224 {
1225 return nullptr;
1226 }
1227
1228 uiListDrawItemFunc draw_item = ui_list_type->draw_item ? ui_list_type->draw_item :
1230 uiListDrawFilterFunc draw_filter = ui_list_type->draw_filter ? ui_list_type->draw_filter :
1232 uiListFilterItemsFunc filter_items = ui_list_type->filter_items ? ui_list_type->filter_items :
1234
1235 uiList *ui_list = ui_list_ensure(C,
1236 ui_list_type,
1237 list_id,
1238 layout_type,
1241 uiListDyn *dyn_data = ui_list->dyn_data;
1242
1243 MEM_SAFE_FREE(dyn_data->customdata);
1244 dyn_data->customdata = customdata;
1245
1246 /* When active item changed since last draw, scroll to it. */
1247 if (input_data.active_item_idx != ui_list->list_last_activei) {
1249 ui_list->list_last_activei = input_data.active_item_idx;
1250 }
1251
1252 TemplateListItems items;
1253 ui_template_list_collect_display_items(C, ui_list, &input_data, filter_items, &items);
1254
1255 TemplateListLayoutDrawData layout_data;
1256 layout_data.draw_item = draw_item;
1257 layout_data.draw_filter = draw_filter;
1258 layout_data.rows = rows;
1259 layout_data.maxrows = maxrows;
1260 layout_data.columns = columns;
1261
1262 ui_template_list_layout_draw(C, ui_list, layout, &input_data, &items, &layout_data, flags);
1263
1264 return ui_list;
1265}
1266
1268 const bContext *C,
1269 const char *listtype_name,
1270 const char *list_id,
1271 PointerRNA *dataptr,
1272 blender::StringRefNull propname,
1273 PointerRNA *active_dataptr,
1274 const char *active_propname,
1275 const char *item_dyntip_propname,
1276 int rows,
1277 int maxrows,
1278 int layout_type,
1279 int columns,
1280 enum uiTemplateListFlags flags)
1281{
1282 uiTemplateList_ex(layout,
1283 C,
1284 listtype_name,
1285 list_id,
1286 dataptr,
1287 propname,
1288 active_dataptr,
1289 active_propname,
1290 item_dyntip_propname,
1291 rows,
1292 maxrows,
1293 layout_type,
1294 columns,
1295 flags,
1296 nullptr);
1297}
1298
1300 const StringRefNull opname,
1301 bool create_properties)
1302{
1303 uiListDyn *dyn_data = ui_list->dyn_data;
1304 dyn_data->custom_activate_optype = WM_operatortype_find(opname.c_str(), false);
1305 if (!dyn_data->custom_activate_optype) {
1306 return nullptr;
1307 }
1308
1309 if (create_properties) {
1310 PointerRNA *opptr = dyn_data->custom_activate_opptr;
1312 opptr ? (IDProperty **)&opptr->data : nullptr,
1313 opname.c_str());
1314 }
1315
1316 return dyn_data->custom_activate_opptr;
1317}
1318
1320 const StringRefNull opname,
1321 bool create_properties)
1322{
1323 uiListDyn *dyn_data = ui_list->dyn_data;
1324 dyn_data->custom_drag_optype = WM_operatortype_find(opname.c_str(), false);
1325 if (!dyn_data->custom_drag_optype) {
1326 return nullptr;
1327 }
1328
1329 if (create_properties) {
1330 PointerRNA *opptr = dyn_data->custom_drag_opptr;
1332 opptr ? (IDProperty **)&opptr->data : nullptr,
1333 opname.c_str());
1334 }
1335
1336 return dyn_data->custom_drag_opptr;
1337}
1338
1339/* -------------------------------------------------------------------- */
1340
1343
1349
ARegion * CTX_wm_region_popup(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
void(*)(uiList *ui_list, const bContext *C, PointerRNA *, const char *propname) uiListFilterItemsFunc
void(*)(uiList *ui_list, const bContext *C, uiLayout *layout) uiListDrawFilterFunc
void(*)(uiList *ui_list, const bContext *C, uiLayout *layout, PointerRNA *dataptr, PointerRNA *itemptr, int icon, PointerRNA *active_dataptr, const char *active_propname, int index, int flt_flag) uiListDrawItemFunc
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
MINLINE int round_fl_to_int(float a)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
int char char int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
char char * BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, char pad, size_t dst_maxncpy) ATTR_NONNULL(1
#define CLAMP(a, b, c)
#define TIP_(msgid)
@ UILST_SCROLL_TO_ACTIVE_ITEM
@ UILST_FLT_EXCLUDE
@ UILST_FLT_SHOW
#define UI_LIST_AUTO_SIZE_THRESHOLD
@ UILST_FLT_SORT_LOCK
@ UILST_FLT_SORT_ALPHA
@ UILST_FLT_SORT_REVERSE
@ UILST_LAYOUT_COMPACT
@ UILST_LAYOUT_DEFAULT
@ UILST_LAYOUT_BIG_PREVIEW_GRID
@ UILST_LAYOUT_GRID
@ UILST_FLT_ITEM
@ UILST_FLT_ITEM_NEVER_SHOW
void ED_region_tag_refresh_ui(ARegion *region)
Definition area.cc:668
Read Guarded memory(de)allocation.
#define RNA_PROP_END
#define RNA_PROP_BEGIN(sptr, itemptr, prop)
#define RNA_warning(format,...)
PropertyType
Definition RNA_types.hh:149
@ PROP_INT
Definition RNA_types.hh:151
@ PROP_STRING
Definition RNA_types.hh:153
@ PROP_COLLECTION
Definition RNA_types.hh:156
@ PROP_EDITABLE
Definition RNA_types.hh:292
#define C
Definition RandGen.cpp:29
blender::FunctionRef< eUIListFilterResult( const PointerRNA &itemptr, blender::StringRefNull name, int index)> uiListItemFilterFn
void UI_but_func_set(uiBut *but, std::function< void(bContext &)> func)
eUIListFilterResult
@ UI_LIST_ITEM_FILTER_MISMATCHES
@ UI_LIST_ITEM_NEVER_SHOW
@ UI_LIST_ITEM_FILTER_MATCHES
blender::FunctionRef< std::string(const PointerRNA &itemptr, int index)> uiListItemGetNameFn
void UI_but_flag_disable(uiBut *but, int flag)
uiBut * uiDefIconTextButR_prop(uiBlock *block, int type, int retval, int icon, std::optional< blender::StringRef > str, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, std::optional< blender::StringRef > tip)
#define UI_UNIT_Y
void UI_block_emboss_set(uiBlock *block, blender::ui::EmbossType emboss)
uiBut * uiDefButR_prop(uiBlock *block, int type, int retval, std::optional< blender::StringRef > str, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, std::optional< blender::StringRef > tip)
@ UI_BUT_NO_TOOLTIP
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *arg, uiFreeArgFunc free_arg)
uiBut * uiDefBut(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > tip)
int UI_preview_tile_size_y(const int size_px=96)
void UI_block_flag_disable(uiBlock *block, int flag)
void UI_but_drawflag_enable(uiBut *but, int flag)
#define UI_UL_DEFAULT_CLASS_NAME
uiBut * uiDefButI(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, int *poin, float min, float max, std::optional< blender::StringRef > tip)
uiBut * uiDefIconButI(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, int *poin, float min, float max, std::optional< blender::StringRef > tip)
@ UI_BLOCK_LIST_ITEM
int UI_preview_tile_size_x(const int size_px=96)
#define UI_UNIT_X
void UI_block_flag_enable(uiBlock *block, int flag)
@ UI_BTYPE_TOGGLE
@ UI_BTYPE_LISTROW
@ UI_BTYPE_SEPR
@ UI_BTYPE_NUM
@ UI_BTYPE_GRIP
@ UI_BTYPE_SCROLL
int UI_preview_tile_size_y_no_label(const int size_px=96)
@ UI_BUT_UNDO
@ UI_BUT_DISABLED
uiBut * uiDefIconButBitI(uiBlock *block, int type, int bit, int retval, int icon, int x, int y, short width, short height, int *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_but_flag_enable(uiBut *but, int flag)
uiTemplateListFlags
@ UI_TEMPLATE_LIST_SORT_LOCK
@ UI_TEMPLATE_LIST_SORT_REVERSE
@ UI_TEMPLATE_LIST_NO_NAMES
@ UI_TEMPLATE_LIST_NO_FILTER_OPTIONS
@ UI_TEMPLATE_LIST_NO_GRIP
int UI_icon_from_rnaptr(const bContext *C, PointerRNA *ptr, int rnaicon, bool big)
@ UI_ITEM_R_TOGGLE
@ UI_ITEM_R_NO_BG
@ UI_ITEM_R_ICON_ONLY
uiBlock * uiLayoutGetBlock(uiLayout *layout)
#define UI_ITEM_NONE
int uiLayoutGetWidth(uiLayout *layout)
void uiLayoutListItemAddPadding(uiLayout *layout)
bContextStore * uiLayoutGetContextStore(uiLayout *layout)
#define UI_MAX_NAME_STR
#define V2D_SCROLL_WIDTH
Definition UI_view2d.hh:54
int64_t size() const
void resize(const int64_t new_size)
constexpr bool is_empty() const
constexpr const char * c_str() const
eUIListFilterResult operator()(const PointerRNA &itemptr, blender::StringRefNull name, int index)
#define offsetof(t, d)
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
Definition frames.inl:1166
uint col
#define floor
#define ceil
#define MEM_SAFE_FREE(v)
#define MAX_IDPROP_NAME
#define RNA_NO_INDEX
uiListType * UI_UL_asset_view()
void ui_layout_list_set_labels_active(uiLayout *layout)
uiListType * UI_UL_cache_file_layers()
static int cmpstringp(const void *p1, const void *p2)
static std::string uilist_item_tooltip_func(bContext *, void *argN, const StringRef tip)
static uiList * ui_list_ensure(const bContext *C, uiListType *ui_list_type, const char *list_id, int layout_type, bool sort_reverse, bool sort_lock)
static void uilist_resize_update(bContext *C, uiList *ui_list)
PointerRNA * UI_list_custom_activate_operator_set(uiList *ui_list, const StringRefNull opname, bool create_properties)
static void uilist_free_dyn_data(uiList *ui_list)
static void * uilist_item_use_dynamic_tooltip(PointerRNA *itemptr, const char *propname)
static bool ui_template_list_data_retrieve(const StringRef listtype_name, const char *list_id, PointerRNA *dataptr, const StringRefNull propname, PointerRNA *active_dataptr, const StringRefNull active_propname, const char *item_dyntip_propname, TemplateListInputData *r_input_data, uiListType **r_list_type)
void UI_list_filter_and_sort_items(uiList *ui_list, const bContext *, uiListItemFilterFn item_filter_fn, PointerRNA *dataptr, const char *propname, uiListItemGetNameFn get_name_fn)
static void ui_template_list_collect_display_items(const bContext *C, uiList *ui_list, TemplateListInputData *input_data, const uiListFilterItemsFunc filter_items_fn, TemplateListItems *r_items)
static void uilist_draw_filter_default(uiList *ui_list, const bContext *, uiLayout *layout)
static void uilist_filter_items_default(uiList *ui_list, const bContext *C, PointerRNA *dataptr, const char *propname)
void uiTemplateList(uiLayout *layout, const bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, blender::StringRefNull propname, PointerRNA *active_dataptr, const char *active_propname, const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns, enum uiTemplateListFlags flags)
uiList * uiTemplateList_ex(uiLayout *layout, const bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, const StringRefNull propname, PointerRNA *active_dataptr, const StringRefNull active_propname, const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns, enum uiTemplateListFlags flags, void *customdata)
static void ui_template_list_collect_items(PointerRNA *list_ptr, PropertyRNA *list_prop, const uiList *ui_list, int activei, TemplateListItems *r_items)
static void ui_template_list_layout_draw(const bContext *C, uiList *ui_list, uiLayout *layout, TemplateListInputData *input_data, TemplateListItems *items, const TemplateListLayoutDrawData *layout_data, const enum uiTemplateListFlags flags)
void ED_uilisttypes_ui()
static void uilist_prepare(uiList *ui_list, const TemplateListItems *items, const TemplateListLayoutDrawData *layout_data, TemplateListVisualInfo *r_visual_info)
PointerRNA * UI_list_custom_drag_operator_set(uiList *ui_list, const StringRefNull opname, bool create_properties)
bool UI_list_item_index_is_filtered_visible(const uiList *ui_list, const int item_idx)
static void uilist_draw_item_default(uiList *ui_list, const bContext *, uiLayout *layout, PointerRNA *, PointerRNA *itemptr, int icon, PointerRNA *, const char *, int, int)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
StructRNA * RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
char * RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len)
PropertyType RNA_property_type(PropertyRNA *prop)
char * RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len)
const char * RNA_struct_identifier(const StructRNA *type)
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_flag(PropertyRNA *prop)
int RNA_struct_ui_icon(const StructRNA *type)
PropertyRNA * RNA_struct_name_property(const StructRNA *type)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
const char * RNA_property_identifier(const PropertyRNA *prop)
int RNA_property_collection_length(PointerRNA *ptr, PropertyRNA *prop)
ListBase ui_lists
StructRNA * type
Definition RNA_types.hh:52
void * data
Definition RNA_types.hh:53
char name[MAX_IDPROP_NAME]
blender::Vector< _uilist_item > item_vec
const bContextStore * context
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
uiLayout & grid_flow(bool row_major, int columns_len, bool even_columns, bool even_rows, bool align)
uiLayout & row(bool align)
uiLayout & list_box(uiList *ui_list, PointerRNA *actptr, PropertyRNA *actprop)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
uiLayout & overlap()
struct wmOperatorType * custom_activate_optype
struct PointerRNA * custom_drag_opptr
uiListFreeRuntimeDataFunc free_runtime_data_fn
int * items_filter_neworder
struct wmOperatorType * custom_drag_optype
int * items_filter_flags
struct PointerRNA * custom_activate_opptr
uiListFilterItemsFunc filter_items
uiListDrawFilterFunc draw_filter
uiListDrawItemFunc draw_item
char filter_byname[128]
int filter_sort_flag
char list_id[128]
uiListDyn * dyn_data
int list_last_activei
struct uiListType * type
i
Definition text_draw.cc:230
uint len
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring)
void WM_operator_properties_free(PointerRNA *ptr)
bool WM_uilisttype_add(uiListType *ult)
uiListType * WM_uilisttype_find(const StringRef idname, bool quiet)
void WM_uilisttype_to_full_list_id(const uiListType *ult, const char *list_id, char r_full_list_id[])