/* SPDX-FileCopyrightText: 2023 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup editorui */ #pragma once #include #include #include "BLI_function_ref.hh" #include "BLI_string_ref.hh" #include "BLI_vector.hh" #include "UI_resources.hh" #include "UI_interface_c.hh" // IWYU pragma: export namespace blender::nodes::geo_eval_log { struct GeometryAttributeInfo; } struct ARegion; struct bContext; struct PointerRNA; struct StructRNA; struct uiBlock; struct uiBut; struct uiLayout; struct uiList; struct uiSearchItems; struct wmDrag; struct wmEvent; namespace blender::ui { class AbstractView; class AbstractViewItem; } // namespace blender::ui void UI_but_func_set(uiBut *but, std::function func); void UI_but_func_pushed_state_set(uiBut *but, std::function func); /** * Template generating a freeing callback matching the #uiButArgNFree signature, for data created * with #MEM_new. */ template void but_func_argN_free(void *argN) { MEM_delete(static_cast(argN)); } /** * Template generating a copying callback matching the #uiButArgNCopy signature, for data created * with #MEM_new. */ template void *but_func_argN_copy(const void *argN) { return MEM_new(__func__, *static_cast(argN)); } namespace blender::ui { class AbstractGridView; class AbstractTreeView; class DropTargetInterface; /** * An item in a breadcrumb-like context. Currently this struct is very simple, but more * could be added to it in the future, to support interactivity or tooltips, for example. */ struct ContextPathItem { /* Text to display in the UI. */ std::string name; /* #BIFIconID */ int icon; int icon_indicator_number; }; void context_path_add_generic(Vector &path, StructRNA &rna_type, void *ptr, const BIFIconID icon_override = ICON_NONE); void template_breadcrumbs(uiLayout &layout, Span context_path); void attribute_search_add_items(StringRef str, bool can_create_attribute, Span infos, uiSearchItems *items, bool is_first); void grease_pencil_layer_search_add_items(StringRef str, Span layer_names, uiSearchItems &items, bool is_first); bool asset_shelf_popover_invoke(bContext &C, blender::StringRef asset_shelf_idname, ReportList &reports); /** * Some drop targets simply allow dropping onto/into them, others support dragging in-between them. * Classes implementing the drop-target interface can use this type to control the behavior by * letting it influence the result of #choose_drop_location(). */ enum class DropBehavior { /** * Enable dropping before (#DropLocation::Before) and after (#DropLocation::After) the * drop target. Typically used for reordering items. */ Reorder, /** Only enable dropping onto/into the drop target (#DropLocation::Into). */ Insert, /** * Enable dropping onto/into (#DropLocation::Into), before (#DropLocation::Before) and after * (#DropLocation::After) the drop target. Typically used for reordering items with nesting * support. */ ReorderAndInsert, }; /** * Information on how dragged data should be inserted on drop, as determined through * #DropTargetInterface::choose_drop_location(). Also see #DropBehavior. */ enum class DropLocation { Into, Before, After, }; /** * Information passed to drop targets while dragging over them. */ struct DragInfo { const wmDrag &drag_data; const wmEvent &event; const DropLocation drop_location; DragInfo(const wmDrag &drag, const wmEvent &event, DropLocation drop_location); }; /** * This provides a common interface for UI elements that want to support dragging & dropping * entities into/onto them. With it, the element can determine if the dragged entity can be dropped * onto itself, provide feedback while dragging and run custom code for the dropping. * * By default the drop target behaves so that data can be dragged into or onto it. * #choose_drop_location() can be overridden to change that. * * Note that this is just an interface (not in the strict sense of a Java/C# interface though). A * #wmDropBox is needed to request instances of it from a UI element and call its functions. For * example the drop box using "UI_OT_view_drop" implements dropping for views and view items via * this interface. To support other kinds of UI elements, similar drop boxes would be necessary. */ class DropTargetInterface { public: DropTargetInterface() = default; virtual ~DropTargetInterface() = default; /** * Check if the data dragged with \a drag can be dropped on the element this drop target is for. * \param r_disabled_hint: Return a static string to display to the user, explaining why dropping * isn't possible on this UI element. Shouldn't be done too aggressively, * e.g. don't set this if the drag-type can't be dropped here; only if it * can but there's another reason it can't be dropped. Can assume this is * a non-null pointer. */ virtual bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const = 0; /** * Once the drop target validated that it can receive the dragged data using #can_drop(), this * method can determine where/how the data should be dropped exactly: before, after or into the * drop target. Additional feedback can be drawn then while dragging, and the #on_drop() function * should operate accordingly. Implementations of this function may want to use #DropBehavior to * control which locations may be returned here. * * If the returned optional is unset, dropping will be disabled. The default implementation * returns #DropLocation::Into. */ virtual std::optional choose_drop_location(const ARegion ®ion, const wmEvent &event) const; /** * Custom text to display when dragging over the element using this drop target. Should * explain what happens when dropping the data onto this UI element. Will only be used if * #DropTargetInterface::can_drop() returns true, so the implementing override doesn't have * to check that again. The returned value must be a translated string. */ virtual std::string drop_tooltip(const DragInfo &drag) const = 0; /** * Execute the logic to apply a drop of the data dragged with \a drag onto/into the UI element * this drop target is for. */ virtual bool on_drop(bContext *C, const DragInfo &drag) const = 0; }; /** * Let a drop target handle a drop event. * \return True if the dropping was successful. */ bool drop_target_apply_drop(bContext &C, const ARegion ®ion, const wmEvent &event, const DropTargetInterface &drop_target, const ListBase &drags); /** * Call #DropTargetInterface::drop_tooltip() and return the result as newly allocated C string * (unless the result is empty, returns null then). Needs freeing with MEM_freeN(). */ std::string drop_target_tooltip(const ARegion ®ion, const DropTargetInterface &drop_target, const wmDrag &drag, const wmEvent &event); /** * Try to find a view item with a drop target under the mouse cursor, or if not found, a view * with a drop target. * \param xy: Coordinate to find a drop target at, in window space. */ std::unique_ptr region_views_find_drop_target_at(const ARegion *region, const int xy[2]); } // namespace blender::ui enum eUIListFilterResult { /** Never show this item, even when filter results are inverted (#UILST_FLT_EXCLUDE). */ UI_LIST_ITEM_NEVER_SHOW, /** Show this item, unless filter results are inverted (#UILST_FLT_EXCLUDE). */ UI_LIST_ITEM_FILTER_MATCHES, /** Don't show this item, unless filter results are inverted (#UILST_FLT_EXCLUDE). */ UI_LIST_ITEM_FILTER_MISMATCHES, }; /** * Function object for UI list item filtering that does the default name comparison with '*' * wildcards. Create an instance of this once and pass it to #UI_list_filter_and_sort_items(), do * NOT create an instance for every item, this would be costly. */ class uiListNameFilter { /* Storage with an inline buffer for smaller strings (small buffer optimization). */ struct { char filter_buff[32]; char *filter_dyn = nullptr; } storage_; char *filter_ = nullptr; public: uiListNameFilter(uiList &list); ~uiListNameFilter(); eUIListFilterResult operator()(const PointerRNA &itemptr, blender::StringRefNull name, int index); }; using uiListItemFilterFn = blender::FunctionRef; using uiListItemGetNameFn = blender::FunctionRef; /** * Filter list items using \a item_filter_fn and sort the result. This respects the normal UI list * filter settings like alphabetical sorting (#UILST_FLT_SORT_ALPHA), and result inverting * (#UILST_FLT_EXCLUDE). * * Call this from a #uiListType::filter_items callback with any #item_filter_fn. #uiListNameFilter * can be used to apply the default name based filtering. * * \param get_name_fn: In some cases the name cannot be retrieved via RNA. This function can be set * to provide the name still. */ void UI_list_filter_and_sort_items(uiList *ui_list, const bContext *C, uiListItemFilterFn item_filter_fn, PointerRNA *dataptr, const char *propname, uiListItemGetNameFn get_name_fn = nullptr); /** * Override this for all available view types. * \param idname: Used for restoring persistent state of this view, potentially written to files. * Must not be longer than #BKE_ST_MAXNAME (including 0 terminator). */ blender::ui::AbstractGridView *UI_block_add_view( uiBlock &block, blender::StringRef idname, std::unique_ptr grid_view); blender::ui::AbstractTreeView *UI_block_add_view( uiBlock &block, blender::StringRef idname, std::unique_ptr tree_view);