diff --git a/source/blender/editors/asset/intern/asset_shelf.cc b/source/blender/editors/asset/intern/asset_shelf.cc index 75794ebae5f..58f505d5ea7 100644 --- a/source/blender/editors/asset/intern/asset_shelf.cc +++ b/source/blender/editors/asset/intern/asset_shelf.cc @@ -842,7 +842,7 @@ static void asset_shelf_header_draw(const bContext *C, Header *header) list::storage_fetch(library_ref, C); UI_block_emboss_set(block, blender::ui::EmbossType::None); - uiItemPopoverPanel(layout, C, "ASSETSHELF_PT_catalog_selector", "", ICON_COLLAPSEMENU); + layout->popover(C, "ASSETSHELF_PT_catalog_selector", "", ICON_COLLAPSEMENU); UI_block_emboss_set(block, blender::ui::EmbossType::Emboss); layout->separator(); @@ -852,9 +852,9 @@ static void asset_shelf_header_draw(const bContext *C, Header *header) add_catalog_tabs(*shelf, *layout); } - uiItemSpacer(layout); + layout->separator_spacer(); - uiItemPopoverPanel(layout, C, "ASSETSHELF_PT_display", "", ICON_IMGDISPLAY); + layout->popover(C, "ASSETSHELF_PT_display", "", ICON_IMGDISPLAY); uiLayout *sub = &layout->row(false); /* Same as file/asset browser header. */ sub->ui_units_x_set(8); diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index 42472179a3a..2f1d82ce729 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -954,10 +954,10 @@ void UI_block_lock_clear(uiBlock *block); enum class uiButtonSectionsAlign : int8_t { None = 1, Top, Bottom }; /** * Draw a background with rounded corners behind each visual group of buttons. The visual groups - * are separated by spacer buttons (#uiItemSpacer()). Button groups that are closer than - * #UI_BUTTON_SECTION_MERGE_DISTANCE will be merged into one visual section. If the group is closer - * than that to a region edge, it will also be extended to that, and the rounded corners will be - * removed on that edge. + * are separated by spacer buttons (#uiLayout::separator_spacer()). Button groups that are closer + * than #UI_BUTTON_SECTION_MERGE_DISTANCE will be merged into one visual section. If the group is + * closer than that to a region edge, it will also be extended to that, and the rounded corners + * will be removed on that edge. * * \note This currently only works well for horizontal, header like regions. */ diff --git a/source/blender/editors/include/UI_interface_layout.hh b/source/blender/editors/include/UI_interface_layout.hh index c99fd79a528..bb02fc3bcfd 100644 --- a/source/blender/editors/include/UI_interface_layout.hh +++ b/source/blender/editors/include/UI_interface_layout.hh @@ -424,6 +424,22 @@ struct uiLayout : uiItem { int icon, wmOperatorCallContext context, eUI_Item_Flag flag); + /** + * Adds a operator item, places a button in the layout to call the operator, if the button is + * held down, a menu will be displayed instead. + * \param ot: Operator to add. + * \param name: Text to show in the layout. + * \param context: Operator call context for #WM_operator_name_call. + * \param menu_id: menu to show on held down. + * \returns Operator pointer to write properties, might be #PointerRNA_NULL if operator does not + * exists. + */ + PointerRNA op_menu_hold(wmOperatorType *ot, + std::optional name, + int icon, + wmOperatorCallContext context, + eUI_Item_Flag flag, + const char *menu_id); /** * Adds a RNA property item, and exposes it into the layout. * \param ptr: RNA pointer to the struct owner of \a prop. @@ -446,6 +462,17 @@ struct uiLayout : uiItem { std::optional name, int icon); + void popover(const bContext *C, + PanelType *pt, + std::optional name_opt, + int icon); + void popover(const bContext *C, + blender::StringRef panel_type, + std::optional name_opt, + int icon); + void popover_group( + bContext *C, int space_id, int region_id, const char *context, const char *category); + /** * Add a enum property value item. This button acts like a radio button that are used to chose * a single enum value from a set of the enum property value items. @@ -516,8 +543,35 @@ struct uiLayout : uiItem { std::optional name, int icon); + /** + * Adds a RNA property item, and sets a custom popover to expose its value. + */ + void prop_with_popover(PointerRNA *ptr, + PropertyRNA *prop, + int index, + int value, + eUI_Item_Flag flag, + std::optional name, + int icon, + const char *panel_type); + + /** + * Adds a RNA property item, and sets a custom menu to expose its value. + */ + void prop_with_menu(PointerRNA *ptr, + PropertyRNA *prop, + int index, + int value, + eUI_Item_Flag flag, + std::optional name, + int icon, + const char *menu_type); + /** Adds a separator item, that adds empty space between items. */ void separator(float factor = 1.0f, LayoutSeparatorType type = LayoutSeparatorType::Auto); + + /** Adds a spacer item that inserts empty horizontal space between other items in the layout. */ + void separator_spacer(); }; inline bool uiLayout::active() const @@ -786,37 +840,6 @@ void uiItemsEnumO(uiLayout *layout, blender::StringRefNull opname, blender::StringRefNull propname); -void uiItemFullOMenuHold_ptr(uiLayout *layout, - wmOperatorType *ot, - std::optional name, - int icon, - wmOperatorCallContext context, - eUI_Item_Flag flag, - const char *menu_id, /* extra menu arg. */ - PointerRNA *r_opptr); - -/** - * Use a wrapper function since re-implementing all the logic in this function would be messy. - */ -void uiItemFullR_with_popover(uiLayout *layout, - PointerRNA *ptr, - PropertyRNA *prop, - int index, - int value, - eUI_Item_Flag flag, - std::optional name, - int icon, - const char *panel_type); -void uiItemFullR_with_menu(uiLayout *layout, - PointerRNA *ptr, - PropertyRNA *prop, - int index, - int value, - eUI_Item_Flag flag, - std::optional name, - int icon, - const char *menu_type); - /** * Create a list of enum items. * @@ -900,9 +923,6 @@ void uiItemDecoratorR(uiLayout *layout, std::optional propname, int index); -/** Flexible spacing. */ -void uiItemSpacer(uiLayout *layout); - enum eButProgressType { UI_BUT_PROGRESS_TYPE_BAR = 0, UI_BUT_PROGRESS_TYPE_RING = 1, @@ -913,24 +933,6 @@ void uiItemProgressIndicator(uiLayout *layout, float factor, eButProgressType progress_type); -/* popover */ -void uiItemPopoverPanel_ptr(uiLayout *layout, - const bContext *C, - PanelType *pt, - std::optional name_opt, - int icon); -void uiItemPopoverPanel(uiLayout *layout, - const bContext *C, - blender::StringRef panel_type, - std::optional name_opt, - int icon); -void uiItemPopoverPanelFromGroup(uiLayout *layout, - bContext *C, - int space_id, - int region_id, - const char *context, - const char *category); - /** * Level items. */ diff --git a/source/blender/editors/interface/interface_handlers.cc b/source/blender/editors/interface/interface_handlers.cc index 8d4d7dcbc1d..4f9de34aec6 100644 --- a/source/blender/editors/interface/interface_handlers.cc +++ b/source/blender/editors/interface/interface_handlers.cc @@ -9642,7 +9642,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) /* Cancel because this `but` handles all events and we don't want * the parent button's update function to do anything. * - * Causes issues with buttons defined by #uiItemFullR_with_popover. */ + * Causes issues with buttons defined by #uiLayout::prop_with_popover. */ block->handle->menuretval = UI_RETURN_CANCEL; } else if (ui_but_is_editable_as_text(but)) { diff --git a/source/blender/editors/interface/interface_layout.cc b/source/blender/editors/interface/interface_layout.cc index 946fd206cea..c485d1bd045 100644 --- a/source/blender/editors/interface/interface_layout.cc +++ b/source/blender/editors/interface/interface_layout.cc @@ -1366,17 +1366,17 @@ PointerRNA uiLayout::op(wmOperatorType *ot, return ptr; } -void uiItemFullOMenuHold_ptr(uiLayout *layout, - wmOperatorType *ot, - std::optional name, - int icon, - const wmOperatorCallContext context, - const eUI_Item_Flag flag, - const char *menu_id, - PointerRNA *r_opptr) +PointerRNA uiLayout::op_menu_hold(wmOperatorType *ot, + std::optional name, + int icon, + const wmOperatorCallContext context, + const eUI_Item_Flag flag, + const char *menu_id) { - uiBut *but = uiItemFullO_ptr_ex(layout, ot, name, icon, context, flag, r_opptr); + PointerRNA ptr; + uiBut *but = uiItemFullO_ptr_ex(this, ot, name, icon, context, flag, &ptr); UI_but_func_hold_set(but, ui_item_menu_hold, BLI_strdup(menu_id)); + return ptr; } PointerRNA uiLayout::op(const blender::StringRefNull opname, @@ -2410,19 +2410,18 @@ void uiLayout::prop(PointerRNA *ptr, this->prop(ptr, prop, RNA_NO_INDEX, 0, flag, name, icon); } -void uiItemFullR_with_popover(uiLayout *layout, - PointerRNA *ptr, - PropertyRNA *prop, - int index, - int value, - const eUI_Item_Flag flag, - const std::optional name, - int icon, - const char *panel_type) +void uiLayout::prop_with_popover(PointerRNA *ptr, + PropertyRNA *prop, + int index, + int value, + const eUI_Item_Flag flag, + const std::optional name, + int icon, + const char *panel_type) { - uiBlock *block = layout->block(); + uiBlock *block = this->block(); int i = block->buttons.size(); - layout->prop(ptr, prop, index, value, flag, name, icon); + this->prop(ptr, prop, index, value, flag, name, icon); for (; i < block->buttons.size(); i++) { uiBut *but = block->buttons[i].get(); if (but->rnaprop == prop && ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_COLOR)) { @@ -2432,7 +2431,7 @@ void uiItemFullR_with_popover(uiLayout *layout, } if (i == block->buttons.size()) { const StringRefNull propname = RNA_property_identifier(prop); - ui_item_disabled(layout, panel_type); + ui_item_disabled(this, panel_type); RNA_warning("property could not use a popover: %s.%s (%s)", RNA_struct_identifier(ptr->type), propname.c_str(), @@ -2440,19 +2439,18 @@ void uiItemFullR_with_popover(uiLayout *layout, } } -void uiItemFullR_with_menu(uiLayout *layout, - PointerRNA *ptr, - PropertyRNA *prop, - int index, - int value, - const eUI_Item_Flag flag, - const std::optional name, - int icon, - const char *menu_type) +void uiLayout::prop_with_menu(PointerRNA *ptr, + PropertyRNA *prop, + int index, + int value, + const eUI_Item_Flag flag, + const std::optional name, + int icon, + const char *menu_type) { - uiBlock *block = layout->block(); + uiBlock *block = this->block(); int i = block->buttons.size(); - layout->prop(ptr, prop, index, value, flag, name, icon); + this->prop(ptr, prop, index, value, flag, name, icon); while (i < block->buttons.size()) { uiBut *but = block->buttons[i].get(); if (but->rnaprop == prop && but->type == UI_BTYPE_MENU) { @@ -2463,7 +2461,7 @@ void uiItemFullR_with_menu(uiLayout *layout, } if (i == block->buttons.size()) { const StringRefNull propname = RNA_property_identifier(prop); - ui_item_disabled(layout, menu_type); + ui_item_disabled(this, menu_type); RNA_warning("property could not use a menu: %s.%s (%s)", RNA_struct_identifier(ptr->type), propname.c_str(), @@ -3022,25 +3020,25 @@ void uiItemDecoratorR(uiLayout *layout, uiItemDecoratorR_prop(layout, ptr, prop, index); } -void uiItemPopoverPanel_ptr(uiLayout *layout, - const bContext *C, - PanelType *pt, - const std::optional name_opt, - int icon) +void uiLayout::popover(const bContext *C, + PanelType *pt, + const std::optional name_opt, + int icon) { + uiLayout *layout = this; const StringRef name = name_opt.value_or(CTX_IFACE_(pt->translation_context, pt->label)); - if (layout->root_->type == UI_LAYOUT_MENU && !icon) { + if (root_->type == UI_LAYOUT_MENU && !icon) { icon = ICON_BLANK1; } const bContextStore *previous_ctx = CTX_store_get(C); /* Set context for polling (and panel header drawing). */ - CTX_store_set(const_cast(C), layout->context_); + CTX_store_set(const_cast(C), context_); const bool ok = (pt->poll == nullptr) || pt->poll(C, pt); if (ok && (pt->draw_header != nullptr)) { - layout = &layout->row(true); + layout = &this->row(true); Panel panel{}; Panel_Runtime panel_runtime{}; panel.runtime = &panel_runtime; @@ -3060,26 +3058,21 @@ void uiItemPopoverPanel_ptr(uiLayout *layout, } } -void uiItemPopoverPanel(uiLayout *layout, - const bContext *C, - const StringRef panel_type, - std::optional name_opt, - int icon) +void uiLayout::popover(const bContext *C, + const StringRef panel_type, + std::optional name_opt, + int icon) { PanelType *pt = WM_paneltype_find(panel_type, true); if (pt == nullptr) { RNA_warning("Panel type not found '%s'", std::string(panel_type).c_str()); return; } - uiItemPopoverPanel_ptr(layout, C, pt, name_opt, icon); + this->popover(C, pt, name_opt, icon); } -void uiItemPopoverPanelFromGroup(uiLayout *layout, - bContext *C, - int space_id, - int region_id, - const char *context, - const char *category) +void uiLayout::popover_group( + bContext *C, int space_id, int region_id, const char *context, const char *category) { SpaceType *st = BKE_spacetype_from_id(space_id); if (st == nullptr) { @@ -3098,7 +3091,7 @@ void uiItemPopoverPanelFromGroup(uiLayout *layout, if (/* (*context == '\0') || */ STREQ(pt->context, context)) { if ((*category == '\0') || STREQ(pt->category, category)) { if (pt->poll == nullptr || pt->poll(C, pt)) { - uiItemPopoverPanel_ptr(layout, C, pt, std::nullopt, ICON_NONE); + this->popover(C, pt, std::nullopt, ICON_NONE); } } } @@ -3314,9 +3307,9 @@ void uiItemProgressIndicator(uiLayout *layout, progress_bar->progress_factor = factor; } -void uiItemSpacer(uiLayout *layout) +void uiLayout::separator_spacer() { - uiBlock *block = layout->block(); + uiBlock *block = this->block(); const bool is_popup = ui_block_is_popup_any(block); if (is_popup) { @@ -3329,7 +3322,7 @@ void uiItemSpacer(uiLayout *layout) return; } - UI_block_layout_set_current(block, layout); + UI_block_layout_set_current(block, this); uiDefBut(block, UI_BTYPE_SEPR_SPACER, 0, @@ -5993,7 +5986,7 @@ static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout, /* This check may be paranoid, this function might run outside the context of a popup or can run * in popovers that are not supposed to support refreshing, see #ui_popover_create_block. */ if (block->handle && block->handle->region) { - /* Allow popovers to contain collapsible sections, see #uiItemPopoverPanel. */ + /* Allow popovers to contain collapsible sections, see #uiLayout::popover. */ UI_popup_dummy_panel_set(block->handle->region, block); } diff --git a/source/blender/editors/interface/templates/interface_template_asset_shelf_popover.cc b/source/blender/editors/interface/templates/interface_template_asset_shelf_popover.cc index a30ad49c5cd..d70ddcb1774 100644 --- a/source/blender/editors/interface/templates/interface_template_asset_shelf_popover.cc +++ b/source/blender/editors/interface/templates/interface_template_asset_shelf_popover.cc @@ -53,7 +53,7 @@ void template_asset_shelf_popover(uiLayout &layout, ed::asset::shelf::ensure_asset_library_fetched(C, *shelf_type); - uiItemPopoverPanel(row, &C, "ASSETSHELF_PT_popover_panel", name, icon); + row->popover(&C, "ASSETSHELF_PT_popover_panel", name, icon); uiBut *but = block->buttons.last().get(); if (use_preview_icon) { ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW); diff --git a/source/blender/editors/interface/templates/interface_template_operator_property.cc b/source/blender/editors/interface/templates/interface_template_operator_property.cc index 327c42a993c..0cf815a9df8 100644 --- a/source/blender/editors/interface/templates/interface_template_operator_property.cc +++ b/source/blender/editors/interface/templates/interface_template_operator_property.cc @@ -351,7 +351,7 @@ static void draw_export_controls( if (valid) { uiLayout *row = &layout->row(false); row->emboss_set(blender::ui::EmbossType::None); - uiItemPopoverPanel(row, C, "WM_PT_operator_presets", "", ICON_PRESET); + row->popover(C, "WM_PT_operator_presets", "", ICON_PRESET); PointerRNA op_ptr = row->op("COLLECTION_OT_exporter_export", "", ICON_EXPORT); RNA_int_set(&op_ptr, "index", index); } diff --git a/source/blender/editors/space_buttons/buttons_context.cc b/source/blender/editors/space_buttons/buttons_context.cc index 0e952c62346..a00905369e5 100644 --- a/source/blender/editors/space_buttons/buttons_context.cc +++ b/source/blender/editors/space_buttons/buttons_context.cc @@ -1252,7 +1252,7 @@ static void buttons_panel_context_draw(const bContext *C, Panel *panel) uiLayout *pin_row = &row->row(false); pin_row->alignment_set(blender::ui::LayoutAlign::Right); - uiItemSpacer(pin_row); + pin_row->separator_spacer(); pin_row->emboss_set(blender::ui::EmbossType::None); pin_row->op( "BUTTONS_OT_toggle_pin", "", (sbuts->flag & SB_PIN_CONTEXT) ? ICON_PINNED : ICON_UNPINNED); diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index c3d963701d9..ee25a120e6f 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -659,7 +659,7 @@ static void spreadsheet_footer_region_draw(const bContext *C, ARegion *region) 1, 0, style); - uiItemSpacer(layout); + layout->separator_spacer(); layout->alignment_set(blender::ui::LayoutAlign::Right); layout->label(stats_str, ICON_NONE); UI_block_layout_resolve(block, nullptr, nullptr); diff --git a/source/blender/makesrna/intern/rna_ui_api.cc b/source/blender/makesrna/intern/rna_ui_api.cc index a7bc7ad9192..ec145c225cb 100644 --- a/source/blender/makesrna/intern/rna_ui_api.cc +++ b/source/blender/makesrna/intern/rna_ui_api.cc @@ -185,7 +185,7 @@ static void rna_uiItemR_with_popover(uiLayout *layout, /* Get translated name (label). */ std::optional text = rna_translate_ui_text( name, text_ctxt, nullptr, prop, translate); - uiItemFullR_with_popover(layout, ptr, prop, -1, 0, flag, text, icon, panel_type); + layout->prop_with_popover(ptr, prop, -1, 0, flag, text, icon, panel_type); } static void rna_uiItemR_with_menu(uiLayout *layout, @@ -216,7 +216,7 @@ static void rna_uiItemR_with_menu(uiLayout *layout, /* Get translated name (label). */ std::optional text = rna_translate_ui_text( name, text_ctxt, nullptr, prop, translate); - uiItemFullR_with_menu(layout, ptr, prop, -1, 0, flag, text, icon, menu_type); + layout->prop_with_menu(ptr, prop, -1, 0, flag, text, icon, menu_type); } static void rna_uiItemMenuEnumR(uiLayout *layout, @@ -418,9 +418,7 @@ static PointerRNA rna_uiItemOMenuHold(uiLayout *layout, flag |= UI_ITEM_O_DEPRESS; } - PointerRNA opptr; - uiItemFullOMenuHold_ptr(layout, ot, text, icon, layout->operator_context(), flag, menu, &opptr); - return opptr; + return layout->op_menu_hold(ot, text, icon, layout->operator_context(), flag, menu); } static void rna_uiItemsEnumO(uiLayout *layout, @@ -516,7 +514,7 @@ static void rna_uiItemPopoverPanel(uiLayout *layout, icon = icon_value; } - uiItemPopoverPanel(layout, C, panel_type, text, icon); + layout->popover(C, panel_type, text, icon); } static void rna_uiItemPopoverPanelFromGroup(uiLayout *layout, @@ -526,7 +524,7 @@ static void rna_uiItemPopoverPanelFromGroup(uiLayout *layout, const char *context, const char *category) { - uiItemPopoverPanelFromGroup(layout, C, space_id, region_id, context, category); + layout->popover_group(C, space_id, region_id, context, category); } static void rna_uiItemProgress(uiLayout *layout, @@ -558,6 +556,11 @@ static void rna_uiLayoutContextStringSet(uiLayout *layout, const char *name, con layout->context_string_set(name, value); } +static void rna_uiLayoutSeparatorSpacer(uiLayout *layout) +{ + layout->separator_spacer(); +} + static void rna_uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, @@ -1595,7 +1598,7 @@ void RNA_api_ui_layout(StructRNA *srna) "Type", "The type of the separator"); - func = RNA_def_function(srna, "separator_spacer", "uiItemSpacer"); + func = RNA_def_function(srna, "separator_spacer", "rna_uiLayoutSeparatorSpacer"); RNA_def_function_ui_description( func, "Item. Inserts horizontal spacing empty space into the layout between items.");