diff options
Diffstat (limited to 'source/blender/editors/interface/interface_templates.c')
-rw-r--r-- | source/blender/editors/interface/interface_templates.c | 571 |
1 files changed, 467 insertions, 104 deletions
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 61cc021800e..6b6b7114c84 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1,4 +1,5 @@ /* + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -43,6 +44,7 @@ #include "BLI_rect.h" #include "BLI_math.h" #include "BLI_listbase.h" +#include "BLI_fnmatch.h" #include "BLF_api.h" #include "BLF_translation.h" @@ -1017,6 +1019,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) Scene *scene = CTX_data_scene(C); Object *ob; ModifierData *md, *vmd; + VirtualModifierData virtualModifierData; int i, lastCageIndex, cageIndex; /* verify we have valid data */ @@ -1039,7 +1042,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0); /* XXX virtual modifiers are not accesible for python */ - vmd = modifiers_getVirtualModifierList(ob); + vmd = modifiers_getVirtualModifierList(ob, &virtualModifierData); for (i = 0; vmd; i++, vmd = vmd->next) { if (md == vmd) @@ -1145,9 +1148,10 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) uiBlockSetEmboss(block, UI_EMBOSSN); uiItemR(row, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); uiBlockSetEmboss(block, UI_EMBOSS); - + /* name */ - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco + 0.5f*UI_UNIT_X, yco, 5 * UI_UNIT_X, 0.9f*UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, + xco + 0.5f * UI_UNIT_X, yco, 5 * UI_UNIT_X, 0.9f * UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, ""); if (con->flag & CONSTRAINT_DISABLE) uiLayoutSetRedAlert(row, TRUE); @@ -2468,7 +2472,7 @@ void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propnam static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout, struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon, struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname), - int UNUSED(index)) + int UNUSED(index), int UNUSED(flt_flag)) { char *namebuf; const char *name; @@ -2494,30 +2498,245 @@ static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UN } } +static void uilist_draw_filter_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout) +{ + PointerRNA listptr; + uiLayout *row, *subrow; + + RNA_pointer_create(NULL, &RNA_UIList, ui_list, &listptr); + + row = uiLayoutRow(layout, FALSE); + + subrow = uiLayoutRow(row, TRUE); + uiItemR(subrow, &listptr, "filter_name", 0, "", ICON_NONE); + uiItemR(subrow, &listptr, "use_filter_invert", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", + (ui_list->filter_flag & UILST_FLT_EXCLUDE) ? ICON_ZOOM_OUT : ICON_ZOOM_IN); + + subrow = uiLayoutRow(row, TRUE); + uiItemR(subrow, &listptr, "use_filter_sort_alpha", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + uiItemR(subrow, &listptr, "use_filter_sort_reverse", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", + (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) ? ICON_TRIA_UP : ICON_TRIA_DOWN); +} + +typedef struct { + char name[MAX_IDPROP_NAME]; + int org_idx; +} StringCmp; + +static int cmpstringp(const void *p1, const void *p2) +{ + /* Case-insensitive comparison. */ + return BLI_strcasecmp(((StringCmp *) p1)->name, ((StringCmp *) p2)->name); +} + +static void uilist_filter_items_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct PointerRNA *dataptr, + const char *propname) +{ + uiListDyn *dyn_data = ui_list->dyn_data; + PropertyRNA *prop = RNA_struct_find_property(dataptr, propname); + + const char *filter_raw = ui_list->filter_byname; + char *filter = (char *)filter_raw, filter_buff[32], *filter_dyn = NULL; + bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0; + bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_ALPHA) != 0; + int len = RNA_property_collection_length(dataptr, prop); + + dyn_data->items_shown = dyn_data->items_len = len; + + if (len && (order_by_name || filter_raw[0])) { + StringCmp *names = NULL; + int order_idx = 0, i = 0; + + if (order_by_name) { + names = MEM_callocN(sizeof(StringCmp) * len, AT); + } + if (filter_raw[0]) { + size_t idx = 0, slen = strlen(filter_raw); + + dyn_data->items_filter_flags = MEM_callocN(sizeof(int) * len, AT); + dyn_data->items_shown = 0; + + /* Implicitly add heading/trailing wildcards if needed. */ + if (len + 3 <= 32) { + filter = filter_buff; + } + else { + filter = filter_dyn = MEM_mallocN((slen + 3) * sizeof(char), AT); + } + if (filter_raw[idx] != '*') { + filter[idx++] = '*'; + } + memcpy(filter + idx, filter_raw, slen); + idx += slen; + if (filter[idx - 1] != '*') { + filter[idx++] = '*'; + } + filter[idx] = '\0'; + } + + RNA_PROP_BEGIN (dataptr, itemptr, prop) + { + char *namebuf; + const char *name; + bool do_order = false; + + namebuf = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); + name = namebuf ? namebuf : ""; + + if (filter[0]) { + /* Case-insensitive! */ + if (fnmatch(filter, name, FNM_CASEFOLD) == 0) { + dyn_data->items_filter_flags[i] = UILST_FLT_ITEM; + if (!filter_exclude) { + dyn_data->items_shown++; + do_order = order_by_name; + } + //printf("%s: '%s' matches '%s'\n", __func__, name, filter); + } + else if (filter_exclude) { + dyn_data->items_shown++; + do_order = order_by_name; + } + } + else { + do_order = order_by_name; + } + + if (do_order) { + names[order_idx].org_idx = order_idx; + BLI_strncpy(names[order_idx++].name, name, MAX_IDPROP_NAME); + } + + /* free name */ + if (namebuf) { + MEM_freeN(namebuf); + } + i++; + } + RNA_PROP_END; + + if (order_by_name) { + int new_idx; + /* note: order_idx equals either to ui_list->items_len if no filtering done, + * or to ui_list->items_shown if filter is enabled, + * or to (ui_list->items_len - ui_list->items_shown) if filtered items are excluded. + * This way, we only sort items we actually intend to draw! + */ + qsort(names, order_idx, sizeof(StringCmp), cmpstringp); + + dyn_data->items_filter_neworder = MEM_mallocN(sizeof(int) * order_idx, AT); + for (new_idx = 0; new_idx < order_idx; new_idx++) { + dyn_data->items_filter_neworder[names[new_idx].org_idx] = new_idx; + } + } + + if (filter_dyn) { + MEM_freeN(filter_dyn); + } + if (names) { + MEM_freeN(names); + } + } +} + +typedef struct { + PointerRNA item; + int org_idx; + int flt_flag; +} _uilist_item; + +typedef struct { + int visual_items; /* Visual number of items (i.e. number of items we have room to display). */ + int start_idx; /* Index of first item to display. */ + int end_idx; /* Index of last item to display + 1. */ +} uiListLayoutdata; + +static void prepare_list(uiList *ui_list, int len, int activei, int rows, int maxrows, int columns, + uiListLayoutdata *layoutdata) +{ + uiListDyn *dyn_data = ui_list->dyn_data; + int activei_row, max_scroll; + + /* default rows */ + if (rows == 0) + rows = 5; + dyn_data->visual_height_min = rows; + if (maxrows == 0) + maxrows = 5; + if (columns == 0) + columns = 9; + + if (ui_list->list_grip >= rows) { + maxrows = rows = ui_list->list_grip; + } + else { + ui_list->list_grip = 0; /* Reset to auto-size mode. */ + /* Prevent auto-size mode to take effect while grab-resizing! */ + if (ui_list->flag & UILST_RESIZING) { + maxrows = rows; + } + } + + if (columns > 1) { + dyn_data->height = (int)ceil((double)len / (double)columns); + activei_row = (int)floor((double)activei / (double)columns); + } + else { + dyn_data->height = len; + activei_row = activei; + } + + /* Expand size if needed and possible. */ + if ((ui_list->list_grip == 0) && (rows != maxrows) && (dyn_data->height > rows)) { + rows = min_ii(dyn_data->height, maxrows); + } + + /* If list length changes or list is tagged to check this, and active is out of view, scroll to it .*/ + if (ui_list->list_last_len != len || ui_list->flag & UILST_SCROLL_TO_ACTIVE_ITEM) { + if (activei_row < ui_list->list_scroll) { + ui_list->list_scroll = activei_row; + } + else if (activei_row >= ui_list->list_scroll + rows) { + ui_list->list_scroll = activei_row - rows + 1; + } + ui_list->flag &= ~UILST_SCROLL_TO_ACTIVE_ITEM; + } + + max_scroll = max_ii(0, dyn_data->height - rows); + CLAMP(ui_list->list_scroll, 0, max_scroll); + ui_list->list_last_len = len; + dyn_data->visual_height = rows; + layoutdata->visual_items = rows * columns; + layoutdata->start_idx = ui_list->list_scroll * columns; + layoutdata->end_idx = min_ii(layoutdata->start_idx + rows * columns, len); +} + void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, - const char *active_propname, int rows, int maxrows, int layout_type) + const char *active_propname, int rows, int maxrows, int layout_type, int columns) { uiListType *ui_list_type; uiList *ui_list = NULL; + uiListDyn *dyn_data; ARegion *ar; uiListDrawItemFunc draw_item; + uiListDrawFilterFunc draw_filter; + uiListFilterItemsFunc filter_items; PropertyRNA *prop = NULL, *activeprop; PropertyType type, activetype; + _uilist_item *items_ptr = NULL; StructRNA *ptype; - uiLayout *box, *row, *col, *sub, *overlap; + uiLayout *glob = NULL, *box, *row, *col, *subrow, *sub, *overlap; uiBlock *block, *subblock; uiBut *but; + uiListLayoutdata layoutdata; char ui_list_id[UI_MAX_NAME_STR]; char numstr[32]; int rnaicon = ICON_NONE, icon = ICON_NONE; int i = 0, activei = 0; int len = 0; - int items; - int found; - int min, max; /* validate arguments */ /* Forbid default UI_UL_DEFAULT_CLASS_NAME list class without a custom list_id! */ @@ -2580,6 +2799,8 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co } draw_item = ui_list_type->draw_item ? ui_list_type->draw_item : uilist_draw_item_default; + draw_filter = ui_list_type->draw_filter ? ui_list_type->draw_filter : uilist_draw_filter_default; + filter_items = ui_list_type->filter_items ? ui_list_type->filter_items : uilist_filter_items_default; /* Find or add the uiList to the current Region. */ /* We tag the list id with the list type... */ @@ -2589,146 +2810,211 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co ui_list = BLI_findstring(&ar->ui_lists, ui_list_id, offsetof(uiList, list_id)); if (!ui_list) { - ui_list = MEM_callocN(sizeof(uiList), __func__); + ui_list = MEM_callocN(sizeof(uiList), AT); BLI_strncpy(ui_list->list_id, ui_list_id, sizeof(ui_list->list_id)); BLI_addtail(&ar->ui_lists, ui_list); } + if (!ui_list->dyn_data) { + ui_list->dyn_data = MEM_callocN(sizeof(uiListDyn), AT); + } + dyn_data = ui_list->dyn_data; + /* Because we can't actually pass type across save&load... */ ui_list->type = ui_list_type; ui_list->layout_type = layout_type; + /* Reset filtering data. */ + if (dyn_data->items_filter_flags) { + MEM_freeN(dyn_data->items_filter_flags); + dyn_data->items_filter_flags = NULL; + } + if (dyn_data->items_filter_neworder) { + MEM_freeN(dyn_data->items_filter_neworder); + dyn_data->items_filter_neworder = NULL; + } + dyn_data->items_len = dyn_data->items_shown = -1; + + /* Filter list items! (not for compact layout, though) */ + if (dataptr->data && prop) { + int filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE; + bool order_reverse = (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) != 0; + int items_shown, idx = 0; +#if 0 + int prev_ii = -1, prev_i; +#endif + + if (layout_type == UILST_LAYOUT_COMPACT) { + dyn_data->items_len = dyn_data->items_shown = RNA_property_collection_length(dataptr, prop); + } + else { + //printf("%s: filtering...\n", __func__); + filter_items(ui_list, C, dataptr, propname); + //printf("%s: filtering done.\n", __func__); + } + + items_shown = dyn_data->items_shown; + if (items_shown >= 0) { + items_ptr = MEM_mallocN(sizeof(_uilist_item) * items_shown, AT); + //printf("%s: items shown: %d.\n", __func__, items_shown); + RNA_PROP_BEGIN (dataptr, itemptr, prop) + { + if (!dyn_data->items_filter_flags || + ((dyn_data->items_filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude)) + { + int ii; + if (dyn_data->items_filter_neworder) { + ii = dyn_data->items_filter_neworder[idx++]; + ii = order_reverse ? items_shown - ii - 1 : ii; + } + else { + ii = order_reverse ? items_shown - ++idx : idx++; + } + //printf("%s: ii: %d\n", __func__, ii); + items_ptr[ii].item = itemptr; + items_ptr[ii].org_idx = i; + items_ptr[ii].flt_flag = dyn_data->items_filter_flags ? dyn_data->items_filter_flags[i] : 0; + + if (activei == i) { + activei = ii; + } +# if 0 /* For now, do not alter active element, even if it will be hidden... */ + else if (activei < i) { + /* We do not want an active but invisible item! + * Only exception is when all items are filtered out... + */ + if (prev_ii >= 0) { + activei = prev_ii; + RNA_property_int_set(active_dataptr, activeprop, prev_i); + } + else { + activei = ii; + RNA_property_int_set(active_dataptr, activeprop, i); + } + } + prev_i = i; + prev_ii = ii; +#endif + } + i++; + } + RNA_PROP_END; + } + if (dyn_data->items_shown >= 0) { + len = dyn_data->items_shown; + } + else { + len = dyn_data->items_len; + } + } + switch (layout_type) { case UILST_LAYOUT_DEFAULT: - /* default rows */ - if (rows == 0) - rows = 5; - if (maxrows == 0) - maxrows = 5; - if (ui_list->list_grip_size != 0) - rows = ui_list->list_grip_size; - /* layout */ box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); - row = uiLayoutRow(box, FALSE); + glob = uiLayoutColumn(box, TRUE); + row = uiLayoutRow(glob, FALSE); col = uiLayoutColumn(row, TRUE); /* init numbers */ - RNA_property_int_range(active_dataptr, activeprop, &min, &max); - - if (prop) - len = RNA_property_collection_length(dataptr, prop); - items = CLAMPIS(len, rows, MAX2(rows, maxrows)); - - /* if list length changes and active is out of view, scroll to it */ - if ((ui_list->list_last_len != len) && - (activei < ui_list->list_scroll || activei >= ui_list->list_scroll + items)) - { - ui_list->list_scroll = activei; - } - - ui_list->list_scroll = min_ii(ui_list->list_scroll, len - items); - ui_list->list_scroll = max_ii(ui_list->list_scroll, 0); - ui_list->list_size = items; - ui_list->list_last_len = len; + prepare_list(ui_list, len, activei, rows, maxrows, 1, &layoutdata); if (dataptr->data && prop) { /* create list items */ - RNA_PROP_BEGIN (dataptr, itemptr, prop) - { - if (i >= ui_list->list_scroll && i < ui_list->list_scroll + items) { - subblock = uiLayoutGetBlock(col); - overlap = uiLayoutOverlap(col); + for (i = layoutdata.start_idx; i < layoutdata.end_idx; i++) { + PointerRNA *itemptr = &items_ptr[i].item; + int org_i = items_ptr[i].org_idx; + int flt_flag = items_ptr[i].flt_flag; + subblock = uiLayoutGetBlock(col); - uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM); + overlap = uiLayoutOverlap(col); + + uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM); - /* list item behind label & other buttons */ - sub = uiLayoutRow(overlap, FALSE); + /* list item behind label & other buttons */ + sub = uiLayoutRow(overlap, FALSE); - but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, - active_dataptr, activeprop, 0, 0, i, 0, 0, NULL); - uiButSetFlag(but, UI_BUT_NO_TOOLTIP); + but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, + active_dataptr, activeprop, 0, 0, org_i, 0, 0, NULL); + uiButSetFlag(but, UI_BUT_NO_TOOLTIP); - sub = uiLayoutRow(overlap, FALSE); + sub = uiLayoutRow(overlap, FALSE); - icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, false); - if (icon == ICON_DOT) - icon = ICON_NONE; - draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + icon = UI_rnaptr_icon_get(C, itemptr, rnaicon, false); + if (icon == ICON_DOT) + icon = ICON_NONE; + draw_item(ui_list, C, sub, dataptr, itemptr, icon, active_dataptr, active_propname, + org_i, flt_flag); - /* If we are "drawing" active item, set all labels as active. */ - if (i == activei) { - ui_layout_list_set_labels_active(sub); - } - uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM); + /* If we are "drawing" active item, set all labels as active. */ + if (i == activei) { + ui_layout_list_set_labels_active(sub); } - i++; + + uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM); } - RNA_PROP_END; } /* add dummy buttons to fill space */ - while (i < ui_list->list_scroll + items) { - if (i >= ui_list->list_scroll) - uiItemL(col, "", ICON_NONE); - i++; + for (; i < layoutdata.start_idx + layoutdata.visual_items; i++) { + uiItemL(col, "", ICON_NONE); } /* add scrollbar */ - if (len > items) { + if (len > layoutdata.visual_items) { col = uiLayoutColumn(row, FALSE); - uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &ui_list->list_scroll, - 0, len - items, items, 0, ""); + uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height, + &ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height, + dyn_data->visual_height, 0, ""); } break; case UILST_LAYOUT_COMPACT: row = uiLayoutRow(layout, TRUE); - if (dataptr->data && prop) { - /* create list items */ - RNA_PROP_BEGIN (dataptr, itemptr, prop) - { - found = (activei == i); - - if (found) { - icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, false); - if (icon == ICON_DOT) - icon = ICON_NONE; - draw_item(ui_list, C, row, dataptr, &itemptr, icon, active_dataptr, active_propname, i); - } + if (dataptr->data && prop && dyn_data->items_shown > 0) { + PointerRNA *itemptr = &items_ptr[activei].item; + int org_i = items_ptr[activei].org_idx; - i++; - } - RNA_PROP_END; + icon = UI_rnaptr_icon_get(C, itemptr, rnaicon, false); + if (icon == ICON_DOT) + icon = ICON_NONE; + draw_item(ui_list, C, row, dataptr, itemptr, icon, active_dataptr, active_propname, org_i, 0); } - /* if list is empty, add in dummy button */ - if (i == 0) + else { uiItemL(row, "", ICON_NONE); + } /* next/prev button */ - BLI_snprintf(numstr, sizeof(numstr), "%d :", i); + BLI_snprintf(numstr, sizeof(numstr), "%d :", dyn_data->items_shown); but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, active_dataptr, activeprop, 0, 0, 0, 0, 0, ""); - if (i == 0) + if (dyn_data->items_shown == 0) uiButSetFlag(but, UI_BUT_DISABLED); break; case UILST_LAYOUT_GRID: box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); - col = uiLayoutColumn(box, TRUE); - row = uiLayoutRow(col, FALSE); + glob = uiLayoutColumn(box, TRUE); + row = uiLayoutRow(glob, FALSE); + col = uiLayoutColumn(row, TRUE); + subrow = NULL; /* Quite gcc warning! */ + + prepare_list(ui_list, len, activei, rows, maxrows, columns, &layoutdata); if (dataptr->data && prop) { /* create list items */ - RNA_PROP_BEGIN (dataptr, itemptr, prop) - { + for (i = layoutdata.start_idx; i < layoutdata.end_idx; i++) { + PointerRNA *itemptr = &items_ptr[i].item; + int org_i = items_ptr[i].org_idx; + int flt_flag = items_ptr[i].flt_flag; + /* create button */ - if (!(i % 9)) - row = uiLayoutRow(col, FALSE); + if (!(i % columns)) + subrow = uiLayoutRow(col, FALSE); - subblock = uiLayoutGetBlock(row); - overlap = uiLayoutOverlap(row); + subblock = uiLayoutGetBlock(subrow); + overlap = uiLayoutOverlap(subrow); uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM); @@ -2736,13 +3022,14 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co sub = uiLayoutRow(overlap, FALSE); but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, - active_dataptr, activeprop, 0, 0, i, 0, 0, NULL); + active_dataptr, activeprop, 0, 0, org_i, 0, 0, NULL); uiButSetFlag(but, UI_BUT_NO_TOOLTIP); sub = uiLayoutRow(overlap, FALSE); - icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, false); - draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + icon = UI_rnaptr_icon_get(C, itemptr, rnaicon, false); + draw_item(ui_list, C, sub, dataptr, itemptr, icon, active_dataptr, active_propname, + org_i, flt_flag); /* If we are "drawing" active item, set all labels as active. */ if (i == activei) { @@ -2750,13 +3037,67 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co } uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM); + } + } - i++; + /* add dummy buttons to fill space */ + for (; i < layoutdata.start_idx + layoutdata.visual_items; i++) { + if (!(i % columns)) { + subrow = uiLayoutRow(col, FALSE); } - RNA_PROP_END; + uiItemL(subrow, "", ICON_NONE); + } + + /* add scrollbar */ + if (len > layoutdata.visual_items) { + col = uiLayoutColumn(row, FALSE); + uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height, + &ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height, + dyn_data->visual_height, 0, ""); } break; } + + if (glob) { + row = uiLayoutRow(glob, TRUE); + subblock = uiLayoutGetBlock(row); + uiBlockSetEmboss(subblock, UI_EMBOSSN); + + if (ui_list->filter_flag & UILST_FLT_SHOW) { + but = uiDefIconButBitI(subblock, TOG, UILST_FLT_SHOW, 0, ICON_DISCLOSURE_TRI_DOWN, 0, 0, + UI_UNIT_X, UI_UNIT_Y * 0.6f, &(ui_list->filter_flag), 0, 0, 0, 0, + TIP_("Hide filtering options")); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + but = uiDefIconBut(subblock, BUT, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10.0f, UI_UNIT_Y * 0.6f, ui_list, + 0.0, 0.0, 0, -1, ""); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + uiBlockSetEmboss(subblock, UI_EMBOSS); + + col = uiLayoutColumn(glob, FALSE); + subblock = uiLayoutGetBlock(col); + uiDefBut(subblock, SEPR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y * 0.05f, NULL, 0.0, 0.0, 0, 0, ""); + + draw_filter(ui_list, C, col); + } + else { + but = uiDefIconButBitI(subblock, TOG, UILST_FLT_SHOW, 0, ICON_DISCLOSURE_TRI_RIGHT, 0, 0, + UI_UNIT_X, UI_UNIT_Y * 0.6f, &(ui_list->filter_flag), 0, 0, 0, 0, + TIP_("Show filtering options")); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + but = uiDefIconBut(subblock, BUT, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10.0f, UI_UNIT_Y * 0.6f, ui_list, + 0.0, 0.0, 0, -1, ""); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + uiBlockSetEmboss(subblock, UI_EMBOSS); + } + } + + if (items_ptr) { + MEM_freeN(items_ptr); + } } /************************* Operator Search Template **************************/ @@ -2792,7 +3133,7 @@ static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char if (WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, true, &name[len + 1], sizeof(name) - len - 1)) { - name[len] = '|'; + name[len] = UI_SEP_CHAR; } } @@ -3003,7 +3344,7 @@ static void keymap_item_modified(bContext *UNUSED(C), void *kmi_p, void *UNUSED( static void template_keymap_item_properties(uiLayout *layout, const char *title, PointerRNA *ptr) { - uiLayout *flow; + uiLayout *flow, *box, *row; uiItemS(layout); @@ -3015,6 +3356,8 @@ static void template_keymap_item_properties(uiLayout *layout, const char *title, RNA_STRUCT_BEGIN (ptr, prop) { int flag = RNA_property_flag(prop); + bool is_set = RNA_property_is_set(ptr, prop); + uiBut *but; if (flag & PROP_HIDDEN) continue; @@ -3030,8 +3373,22 @@ static void template_keymap_item_properties(uiLayout *layout, const char *title, } } - /* add property */ - uiItemFullR(flow, ptr, prop, -1, 0, 0, NULL, ICON_NONE); + box = uiLayoutBox(flow); + uiLayoutSetActive(box, is_set); + row = uiLayoutRow(box, false); + + /* property value */ + uiItemFullR(row, ptr, prop, -1, 0, 0, NULL, ICON_NONE); + + if (is_set) { + /* unset operator */ + uiBlock *block = uiLayoutGetBlock(row); + uiBlockSetEmboss(block, UI_EMBOSSN); + but = uiDefIconButO(block, BUT, "UI_OT_unset_property_button", WM_OP_EXEC_DEFAULT, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL); + but->rnapoin = *ptr; + but->rnaprop = prop; + uiBlockSetEmboss(block, UI_EMBOSS); + } } RNA_STRUCT_END; } @@ -3047,8 +3404,12 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr) /* attach callbacks to compensate for missing properties update, * we don't know which keymap (item) is being modified there */ - for (; but; but = but->next) - uiButSetFunc(but, keymap_item_modified, ptr->data, NULL); + for (; but; but = but->next) { + /* operator buttons may store props for use (file selector, [#36492]) */ + if (but->rnaprop) { + uiButSetFunc(but, keymap_item_modified, ptr->data, NULL); + } + } } } @@ -3100,6 +3461,8 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), P uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE); uiItemR(col, &view_transform_ptr, "gamma", 0, NULL, ICON_NONE); + uiItemR(col, &view_transform_ptr, "look", 0, IFACE_("Look"), ICON_NONE); + col = uiLayoutColumn(layout, FALSE); uiItemR(col, &view_transform_ptr, "use_curve_mapping", 0, NULL, ICON_NONE); if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) |