Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/interface/interface_layout.c
| Show First 20 Lines • Show All 1,458 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout) | BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout) | ||||
| { | { | ||||
| return (layout->item.type == ITEM_LAYOUT_RADIAL) || | return (layout->item.type == ITEM_LAYOUT_RADIAL) || | ||||
| ((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU)); | ((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU)); | ||||
| } | } | ||||
| /** | |||||
| * Create UI items for enum items in \a item_array. | |||||
| * | |||||
| * A version of #uiItemsFullEnumO that takes pre-calculated item array. | |||||
| */ | |||||
| void uiItemsFullEnumO_items(uiLayout *layout, | void uiItemsFullEnumO_items(uiLayout *layout, | ||||
| wmOperatorType *ot, | wmOperatorType *ot, | ||||
| PointerRNA ptr, | PointerRNA ptr, | ||||
| PropertyRNA *prop, | PropertyRNA *prop, | ||||
| IDProperty *properties, | IDProperty *properties, | ||||
| wmOperatorCallContext context, | wmOperatorCallContext context, | ||||
| int flag, | int flag, | ||||
| const EnumPropertyItem *item_array, | const EnumPropertyItem *item_array, | ||||
| ▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | #endif | ||||
| } | } | ||||
| } | } | ||||
| void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname) | void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname) | ||||
| { | { | ||||
| uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0); | uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0); | ||||
| } | } | ||||
| /* for use in cases where we have */ | |||||
| void uiItemEnumO_value(uiLayout *layout, | void uiItemEnumO_value(uiLayout *layout, | ||||
| const char *name, | const char *name, | ||||
| int icon, | int icon, | ||||
| const char *opname, | const char *opname, | ||||
| const char *propname, | const char *propname, | ||||
| int value) | int value) | ||||
| { | { | ||||
| wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ | wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ | ||||
| ▲ Show 20 Lines • Show All 758 Lines • ▼ Show 20 Lines | if (!prop) { | ||||
| ui_item_disabled(layout, propname); | ui_item_disabled(layout, propname); | ||||
| RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); | RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); | ||||
| return; | return; | ||||
| } | } | ||||
| uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon); | uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon); | ||||
| } | } | ||||
| /** | |||||
| * Use a wrapper function since re-implementing all the logic in this function would be messy. | |||||
| */ | |||||
| void uiItemFullR_with_popover(uiLayout *layout, | void uiItemFullR_with_popover(uiLayout *layout, | ||||
| PointerRNA *ptr, | PointerRNA *ptr, | ||||
| PropertyRNA *prop, | PropertyRNA *prop, | ||||
| int index, | int index, | ||||
| int value, | int value, | ||||
| int flag, | int flag, | ||||
| const char *name, | const char *name, | ||||
| int icon, | int icon, | ||||
| ▲ Show 20 Lines • Show All 237 Lines • ▼ Show 20 Lines | |||||
| static void ui_rna_collection_search_arg_free_fn(void *ptr) | static void ui_rna_collection_search_arg_free_fn(void *ptr) | ||||
| { | { | ||||
| uiRNACollectionSearch *coll_search = ptr; | uiRNACollectionSearch *coll_search = ptr; | ||||
| UI_butstore_free(coll_search->butstore_block, coll_search->butstore); | UI_butstore_free(coll_search->butstore_block, coll_search->butstore); | ||||
| MEM_freeN(ptr); | MEM_freeN(ptr); | ||||
| } | } | ||||
| /** | |||||
| * \note May reallocate \a but, so the possibly new address is returned. | |||||
| */ | |||||
| uiBut *ui_but_add_search( | uiBut *ui_but_add_search( | ||||
| uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop) | uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop) | ||||
| { | { | ||||
| /* for ID's we do automatic lookup */ | /* for ID's we do automatic lookup */ | ||||
| PointerRNA sptr; | PointerRNA sptr; | ||||
| if (!searchprop) { | if (!searchprop) { | ||||
| if (RNA_property_type(prop) == PROP_POINTER) { | if (RNA_property_type(prop) == PROP_POINTER) { | ||||
| StructRNA *ptype = RNA_property_pointer_type(ptr, prop); | StructRNA *ptype = RNA_property_pointer_type(ptr, prop); | ||||
| ▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | RNA_warning("search collection property not found: %s.%s", | ||||
| RNA_struct_identifier(searchptr->type), | RNA_struct_identifier(searchptr->type), | ||||
| searchpropname); | searchpropname); | ||||
| return; | return; | ||||
| } | } | ||||
| uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon); | uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon); | ||||
| } | } | ||||
| /* menu item */ | |||||
| void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt) | void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt) | ||||
| { | { | ||||
| MenuType *mt = (MenuType *)arg_mt; | MenuType *mt = (MenuType *)arg_mt; | ||||
| UI_menutype_draw(C, mt, layout); | UI_menutype_draw(C, mt, layout); | ||||
| /* Menus are created flipped (from event handling point of view). */ | /* Menus are created flipped (from event handling point of view). */ | ||||
| layout->root->block->flag ^= UI_BLOCK_IS_FLIP; | layout->root->block->flag ^= UI_BLOCK_IS_FLIP; | ||||
| ▲ Show 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | void uiItemMContents(uiLayout *layout, const char *menuname) | ||||
| uiBlock *block = layout->root->block; | uiBlock *block = layout->root->block; | ||||
| bContext *C = block->evil_C; | bContext *C = block->evil_C; | ||||
| if (WM_menutype_poll(C, mt) == false) { | if (WM_menutype_poll(C, mt) == false) { | ||||
| return; | return; | ||||
| } | } | ||||
| UI_menutype_draw(C, mt, layout); | UI_menutype_draw(C, mt, layout); | ||||
| } | } | ||||
| /** | |||||
| * Insert a decorator item for a button with the same property as \a prop. | |||||
| * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a prop. | |||||
| */ | |||||
| void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index) | void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index) | ||||
| { | { | ||||
| uiBlock *block = layout->root->block; | uiBlock *block = layout->root->block; | ||||
| UI_block_layout_set_current(block, layout); | UI_block_layout_set_current(block, layout); | ||||
| uiLayout *col = uiLayoutColumn(layout, false); | uiLayout *col = uiLayoutColumn(layout, false); | ||||
| col->space = 0; | col->space = 0; | ||||
| col->emboss = UI_EMBOSS_NONE; | col->emboss = UI_EMBOSS_NONE; | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | for (int i = 0; i < (is_expand ? RNA_property_array_length(ptr, prop) : 1); i++) { | ||||
| /* Reusing RNA search members, setting actual RNA data has many side-effects. */ | /* Reusing RNA search members, setting actual RNA data has many side-effects. */ | ||||
| decorator_but->rnapoin = *ptr; | decorator_but->rnapoin = *ptr; | ||||
| decorator_but->rnaprop = prop; | decorator_but->rnaprop = prop; | ||||
| /* ui_def_but_rna() sets non-array buttons to have a RNA index of 0. */ | /* ui_def_but_rna() sets non-array buttons to have a RNA index of 0. */ | ||||
| decorator_but->rnaindex = (!is_array || is_expand) ? i : index; | decorator_but->rnaindex = (!is_array || is_expand) ? i : index; | ||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Insert a decorator item for a button with the same property as \a prop. | |||||
| * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a propname. | |||||
| */ | |||||
| void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index) | void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index) | ||||
| { | { | ||||
| PropertyRNA *prop = NULL; | PropertyRNA *prop = NULL; | ||||
| if (ptr && propname) { | if (ptr && propname) { | ||||
| /* validate arguments */ | /* validate arguments */ | ||||
| prop = RNA_struct_find_property(ptr, propname); | prop = RNA_struct_find_property(ptr, propname); | ||||
| if (!prop) { | if (!prop) { | ||||
| ui_item_disabled(layout, propname); | ui_item_disabled(layout, propname); | ||||
| RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); | RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| /* ptr and prop are allowed to be NULL here. */ | /* ptr and prop are allowed to be NULL here. */ | ||||
| uiItemDecoratorR_prop(layout, ptr, prop, index); | uiItemDecoratorR_prop(layout, ptr, prop, index); | ||||
| } | } | ||||
| /* popover */ | |||||
| void uiItemPopoverPanel_ptr( | void uiItemPopoverPanel_ptr( | ||||
| uiLayout *layout, const bContext *C, PanelType *pt, const char *name, int icon) | uiLayout *layout, const bContext *C, PanelType *pt, const char *name, int icon) | ||||
| { | { | ||||
| if (!name) { | if (!name) { | ||||
| name = CTX_IFACE_(pt->translation_context, pt->label); | name = CTX_IFACE_(pt->translation_context, pt->label); | ||||
| } | } | ||||
| if (layout->root->type == UI_LAYOUT_MENU && !icon) { | if (layout->root->type == UI_LAYOUT_MENU && !icon) { | ||||
| ▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | void uiItemL_ex( | ||||
| } | } | ||||
| } | } | ||||
| void uiItemL(uiLayout *layout, const char *name, int icon) | void uiItemL(uiLayout *layout, const char *name, int icon) | ||||
| { | { | ||||
| uiItemL_(layout, name, icon); | uiItemL_(layout, name, icon); | ||||
| } | } | ||||
| /** | |||||
| * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where the | |||||
| * logic is needed. Ideally, #uiItemFullR() could just call this, but it currently has too many | |||||
| * special needs. | |||||
| */ | |||||
| uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout) | uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout) | ||||
| { | { | ||||
| uiPropertySplitWrapper split_wrapper = {NULL}; | uiPropertySplitWrapper split_wrapper = {NULL}; | ||||
| uiLayout *layout_row = uiLayoutRow(parent_layout, true); | uiLayout *layout_row = uiLayoutRow(parent_layout, true); | ||||
| uiLayout *layout_split = uiLayoutSplit(layout_row, UI_ITEM_PROP_SEP_DIVIDE, true); | uiLayout *layout_split = uiLayoutSplit(layout_row, UI_ITEM_PROP_SEP_DIVIDE, true); | ||||
| split_wrapper.label_column = uiLayoutColumn(layout_split, true); | split_wrapper.label_column = uiLayoutColumn(layout_split, true); | ||||
| split_wrapper.label_column->alignment = UI_LAYOUT_ALIGN_RIGHT; | split_wrapper.label_column->alignment = UI_LAYOUT_ALIGN_RIGHT; | ||||
| split_wrapper.property_row = ui_item_prop_split_layout_hack(parent_layout, layout_split); | split_wrapper.property_row = ui_item_prop_split_layout_hack(parent_layout, layout_split); | ||||
| split_wrapper.decorate_column = uiLayoutColumn(layout_row, true); | split_wrapper.decorate_column = uiLayoutColumn(layout_row, true); | ||||
| return split_wrapper; | return split_wrapper; | ||||
| } | } | ||||
| /* | |||||
| * Helper to add a label and creates a property split layout if needed. | |||||
| */ | |||||
| uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon) | uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon) | ||||
| { | { | ||||
| if (layout->item.flag & UI_ITEM_PROP_SEP) { | if (layout->item.flag & UI_ITEM_PROP_SEP) { | ||||
| uiBlock *block = uiLayoutGetBlock(layout); | uiBlock *block = uiLayoutGetBlock(layout); | ||||
| const uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(layout); | const uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(layout); | ||||
| /* Further items added to 'layout' will automatically be added to split_wrapper.property_row */ | /* Further items added to 'layout' will automatically be added to split_wrapper.property_row */ | ||||
| uiItemL_(split_wrapper.label_column, text, icon); | uiItemL_(split_wrapper.label_column, text, icon); | ||||
| Show All 17 Lines | void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon) | ||||
| if (ptr && ptr->type) { | if (ptr && ptr->type) { | ||||
| if (RNA_struct_is_ID(ptr->type)) { | if (RNA_struct_is_ID(ptr->type)) { | ||||
| UI_but_drag_set_id(but, ptr->owner_id); | UI_but_drag_set_id(but, ptr->owner_id); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* value item */ | |||||
| void uiItemV(uiLayout *layout, const char *name, int icon, int argval) | void uiItemV(uiLayout *layout, const char *name, int icon, int argval) | ||||
| { | { | ||||
| /* label */ | /* label */ | ||||
| uiBlock *block = layout->root->block; | uiBlock *block = layout->root->block; | ||||
| int *retvalue = (block->handle) ? &block->handle->retvalue : NULL; | int *retvalue = (block->handle) ? &block->handle->retvalue : NULL; | ||||
| UI_block_layout_set_current(block, layout); | UI_block_layout_set_current(block, layout); | ||||
| Show All 28 Lines | uiDefIconButI( | ||||
| block, UI_BTYPE_BUT, argval, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, ""); | block, UI_BTYPE_BUT, argval, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, ""); | ||||
| } | } | ||||
| else { | else { | ||||
| uiDefButI( | uiDefButI( | ||||
| block, UI_BTYPE_BUT, argval, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, ""); | block, UI_BTYPE_BUT, argval, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, ""); | ||||
| } | } | ||||
| } | } | ||||
| /* separator item */ | |||||
| void uiItemS_ex(uiLayout *layout, float factor) | void uiItemS_ex(uiLayout *layout, float factor) | ||||
| { | { | ||||
| uiBlock *block = layout->root->block; | uiBlock *block = layout->root->block; | ||||
| const bool is_menu = ui_block_is_menu(block); | const bool is_menu = ui_block_is_menu(block); | ||||
| if (is_menu && !UI_block_can_add_separator(block)) { | if (is_menu && !UI_block_can_add_separator(block)) { | ||||
| return; | return; | ||||
| } | } | ||||
| int space = (is_menu) ? 0.45f * UI_UNIT_X : 0.3f * UI_UNIT_X; | int space = (is_menu) ? 0.45f * UI_UNIT_X : 0.3f * UI_UNIT_X; | ||||
| Show All 11 Lines | uiDefBut(block, | ||||
| NULL, | NULL, | ||||
| 0.0, | 0.0, | ||||
| 0.0, | 0.0, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| ""); | ""); | ||||
| } | } | ||||
| /* separator item */ | |||||
| void uiItemS(uiLayout *layout) | void uiItemS(uiLayout *layout) | ||||
| { | { | ||||
| uiItemS_ex(layout, 1.0f); | uiItemS_ex(layout, 1.0f); | ||||
| } | } | ||||
| /* Flexible spacing. */ | |||||
| void uiItemSpacer(uiLayout *layout) | void uiItemSpacer(uiLayout *layout) | ||||
| { | { | ||||
| uiBlock *block = layout->root->block; | uiBlock *block = layout->root->block; | ||||
| const bool is_popup = ui_block_is_popup_any(block); | const bool is_popup = ui_block_is_popup_any(block); | ||||
| if (is_popup) { | if (is_popup) { | ||||
| printf("Error: separator_spacer() not supported in popups.\n"); | printf("Error: separator_spacer() not supported in popups.\n"); | ||||
| return; | return; | ||||
| Show All 16 Lines | uiDefBut(block, | ||||
| NULL, | NULL, | ||||
| 0.0, | 0.0, | ||||
| 0.0, | 0.0, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| ""); | ""); | ||||
| } | } | ||||
| /* level items */ | |||||
| void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg) | void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg) | ||||
| { | { | ||||
| if (!func) { | if (!func) { | ||||
| return; | return; | ||||
| } | } | ||||
| ui_item_menu(layout, name, icon, func, arg, NULL, "", false); | ui_item_menu(layout, name, icon, func, arg, NULL, "", false); | ||||
| } | } | ||||
| /** | |||||
| * Version of #uiItemMenuF that free's `argN`. | |||||
| */ | |||||
| void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN) | void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN) | ||||
| { | { | ||||
| if (!func) { | if (!func) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Second 'argN' only ensures it gets freed. */ | /* Second 'argN' only ensures it gets freed. */ | ||||
| ui_item_menu(layout, name, icon, func, argN, argN, "", false); | ui_item_menu(layout, name, icon, func, argN, argN, "", false); | ||||
| ▲ Show 20 Lines • Show All 1,292 Lines • ▼ Show 20 Lines | |||||
| static void ui_layout_heading_set(uiLayout *layout, const char *heading) | static void ui_layout_heading_set(uiLayout *layout, const char *heading) | ||||
| { | { | ||||
| BLI_assert(layout->heading[0] == '\0'); | BLI_assert(layout->heading[0] == '\0'); | ||||
| if (heading) { | if (heading) { | ||||
| STRNCPY(layout->heading, heading); | STRNCPY(layout->heading, heading); | ||||
| } | } | ||||
| } | } | ||||
| /* layout create functions */ | |||||
| uiLayout *uiLayoutRow(uiLayout *layout, bool align) | uiLayout *uiLayoutRow(uiLayout *layout, bool align) | ||||
| { | { | ||||
| uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow"); | uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow"); | ||||
| ui_litem_init_from_parent(litem, layout, align); | ui_litem_init_from_parent(litem, layout, align); | ||||
| litem->item.type = ITEM_LAYOUT_ROW; | litem->item.type = ITEM_LAYOUT_ROW; | ||||
| litem->space = (align) ? 0 : layout->root->style->buttonspacex; | litem->space = (align) ? 0 : layout->root->style->buttonspacex; | ||||
| UI_block_layout_set_current(layout->root->block, litem); | UI_block_layout_set_current(layout->root->block, litem); | ||||
| return litem; | return litem; | ||||
| } | } | ||||
| /** | |||||
| * See #uiLayoutColumnWithHeading(). | |||||
| */ | |||||
| uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading) | uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading) | ||||
| { | { | ||||
| uiLayout *litem = uiLayoutRow(layout, align); | uiLayout *litem = uiLayoutRow(layout, align); | ||||
| ui_layout_heading_set(litem, heading); | ui_layout_heading_set(litem, heading); | ||||
| return litem; | return litem; | ||||
| } | } | ||||
| uiLayout *uiLayoutColumn(uiLayout *layout, bool align) | uiLayout *uiLayoutColumn(uiLayout *layout, bool align) | ||||
| { | { | ||||
| uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutColumn"); | uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutColumn"); | ||||
| ui_litem_init_from_parent(litem, layout, align); | ui_litem_init_from_parent(litem, layout, align); | ||||
| litem->item.type = ITEM_LAYOUT_COLUMN; | litem->item.type = ITEM_LAYOUT_COLUMN; | ||||
| litem->space = (align) ? 0 : layout->root->style->buttonspacey; | litem->space = (align) ? 0 : layout->root->style->buttonspacey; | ||||
| UI_block_layout_set_current(layout->root->block, litem); | UI_block_layout_set_current(layout->root->block, litem); | ||||
| return litem; | return litem; | ||||
| } | } | ||||
| /** | |||||
| * Variant of #uiLayoutColumn() that sets a heading label for the layout if the first item is | |||||
| * added through #uiItemFullR(). If split layout is used and the item has no string to add to the | |||||
| * first split-column, the heading is added there instead. Otherwise the heading inserted with a | |||||
| * new row. | |||||
| */ | |||||
| uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading) | uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading) | ||||
| { | { | ||||
| uiLayout *litem = uiLayoutColumn(layout, align); | uiLayout *litem = uiLayoutColumn(layout, align); | ||||
| ui_layout_heading_set(litem, heading); | ui_layout_heading_set(litem, heading); | ||||
| return litem; | return litem; | ||||
| } | } | ||||
| uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align) | uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align) | ||||
| ▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | uiLayout *uiLayoutRadial(uiLayout *layout) | ||||
| return litem; | return litem; | ||||
| } | } | ||||
| uiLayout *uiLayoutBox(uiLayout *layout) | uiLayout *uiLayoutBox(uiLayout *layout) | ||||
| { | { | ||||
| return (uiLayout *)ui_layout_box(layout, UI_BTYPE_ROUNDBOX); | return (uiLayout *)ui_layout_box(layout, UI_BTYPE_ROUNDBOX); | ||||
| } | } | ||||
| /** | |||||
| * Check all buttons defined in this layout, | |||||
| * and set any button flagged as UI_BUT_LIST_ITEM as active/selected. | |||||
| * Needed to handle correctly text colors of active (selected) list item. | |||||
| */ | |||||
| void ui_layout_list_set_labels_active(uiLayout *layout) | void ui_layout_list_set_labels_active(uiLayout *layout) | ||||
| { | { | ||||
| LISTBASE_FOREACH (uiButtonItem *, bitem, &layout->items) { | LISTBASE_FOREACH (uiButtonItem *, bitem, &layout->items) { | ||||
| if (bitem->item.type != ITEM_BUTTON) { | if (bitem->item.type != ITEM_BUTTON) { | ||||
| ui_layout_list_set_labels_active((uiLayout *)(&bitem->item)); | ui_layout_list_set_labels_active((uiLayout *)(&bitem->item)); | ||||
| } | } | ||||
| else if (bitem->but->flag & UI_BUT_LIST_ITEM) { | else if (bitem->but->flag & UI_BUT_LIST_ITEM) { | ||||
| UI_but_flag_enable(bitem->but, UI_SELECT); | UI_but_flag_enable(bitem->but, UI_SELECT); | ||||
| ▲ Show 20 Lines • Show All 331 Lines • ▼ Show 20 Lines | else { | ||||
| uiBut *but = link->data; | uiBut *but = link->data; | ||||
| but->flag |= UI_SEARCH_FILTER_NO_MATCH; | but->flag |= UI_SEARCH_FILTER_NO_MATCH; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return has_result; | return has_result; | ||||
| } | } | ||||
| /** | |||||
| * Apply property search behavior, setting panel flags and deactivating buttons that don't match. | |||||
| * | |||||
| * \note Must not be run after #UI_block_layout_resolve. | |||||
| */ | |||||
| bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter) | bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter) | ||||
| { | { | ||||
| if (search_filter == NULL || search_filter[0] == '\0') { | if (search_filter == NULL || search_filter[0] == '\0') { | ||||
| return false; | return false; | ||||
| } | } | ||||
| Panel *panel = block->panel; | Panel *panel = block->panel; | ||||
| ▲ Show 20 Lines • Show All 408 Lines • ▼ Show 20 Lines | void ui_layout_remove_but(uiLayout *layout, const uiBut *but) | ||||
| uiButtonItem *bitem = ui_layout_find_button_item(layout, but); | uiButtonItem *bitem = ui_layout_find_button_item(layout, but); | ||||
| if (!bitem) { | if (!bitem) { | ||||
| return; | return; | ||||
| } | } | ||||
| BLI_freelinkN(&layout->items, bitem); | BLI_freelinkN(&layout->items, bitem); | ||||
| } | } | ||||
| /** | |||||
| * \return true if the button was successfully replaced. | |||||
| */ | |||||
| bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but) | bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but) | ||||
| { | { | ||||
| uiButtonItem *bitem = ui_layout_find_button_item(layout, old_but_ptr); | uiButtonItem *bitem = ui_layout_find_button_item(layout, old_but_ptr); | ||||
| if (!bitem) { | if (!bitem) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| bitem->but = new_but; | bitem->but = new_but; | ||||
| Show All 21 Lines | |||||
| } | } | ||||
| void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv) | void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv) | ||||
| { | { | ||||
| layout->root->handlefunc = handlefunc; | layout->root->handlefunc = handlefunc; | ||||
| layout->root->argv = argv; | layout->root->argv = argv; | ||||
| } | } | ||||
| /** | |||||
| * Used for property search when the layout process needs to be cancelled in order to avoid | |||||
| * computing the locations for buttons, but the layout items created while adding the buttons | |||||
| * must still be freed. | |||||
| */ | |||||
| void UI_block_layout_free(uiBlock *block) | void UI_block_layout_free(uiBlock *block) | ||||
| { | { | ||||
| LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) { | LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) { | ||||
| ui_layout_free(root->layout); | ui_layout_free(root->layout); | ||||
| MEM_freeN(root); | MEM_freeN(root); | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | if (but->rnapoin.data && but->rnaprop) { | ||||
| /* TODO: index could be supported as well */ | /* TODO: index could be supported as well */ | ||||
| PointerRNA ptr_prop; | PointerRNA ptr_prop; | ||||
| RNA_pointer_create(NULL, &RNA_Property, but->rnaprop, &ptr_prop); | RNA_pointer_create(NULL, &RNA_Property, but->rnaprop, &ptr_prop); | ||||
| uiLayoutSetContextPointer(layout, "button_prop", &ptr_prop); | uiLayoutSetContextPointer(layout, "button_prop", &ptr_prop); | ||||
| uiLayoutSetContextPointer(layout, "button_pointer", &but->rnapoin); | uiLayoutSetContextPointer(layout, "button_pointer", &but->rnapoin); | ||||
| } | } | ||||
| } | } | ||||
| /* this is a bit of a hack but best keep it in one place at least */ | |||||
| wmOperatorType *UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA **r_prop) | wmOperatorType *UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA **r_prop) | ||||
| { | { | ||||
| if (r_prop != NULL) { | if (r_prop != NULL) { | ||||
| *r_prop = NULL; | *r_prop = NULL; | ||||
| } | } | ||||
| if (but->menu_create_func == menu_item_enum_opname_menu) { | if (but->menu_create_func == menu_item_enum_opname_menu) { | ||||
| MenuItemLevel *lvl = but->func_argN; | MenuItemLevel *lvl = but->func_argN; | ||||
| wmOperatorType *ot = WM_operatortype_find(lvl->opname, false); | wmOperatorType *ot = WM_operatortype_find(lvl->opname, false); | ||||
| if ((ot != NULL) && (r_prop != NULL)) { | if ((ot != NULL) && (r_prop != NULL)) { | ||||
| *r_prop = RNA_struct_type_find_property(ot->srna, lvl->propname); | *r_prop = RNA_struct_type_find_property(ot->srna, lvl->propname); | ||||
| } | } | ||||
| return ot; | return ot; | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* this is a bit of a hack but best keep it in one place at least */ | |||||
| MenuType *UI_but_menutype_get(uiBut *but) | MenuType *UI_but_menutype_get(uiBut *but) | ||||
| { | { | ||||
| if (but->menu_create_func == ui_item_menutype_func) { | if (but->menu_create_func == ui_item_menutype_func) { | ||||
| return (MenuType *)but->poin; | return (MenuType *)but->poin; | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* this is a bit of a hack but best keep it in one place at least */ | |||||
| PanelType *UI_but_paneltype_get(uiBut *but) | PanelType *UI_but_paneltype_get(uiBut *but) | ||||
| { | { | ||||
| if (but->menu_create_func == ui_item_paneltype_func) { | if (but->menu_create_func == ui_item_paneltype_func) { | ||||
| return (PanelType *)but->poin; | return (PanelType *)but->poin; | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | if (child_pt->poll == NULL || child_pt->poll(C, child_pt)) { | ||||
| } | } | ||||
| uiLayout *col = uiLayoutColumn(layout, false); | uiLayout *col = uiLayoutColumn(layout, false); | ||||
| ui_paneltype_draw_impl(C, child_pt, col, true); | ui_paneltype_draw_impl(C, child_pt, col, true); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Used for popup panels only. | |||||
| */ | |||||
| void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout) | void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout) | ||||
| { | { | ||||
| if (layout->context) { | if (layout->context) { | ||||
| CTX_store_set(C, layout->context); | CTX_store_set(C, layout->context); | ||||
| } | } | ||||
| ui_paneltype_draw_impl(C, pt, layout, false); | ui_paneltype_draw_impl(C, pt, layout, false); | ||||
| ▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | if (item != lb->last) { | ||||
| BLI_dynstr_append(ds, ", "); | BLI_dynstr_append(ds, ", "); | ||||
| } | } | ||||
| } | } | ||||
| /* Don't use a comma here as it's not needed and | /* Don't use a comma here as it's not needed and | ||||
| * causes the result to evaluate to a tuple of 1. */ | * causes the result to evaluate to a tuple of 1. */ | ||||
| BLI_dynstr_append(ds, "]"); | BLI_dynstr_append(ds, "]"); | ||||
| } | } | ||||
| /** | |||||
| * Evaluate layout items as a Python dictionary. | |||||
| */ | |||||
| const char *UI_layout_introspect(uiLayout *layout) | const char *UI_layout_introspect(uiLayout *layout) | ||||
| { | { | ||||
| DynStr *ds = BLI_dynstr_new(); | DynStr *ds = BLI_dynstr_new(); | ||||
| uiLayout layout_copy = *layout; | uiLayout layout_copy = *layout; | ||||
| layout_copy.item.next = NULL; | layout_copy.item.next = NULL; | ||||
| layout_copy.item.prev = NULL; | layout_copy.item.prev = NULL; | ||||
| ListBase layout_dummy_list = {&layout_copy, &layout_copy}; | ListBase layout_dummy_list = {&layout_copy, &layout_copy}; | ||||
| ui_layout_introspect_items(ds, &layout_dummy_list); | ui_layout_introspect_items(ds, &layout_dummy_list); | ||||
| const char *result = BLI_dynstr_get_cstring(ds); | const char *result = BLI_dynstr_get_cstring(ds); | ||||
| BLI_dynstr_free(ds); | BLI_dynstr_free(ds); | ||||
| return result; | return result; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Alert Box with Big Icon | /** \name Alert Box with Big Icon | ||||
| * \{ */ | * \{ */ | ||||
| /** | |||||
| * Helper to add a big icon and create a split layout for alert popups. | |||||
| * Returns the layout to place further items into the alert box. | |||||
| */ | |||||
| uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon) | uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon) | ||||
| { | { | ||||
| const uiStyle *style = UI_style_get_dpi(); | const uiStyle *style = UI_style_get_dpi(); | ||||
| const short icon_size = 64 * U.dpi_fac; | const short icon_size = 64 * U.dpi_fac; | ||||
| const int text_points_max = MAX2(style->widget.points, style->widgetlabel.points); | const int text_points_max = MAX2(style->widget.points, style->widgetlabel.points); | ||||
| const int dialog_width = icon_size + (text_points_max * size * U.dpi_fac); | const int dialog_width = icon_size + (text_points_max * size * U.dpi_fac); | ||||
| /* By default, the space between icon and text/buttons will be equal to the 'columnspace', | /* By default, the space between icon and text/buttons will be equal to the 'columnspace', | ||||
| * this extra padding will add some space by increasing the left column width, | * this extra padding will add some space by increasing the left column width, | ||||
| Show All 25 Lines | |||||