From 71e0c6c043ba72aa71cb7ec3440291dcfb0c738e Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 21 Mar 2023 17:29:07 +0100 Subject: [PATCH 1/5] UI: Generalize drop controllers, support them for UI views Previously UI view items would support custom drop controllers (so they could react to data being dragged over them and dropped). This is now more generalized so the views themselves can do this as well. --- .../editors/include/UI_abstract_view.hh | 52 +++++---- source/blender/editors/include/UI_interface.h | 16 +-- .../blender/editors/include/UI_interface.hh | 66 +++++++++++ .../blender/editors/interface/CMakeLists.txt | 1 + source/blender/editors/interface/interface.cc | 2 + .../editors/interface/interface_drop.cc | 31 ++++++ .../editors/interface/interface_dropboxes.cc | 21 ++-- .../editors/interface/interface_intern.hh | 1 + .../editors/interface/interface_ops.cc | 20 ++-- .../editors/interface/views/abstract_view.cc | 25 +++++ .../interface/views/abstract_view_item.cc | 62 +---------- .../editors/interface/views/interface_view.cc | 103 ++++++++++++++++++ .../space_file/asset_catalog_tree_view.cc | 12 +- 13 files changed, 295 insertions(+), 117 deletions(-) create mode 100644 source/blender/editors/interface/interface_drop.cc diff --git a/source/blender/editors/include/UI_abstract_view.hh b/source/blender/editors/include/UI_abstract_view.hh index e2f395ec203..7161d2b4c47 100644 --- a/source/blender/editors/include/UI_abstract_view.hh +++ b/source/blender/editors/include/UI_abstract_view.hh @@ -19,16 +19,21 @@ #include #include +#include #include "DNA_defs.h" +#include "DNA_vec_types.h" #include "BLI_span.hh" #include "BLI_string_ref.hh" +#include "UI_interface.hh" + struct bContext; struct uiBlock; struct uiLayout; struct uiViewItemHandle; +struct ViewLink; struct wmDrag; struct wmNotifier; @@ -38,8 +43,13 @@ class AbstractViewItem; class AbstractViewItemDropController; class AbstractViewItemDragController; +/** The view drop controller can share logic with the view item drop controller for now, so just an + * alias. */ +using AbstractViewDropController = AbstractViewItemDropController; + class AbstractView { friend class AbstractViewItem; + friend struct ::ViewLink; bool is_reconstructed_ = false; /** @@ -51,9 +61,21 @@ class AbstractView { */ std::unique_ptr> rename_buffer_; + /* See #get_bounds(). */ + std::optional bounds_; + public: virtual ~AbstractView() = default; + /** + * If a view wants to support dropping data into it, it has to return a drop controller here. + * That is an object implementing #AbstractViewDropController. + * + * \note This drop controller may be requested for each event. The view doesn't keep a drop + * controller around currently. So it can not contain persistent state. + */ + virtual std::unique_ptr create_drop_controller() const; + /** Listen to a notifier, returning true if a redraw is needed. */ virtual bool listen(const wmNotifier &) const; @@ -70,6 +92,11 @@ class AbstractView { void end_renaming(); Span get_rename_buffer() const; MutableSpan get_rename_buffer(); + /** + * Get the rectangle containing all the view items that are in the layout, in button space. + * Updated as part of #UI_block_end(), before that it's unset. + */ + std::optional get_bounds() const; protected: AbstractView() = default; @@ -225,35 +252,12 @@ class AbstractViewItemDragController { * when dragging over this item. An item can return a drop controller for itself via a custom * implementation of #AbstractViewItem::create_drop_controller(). */ -class AbstractViewItemDropController { +class AbstractViewItemDropController : public DropControllerInterface { protected: AbstractView &view_; public: AbstractViewItemDropController(AbstractView &view); - virtual ~AbstractViewItemDropController() = default; - - /** - * Check if the data dragged with \a drag can be dropped on the item this controller is for. - * \param r_disabled_hint: Return a static string to display to the user, explaining why dropping - * isn't possible on this item. 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; - /** - * Custom text to display when dragging over a view item. Should explain what happens when - * dropping the data onto this item. Will only be used if #AbstractViewItem::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 wmDrag &drag) const = 0; - /** - * Execute the logic to apply a drop of the data dragged with \a drag onto/into the item this - * controller is for. - */ - virtual bool on_drop(struct bContext *C, const wmDrag &drag) = 0; /** Request the view the item is registered for as type #ViewType. Throws a `std::bad_cast` * exception if the view is not of the requested type. */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 0ad39f8c05f..4759afe24a2 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -3274,18 +3274,12 @@ void UI_view_item_context_menu_build(struct bContext *C, * \return True if dragging started successfully, otherwise false. */ bool UI_view_item_drag_start(struct bContext *C, const uiViewItemHandle *item_); -bool UI_view_item_can_drop(const uiViewItemHandle *item_, - const struct wmDrag *drag, - const char **r_disabled_hint); -char *UI_view_item_drop_tooltip(const uiViewItemHandle *item, const struct wmDrag *drag); -/** - * Let a view item handle a drop event. - * \return True if the drop was handled by the view item. - */ -bool UI_view_item_drop_handle(struct bContext *C, - const uiViewItemHandle *item_, - const struct ListBase *drags); +/** + * \param xy: Coordinate to find a view item at, in window space. + * \param pad: Extra padding added to the bounding box of the view. + */ +uiViewHandle *UI_region_view_find_at(const struct ARegion *region, const int xy[2], int pad); /** * \param xy: Coordinate to find a view item at, in window space. */ diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index 147b48b454e..d9a46904829 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -18,11 +18,17 @@ namespace blender::nodes::geo_eval_log { struct GeometryAttributeInfo; } +struct ARegion; +struct bContext; struct PointerRNA; struct StructRNA; struct uiBlock; +struct uiLayout; struct uiList; struct uiSearchItems; +struct uiViewHandle; +struct uiViewItemHandle; +struct wmDrag; namespace blender::ui { @@ -54,6 +60,39 @@ void attribute_search_add_items(StringRefNull str, uiSearchItems *items, bool is_first); +/** + * Interface class to implement dropping for various kinds of UI elements. This isn't used widely, + * only UI views and view items use it. Would probably be nice to have more general support for + * dropping this way. + */ +class DropControllerInterface { + public: + DropControllerInterface() = default; + virtual ~DropControllerInterface() = default; + + /** + * Check if the data dragged with \a drag can be dropped on the element this controller 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; + /** + * Custom text to display when dragging over the element using this drop controller. Should + * explain what happens when dropping the data onto this UI element. Will only be used if + * #DropControllerInterface::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 wmDrag &drag) const = 0; + /** + * Execute the logic to apply a drop of the data dragged with \a drag onto/into the UI element + * this controller is for. + */ + virtual bool on_drop(bContext *C, const wmDrag &drag) const = 0; +}; + } // namespace blender::ui enum eUIListFilterResult { @@ -110,6 +149,33 @@ void UI_list_filter_and_sort_items(uiList *ui_list, const char *propname, uiListItemGetNameFn get_name_fn = nullptr); +std::unique_ptr UI_view_drop_controller( + const uiViewHandle *view_handle); +std::unique_ptr UI_view_item_drop_controller( + const uiViewItemHandle *item_handle); + +/** + * Let a drop controller handle a drop event. + * \return True if the dropping was successful. + */ +bool UI_drop_controller_apply_drop(bContext &C, + const blender::ui::DropControllerInterface &drop_controller, + const ListBase &drags); +/** + * Call #DropControllerInterface::drop_tooltip() and return the result as newly allocated C string + * (unless the result is empty, returns null then). Needs freeing with MEM_freeN(). + */ +char *UI_drop_controller_drop_tooltip(const blender::ui::DropControllerInterface &drop_controller, + const wmDrag &drag); + +/** + * Try to find a view item with a drop controller under the mouse cursor, or if not found, a view + * with a drop controller. + * \param xy: Coordinate to find a drop controller at, in window space. + */ +std::unique_ptr UI_region_views_find_drop_controller_at( + const ARegion *region, const int xy[2]); + /** * Override this for all available view types. */ diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 5ecf4c59ed8..c3ca44ceb3c 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -46,6 +46,7 @@ set(SRC interface_context_path.cc interface_drag.cc interface_draw.cc + interface_drop.cc interface_dropboxes.cc interface_handlers.cc interface_icons.cc diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index 6f593c74fb9..6a0c2757eb9 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -2014,6 +2014,8 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x break; } + ui_block_views_bounds_calc(block); + if (block->rect.xmin == 0.0f && block->rect.xmax == 0.0f) { UI_block_bounds_set_normal(block, 0); } diff --git a/source/blender/editors/interface/interface_drop.cc b/source/blender/editors/interface/interface_drop.cc new file mode 100644 index 00000000000..a63df1fb364 --- /dev/null +++ b/source/blender/editors/interface/interface_drop.cc @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edinterface + */ + +#include "UI_interface.hh" + +using namespace blender::ui; + +bool UI_drop_controller_apply_drop(bContext &C, + const DropControllerInterface &drop_controller, + const ListBase &drags) +{ + + const char *disabled_hint_dummy = nullptr; + LISTBASE_FOREACH (const wmDrag *, drag, &drags) { + if (drop_controller.can_drop(*drag, &disabled_hint_dummy)) { + return drop_controller.on_drop(&C, *drag); + } + } + + return false; +} + +char *UI_drop_controller_drop_tooltip(const DropControllerInterface &drop_controller, + const wmDrag &drag) +{ + const std::string tooltip = drop_controller.drop_tooltip(drag); + return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str()); +} diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc index 60e1c0abfa1..d22e6ea8e30 100644 --- a/source/blender/editors/interface/interface_dropboxes.cc +++ b/source/blender/editors/interface/interface_dropboxes.cc @@ -20,6 +20,9 @@ #include "WM_api.h" #include "UI_interface.h" +#include "UI_interface.hh" + +using namespace blender::ui; /* -------------------------------------------------------------------- */ /** \name View Drag/Drop Callbacks @@ -28,28 +31,28 @@ static bool ui_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { const ARegion *region = CTX_wm_region(C); - const uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, event->xy); - if (!hovered_item) { + + std::unique_ptr drop_controller = + UI_region_views_find_drop_controller_at(region, event->xy); + if (!drop_controller) { return false; } if (drag->drop_state.free_disabled_info) { MEM_SAFE_FREE(drag->drop_state.disabled_info); } - drag->drop_state.free_disabled_info = false; - return UI_view_item_can_drop(hovered_item, drag, &drag->drop_state.disabled_info); + + return drop_controller->can_drop(*drag, &drag->drop_state.disabled_info); } static char *ui_view_drop_tooltip(bContext *C, wmDrag *drag, const int xy[2], wmDropBox * /*drop*/) { const ARegion *region = CTX_wm_region(C); - const uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, xy); - if (!hovered_item) { - return nullptr; - } + std::unique_ptr drop_controller = + UI_region_views_find_drop_controller_at(region, xy); - return UI_view_item_drop_tooltip(hovered_item, drag); + return UI_drop_controller_drop_tooltip(*drop_controller, *drag); } /** \} */ diff --git a/source/blender/editors/interface/interface_intern.hh b/source/blender/editors/interface/interface_intern.hh index 830cc977d49..ae6f5c9cbce 100644 --- a/source/blender/editors/interface/interface_intern.hh +++ b/source/blender/editors/interface/interface_intern.hh @@ -1452,6 +1452,7 @@ void ui_interface_tag_script_reload_queries(); /* interface_view.cc */ void ui_block_free_views(uiBlock *block); +void ui_block_views_bounds_calc(const uiBlock *block); void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params); uiViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block, const uiViewHandle *new_view); diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc index 604c493c989..59814ee0b72 100644 --- a/source/blender/editors/interface/interface_ops.cc +++ b/source/blender/editors/interface/interface_ops.cc @@ -47,6 +47,7 @@ #include "RNA_types.h" #include "UI_interface.h" +#include "UI_interface.hh" #include "interface_intern.hh" @@ -65,6 +66,8 @@ #include "ED_screen.h" #include "ED_text.h" +using namespace blender::ui; + /* -------------------------------------------------------------------- */ /** \name Immediate redraw helper * @@ -2351,7 +2354,7 @@ static void UI_OT_list_start_filter(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name UI Tree-View Drop Operator +/** \name UI View Drop Operator * \{ */ static bool ui_view_drop_poll(bContext *C) @@ -2361,9 +2364,7 @@ static bool ui_view_drop_poll(bContext *C) if (region == nullptr) { return false; } - const uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, win->eventstate->xy); - - return hovered_item != nullptr; + return UI_region_views_find_drop_controller_at(region, win->eventstate->xy) != nullptr; } static int ui_view_drop_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event) @@ -2373,10 +2374,11 @@ static int ui_view_drop_invoke(bContext *C, wmOperator * /*op*/, const wmEvent * } const ARegion *region = CTX_wm_region(C); - uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, event->xy); + std::unique_ptr drop_controller = + UI_region_views_find_drop_controller_at(region, event->xy); - if (!UI_view_item_drop_handle( - C, hovered_item, static_cast(event->customdata))) { + if (!UI_drop_controller_apply_drop( + *C, *drop_controller, *static_cast(event->customdata))) { return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } @@ -2385,9 +2387,9 @@ static int ui_view_drop_invoke(bContext *C, wmOperator * /*op*/, const wmEvent * static void UI_OT_view_drop(wmOperatorType *ot) { - ot->name = "View drop"; + ot->name = "View Drop"; ot->idname = "UI_OT_view_drop"; - ot->description = "Drag and drop items onto a data-set item"; + ot->description = "Drag and drop onto a data-set or item within the data-set"; ot->invoke = ui_view_drop_invoke; ot->poll = ui_view_drop_poll; diff --git a/source/blender/editors/interface/views/abstract_view.cc b/source/blender/editors/interface/views/abstract_view.cc index 301302d818a..74f7390b8ee 100644 --- a/source/blender/editors/interface/views/abstract_view.cc +++ b/source/blender/editors/interface/views/abstract_view.cc @@ -62,6 +62,12 @@ void AbstractView::update_from_old(uiBlock &new_block) /** \name Default implementations of virtual functions * \{ */ +std::unique_ptr AbstractView::create_drop_controller() const +{ + /* There's no drop controller (and hence no drop support) by default. */ + return nullptr; +} + bool AbstractView::listen(const wmNotifier & /*notifier*/) const { /* Nothing by default. */ @@ -104,6 +110,25 @@ MutableSpan AbstractView::get_rename_buffer() return *rename_buffer_; } +std::optional AbstractView::get_bounds() const +{ + return bounds_; +} + /** \} */ } // namespace blender::ui + +/* ---------------------------------------------------------------------- */ +/** \name C-API + * \{ */ + +using namespace blender::ui; + +std::unique_ptr UI_view_drop_controller(const uiViewHandle *view_handle) +{ + const AbstractView &view = reinterpret_cast(*view_handle); + return view.create_drop_controller(); +} + +/** \} */ diff --git a/source/blender/editors/interface/views/abstract_view_item.cc b/source/blender/editors/interface/views/abstract_view_item.cc index 5e59591dd96..98e9f32bef1 100644 --- a/source/blender/editors/interface/views/abstract_view_item.cc +++ b/source/blender/editors/interface/views/abstract_view_item.cc @@ -264,45 +264,6 @@ class ViewItemAPIWrapper { return true; } - - static bool can_drop(const AbstractViewItem &item, - const wmDrag &drag, - const char **r_disabled_hint) - { - const std::unique_ptr drop_controller = - item.create_drop_controller(); - if (!drop_controller) { - return false; - } - - return drop_controller->can_drop(drag, r_disabled_hint); - } - - static std::string drop_tooltip(const AbstractViewItem &item, const wmDrag &drag) - { - const std::unique_ptr drop_controller = - item.create_drop_controller(); - if (!drop_controller) { - return {}; - } - - return drop_controller->drop_tooltip(drag); - } - - static bool drop_handle(bContext &C, const AbstractViewItem &item, const ListBase &drags) - { - std::unique_ptr drop_controller = - item.create_drop_controller(); - - const char *disabled_hint_dummy = nullptr; - LISTBASE_FOREACH (const wmDrag *, drag, &drags) { - if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) { - return drop_controller->on_drop(&C, *drag); - } - } - - return false; - } }; } // namespace blender::ui @@ -348,26 +309,11 @@ bool UI_view_item_drag_start(bContext *C, const uiViewItemHandle *item_) return ViewItemAPIWrapper::drag_start(*C, item); } -bool UI_view_item_can_drop(const uiViewItemHandle *item_, - const wmDrag *drag, - const char **r_disabled_hint) +std::unique_ptr UI_view_item_drop_controller( + const uiViewItemHandle *item_handle) { - const AbstractViewItem &item = reinterpret_cast(*item_); - return ViewItemAPIWrapper::can_drop(item, *drag, r_disabled_hint); -} - -char *UI_view_item_drop_tooltip(const uiViewItemHandle *item_, const wmDrag *drag) -{ - const AbstractViewItem &item = reinterpret_cast(*item_); - - const std::string tooltip = ViewItemAPIWrapper::drop_tooltip(item, *drag); - return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str()); -} - -bool UI_view_item_drop_handle(bContext *C, const uiViewItemHandle *item_, const ListBase *drags) -{ - const AbstractViewItem &item = reinterpret_cast(*item_); - return ViewItemAPIWrapper::drop_handle(*C, item, *drags); + const AbstractViewItem &item = reinterpret_cast(*item_handle); + return item.create_drop_controller(); } /** \} */ diff --git a/source/blender/editors/interface/views/interface_view.cc b/source/blender/editors/interface/views/interface_view.cc index 9b77f3132e8..b8a440d1eee 100644 --- a/source/blender/editors/interface/views/interface_view.cc +++ b/source/blender/editors/interface/views/interface_view.cc @@ -24,6 +24,7 @@ #include "BKE_screen.h" #include "BLI_listbase.h" +#include "BLI_map.hh" #include "ED_screen.h" @@ -44,6 +45,8 @@ using namespace blender::ui; struct ViewLink : public Link { std::string idname; std::unique_ptr view; + + static void views_bounds_calc(const uiBlock &block); }; template @@ -81,6 +84,51 @@ void ui_block_free_views(uiBlock *block) } } +void ViewLink::views_bounds_calc(const uiBlock &block) +{ + Map views_bounds; + + rcti minmax; + BLI_rcti_init_minmax(&minmax); + LISTBASE_FOREACH (ViewLink *, link, &block.views) { + views_bounds.add(link->view.get(), minmax); + } + + LISTBASE_FOREACH (uiBut *, but, &block.buttons) { + if (but->type != UI_BTYPE_VIEW_ITEM) { + continue; + } + uiButViewItem *view_item_but = static_cast(but); + if (!view_item_but->view_item) { + continue; + } + + /* Get the view from the button. */ + AbstractViewItem &view_item = reinterpret_cast(*view_item_but->view_item); + AbstractView &view = view_item.get_view(); + + rcti &bounds = views_bounds.lookup(&view); + rcti but_rcti{}; + BLI_rcti_rctf_copy_round(&but_rcti, &view_item_but->rect); + BLI_rcti_do_minmax_rcti(&bounds, &but_rcti); + } + + for (const auto item : views_bounds.items()) { + const rcti &bounds = item.value; + if (BLI_rcti_is_empty(&bounds)) { + continue; + } + + AbstractView &view = *item.key; + view.bounds_ = bounds; + } +} + +void ui_block_views_bounds_calc(const uiBlock *block) +{ + ViewLink::views_bounds_calc(*block); +} + void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params) { ARegion *region = listener_params->region; @@ -92,6 +140,35 @@ void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *l } } +/* Similar to #ui_but_find_mouse_over_ex(). */ +uiViewHandle *UI_region_view_find_at(const ARegion *region, const int xy[2], const int pad) +{ + if (!ui_region_contains_point_px(region, xy)) { + return nullptr; + } + LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { + float mx = xy[0], my = xy[1]; + ui_window_to_block_fl(region, block, &mx, &my); + + LISTBASE_FOREACH (ViewLink *, view_link, &block->views) { + std::optional bounds = view_link->view->get_bounds(); + if (!bounds) { + continue; + } + + rcti padded_bounds = *bounds; + if (pad) { + BLI_rcti_pad(&padded_bounds, pad, pad); + } + if (BLI_rcti_isect_pt(&padded_bounds, mx, my)) { + return reinterpret_cast(view_link->view.get()); + } + } + } + + return nullptr; +} + uiViewItemHandle *UI_region_views_find_item_at(const ARegion *region, const int xy[2]) { uiButViewItem *item_but = (uiButViewItem *)ui_view_item_find_mouse_over(region, xy); @@ -112,6 +189,32 @@ uiViewItemHandle *UI_region_views_find_active_item(const ARegion *region) return item_but->view_item; } +std::unique_ptr UI_region_views_find_drop_controller_at( + const ARegion *region, const int xy[2]) +{ + const uiViewItemHandle *hovered_view_item = UI_region_views_find_item_at(region, xy); + if (hovered_view_item) { + std::unique_ptr drop_controller = UI_view_item_drop_controller( + hovered_view_item); + if (drop_controller) { + return drop_controller; + } + } + + /* Get style for some sensible padding around the view items. */ + const uiStyle *style = UI_style_get_dpi(); + const uiViewHandle *hovered_view = UI_region_view_find_at(region, xy, style->buttonspacex); + if (hovered_view) { + std::unique_ptr drop_controller = UI_view_drop_controller( + hovered_view); + if (drop_controller) { + return drop_controller; + } + } + + return nullptr; +} + static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractView &view) { /* First get the idname the of the view we're looking for. */ diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index 535121ab252..3b13f1d1286 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -113,7 +113,7 @@ class AssetCatalogDropController : public ui::AbstractViewItemDropController { bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override; std::string drop_tooltip(const wmDrag &drag) const override; - bool on_drop(struct bContext *C, const wmDrag &drag) override; + bool on_drop(struct bContext *C, const wmDrag &drag) const override; ::AssetLibrary &get_asset_library() const; @@ -151,7 +151,7 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem { bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override; std::string drop_tooltip(const wmDrag &drag) const override; - bool on_drop(struct bContext *C, const wmDrag &drag) override; + bool on_drop(struct bContext *C, const wmDrag &drag) const override; }; std::unique_ptr create_drop_controller() const override; @@ -165,7 +165,7 @@ class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem { bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override; std::string drop_tooltip(const wmDrag &drag) const override; - bool on_drop(struct bContext *C, const wmDrag &drag) override; + bool on_drop(struct bContext *C, const wmDrag &drag) const override; }; std::unique_ptr create_drop_controller() const override; @@ -429,7 +429,7 @@ std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &dr return basic_tip; } -bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag) +bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag) const { if (drag.type == WM_DRAG_ASSET_CATALOG) { return drop_asset_catalog_into_catalog( @@ -623,7 +623,7 @@ std::string AssetCatalogTreeViewAllItem::DropController::drop_tooltip(const wmDr } bool AssetCatalogTreeViewAllItem::DropController::on_drop(struct bContext * /*C*/, - const wmDrag &drag) + const wmDrag &drag) const { BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG); return AssetCatalogDropController::drop_asset_catalog_into_catalog( @@ -667,7 +667,7 @@ std::string AssetCatalogTreeViewUnassignedItem::DropController::drop_tooltip( } bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(struct bContext *C, - const wmDrag &drag) + const wmDrag &drag) const { /* Assign to nil catalog ID. */ return AssetCatalogDropController::drop_assets_into_catalog( -- 2.30.2 From 232a9a9f10e520f8ddf3327ceb79efa1bcc231b4 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 22 Mar 2023 15:57:22 +0100 Subject: [PATCH 2/5] Rename drop controller -> drop target --- .../editors/include/UI_abstract_view.hh | 42 +++--- .../blender/editors/include/UI_interface.hh | 45 ++++--- .../editors/interface/interface_drop.cc | 15 +-- .../editors/interface/interface_dropboxes.cc | 14 +- .../editors/interface/interface_ops.cc | 10 +- .../editors/interface/views/abstract_view.cc | 8 +- .../interface/views/abstract_view_item.cc | 11 +- .../editors/interface/views/interface_view.cc | 18 ++- .../space_file/asset_catalog_tree_view.cc | 120 +++++++++--------- 9 files changed, 138 insertions(+), 145 deletions(-) diff --git a/source/blender/editors/include/UI_abstract_view.hh b/source/blender/editors/include/UI_abstract_view.hh index 7161d2b4c47..d34c9a67d25 100644 --- a/source/blender/editors/include/UI_abstract_view.hh +++ b/source/blender/editors/include/UI_abstract_view.hh @@ -12,7 +12,7 @@ * - Custom context menus * - Notifier listening * - Drag controllers (dragging view items) - * - Drop controllers (dropping onto/into view items) + * - Drop targets (dropping onto/into view items) */ #pragma once @@ -40,12 +40,12 @@ struct wmNotifier; namespace blender::ui { class AbstractViewItem; -class AbstractViewItemDropController; +class AbstractViewItemDropTarget; class AbstractViewItemDragController; -/** The view drop controller can share logic with the view item drop controller for now, so just an - * alias. */ -using AbstractViewDropController = AbstractViewItemDropController; +/** The view drop target can share logic with the view item drop target for now, so just an alias. + */ +using AbstractViewDropTarget = AbstractViewItemDropTarget; class AbstractView { friend class AbstractViewItem; @@ -68,13 +68,13 @@ class AbstractView { virtual ~AbstractView() = default; /** - * If a view wants to support dropping data into it, it has to return a drop controller here. - * That is an object implementing #AbstractViewDropController. + * If a view wants to support dropping data into it, it has to return a drop target here. + * That is an object implementing #AbstractViewDropTarget. * - * \note This drop controller may be requested for each event. The view doesn't keep a drop - * controller around currently. So it can not contain persistent state. + * \note This drop target may be requested for each event. The view doesn't keep the drop target + * around currently. So it cannot contain persistent state. */ - virtual std::unique_ptr create_drop_controller() const; + virtual std::unique_ptr create_drop_target() const; /** Listen to a notifier, returning true if a redraw is needed. */ virtual bool listen(const wmNotifier &) const; @@ -160,13 +160,13 @@ class AbstractViewItem { */ virtual std::unique_ptr create_drag_controller() const; /** - * If an item wants to support dropping data into it, it has to return a drop controller here. - * That is an object implementing #AbstractViewItemDropController. + * If an item wants to support dropping data into it, it has to return a drop target here. + * That is an object implementing #AbstractViewItemDropTarget. * - * \note This drop controller may be requested for each event. The view doesn't keep a drop - * controller around currently. So it can not contain persistent state. + * \note This drop target may be requested for each event. The view doesn't keep a drop target + * around currently. So it can not contain persistent state. */ - virtual std::unique_ptr create_drop_controller() const; + virtual std::unique_ptr create_drop_target() const; /** Get the view this item is registered for using #AbstractView::register_item(). */ AbstractView &get_view() const; @@ -227,7 +227,7 @@ template ToType *AbstractViewItem::from_item_handle(uiViewItemH * \{ */ /** - * Class to enable dragging a view item. An item can return a drop controller for itself by + * Class to enable dragging a view item. An item can return a drag controller for itself by * implementing #AbstractViewItem::create_drag_controller(). */ class AbstractViewItemDragController { @@ -249,15 +249,15 @@ class AbstractViewItemDragController { /** * Class to define the behavior when dropping something onto/into a view item, plus the behavior - * when dragging over this item. An item can return a drop controller for itself via a custom - * implementation of #AbstractViewItem::create_drop_controller(). + * when dragging over this item. An item can return a drop target for itself via a custom + * implementation of #AbstractViewItem::create_drop_target(). */ -class AbstractViewItemDropController : public DropControllerInterface { +class AbstractViewItemDropTarget : public DropTargetInterface { protected: AbstractView &view_; public: - AbstractViewItemDropController(AbstractView &view); + AbstractViewItemDropTarget(AbstractView &view); /** Request the view the item is registered for as type #ViewType. Throws a `std::bad_cast` * exception if the view is not of the requested type. */ @@ -271,7 +271,7 @@ template ViewType &AbstractViewItemDragController::get_view() co return dynamic_cast(view_); } -template ViewType &AbstractViewItemDropController::get_view() const +template ViewType &AbstractViewItemDropTarget::get_view() const { static_assert(std::is_base_of::value, "Type must derive from and implement the ui::AbstractView interface"); diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index d9a46904829..c9356c71f4c 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -61,17 +61,16 @@ void attribute_search_add_items(StringRefNull str, bool is_first); /** - * Interface class to implement dropping for various kinds of UI elements. This isn't used widely, - * only UI views and view items use it. Would probably be nice to have more general support for - * dropping this way. + * Interface class to implement dropping for various kinds of UI elements. This isn't used widely + * yet, only UI views and view items use it. */ -class DropControllerInterface { +class DropTargetInterface { public: - DropControllerInterface() = default; - virtual ~DropControllerInterface() = default; + DropTargetInterface() = default; + virtual ~DropTargetInterface() = default; /** - * Check if the data dragged with \a drag can be dropped on the element this controller is for. + * 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 @@ -80,15 +79,15 @@ class DropControllerInterface { */ virtual bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const = 0; /** - * Custom text to display when dragging over the element using this drop controller. Should + * 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 - * #DropControllerInterface::can_drop() returns true, so the implementing override doesn't have + * #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 wmDrag &drag) const = 0; /** * Execute the logic to apply a drop of the data dragged with \a drag onto/into the UI element - * this controller is for. + * this drop target is for. */ virtual bool on_drop(bContext *C, const wmDrag &drag) const = 0; }; @@ -149,31 +148,31 @@ void UI_list_filter_and_sort_items(uiList *ui_list, const char *propname, uiListItemGetNameFn get_name_fn = nullptr); -std::unique_ptr UI_view_drop_controller( +std::unique_ptr UI_view_drop_target( const uiViewHandle *view_handle); -std::unique_ptr UI_view_item_drop_controller( +std::unique_ptr UI_view_item_drop_target( const uiViewItemHandle *item_handle); /** - * Let a drop controller handle a drop event. + * Let a drop target handle a drop event. * \return True if the dropping was successful. */ -bool UI_drop_controller_apply_drop(bContext &C, - const blender::ui::DropControllerInterface &drop_controller, - const ListBase &drags); +bool UI_drop_target_apply_drop(bContext &C, + const blender::ui::DropTargetInterface &drop_target, + const ListBase &drags); /** - * Call #DropControllerInterface::drop_tooltip() and return the result as newly allocated C string + * 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(). */ -char *UI_drop_controller_drop_tooltip(const blender::ui::DropControllerInterface &drop_controller, - const wmDrag &drag); +char *UI_drop_target_tooltip(const blender::ui::DropTargetInterface &drop_target, + const wmDrag &drag); /** - * Try to find a view item with a drop controller under the mouse cursor, or if not found, a view - * with a drop controller. - * \param xy: Coordinate to find a drop controller at, in window space. + * 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 UI_region_views_find_drop_controller_at( +std::unique_ptr UI_region_views_find_drop_target_at( const ARegion *region, const int xy[2]); /** diff --git a/source/blender/editors/interface/interface_drop.cc b/source/blender/editors/interface/interface_drop.cc index a63df1fb364..7675936602f 100644 --- a/source/blender/editors/interface/interface_drop.cc +++ b/source/blender/editors/interface/interface_drop.cc @@ -8,24 +8,23 @@ using namespace blender::ui; -bool UI_drop_controller_apply_drop(bContext &C, - const DropControllerInterface &drop_controller, - const ListBase &drags) +bool UI_drop_target_apply_drop(bContext &C, + const DropTargetInterface &drop_target, + const ListBase &drags) { const char *disabled_hint_dummy = nullptr; LISTBASE_FOREACH (const wmDrag *, drag, &drags) { - if (drop_controller.can_drop(*drag, &disabled_hint_dummy)) { - return drop_controller.on_drop(&C, *drag); + if (drop_target.can_drop(*drag, &disabled_hint_dummy)) { + return drop_target.on_drop(&C, *drag); } } return false; } -char *UI_drop_controller_drop_tooltip(const DropControllerInterface &drop_controller, - const wmDrag &drag) +char *UI_drop_target_tooltip(const DropTargetInterface &drop_target, const wmDrag &drag) { - const std::string tooltip = drop_controller.drop_tooltip(drag); + const std::string tooltip = drop_target.drop_tooltip(drag); return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str()); } diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc index d22e6ea8e30..cd62b39c23d 100644 --- a/source/blender/editors/interface/interface_dropboxes.cc +++ b/source/blender/editors/interface/interface_dropboxes.cc @@ -32,9 +32,9 @@ static bool ui_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { const ARegion *region = CTX_wm_region(C); - std::unique_ptr drop_controller = - UI_region_views_find_drop_controller_at(region, event->xy); - if (!drop_controller) { + std::unique_ptr drop_target = UI_region_views_find_drop_target_at( + region, event->xy); + if (!drop_target) { return false; } @@ -43,16 +43,16 @@ static bool ui_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) } drag->drop_state.free_disabled_info = false; - return drop_controller->can_drop(*drag, &drag->drop_state.disabled_info); + return drop_target->can_drop(*drag, &drag->drop_state.disabled_info); } static char *ui_view_drop_tooltip(bContext *C, wmDrag *drag, const int xy[2], wmDropBox * /*drop*/) { const ARegion *region = CTX_wm_region(C); - std::unique_ptr drop_controller = - UI_region_views_find_drop_controller_at(region, xy); + std::unique_ptr drop_target = UI_region_views_find_drop_target_at(region, + xy); - return UI_drop_controller_drop_tooltip(*drop_controller, *drag); + return UI_drop_target_tooltip(*drop_target, *drag); } /** \} */ diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc index 59814ee0b72..bec276c84cb 100644 --- a/source/blender/editors/interface/interface_ops.cc +++ b/source/blender/editors/interface/interface_ops.cc @@ -2364,7 +2364,7 @@ static bool ui_view_drop_poll(bContext *C) if (region == nullptr) { return false; } - return UI_region_views_find_drop_controller_at(region, win->eventstate->xy) != nullptr; + return UI_region_views_find_drop_target_at(region, win->eventstate->xy) != nullptr; } static int ui_view_drop_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event) @@ -2374,11 +2374,11 @@ static int ui_view_drop_invoke(bContext *C, wmOperator * /*op*/, const wmEvent * } const ARegion *region = CTX_wm_region(C); - std::unique_ptr drop_controller = - UI_region_views_find_drop_controller_at(region, event->xy); + std::unique_ptr drop_target = UI_region_views_find_drop_target_at( + region, event->xy); - if (!UI_drop_controller_apply_drop( - *C, *drop_controller, *static_cast(event->customdata))) { + if (!UI_drop_target_apply_drop( + *C, *drop_target, *static_cast(event->customdata))) { return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } diff --git a/source/blender/editors/interface/views/abstract_view.cc b/source/blender/editors/interface/views/abstract_view.cc index 74f7390b8ee..9bab37eba2f 100644 --- a/source/blender/editors/interface/views/abstract_view.cc +++ b/source/blender/editors/interface/views/abstract_view.cc @@ -62,9 +62,9 @@ void AbstractView::update_from_old(uiBlock &new_block) /** \name Default implementations of virtual functions * \{ */ -std::unique_ptr AbstractView::create_drop_controller() const +std::unique_ptr AbstractView::create_drop_target() const { - /* There's no drop controller (and hence no drop support) by default. */ + /* There's no drop target (and hence no drop support) by default. */ return nullptr; } @@ -125,10 +125,10 @@ std::optional AbstractView::get_bounds() const using namespace blender::ui; -std::unique_ptr UI_view_drop_controller(const uiViewHandle *view_handle) +std::unique_ptr UI_view_drop_target(const uiViewHandle *view_handle) { const AbstractView &view = reinterpret_cast(*view_handle); - return view.create_drop_controller(); + return view.create_drop_target(); } /** \} */ diff --git a/source/blender/editors/interface/views/abstract_view_item.cc b/source/blender/editors/interface/views/abstract_view_item.cc index 98e9f32bef1..c7ba1e6190d 100644 --- a/source/blender/editors/interface/views/abstract_view_item.cc +++ b/source/blender/editors/interface/views/abstract_view_item.cc @@ -174,9 +174,9 @@ std::unique_ptr AbstractViewItem::create_drag_co return nullptr; } -std::unique_ptr AbstractViewItem::create_drop_controller() const +std::unique_ptr AbstractViewItem::create_drop_target() const { - /* There's no drop controller (and hence no drop support) by default. */ + /* There's no drop target (and hence no drop support) by default. */ return nullptr; } @@ -189,7 +189,7 @@ void AbstractViewItemDragController::on_drag_start() /* Do nothing by default. */ } -AbstractViewItemDropController::AbstractViewItemDropController(AbstractView &view) : view_(view) +AbstractViewItemDropTarget::AbstractViewItemDropTarget(AbstractView &view) : view_(view) { } @@ -309,11 +309,10 @@ bool UI_view_item_drag_start(bContext *C, const uiViewItemHandle *item_) return ViewItemAPIWrapper::drag_start(*C, item); } -std::unique_ptr UI_view_item_drop_controller( - const uiViewItemHandle *item_handle) +std::unique_ptr UI_view_item_drop_target(const uiViewItemHandle *item_handle) { const AbstractViewItem &item = reinterpret_cast(*item_handle); - return item.create_drop_controller(); + return item.create_drop_target(); } /** \} */ diff --git a/source/blender/editors/interface/views/interface_view.cc b/source/blender/editors/interface/views/interface_view.cc index b8a440d1eee..11b1a1ac671 100644 --- a/source/blender/editors/interface/views/interface_view.cc +++ b/source/blender/editors/interface/views/interface_view.cc @@ -189,15 +189,14 @@ uiViewItemHandle *UI_region_views_find_active_item(const ARegion *region) return item_but->view_item; } -std::unique_ptr UI_region_views_find_drop_controller_at( - const ARegion *region, const int xy[2]) +std::unique_ptr UI_region_views_find_drop_target_at(const ARegion *region, + const int xy[2]) { const uiViewItemHandle *hovered_view_item = UI_region_views_find_item_at(region, xy); if (hovered_view_item) { - std::unique_ptr drop_controller = UI_view_item_drop_controller( - hovered_view_item); - if (drop_controller) { - return drop_controller; + std::unique_ptr drop_target = UI_view_item_drop_target(hovered_view_item); + if (drop_target) { + return drop_target; } } @@ -205,10 +204,9 @@ std::unique_ptr UI_region_views_find_drop_controller_at const uiStyle *style = UI_style_get_dpi(); const uiViewHandle *hovered_view = UI_region_view_find_at(region, xy, style->buttonspacex); if (hovered_view) { - std::unique_ptr drop_controller = UI_view_drop_controller( - hovered_view); - if (drop_controller) { - return drop_controller; + std::unique_ptr drop_target = UI_view_drop_target(hovered_view); + if (drop_target) { + return drop_target; } } diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index 3b13f1d1286..85f36b96f22 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -49,7 +49,7 @@ class AssetCatalogTreeView : public ui::AbstractTreeView { SpaceFile &space_file_; friend class AssetCatalogTreeViewItem; - friend class AssetCatalogDropController; + friend class AssetCatalogDropTarget; friend class AssetCatalogTreeViewAllItem; public: @@ -90,7 +90,7 @@ class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem { /** Add drag support for catalog items. */ std::unique_ptr create_drag_controller() const override; /** Add dropping support for catalog items. */ - std::unique_ptr create_drop_controller() const override; + std::unique_ptr create_drop_target() const override; }; class AssetCatalogDragController : public ui::AbstractViewItemDragController { @@ -105,11 +105,11 @@ class AssetCatalogDragController : public ui::AbstractViewItemDragController { void on_drag_start() override; }; -class AssetCatalogDropController : public ui::AbstractViewItemDropController { +class AssetCatalogDropTarget : public ui::AbstractViewItemDropTarget { AssetCatalogTreeItem &catalog_item_; public: - AssetCatalogDropController(AssetCatalogTreeView &tree_view, AssetCatalogTreeItem &catalog_item); + AssetCatalogDropTarget(AssetCatalogTreeView &tree_view, AssetCatalogTreeItem &catalog_item); bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override; std::string drop_tooltip(const wmDrag &drag) const override; @@ -146,29 +146,29 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem { void build_row(uiLayout &row) override; - struct DropController : public ui::AbstractViewItemDropController { - DropController(AssetCatalogTreeView &tree_view); + struct DropTarget : public ui::AbstractViewItemDropTarget { + DropTarget(AssetCatalogTreeView &tree_view); bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override; std::string drop_tooltip(const wmDrag &drag) const override; bool on_drop(struct bContext *C, const wmDrag &drag) const override; }; - std::unique_ptr create_drop_controller() const override; + std::unique_ptr create_drop_target() const override; }; class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem { using BasicTreeViewItem::BasicTreeViewItem; - struct DropController : public ui::AbstractViewItemDropController { - DropController(AssetCatalogTreeView &tree_view); + struct DropTarget : public ui::AbstractViewItemDropTarget { + DropTarget(AssetCatalogTreeView &tree_view); bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override; std::string drop_tooltip(const wmDrag &drag) const override; bool on_drop(struct bContext *C, const wmDrag &drag) const override; }; - std::unique_ptr create_drop_controller() const override; + std::unique_ptr create_drop_target() const override; }; /* ---------------------------------------------------------------------- */ @@ -339,10 +339,10 @@ bool AssetCatalogTreeViewItem::rename(StringRefNull new_name) return true; } -std::unique_ptr AssetCatalogTreeViewItem:: - create_drop_controller() const +std::unique_ptr AssetCatalogTreeViewItem::create_drop_target() + const { - return std::make_unique( + return std::make_unique( static_cast(get_tree_view()), catalog_item_); } @@ -355,13 +355,13 @@ std::unique_ptr AssetCatalogTreeViewItem:: /* ---------------------------------------------------------------------- */ -AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tree_view, - AssetCatalogTreeItem &catalog_item) - : ui::AbstractViewItemDropController(tree_view), catalog_item_(catalog_item) +AssetCatalogDropTarget::AssetCatalogDropTarget(AssetCatalogTreeView &tree_view, + AssetCatalogTreeItem &catalog_item) + : ui::AbstractViewItemDropTarget(tree_view), catalog_item_(catalog_item) { } -bool AssetCatalogDropController::can_drop(const wmDrag &drag, const char **r_disabled_hint) const +bool AssetCatalogDropTarget::can_drop(const wmDrag &drag, const char **r_disabled_hint) const { if (drag.type == WM_DRAG_ASSET_CATALOG) { const ::AssetLibrary &library = get_asset_library(); @@ -389,7 +389,7 @@ bool AssetCatalogDropController::can_drop(const wmDrag &drag, const char **r_dis return false; } -std::string AssetCatalogDropController::drop_tooltip(const wmDrag &drag) const +std::string AssetCatalogDropTarget::drop_tooltip(const wmDrag &drag) const { if (drag.type == WM_DRAG_ASSET_CATALOG) { return drop_tooltip_asset_catalog(drag); @@ -397,7 +397,7 @@ std::string AssetCatalogDropController::drop_tooltip(const wmDrag &drag) const return drop_tooltip_asset_list(drag); } -std::string AssetCatalogDropController::drop_tooltip_asset_catalog(const wmDrag &drag) const +std::string AssetCatalogDropTarget::drop_tooltip_asset_catalog(const wmDrag &drag) const { BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG); const AssetCatalog *src_catalog = get_drag_catalog(drag, get_asset_library()); @@ -406,7 +406,7 @@ std::string AssetCatalogDropController::drop_tooltip_asset_catalog(const wmDrag TIP_("into") + " '" + catalog_item_.get_name() + "'"; } -std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &drag) const +std::string AssetCatalogDropTarget::drop_tooltip_asset_list(const wmDrag &drag) const { BLI_assert(drag.type == WM_DRAG_ASSET_LIST); @@ -429,7 +429,7 @@ std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &dr return basic_tip; } -bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag) const +bool AssetCatalogDropTarget::on_drop(struct bContext *C, const wmDrag &drag) const { if (drag.type == WM_DRAG_ASSET_CATALOG) { return drop_asset_catalog_into_catalog( @@ -442,7 +442,7 @@ bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag) catalog_item_.get_simple_name()); } -bool AssetCatalogDropController::drop_asset_catalog_into_catalog( +bool AssetCatalogDropTarget::drop_asset_catalog_into_catalog( const wmDrag &drag, AssetCatalogTreeView &tree_view, const std::optional drop_catalog_id) @@ -456,11 +456,11 @@ bool AssetCatalogDropController::drop_asset_catalog_into_catalog( return true; } -bool AssetCatalogDropController::drop_assets_into_catalog(struct bContext *C, - const AssetCatalogTreeView &tree_view, - const wmDrag &drag, - CatalogID catalog_id, - StringRefNull simple_name) +bool AssetCatalogDropTarget::drop_assets_into_catalog(struct bContext *C, + const AssetCatalogTreeView &tree_view, + const wmDrag &drag, + CatalogID catalog_id, + StringRefNull simple_name) { BLI_assert(drag.type == WM_DRAG_ASSET_LIST); const ListBase *asset_drags = WM_drag_asset_list_get(&drag); @@ -491,8 +491,8 @@ bool AssetCatalogDropController::drop_assets_into_catalog(struct bContext *C, return true; } -AssetCatalog *AssetCatalogDropController::get_drag_catalog(const wmDrag &drag, - const ::AssetLibrary &asset_library) +AssetCatalog *AssetCatalogDropTarget::get_drag_catalog(const wmDrag &drag, + const ::AssetLibrary &asset_library) { if (drag.type != WM_DRAG_ASSET_CATALOG) { return nullptr; @@ -504,8 +504,7 @@ AssetCatalog *AssetCatalogDropController::get_drag_catalog(const wmDrag &drag, return catalog_service->find_catalog(catalog_drag->drag_catalog_id); } -bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag, - const char **r_disabled_hint) +bool AssetCatalogDropTarget::has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint) { const ListBase *asset_drags = WM_drag_asset_list_get(&drag); @@ -521,8 +520,8 @@ bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag, return false; } -bool AssetCatalogDropController::can_modify_catalogs(const ::AssetLibrary &library, - const char **r_disabled_hint) +bool AssetCatalogDropTarget::can_modify_catalogs(const ::AssetLibrary &library, + const char **r_disabled_hint) { if (ED_asset_catalogs_read_only(library)) { *r_disabled_hint = "Catalogs cannot be edited in this asset library"; @@ -531,7 +530,7 @@ bool AssetCatalogDropController::can_modify_catalogs(const ::AssetLibrary &libra return true; } -::AssetLibrary &AssetCatalogDropController::get_asset_library() const +::AssetLibrary &AssetCatalogDropTarget::get_asset_library() const { return *get_view().asset_library_; } @@ -580,30 +579,30 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row) RNA_string_set(props, "parent_path", nullptr); } -std::unique_ptr AssetCatalogTreeViewAllItem:: - create_drop_controller() const +std::unique_ptr AssetCatalogTreeViewAllItem::create_drop_target() + const { - return std::make_unique( + return std::make_unique( static_cast(get_tree_view())); } -AssetCatalogTreeViewAllItem::DropController::DropController(AssetCatalogTreeView &tree_view) - : ui::AbstractViewItemDropController(tree_view) +AssetCatalogTreeViewAllItem::DropTarget::DropTarget(AssetCatalogTreeView &tree_view) + : ui::AbstractViewItemDropTarget(tree_view) { } -bool AssetCatalogTreeViewAllItem::DropController::can_drop(const wmDrag &drag, - const char **r_disabled_hint) const +bool AssetCatalogTreeViewAllItem::DropTarget::can_drop(const wmDrag &drag, + const char **r_disabled_hint) const { if (drag.type != WM_DRAG_ASSET_CATALOG) { return false; } ::AssetLibrary &library = *get_view().asset_library_; - if (!AssetCatalogDropController::can_modify_catalogs(library, r_disabled_hint)) { + if (!AssetCatalogDropTarget::can_modify_catalogs(library, r_disabled_hint)) { return false; } - const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(drag, library); + const AssetCatalog *drag_catalog = AssetCatalogDropTarget::get_drag_catalog(drag, library); if (drag_catalog->path.parent() == "") { *r_disabled_hint = "Catalog is already placed at the highest level"; return false; @@ -612,21 +611,21 @@ bool AssetCatalogTreeViewAllItem::DropController::can_drop(const wmDrag &drag, return true; } -std::string AssetCatalogTreeViewAllItem::DropController::drop_tooltip(const wmDrag &drag) const +std::string AssetCatalogTreeViewAllItem::DropTarget::drop_tooltip(const wmDrag &drag) const { BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG); - const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog( + const AssetCatalog *drag_catalog = AssetCatalogDropTarget::get_drag_catalog( drag, *get_view().asset_library_); return std::string(TIP_("Move Catalog")) + " '" + drag_catalog->path.name() + "' " + TIP_("to the top level of the tree"); } -bool AssetCatalogTreeViewAllItem::DropController::on_drop(struct bContext * /*C*/, - const wmDrag &drag) const +bool AssetCatalogTreeViewAllItem::DropTarget::on_drop(struct bContext * /*C*/, + const wmDrag &drag) const { BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG); - return AssetCatalogDropController::drop_asset_catalog_into_catalog( + return AssetCatalogDropTarget::drop_asset_catalog_into_catalog( drag, get_view(), /* No value to drop into the root level. */ @@ -635,29 +634,28 @@ bool AssetCatalogTreeViewAllItem::DropController::on_drop(struct bContext * /*C* /* ---------------------------------------------------------------------- */ -std::unique_ptr AssetCatalogTreeViewUnassignedItem:: - create_drop_controller() const +std::unique_ptr AssetCatalogTreeViewUnassignedItem:: + create_drop_target() const { - return std::make_unique( + return std::make_unique( static_cast(get_tree_view())); } -AssetCatalogTreeViewUnassignedItem::DropController::DropController(AssetCatalogTreeView &tree_view) - : ui::AbstractViewItemDropController(tree_view) +AssetCatalogTreeViewUnassignedItem::DropTarget::DropTarget(AssetCatalogTreeView &tree_view) + : ui::AbstractViewItemDropTarget(tree_view) { } -bool AssetCatalogTreeViewUnassignedItem::DropController::can_drop( - const wmDrag &drag, const char **r_disabled_hint) const +bool AssetCatalogTreeViewUnassignedItem::DropTarget::can_drop(const wmDrag &drag, + const char **r_disabled_hint) const { if (drag.type != WM_DRAG_ASSET_LIST) { return false; } - return AssetCatalogDropController::has_droppable_asset(drag, r_disabled_hint); + return AssetCatalogDropTarget::has_droppable_asset(drag, r_disabled_hint); } -std::string AssetCatalogTreeViewUnassignedItem::DropController::drop_tooltip( - const wmDrag &drag) const +std::string AssetCatalogTreeViewUnassignedItem::DropTarget::drop_tooltip(const wmDrag &drag) const { const ListBase *asset_drags = WM_drag_asset_list_get(&drag); const bool is_multiple_assets = !BLI_listbase_is_single(asset_drags); @@ -666,11 +664,11 @@ std::string AssetCatalogTreeViewUnassignedItem::DropController::drop_tooltip( TIP_("Move asset out of any catalog"); } -bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(struct bContext *C, - const wmDrag &drag) const +bool AssetCatalogTreeViewUnassignedItem::DropTarget::on_drop(struct bContext *C, + const wmDrag &drag) const { /* Assign to nil catalog ID. */ - return AssetCatalogDropController::drop_assets_into_catalog( + return AssetCatalogDropTarget::drop_assets_into_catalog( C, get_view(), drag, CatalogID{}); } -- 2.30.2 From a3886ebbbcc86d9ff15e0de3fa801d02ca7c7ec8 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 22 Mar 2023 17:13:05 +0100 Subject: [PATCH 3/5] Move new API functions to blender::ui namespace, remove `UI_` prefix --- .../blender/editors/include/UI_interface.hh | 50 +++++++++---------- .../editors/interface/interface_drop.cc | 12 +++-- .../editors/interface/interface_dropboxes.cc | 6 +-- .../editors/interface/interface_ops.cc | 6 +-- .../editors/interface/views/abstract_view.cc | 10 ++-- .../interface/views/abstract_view_item.cc | 18 ++++--- .../editors/interface/views/interface_view.cc | 12 +++-- 7 files changed, 60 insertions(+), 54 deletions(-) diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index c9356c71f4c..897d0bfa570 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -92,6 +92,29 @@ class DropTargetInterface { virtual bool on_drop(bContext *C, const wmDrag &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 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(). + */ +char *drop_target_tooltip(const DropTargetInterface &drop_target, const wmDrag &drag); + +std::unique_ptr view_drop_target(const uiViewHandle *view_handle); +std::unique_ptr view_item_drop_target(const uiViewItemHandle *item_handle); +/** + * 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 { @@ -148,33 +171,6 @@ void UI_list_filter_and_sort_items(uiList *ui_list, const char *propname, uiListItemGetNameFn get_name_fn = nullptr); -std::unique_ptr UI_view_drop_target( - const uiViewHandle *view_handle); -std::unique_ptr UI_view_item_drop_target( - const uiViewItemHandle *item_handle); - -/** - * Let a drop target handle a drop event. - * \return True if the dropping was successful. - */ -bool UI_drop_target_apply_drop(bContext &C, - const blender::ui::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(). - */ -char *UI_drop_target_tooltip(const blender::ui::DropTargetInterface &drop_target, - const wmDrag &drag); - -/** - * 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 UI_region_views_find_drop_target_at( - const ARegion *region, const int xy[2]); - /** * Override this for all available view types. */ diff --git a/source/blender/editors/interface/interface_drop.cc b/source/blender/editors/interface/interface_drop.cc index 7675936602f..2449565536b 100644 --- a/source/blender/editors/interface/interface_drop.cc +++ b/source/blender/editors/interface/interface_drop.cc @@ -6,11 +6,11 @@ #include "UI_interface.hh" -using namespace blender::ui; +namespace blender::ui { -bool UI_drop_target_apply_drop(bContext &C, - const DropTargetInterface &drop_target, - const ListBase &drags) +bool drop_target_apply_drop(bContext &C, + const DropTargetInterface &drop_target, + const ListBase &drags) { const char *disabled_hint_dummy = nullptr; @@ -23,8 +23,10 @@ bool UI_drop_target_apply_drop(bContext &C, return false; } -char *UI_drop_target_tooltip(const DropTargetInterface &drop_target, const wmDrag &drag) +char *drop_target_tooltip(const DropTargetInterface &drop_target, const wmDrag &drag) { const std::string tooltip = drop_target.drop_tooltip(drag); return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str()); } + +} // namespace blender::ui diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc index cd62b39c23d..2a9cec4ada0 100644 --- a/source/blender/editors/interface/interface_dropboxes.cc +++ b/source/blender/editors/interface/interface_dropboxes.cc @@ -32,7 +32,7 @@ static bool ui_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { const ARegion *region = CTX_wm_region(C); - std::unique_ptr drop_target = UI_region_views_find_drop_target_at( + std::unique_ptr drop_target = region_views_find_drop_target_at( region, event->xy); if (!drop_target) { return false; @@ -49,10 +49,10 @@ static bool ui_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) static char *ui_view_drop_tooltip(bContext *C, wmDrag *drag, const int xy[2], wmDropBox * /*drop*/) { const ARegion *region = CTX_wm_region(C); - std::unique_ptr drop_target = UI_region_views_find_drop_target_at(region, + std::unique_ptr drop_target = region_views_find_drop_target_at(region, xy); - return UI_drop_target_tooltip(*drop_target, *drag); + return drop_target_tooltip(*drop_target, *drag); } /** \} */ diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc index bec276c84cb..202597f5651 100644 --- a/source/blender/editors/interface/interface_ops.cc +++ b/source/blender/editors/interface/interface_ops.cc @@ -2364,7 +2364,7 @@ static bool ui_view_drop_poll(bContext *C) if (region == nullptr) { return false; } - return UI_region_views_find_drop_target_at(region, win->eventstate->xy) != nullptr; + return region_views_find_drop_target_at(region, win->eventstate->xy) != nullptr; } static int ui_view_drop_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event) @@ -2374,10 +2374,10 @@ static int ui_view_drop_invoke(bContext *C, wmOperator * /*op*/, const wmEvent * } const ARegion *region = CTX_wm_region(C); - std::unique_ptr drop_target = UI_region_views_find_drop_target_at( + std::unique_ptr drop_target = region_views_find_drop_target_at( region, event->xy); - if (!UI_drop_target_apply_drop( + if (!drop_target_apply_drop( *C, *drop_target, *static_cast(event->customdata))) { return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } diff --git a/source/blender/editors/interface/views/abstract_view.cc b/source/blender/editors/interface/views/abstract_view.cc index 9bab37eba2f..2968c475360 100644 --- a/source/blender/editors/interface/views/abstract_view.cc +++ b/source/blender/editors/interface/views/abstract_view.cc @@ -117,18 +117,16 @@ std::optional AbstractView::get_bounds() const /** \} */ -} // namespace blender::ui - /* ---------------------------------------------------------------------- */ -/** \name C-API +/** \name General API functions * \{ */ -using namespace blender::ui; - -std::unique_ptr UI_view_drop_target(const uiViewHandle *view_handle) +std::unique_ptr view_drop_target(const uiViewHandle *view_handle) { const AbstractView &view = reinterpret_cast(*view_handle); return view.create_drop_target(); } /** \} */ + +} // namespace blender::ui diff --git a/source/blender/editors/interface/views/abstract_view_item.cc b/source/blender/editors/interface/views/abstract_view_item.cc index c7ba1e6190d..9f7afb03908 100644 --- a/source/blender/editors/interface/views/abstract_view_item.cc +++ b/source/blender/editors/interface/views/abstract_view_item.cc @@ -217,6 +217,18 @@ bool AbstractViewItem::is_active() const /** \} */ +/* ---------------------------------------------------------------------- */ +/** \name General API functions + * \{ */ + +std::unique_ptr view_item_drop_target(const uiViewItemHandle *item_handle) +{ + const AbstractViewItem &item = reinterpret_cast(*item_handle); + return item.create_drop_target(); +} + +/** \} */ + } // namespace blender::ui /* ---------------------------------------------------------------------- */ @@ -309,10 +321,4 @@ bool UI_view_item_drag_start(bContext *C, const uiViewItemHandle *item_) return ViewItemAPIWrapper::drag_start(*C, item); } -std::unique_ptr UI_view_item_drop_target(const uiViewItemHandle *item_handle) -{ - const AbstractViewItem &item = reinterpret_cast(*item_handle); - return item.create_drop_target(); -} - /** \} */ diff --git a/source/blender/editors/interface/views/interface_view.cc b/source/blender/editors/interface/views/interface_view.cc index 11b1a1ac671..62166b6a449 100644 --- a/source/blender/editors/interface/views/interface_view.cc +++ b/source/blender/editors/interface/views/interface_view.cc @@ -189,12 +189,14 @@ uiViewItemHandle *UI_region_views_find_active_item(const ARegion *region) return item_but->view_item; } -std::unique_ptr UI_region_views_find_drop_target_at(const ARegion *region, - const int xy[2]) +namespace blender::ui { + +std::unique_ptr region_views_find_drop_target_at(const ARegion *region, + const int xy[2]) { const uiViewItemHandle *hovered_view_item = UI_region_views_find_item_at(region, xy); if (hovered_view_item) { - std::unique_ptr drop_target = UI_view_item_drop_target(hovered_view_item); + std::unique_ptr drop_target = view_item_drop_target(hovered_view_item); if (drop_target) { return drop_target; } @@ -204,7 +206,7 @@ std::unique_ptr UI_region_views_find_drop_target_at(const A const uiStyle *style = UI_style_get_dpi(); const uiViewHandle *hovered_view = UI_region_view_find_at(region, xy, style->buttonspacex); if (hovered_view) { - std::unique_ptr drop_target = UI_view_drop_target(hovered_view); + std::unique_ptr drop_target = view_drop_target(hovered_view); if (drop_target) { return drop_target; } @@ -213,6 +215,8 @@ std::unique_ptr UI_region_views_find_drop_target_at(const A return nullptr; } +} // namespace blender::ui + static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractView &view) { /* First get the idname the of the view we're looking for. */ -- 2.30.2 From 7d7a7e919bb0ce1a82642bfa58ef68048a17d1f8 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 22 Mar 2023 17:47:05 +0100 Subject: [PATCH 4/5] Update `DropTargetInterface` comment --- source/blender/editors/include/UI_interface.hh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index 897d0bfa570..5b1ae4f96b5 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -61,8 +61,13 @@ void attribute_search_add_items(StringRefNull str, bool is_first); /** - * Interface class to implement dropping for various kinds of UI elements. This isn't used widely - * yet, only UI views and view items use it. + * 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. + * + * Note that this is just an interface. A #wmDropBox is needed to request instances of it from a UI + * element and call its functions. Currently only #AbstractView and #AbstractViewItem have this and + * make use of the interface this way. */ class DropTargetInterface { public: -- 2.30.2 From b7c32d844e8d92ae3f094bc0ff5746f5d2b5f9c1 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 22 Mar 2023 18:36:16 +0100 Subject: [PATCH 5/5] Improve `DropTargetInterface` comment some more --- source/blender/editors/include/UI_interface.hh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index 5b1ae4f96b5..eddf2e12cba 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -66,8 +66,9 @@ void attribute_search_add_items(StringRefNull str, * onto itself, provide feedback while dragging and run custom code for the dropping. * * Note that this is just an interface. A #wmDropBox is needed to request instances of it from a UI - * element and call its functions. Currently only #AbstractView and #AbstractViewItem have this and - * make use of the interface this way. + * 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: -- 2.30.2