diff options
author | Julian Eisel <julian@blender.org> | 2021-07-15 17:56:18 +0300 |
---|---|---|
committer | Julian Eisel <julian@blender.org> | 2021-07-15 20:09:49 +0300 |
commit | 9d9c879f4bdf05c92826023131e7eb2a57c06102 (patch) | |
tree | 6ab101d1c71bd7e78bb4d2a1364e5282e1debaae /source/blender/editors/interface/interface_templates.c | |
parent | 0cc2a72f94b71d5594a0aca088007ecbb3221b60 (diff) |
Cleanup: Move UI list template code to own file (C++)
This move was already prepared with 788d38046032 and 26b098c04fbe. The
template is quite big already, better to give it its own file. Plus it
could use some C++ features like RAII and maybe some more object
oriented code. I plan further refactoring there.
Diffstat (limited to 'source/blender/editors/interface/interface_templates.c')
-rw-r--r-- | source/blender/editors/interface/interface_templates.c | 1255 |
1 files changed, 0 insertions, 1255 deletions
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 548852b407e..766840909cc 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -5645,1261 +5645,6 @@ void uiTemplateLayers(uiLayout *layout, /** \} */ /* -------------------------------------------------------------------- */ -/** \name List Template - * \{ */ - -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(flt_flag)) -{ - PropertyRNA *nameprop = RNA_struct_name_property(itemptr->type); - - /* Simplest one! */ - switch (ui_list->layout_type) { - case UILST_LAYOUT_GRID: - uiItemL(layout, "", icon); - break; - case UILST_LAYOUT_DEFAULT: - case UILST_LAYOUT_COMPACT: - default: - if (nameprop) { - uiItemFullR(layout, itemptr, nameprop, RNA_NO_INDEX, 0, UI_ITEM_R_NO_BG, "", icon); - } - else { - uiItemL(layout, "", icon); - } - break; - } -} - -static void uilist_draw_filter_default(struct uiList *ui_list, - struct bContext *UNUSED(C), - struct uiLayout *layout) -{ - PointerRNA listptr; - RNA_pointer_create(NULL, &RNA_UIList, ui_list, &listptr); - - uiLayout *row = uiLayoutRow(layout, false); - - uiLayout *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, - "", - ICON_ARROW_LEFTRIGHT); - - if ((ui_list->filter_sort_flag & UILST_FLT_SORT_LOCK) == 0) { - 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_SORT_DESC : ICON_SORT_ASC); - } -} - -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; - const bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0; - const bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_MASK) == - UILST_FLT_SORT_ALPHA; - const 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, "StringCmp"); - } - if (filter_raw[0]) { - const size_t slen = strlen(filter_raw); - - dyn_data->items_filter_flags = MEM_callocN(sizeof(int) * len, "items_filter_flags"); - dyn_data->items_shown = 0; - - /* Implicitly add heading/trailing wildcards if needed. */ - if (slen + 3 <= sizeof(filter_buff)) { - filter = filter_buff; - } - else { - filter = filter_dyn = MEM_mallocN((slen + 3) * sizeof(char), "filter_dyn"); - } - BLI_strncpy_ensure_pad(filter, filter_raw, '*', slen + 3); - } - - RNA_PROP_BEGIN (dataptr, itemptr, prop) { - bool do_order = false; - - char *namebuf = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); - const char *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, - "items_filter_neworder"); - 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); - } - } -} - -static void uilist_free_dyn_data(uiList *ui_list) -{ - uiListDyn *dyn_data = ui_list->dyn_data; - if (!dyn_data) { - return; - } - - if (dyn_data->custom_activate_opptr) { - WM_operator_properties_free(dyn_data->custom_activate_opptr); - MEM_freeN(dyn_data->custom_activate_opptr); - } - if (dyn_data->custom_drag_opptr) { - WM_operator_properties_free(dyn_data->custom_drag_opptr); - MEM_freeN(dyn_data->custom_drag_opptr); - } - - MEM_SAFE_FREE(dyn_data->items_filter_flags); - MEM_SAFE_FREE(dyn_data->items_filter_neworder); - MEM_SAFE_FREE(dyn_data->customdata); -} - -/** - * The validated data that was passed to #uiTemplateList (typically through Python). - * Populated through #ui_template_list_data_retrieve(). - */ -typedef struct { - PointerRNA dataptr; - PropertyRNA *prop; - PointerRNA active_dataptr; - PropertyRNA *activeprop; - const char *item_dyntip_propname; - - /* Index as stored in the input property. I.e. the index before sorting. */ - int active_item_idx; -} TemplateListInputData; - -/** - * Internal wrapper for a single item in the list (well, actually stored as a vector). - */ -typedef struct { - PointerRNA item; - int org_idx; - int flt_flag; -} _uilist_item; - -/** - * Container for the item vector and additional info. - */ -typedef struct { - _uilist_item *item_vec; - /* Index of the active item following visual order. I.e. unlike - * TemplateListInputData.active_item_idx, this is the index after sorting. */ - int active_item_idx; - int tot_items; -} TemplateListItems; - -typedef struct { - uiListDrawItemFunc draw_item; - uiListDrawFilterFunc draw_filter; - - int rows; - int maxrows; - int columns; -} TemplateListLayoutDrawData; - -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. */ -} TemplateListVisualInfo; - -/** - * Validate input parameters and initialize \a r_data from that. Plus find the list-type and return - * it in \a r_list_type. - * - * \return false if the input data isn't valid. Will also raise an RNA warning in that case. - */ -static bool ui_template_list_data_retrieve(const char *listtype_name, - const char *list_id, - PointerRNA *dataptr, - const char *propname, - PointerRNA *active_dataptr, - const char *active_propname, - const char *item_dyntip_propname, - TemplateListInputData *r_input_data, - uiListType **r_list_type) -{ - memset(r_input_data, 0, sizeof(*r_input_data)); - - /* Forbid default UI_UL_DEFAULT_CLASS_NAME list class without a custom list_id! */ - if (STREQ(UI_UL_DEFAULT_CLASS_NAME, listtype_name) && !(list_id && list_id[0])) { - RNA_warning("template_list using default '%s' UIList class must provide a custom list_id", - UI_UL_DEFAULT_CLASS_NAME); - return false; - } - - if (!active_dataptr->data) { - RNA_warning("No active data"); - return false; - } - - r_input_data->dataptr = *dataptr; - if (dataptr->data) { - r_input_data->prop = RNA_struct_find_property(dataptr, propname); - if (!r_input_data->prop) { - RNA_warning("Property not found: %s.%s", RNA_struct_identifier(dataptr->type), propname); - return false; - } - } - - r_input_data->active_dataptr = *active_dataptr; - r_input_data->activeprop = RNA_struct_find_property(active_dataptr, active_propname); - if (!r_input_data->activeprop) { - RNA_warning( - "Property not found: %s.%s", RNA_struct_identifier(active_dataptr->type), active_propname); - return false; - } - - if (r_input_data->prop) { - const PropertyType type = RNA_property_type(r_input_data->prop); - if (type != PROP_COLLECTION) { - RNA_warning("Expected a collection data property"); - return false; - } - } - - const PropertyType activetype = RNA_property_type(r_input_data->activeprop); - if (activetype != PROP_INT) { - RNA_warning("Expected an integer active data property"); - return false; - } - - /* Find the uiList type. */ - if (!(*r_list_type = WM_uilisttype_find(listtype_name, false))) { - RNA_warning("List type %s not found", listtype_name); - return false; - } - - r_input_data->active_item_idx = RNA_property_int_get(&r_input_data->active_dataptr, - r_input_data->activeprop); - r_input_data->item_dyntip_propname = item_dyntip_propname; - - return true; -} - -static void ui_template_list_collect_items(PointerRNA *list_ptr, - PropertyRNA *list_prop, - uiListDyn *dyn_data, - int filter_exclude, - bool order_reverse, - int activei, - TemplateListItems *r_items) -{ - int i = 0; - int reorder_i = 0; - bool activei_mapping_pending = true; - - RNA_PROP_BEGIN (list_ptr, itemptr, list_prop) { - if (!dyn_data->items_filter_flags || - ((dyn_data->items_filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude)) { - int new_order_idx; - if (dyn_data->items_filter_neworder) { - new_order_idx = dyn_data->items_filter_neworder[reorder_i++]; - new_order_idx = order_reverse ? dyn_data->items_shown - new_order_idx - 1 : new_order_idx; - } - else { - new_order_idx = order_reverse ? dyn_data->items_shown - ++reorder_i : reorder_i++; - } - // printf("%s: ii: %d\n", __func__, ii); - r_items->item_vec[new_order_idx].item = itemptr; - r_items->item_vec[new_order_idx].org_idx = i; - r_items->item_vec[new_order_idx].flt_flag = dyn_data->items_filter_flags ? - dyn_data->items_filter_flags[i] : - 0; - - if (activei_mapping_pending && activei == i) { - activei = new_order_idx; - /* So that we do not map again activei! */ - activei_mapping_pending = false; - } -#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_order_idx >= 0) { - activei = prev_order_idx; - RNA_property_int_set(active_dataptr, activeprop, prev_i); - } - else { - activei = new_order_idx; - RNA_property_int_set(active_dataptr, activeprop, i); - } - } - prev_i = i; - prev_ii = new_order_idx; -#endif - } - i++; - } - RNA_PROP_END; - - /* If mapping is still pending, no active item was found. Mark as invalid (-1) */ - r_items->active_item_idx = activei_mapping_pending ? -1 : activei; -} - -/** - * Create the UI-list representation of the list items, sorted and filtered if needed. - */ -static void ui_template_list_collect_display_items(bContext *C, - uiList *ui_list, - TemplateListInputData *input_data, - const uiListFilterItemsFunc filter_items_fn, - TemplateListItems *r_items) -{ - uiListDyn *dyn_data = ui_list->dyn_data; - memset(r_items, 0, sizeof(*r_items)); - - /* Filter list items! (not for compact layout, though) */ - if (input_data->dataptr.data && input_data->prop) { - const int filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE; - const bool order_reverse = (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) != 0; - int items_shown; -#if 0 - int prev_ii = -1, prev_i; -#endif - - if (ui_list->layout_type == UILST_LAYOUT_COMPACT) { - dyn_data->items_len = dyn_data->items_shown = RNA_property_collection_length( - &input_data->dataptr, input_data->prop); - } - else { - // printf("%s: filtering...\n", __func__); - filter_items_fn(ui_list, C, &input_data->dataptr, RNA_property_identifier(input_data->prop)); - // printf("%s: filtering done.\n", __func__); - } - - items_shown = dyn_data->items_shown; - if (items_shown >= 0) { - r_items->item_vec = MEM_mallocN(sizeof(*r_items->item_vec) * items_shown, __func__); - // printf("%s: items shown: %d.\n", __func__, items_shown); - - ui_template_list_collect_items(&input_data->dataptr, - input_data->prop, - dyn_data, - filter_exclude, - order_reverse, - input_data->active_item_idx, - r_items); - } - if (dyn_data->items_shown >= 0) { - r_items->tot_items = dyn_data->items_shown; - } - else { - r_items->tot_items = dyn_data->items_len; - } - } -} - -static void ui_template_list_free_items(TemplateListItems *items) -{ - if (items->item_vec) { - MEM_freeN(items->item_vec); - } -} - -static void uilist_prepare(uiList *ui_list, - const TemplateListItems *items, - const TemplateListLayoutDrawData *layout_data, - TemplateListVisualInfo *r_visual_info) -{ - uiListDyn *dyn_data = ui_list->dyn_data; - const bool use_auto_size = (ui_list->list_grip < - (layout_data->rows - UI_LIST_AUTO_SIZE_THRESHOLD)); - - int actual_rows = layout_data->rows; - int actual_maxrows = layout_data->maxrows; - int columns = layout_data->columns; - - /* default rows */ - if (actual_rows <= 0) { - actual_rows = 5; - } - dyn_data->visual_height_min = actual_rows; - if (actual_maxrows < actual_rows) { - actual_maxrows = max_ii(actual_rows, 5); - } - if (columns <= 0) { - columns = 9; - } - - int activei_row; - if (columns > 1) { - dyn_data->height = (int)ceil((double)items->tot_items / (double)columns); - activei_row = (int)floor((double)items->active_item_idx / (double)columns); - } - else { - dyn_data->height = items->tot_items; - activei_row = items->active_item_idx; - } - - dyn_data->columns = columns; - - if (!use_auto_size) { - /* No auto-size, yet we clamp at min size! */ - actual_rows = max_ii(ui_list->list_grip, actual_rows); - } - else if ((actual_rows != actual_maxrows) && (dyn_data->height > actual_rows)) { - /* Expand size if needed and possible. */ - actual_rows = min_ii(dyn_data->height, actual_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 != items->tot_items) || - (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 + actual_rows) { - ui_list->list_scroll = activei_row - actual_rows + 1; - } - ui_list->flag &= ~UILST_SCROLL_TO_ACTIVE_ITEM; - } - - const int max_scroll = max_ii(0, dyn_data->height - actual_rows); - CLAMP(ui_list->list_scroll, 0, max_scroll); - ui_list->list_last_len = items->tot_items; - dyn_data->visual_height = actual_rows; - r_visual_info->visual_items = actual_rows * columns; - r_visual_info->start_idx = ui_list->list_scroll * columns; - r_visual_info->end_idx = min_ii(r_visual_info->start_idx + actual_rows * columns, - items->tot_items); -} - -static void uilist_resize_update_cb(bContext *C, void *arg1, void *UNUSED(arg2)) -{ - uiList *ui_list = arg1; - uiListDyn *dyn_data = ui_list->dyn_data; - - /* This way we get diff in number of additional items to show (positive) or hide (negative). */ - const int diff = round_fl_to_int((float)(dyn_data->resize - dyn_data->resize_prev) / - (float)UI_UNIT_Y); - - if (diff != 0) { - ui_list->list_grip += diff; - dyn_data->resize_prev += diff * UI_UNIT_Y; - ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; - } - - /* In case uilist is in popup, we need special refreshing */ - ED_region_tag_refresh_ui(CTX_wm_menu(C)); -} - -static void *uilist_item_use_dynamic_tooltip(PointerRNA *itemptr, const char *propname) -{ - if (propname && propname[0] && itemptr && itemptr->data) { - PropertyRNA *prop = RNA_struct_find_property(itemptr, propname); - - if (prop && (RNA_property_type(prop) == PROP_STRING)) { - return RNA_property_string_get_alloc(itemptr, prop, NULL, 0, NULL); - } - } - return NULL; -} - -static char *uilist_item_tooltip_func(bContext *UNUSED(C), void *argN, const char *tip) -{ - char *dyn_tooltip = argN; - return BLI_sprintfN("%s - %s", tip, dyn_tooltip); -} - -/** - * \note Note that \a layout_type may be NULL. - */ -static uiList *ui_list_ensure(bContext *C, - uiListType *ui_list_type, - const char *list_id, - int layout_type, - bool sort_reverse, - bool sort_lock) -{ - /* Allows to work in popups. */ - ARegion *region = CTX_wm_menu(C); - if (region == NULL) { - region = CTX_wm_region(C); - } - - /* Find or add the uiList to the current Region. */ - - char full_list_id[UI_MAX_NAME_STR]; - WM_uilisttype_to_full_list_id(ui_list_type, list_id, full_list_id); - - uiList *ui_list = BLI_findstring(®ion->ui_lists, full_list_id, offsetof(uiList, list_id)); - - if (!ui_list) { - ui_list = MEM_callocN(sizeof(uiList), "uiList"); - BLI_strncpy(ui_list->list_id, full_list_id, sizeof(ui_list->list_id)); - BLI_addtail(®ion->ui_lists, ui_list); - ui_list->list_grip = -UI_LIST_AUTO_SIZE_THRESHOLD; /* Force auto size by default. */ - if (sort_reverse) { - ui_list->filter_sort_flag |= UILST_FLT_SORT_REVERSE; - } - if (sort_lock) { - ui_list->filter_sort_flag |= UILST_FLT_SORT_LOCK; - } - } - - if (!ui_list->dyn_data) { - ui_list->dyn_data = MEM_callocN(sizeof(uiListDyn), "uiList.dyn_data"); - } - uiListDyn *dyn_data = ui_list->dyn_data; - /* Note that this isn't a `uiListType` callback, it's stored in the runtime list data. Otherwise - * the runtime data could leak when the type is unregistered (e.g. on "Reload Scripts"). */ - dyn_data->free_runtime_data_fn = uilist_free_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. */ - MEM_SAFE_FREE(dyn_data->items_filter_flags); - MEM_SAFE_FREE(dyn_data->items_filter_neworder); - dyn_data->items_len = dyn_data->items_shown = -1; - - return ui_list; -} - -static void ui_template_list_layout_draw(bContext *C, - uiList *ui_list, - uiLayout *layout, - TemplateListInputData *input_data, - TemplateListItems *items, - const TemplateListLayoutDrawData *layout_data, - const enum uiTemplateListFlags flags) -{ - uiListDyn *dyn_data = ui_list->dyn_data; - const char *active_propname = RNA_property_identifier(input_data->activeprop); - - uiLayout *glob = NULL, *box, *row, *col, *subrow, *sub, *overlap; - char numstr[32]; - int rnaicon = ICON_NONE, icon = ICON_NONE; - uiBut *but; - - uiBlock *block = uiLayoutGetBlock(layout); - - /* get icon */ - if (input_data->dataptr.data && input_data->prop) { - StructRNA *ptype = RNA_property_pointer_type(&input_data->dataptr, input_data->prop); - rnaicon = RNA_struct_ui_icon(ptype); - } - - TemplateListVisualInfo visual_info; - switch (ui_list->layout_type) { - case UILST_LAYOUT_DEFAULT: { - /* layout */ - box = uiLayoutListBox(layout, ui_list, &input_data->active_dataptr, input_data->activeprop); - glob = uiLayoutColumn(box, true); - row = uiLayoutRow(glob, false); - col = uiLayoutColumn(row, true); - - TemplateListLayoutDrawData adjusted_layout_data = *layout_data; - adjusted_layout_data.columns = 1; - /* init numbers */ - uilist_prepare(ui_list, items, &adjusted_layout_data, &visual_info); - - int i = 0; - if (input_data->dataptr.data && input_data->prop) { - /* create list items */ - for (i = visual_info.start_idx; i < visual_info.end_idx; i++) { - PointerRNA *itemptr = &items->item_vec[i].item; - void *dyntip_data; - const int org_i = items->item_vec[i].org_idx; - const int flt_flag = items->item_vec[i].flt_flag; - uiBlock *subblock = uiLayoutGetBlock(col); - - overlap = uiLayoutOverlap(col); - - UI_block_flag_enable(subblock, UI_BLOCK_LIST_ITEM); - - /* list item behind label & other buttons */ - uiLayoutRow(overlap, false); - - but = uiDefButR_prop(subblock, - UI_BTYPE_LISTROW, - 0, - "", - 0, - 0, - UI_UNIT_X * 10, - UI_UNIT_Y, - &input_data->active_dataptr, - input_data->activeprop, - 0, - 0, - org_i, - 0, - 0, - TIP_("Double click to rename")); - if ((dyntip_data = uilist_item_use_dynamic_tooltip(itemptr, - input_data->item_dyntip_propname))) { - UI_but_func_tooltip_set(but, uilist_item_tooltip_func, dyntip_data, MEM_freeN); - } - - sub = uiLayoutRow(overlap, false); - - icon = UI_icon_from_rnaptr(C, itemptr, rnaicon, false); - if (icon == ICON_DOT) { - icon = ICON_NONE; - } - layout_data->draw_item(ui_list, - C, - sub, - &input_data->dataptr, - itemptr, - icon, - &input_data->active_dataptr, - active_propname, - org_i, - flt_flag); - - /* Items should be able to set context pointers for the layout. But the list-row button - * swallows events, so it needs the context storage too for handlers to see it. */ - but->context = uiLayoutGetContextStore(sub); - - /* If we are "drawing" active item, set all labels as active. */ - if (i == items->active_item_idx) { - ui_layout_list_set_labels_active(sub); - } - - UI_block_flag_disable(subblock, UI_BLOCK_LIST_ITEM); - } - } - - /* add dummy buttons to fill space */ - for (; i < visual_info.start_idx + visual_info.visual_items; i++) { - uiItemL(col, "", ICON_NONE); - } - - /* add scrollbar */ - if (items->tot_items > visual_info.visual_items) { - uiLayoutColumn(row, false); - uiDefButI(block, - UI_BTYPE_SCROLL, - 0, - "", - 0, - 0, - V2D_SCROLL_WIDTH, - 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 ((input_data->dataptr.data && input_data->prop) && (dyn_data->items_shown > 0) && - (items->active_item_idx >= 0) && (items->active_item_idx < dyn_data->items_shown)) { - PointerRNA *itemptr = &items->item_vec[items->active_item_idx].item; - const int org_i = items->item_vec[items->active_item_idx].org_idx; - - icon = UI_icon_from_rnaptr(C, itemptr, rnaicon, false); - if (icon == ICON_DOT) { - icon = ICON_NONE; - } - layout_data->draw_item(ui_list, - C, - row, - &input_data->dataptr, - itemptr, - icon, - &input_data->active_dataptr, - active_propname, - org_i, - 0); - } - /* if list is empty, add in dummy button */ - else { - uiItemL(row, "", ICON_NONE); - } - - /* next/prev button */ - BLI_snprintf(numstr, sizeof(numstr), "%d :", dyn_data->items_shown); - but = uiDefIconTextButR_prop(block, - UI_BTYPE_NUM, - 0, - 0, - numstr, - 0, - 0, - UI_UNIT_X * 5, - UI_UNIT_Y, - &input_data->active_dataptr, - input_data->activeprop, - 0, - 0, - 0, - 0, - 0, - ""); - if (dyn_data->items_shown == 0) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - break; - case UILST_LAYOUT_GRID: { - box = uiLayoutListBox(layout, ui_list, &input_data->active_dataptr, input_data->activeprop); - glob = uiLayoutColumn(box, true); - row = uiLayoutRow(glob, false); - col = uiLayoutColumn(row, true); - subrow = NULL; /* Quite gcc warning! */ - - uilist_prepare(ui_list, items, layout_data, &visual_info); - - int i = 0; - if (input_data->dataptr.data && input_data->prop) { - /* create list items */ - for (i = visual_info.start_idx; i < visual_info.end_idx; i++) { - PointerRNA *itemptr = &items->item_vec[i].item; - const int org_i = items->item_vec[i].org_idx; - const int flt_flag = items->item_vec[i].flt_flag; - - /* create button */ - if (!(i % layout_data->columns)) { - subrow = uiLayoutRow(col, false); - } - - uiBlock *subblock = uiLayoutGetBlock(subrow); - overlap = uiLayoutOverlap(subrow); - - UI_block_flag_enable(subblock, UI_BLOCK_LIST_ITEM); - - /* list item behind label & other buttons */ - uiLayoutRow(overlap, false); - - but = uiDefButR_prop(subblock, - UI_BTYPE_LISTROW, - 0, - "", - 0, - 0, - UI_UNIT_X * 10, - UI_UNIT_Y, - &input_data->active_dataptr, - input_data->activeprop, - 0, - 0, - org_i, - 0, - 0, - NULL); - UI_but_drawflag_enable(but, UI_BUT_NO_TOOLTIP); - - sub = uiLayoutRow(overlap, false); - - icon = UI_icon_from_rnaptr(C, itemptr, rnaicon, false); - layout_data->draw_item(ui_list, - C, - sub, - &input_data->dataptr, - itemptr, - icon, - &input_data->active_dataptr, - active_propname, - org_i, - flt_flag); - - /* If we are "drawing" active item, set all labels as active. */ - if (i == items->active_item_idx) { - ui_layout_list_set_labels_active(sub); - } - - UI_block_flag_disable(subblock, UI_BLOCK_LIST_ITEM); - } - } - - /* add dummy buttons to fill space */ - for (; i < visual_info.start_idx + visual_info.visual_items; i++) { - if (!(i % layout_data->columns)) { - subrow = uiLayoutRow(col, false); - } - uiItemL(subrow, "", ICON_NONE); - } - - /* add scrollbar */ - if (items->tot_items > visual_info.visual_items) { - /* col = */ uiLayoutColumn(row, false); - uiDefButI(block, - UI_BTYPE_SCROLL, - 0, - "", - 0, - 0, - V2D_SCROLL_WIDTH, - 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_BIG_PREVIEW_GRID: - box = uiLayoutListBox(layout, ui_list, &input_data->active_dataptr, input_data->activeprop); - /* For grip button. */ - glob = uiLayoutColumn(box, true); - /* For scrollbar. */ - row = uiLayoutRow(glob, false); - - /* TODO ED_fileselect_init_layout(). Share somehow? */ - float size_x = (96.0f / 20.0f) * UI_UNIT_X; - float size_y = (96.0f / 20.0f) * UI_UNIT_Y; - - const int cols_per_row = MAX2((uiLayoutGetWidth(box) - V2D_SCROLL_WIDTH) / size_x, 1); - uiLayout *grid = uiLayoutGridFlow(row, true, cols_per_row, true, true, true); - - TemplateListLayoutDrawData adjusted_layout_data = *layout_data; - adjusted_layout_data.columns = cols_per_row; - uilist_prepare(ui_list, items, &adjusted_layout_data, &visual_info); - - if (input_data->dataptr.data && input_data->prop) { - /* create list items */ - for (int i = visual_info.start_idx; i < visual_info.end_idx; i++) { - PointerRNA *itemptr = &items->item_vec[i].item; - const int org_i = items->item_vec[i].org_idx; - const int flt_flag = items->item_vec[i].flt_flag; - - overlap = uiLayoutOverlap(grid); - col = uiLayoutColumn(overlap, false); - - uiBlock *subblock = uiLayoutGetBlock(col); - UI_block_flag_enable(subblock, UI_BLOCK_LIST_ITEM); - - but = uiDefButR_prop(subblock, - UI_BTYPE_LISTROW, - 0, - "", - 0, - 0, - size_x, - size_y, - &input_data->active_dataptr, - input_data->activeprop, - 0, - 0, - org_i, - 0, - 0, - NULL); - UI_but_drawflag_enable(but, UI_BUT_NO_TOOLTIP); - - col = uiLayoutColumn(overlap, false); - - icon = UI_icon_from_rnaptr(C, itemptr, rnaicon, false); - layout_data->draw_item(ui_list, - C, - col, - &input_data->dataptr, - itemptr, - icon, - &input_data->active_dataptr, - active_propname, - org_i, - flt_flag); - - /* Items should be able to set context pointers for the layout. But the list-row button - * swallows events, so it needs the context storage too for handlers to see it. */ - but->context = uiLayoutGetContextStore(col); - - /* If we are "drawing" active item, set all labels as active. */ - if (i == items->active_item_idx) { - ui_layout_list_set_labels_active(col); - } - - UI_block_flag_disable(subblock, UI_BLOCK_LIST_ITEM); - } - } - - if (items->tot_items > visual_info.visual_items) { - /* col = */ uiLayoutColumn(row, false); - uiDefButI(block, - UI_BTYPE_SCROLL, - 0, - "", - 0, - 0, - V2D_SCROLL_WIDTH, - size_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) { - const bool add_grip_but = (flags & UI_TEMPLATE_LIST_NO_GRIP) == 0; - - /* About #UI_BTYPE_GRIP drag-resize: - * We can't directly use results from a grip button, since we have a - * rather complex behavior here (sizing by discrete steps and, overall, auto-size feature). - * Since we *never* know whether we are grip-resizing or not - * (because there is no callback for when a button enters/leaves its "edit mode"), - * we use the fact that grip-controlled value (dyn_data->resize) is completely handled - * by the grip during the grab resize, so settings its value here has no effect at all. - * - * It is only meaningful when we are not resizing, - * in which case this gives us the correct "init drag" value. - * Note we cannot affect `dyn_data->resize_prev here`, - * since this value is not controlled by the grip! - */ - dyn_data->resize = dyn_data->resize_prev + - (dyn_data->visual_height - ui_list->list_grip) * UI_UNIT_Y; - - row = uiLayoutRow(glob, true); - uiBlock *subblock = uiLayoutGetBlock(row); - UI_block_emboss_set(subblock, UI_EMBOSS_NONE); - - if (ui_list->filter_flag & UILST_FLT_SHOW) { - but = uiDefIconButBitI(subblock, - UI_BTYPE_TOGGLE, - UILST_FLT_SHOW, - 0, - ICON_DISCLOSURE_TRI_DOWN, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y * 0.5f, - &(ui_list->filter_flag), - 0, - 0, - 0, - 0, - TIP_("Hide filtering options")); - UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */ - - if (add_grip_but) { - but = uiDefIconButI(subblock, - UI_BTYPE_GRIP, - 0, - ICON_GRIP, - 0, - 0, - UI_UNIT_X * 10.0f, - UI_UNIT_Y * 0.5f, - &dyn_data->resize, - 0.0, - 0.0, - 0, - 0, - ""); - UI_but_func_set(but, uilist_resize_update_cb, ui_list, NULL); - } - - UI_block_emboss_set(subblock, UI_EMBOSS); - - col = uiLayoutColumn(glob, false); - subblock = uiLayoutGetBlock(col); - uiDefBut(subblock, - UI_BTYPE_SEPR, - 0, - "", - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y * 0.05f, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - - layout_data->draw_filter(ui_list, C, col); - } - else { - but = uiDefIconButBitI(subblock, - UI_BTYPE_TOGGLE, - UILST_FLT_SHOW, - 0, - ICON_DISCLOSURE_TRI_RIGHT, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y * 0.5f, - &(ui_list->filter_flag), - 0, - 0, - 0, - 0, - TIP_("Show filtering options")); - UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */ - - if (add_grip_but) { - but = uiDefIconButI(subblock, - UI_BTYPE_GRIP, - 0, - ICON_GRIP, - 0, - 0, - UI_UNIT_X * 10.0f, - UI_UNIT_Y * 0.5f, - &dyn_data->resize, - 0.0, - 0.0, - 0, - 0, - ""); - UI_but_func_set(but, uilist_resize_update_cb, ui_list, NULL); - } - - UI_block_emboss_set(subblock, UI_EMBOSS); - } - } -} - -uiList *uiTemplateList_ex(uiLayout *layout, - bContext *C, - const char *listtype_name, - const char *list_id, - PointerRNA *dataptr, - const char *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, - void *customdata) -{ - TemplateListInputData input_data = {0}; - uiListType *ui_list_type; - if (!ui_template_list_data_retrieve(listtype_name, - list_id, - dataptr, - propname, - active_dataptr, - active_propname, - item_dyntip_propname, - &input_data, - &ui_list_type)) { - return NULL; - } - - uiListDrawItemFunc draw_item = ui_list_type->draw_item ? ui_list_type->draw_item : - uilist_draw_item_default; - uiListDrawFilterFunc draw_filter = ui_list_type->draw_filter ? ui_list_type->draw_filter : - uilist_draw_filter_default; - uiListFilterItemsFunc filter_items = ui_list_type->filter_items ? ui_list_type->filter_items : - uilist_filter_items_default; - - uiList *ui_list = ui_list_ensure(C, - ui_list_type, - list_id, - layout_type, - flags & UI_TEMPLATE_LIST_SORT_REVERSE, - flags & UI_TEMPLATE_LIST_SORT_LOCK); - uiListDyn *dyn_data = ui_list->dyn_data; - - MEM_SAFE_FREE(dyn_data->customdata); - dyn_data->customdata = customdata; - - /* When active item changed since last draw, scroll to it. */ - if (input_data.active_item_idx != ui_list->list_last_activei) { - ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; - ui_list->list_last_activei = input_data.active_item_idx; - } - - TemplateListItems items; - ui_template_list_collect_display_items(C, ui_list, &input_data, filter_items, &items); - - TemplateListLayoutDrawData layout_data = { - .draw_item = draw_item, - .draw_filter = draw_filter, - .rows = rows, - .maxrows = maxrows, - .columns = columns, - }; - - ui_template_list_layout_draw(C, ui_list, layout, &input_data, &items, &layout_data, flags); - - ui_template_list_free_items(&items); - - return ui_list; -} - -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, - const char *item_dyntip_propname, - int rows, - int maxrows, - int layout_type, - int columns, - enum uiTemplateListFlags flags) -{ - uiTemplateList_ex(layout, - C, - listtype_name, - list_id, - dataptr, - propname, - active_dataptr, - active_propname, - item_dyntip_propname, - rows, - maxrows, - layout_type, - columns, - flags, - NULL); -} - -/** - * \return: A RNA pointer for the operator properties. - */ -PointerRNA *UI_list_custom_activate_operator_set(uiList *ui_list, - const char *opname, - bool create_properties) -{ - uiListDyn *dyn_data = ui_list->dyn_data; - dyn_data->custom_activate_optype = WM_operatortype_find(opname, false); - if (!dyn_data->custom_activate_optype) { - return NULL; - } - - if (create_properties) { - WM_operator_properties_alloc(&dyn_data->custom_activate_opptr, NULL, opname); - } - - return dyn_data->custom_activate_opptr; -} - -/** - * \return: A RNA pointer for the operator properties. - */ -PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list, - const char *opname, - bool create_properties) -{ - uiListDyn *dyn_data = ui_list->dyn_data; - dyn_data->custom_drag_optype = WM_operatortype_find(opname, false); - if (!dyn_data->custom_drag_optype) { - return NULL; - } - - if (create_properties) { - WM_operator_properties_alloc(&dyn_data->custom_drag_opptr, NULL, opname); - } - - return dyn_data->custom_drag_opptr; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Running Jobs Template * \{ */ |