UI: Basic tree-view drag & drop reordering and inserting support
No user visible changes expected, these are just the internal API preparations. Modifies the Drop API for views so that tree-views can choose to insert items before, after and into other items. Note: While there is support for drag-tooltips that can explain how an item will be inserted, there is no drawing yet like in the Outliner, that indicates if an item is inserted before, after or into. There is some work on that but that can be done separately. Changes: - Removes `AbstractViewDropTarget` that was shared between tree- and grid-views, and adds `AbstractTreeViewDropTarget` and `AbstractGridViewDropTarget`. The tree-view needs specialized handling now, and although they could share some code still, it's not worth having another level of inheritance. - Modifies the drop-target API to use `DragInfo` which contains more info about the dragging operation than just the `wmDrag`. - Adds `determine_drop_location()` to the `DropTargetInterface` which drop targets can use to determine when dropping means inserting before, after or into. - Store the block and region in the view. This is needed unfortunately but shouldn't be an issue since the tree view is recreated on redraws, together with the block. - Various smaller tweaks and additions to views as needed. TODO (outside scope of this change): Increase row height so there is no gap between tree view items, but keep things visually the same otherwise. This reduces flickering while dragging. Pull Request: https://projects.blender.org/blender/blender/pulls/109825
This commit is contained in:
committed by
Julian Eisel
parent
2549272f02
commit
4525527852
@@ -45,14 +45,8 @@ struct wmNotifier;
|
||||
namespace blender::ui {
|
||||
|
||||
class AbstractViewItem;
|
||||
class AbstractViewItemDropTarget;
|
||||
class AbstractViewItemDragController;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
friend struct ::ViewLink;
|
||||
@@ -75,12 +69,12 @@ class AbstractView {
|
||||
|
||||
/**
|
||||
* If a view wants to support dropping data into it, it has to return a drop target here.
|
||||
* That is an object implementing #AbstractViewDropTarget.
|
||||
* That is an object implementing #DropTargetInterface.
|
||||
*
|
||||
* \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<AbstractViewDropTarget> create_drop_target();
|
||||
virtual std::unique_ptr<DropTargetInterface> create_drop_target();
|
||||
|
||||
/** Listen to a notifier, returning true if a redraw is needed. */
|
||||
virtual bool listen(const wmNotifier &) const;
|
||||
@@ -142,7 +136,7 @@ class AbstractViewItem {
|
||||
* If this wasn't done, the behavior of items is undefined.
|
||||
*/
|
||||
AbstractView *view_ = nullptr;
|
||||
/** Every visible item gets a button of type #UI_BTYPE_VIEW_ITEM during the layout building. */
|
||||
/** See #view_item_button() */
|
||||
uiButViewItem *view_item_but_ = nullptr;
|
||||
bool is_activatable_ = true;
|
||||
bool is_interactive_ = true;
|
||||
@@ -183,12 +177,12 @@ class AbstractViewItem {
|
||||
virtual std::unique_ptr<AbstractViewItemDragController> create_drag_controller() const;
|
||||
/**
|
||||
* If an item wants to support dropping data into it, it has to return a drop target here.
|
||||
* That is an object implementing #AbstractViewItemDropTarget.
|
||||
* That is an object implementing #DropTargetInterface.
|
||||
*
|
||||
* \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<AbstractViewItemDropTarget> create_drop_target();
|
||||
virtual std::unique_ptr<DropTargetInterface> create_item_drop_target();
|
||||
|
||||
/** Return the result of #is_filtered_visible(), but ensure the result is cached so it's only
|
||||
* queried once per redraw. */
|
||||
@@ -197,6 +191,13 @@ class AbstractViewItem {
|
||||
/** Get the view this item is registered for using #AbstractView::register_item(). */
|
||||
AbstractView &get_view() const;
|
||||
|
||||
/**
|
||||
* Get the view item button (button of type #UI_BTYPE_VIEW_ITEM) created for this item. Every
|
||||
* visible item gets one during the layout building. Items that are not visible may not have one,
|
||||
* so null is a valid return value.
|
||||
*/
|
||||
uiButViewItem *view_item_button() const;
|
||||
|
||||
/** Disable the interacting with this item, meaning the buttons drawn will be disabled and there
|
||||
* will be no mouse hover feedback for the view row. */
|
||||
void disable_interaction();
|
||||
@@ -286,23 +287,6 @@ class AbstractViewItemDragController {
|
||||
template<class ViewType> inline ViewType &get_view() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 target for itself via a custom
|
||||
* implementation of #AbstractViewItem::create_drop_target().
|
||||
*/
|
||||
class AbstractViewItemDropTarget : public DropTargetInterface {
|
||||
protected:
|
||||
AbstractView &view_;
|
||||
|
||||
public:
|
||||
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. */
|
||||
template<class ViewType> inline ViewType &get_view() const;
|
||||
};
|
||||
|
||||
template<class ViewType> ViewType &AbstractViewItemDragController::get_view() const
|
||||
{
|
||||
static_assert(std::is_base_of<AbstractView, ViewType>::value,
|
||||
@@ -310,13 +294,6 @@ template<class ViewType> ViewType &AbstractViewItemDragController::get_view() co
|
||||
return dynamic_cast<ViewType &>(view_);
|
||||
}
|
||||
|
||||
template<class ViewType> ViewType &AbstractViewItemDropTarget::get_view() const
|
||||
{
|
||||
static_assert(std::is_base_of<AbstractView, ViewType>::value,
|
||||
"Type must derive from and implement the ui::AbstractView interface");
|
||||
return dynamic_cast<ViewType &>(view_);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::ui
|
||||
|
||||
@@ -27,6 +27,7 @@ struct View2D;
|
||||
namespace blender::ui {
|
||||
|
||||
class AbstractGridView;
|
||||
class GridViewItemDropTarget;
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Grid-View Item Type
|
||||
@@ -63,6 +64,9 @@ class AbstractGridViewItem : public AbstractViewItem {
|
||||
*/
|
||||
virtual std::optional<bool> should_be_active() const;
|
||||
|
||||
virtual std::unique_ptr<DropTargetInterface> create_item_drop_target() final;
|
||||
virtual std::unique_ptr<GridViewItemDropTarget> create_drop_target();
|
||||
|
||||
/**
|
||||
* Activates this item, deactivates other items, and calls the
|
||||
* #AbstractGridViewItem::on_activate() function.
|
||||
@@ -156,6 +160,29 @@ class AbstractGridView : public AbstractView {
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Drag & Drop
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* 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 target for itself via a custom
|
||||
* implementation of #AbstractGridViewItem::create_drop_target().
|
||||
*/
|
||||
class GridViewItemDropTarget : public DropTargetInterface {
|
||||
protected:
|
||||
AbstractGridView &view_;
|
||||
|
||||
public:
|
||||
GridViewItemDropTarget(AbstractGridView &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. */
|
||||
template<class ViewType> inline ViewType &get_view() const;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Grid-View Builder
|
||||
*
|
||||
@@ -230,4 +257,11 @@ template<class ItemT, typename... Args> inline ItemT &AbstractGridView::add_item
|
||||
return dynamic_cast<ItemT &>(add_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
|
||||
}
|
||||
|
||||
template<class ViewType> ViewType &GridViewItemDropTarget::get_view() const
|
||||
{
|
||||
static_assert(std::is_base_of<AbstractGridView, ViewType>::value,
|
||||
"Type must derive from and implement the ui::AbstractGridView interface");
|
||||
return dynamic_cast<ViewType &>(view_);
|
||||
}
|
||||
|
||||
} // namespace blender::ui
|
||||
|
||||
@@ -33,6 +33,7 @@ struct uiSearchItems;
|
||||
struct uiViewHandle;
|
||||
struct uiViewItemHandle;
|
||||
struct wmDrag;
|
||||
struct wmEvent;
|
||||
|
||||
void UI_but_func_set(uiBut *but, std::function<void(bContext &)> func);
|
||||
void UI_but_func_pushed_state_set(uiBut *but, std::function<bool(const uiBut &)> func);
|
||||
@@ -41,6 +42,7 @@ namespace blender::ui {
|
||||
|
||||
class AbstractGridView;
|
||||
class AbstractTreeView;
|
||||
class DropTargetInterface;
|
||||
|
||||
/**
|
||||
* An item in a breadcrumb-like context. Currently this struct is very simple, but more
|
||||
@@ -67,15 +69,60 @@ void attribute_search_add_items(StringRefNull str,
|
||||
uiSearchItems *items,
|
||||
bool is_first);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* Note that this is just an interface. 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.
|
||||
* 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:
|
||||
@@ -91,18 +138,31 @@ class DropTargetInterface {
|
||||
* 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<DropLocation> 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 wmDrag &drag) const = 0;
|
||||
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 wmDrag &drag) const = 0;
|
||||
virtual bool on_drop(bContext *C, const DragInfo &drag) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -110,13 +170,18 @@ class DropTargetInterface {
|
||||
* \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().
|
||||
*/
|
||||
char *drop_target_tooltip(const DropTargetInterface &drop_target, const wmDrag &drag);
|
||||
char *drop_target_tooltip(const ARegion ®ion,
|
||||
const DropTargetInterface &drop_target,
|
||||
const wmDrag &drag,
|
||||
const wmEvent &event);
|
||||
|
||||
std::unique_ptr<DropTargetInterface> view_drop_target(uiViewHandle *view_handle);
|
||||
std::unique_ptr<DropTargetInterface> view_item_drop_target(uiViewItemHandle *item_handle);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "DNA_defs.h"
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "UI_abstract_view.hh"
|
||||
@@ -32,6 +33,7 @@ namespace blender::ui {
|
||||
|
||||
class AbstractTreeView;
|
||||
class AbstractTreeViewItem;
|
||||
class TreeViewItemDropTarget;
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Tree-View Item Container
|
||||
@@ -114,6 +116,7 @@ class AbstractTreeView : public AbstractView, public TreeViewItemContainer {
|
||||
|
||||
friend class AbstractTreeViewItem;
|
||||
friend class TreeViewBuilder;
|
||||
friend class TreeViewItemDropTarget;
|
||||
|
||||
public:
|
||||
virtual ~AbstractTreeView() = default;
|
||||
@@ -122,6 +125,11 @@ class AbstractTreeView : public AbstractView, public TreeViewItemContainer {
|
||||
|
||||
void foreach_item(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const;
|
||||
|
||||
/**
|
||||
* \param xy: The mouse coordinates in window space.
|
||||
*/
|
||||
AbstractTreeViewItem *find_hovered(const ARegion ®ion, const int2 &xy);
|
||||
|
||||
/** Visual feature: Define a number of item rows the view will always show at minimum. If there
|
||||
* are fewer items, empty dummy items will be added. These contribute to the view bounds, so the
|
||||
* drop target of the view includes them, but they are not interactive (e.g. no mouse-hover
|
||||
@@ -182,7 +190,15 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
|
||||
|
||||
virtual void build_row(uiLayout &row) = 0;
|
||||
|
||||
virtual std::unique_ptr<DropTargetInterface> create_item_drop_target() final;
|
||||
virtual std::unique_ptr<TreeViewItemDropTarget> create_drop_target();
|
||||
|
||||
AbstractTreeView &get_tree_view() const;
|
||||
/**
|
||||
* Calculate the view item rectangle from its view-item button, converted to window space.
|
||||
* Returns an unset optional if there is no view item button for this item.
|
||||
*/
|
||||
std::optional<rctf> get_win_rect(const ARegion ®ion) const;
|
||||
|
||||
void begin_renaming();
|
||||
void toggle_collapsed();
|
||||
@@ -192,6 +208,7 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
|
||||
* can't be sure about the item state.
|
||||
*/
|
||||
bool is_collapsed() const;
|
||||
bool is_collapsible() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -247,12 +264,9 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
|
||||
* Note that this does a linear lookup in the old block, so isn't too great performance-wise.
|
||||
*/
|
||||
bool is_hovered() const;
|
||||
bool is_collapsible() const;
|
||||
|
||||
void ensure_parents_uncollapsed();
|
||||
|
||||
uiButViewItem *view_item_button() const;
|
||||
|
||||
private:
|
||||
static void tree_row_click_fn(struct bContext *, void *, void *);
|
||||
static void collapse_chevron_click_fn(bContext *, void *but_arg1, void *);
|
||||
@@ -317,6 +331,37 @@ class BasicTreeViewItem : public AbstractTreeViewItem {
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Drag & Drop
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* 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 target for itself via a custom
|
||||
* implementation of #AbstractTreeViewItem::create_drop_target().
|
||||
*
|
||||
* By default the drop target only supports dropping into/onto itself. To support
|
||||
* inserting/reordering behavior, where dropping before or after the drop-target is supported, pass
|
||||
* a different #DropBehavior to the constructor.
|
||||
*/
|
||||
class TreeViewItemDropTarget : public DropTargetInterface {
|
||||
protected:
|
||||
AbstractTreeView &view_;
|
||||
const DropBehavior behavior_;
|
||||
|
||||
public:
|
||||
TreeViewItemDropTarget(AbstractTreeView &view, DropBehavior behavior = DropBehavior::Insert);
|
||||
|
||||
std::optional<DropLocation> choose_drop_location(const ARegion ®ion,
|
||||
const wmEvent &event) const;
|
||||
|
||||
/** 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. */
|
||||
template<class ViewType> inline ViewType &get_view() const;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Tree-View Builder
|
||||
* \{ */
|
||||
@@ -343,4 +388,11 @@ inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
|
||||
add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
|
||||
}
|
||||
|
||||
template<class ViewType> ViewType &TreeViewItemDropTarget::get_view() const
|
||||
{
|
||||
static_assert(std::is_base_of<AbstractTreeView, ViewType>::value,
|
||||
"Type must derive from and implement the ui::AbstractTreeView interface");
|
||||
return dynamic_cast<ViewType &>(view_);
|
||||
}
|
||||
|
||||
} // namespace blender::ui
|
||||
|
||||
@@ -10,24 +10,60 @@
|
||||
|
||||
namespace blender::ui {
|
||||
|
||||
DragInfo::DragInfo(const wmDrag &drag, const wmEvent &event, const DropLocation drop_location)
|
||||
: drag_data(drag), event(event), drop_location(drop_location)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<DropLocation> DropTargetInterface::choose_drop_location(
|
||||
const ARegion & /*region*/, const wmEvent & /*event*/) const
|
||||
{
|
||||
return DropLocation::Into;
|
||||
}
|
||||
|
||||
bool drop_target_apply_drop(bContext &C,
|
||||
const ARegion ®ion,
|
||||
const wmEvent &event,
|
||||
const DropTargetInterface &drop_target,
|
||||
const ListBase &drags)
|
||||
{
|
||||
|
||||
const char *disabled_hint_dummy = nullptr;
|
||||
LISTBASE_FOREACH (const wmDrag *, drag, &drags) {
|
||||
if (drop_target.can_drop(*drag, &disabled_hint_dummy)) {
|
||||
return drop_target.on_drop(&C, *drag);
|
||||
if (!drop_target.can_drop(*drag, &disabled_hint_dummy)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::optional<DropLocation> drop_location = drop_target.choose_drop_location(region,
|
||||
event);
|
||||
if (!drop_location) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const DragInfo drag_info{*drag, event, *drop_location};
|
||||
return drop_target.on_drop(&C, drag_info);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char *drop_target_tooltip(const DropTargetInterface &drop_target, const wmDrag &drag)
|
||||
char *drop_target_tooltip(const ARegion ®ion,
|
||||
const DropTargetInterface &drop_target,
|
||||
const wmDrag &drag,
|
||||
const wmEvent &event)
|
||||
{
|
||||
const std::string tooltip = drop_target.drop_tooltip(drag);
|
||||
const char *disabled_hint_dummy = nullptr;
|
||||
if (!drop_target.can_drop(drag, &disabled_hint_dummy)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::optional<DropLocation> drop_location = drop_target.choose_drop_location(region,
|
||||
event);
|
||||
if (!drop_location) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const DragInfo drag_info{drag, event, *drop_location};
|
||||
const std::string tooltip = drop_target.drop_tooltip(drag_info);
|
||||
return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str());
|
||||
}
|
||||
|
||||
|
||||
@@ -50,10 +50,11 @@ 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 wmWindow *win = CTX_wm_window(C);
|
||||
const ARegion *region = CTX_wm_region(C);
|
||||
std::unique_ptr<DropTargetInterface> drop_target = region_views_find_drop_target_at(region, xy);
|
||||
|
||||
return drop_target_tooltip(*drop_target, *drag);
|
||||
return drop_target_tooltip(*region, *drop_target, *drag, *win->eventstate);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -2404,15 +2404,17 @@ static int ui_view_drop_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *
|
||||
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
const ARegion *region = CTX_wm_region(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
std::unique_ptr<DropTargetInterface> drop_target = region_views_find_drop_target_at(region,
|
||||
event->xy);
|
||||
|
||||
if (!drop_target_apply_drop(*C, *drop_target, *static_cast<const ListBase *>(event->customdata)))
|
||||
if (!drop_target_apply_drop(
|
||||
*C, *region, *event, *drop_target, *static_cast<const ListBase *>(event->customdata)))
|
||||
{
|
||||
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
ED_region_tag_redraw(region);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,12 +35,9 @@ namespace blender::ui::light_linking {
|
||||
|
||||
namespace {
|
||||
|
||||
class CollectionDropTarget : public AbstractViewItemDropTarget {
|
||||
class CollectionDropTarget : public DropTargetInterface {
|
||||
public:
|
||||
CollectionDropTarget(AbstractView &view, Collection &collection)
|
||||
: AbstractViewItemDropTarget(view), collection_(collection)
|
||||
{
|
||||
}
|
||||
CollectionDropTarget(Collection &collection) : collection_(collection) {}
|
||||
|
||||
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override
|
||||
{
|
||||
@@ -64,17 +61,17 @@ class CollectionDropTarget : public AbstractViewItemDropTarget {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string drop_tooltip(const wmDrag & /*drag*/) const override
|
||||
std::string drop_tooltip(const DragInfo & /*drag*/) const override
|
||||
{
|
||||
return TIP_("Add to light linking collection");
|
||||
}
|
||||
|
||||
bool on_drop(struct bContext *C, const wmDrag &drag) const override
|
||||
bool on_drop(struct bContext *C, const DragInfo &drag) const override
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
LISTBASE_FOREACH (wmDragID *, drag_id, &drag.ids) {
|
||||
LISTBASE_FOREACH (wmDragID *, drag_id, &drag.drag_data.ids) {
|
||||
BKE_light_linking_add_receiver_to_collection(
|
||||
bmain, &collection_, drag_id->id, COLLECTION_LIGHT_LINKING_STATE_INCLUDE);
|
||||
}
|
||||
@@ -217,9 +214,9 @@ class CollectionView : public AbstractTreeView {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractViewDropTarget> create_drop_target() override
|
||||
std::unique_ptr<DropTargetInterface> create_drop_target() override
|
||||
{
|
||||
return std::make_unique<CollectionDropTarget>(*this, collection_);
|
||||
return std::make_unique<CollectionDropTarget>(collection_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -66,7 +66,7 @@ void AbstractView::update_from_old(uiBlock &new_block)
|
||||
/** \name Default implementations of virtual functions
|
||||
* \{ */
|
||||
|
||||
std::unique_ptr<AbstractViewDropTarget> AbstractView::create_drop_target()
|
||||
std::unique_ptr<DropTargetInterface> AbstractView::create_drop_target()
|
||||
{
|
||||
/* There's no drop target (and hence no drop support) by default. */
|
||||
return nullptr;
|
||||
|
||||
@@ -197,7 +197,7 @@ std::unique_ptr<AbstractViewItemDragController> AbstractViewItem::create_drag_co
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractViewItemDropTarget> AbstractViewItem::create_drop_target()
|
||||
std::unique_ptr<DropTargetInterface> AbstractViewItem::create_item_drop_target()
|
||||
{
|
||||
/* There's no drop target (and hence no drop support) by default. */
|
||||
return nullptr;
|
||||
@@ -210,8 +210,6 @@ void AbstractViewItemDragController::on_drag_start()
|
||||
/* Do nothing by default. */
|
||||
}
|
||||
|
||||
AbstractViewItemDropTarget::AbstractViewItemDropTarget(AbstractView &view) : view_(view) {}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
@@ -227,6 +225,11 @@ AbstractView &AbstractViewItem::get_view() const
|
||||
return *view_;
|
||||
}
|
||||
|
||||
uiButViewItem *AbstractViewItem::view_item_button() const
|
||||
{
|
||||
return view_item_but_;
|
||||
}
|
||||
|
||||
void AbstractViewItem::disable_activatable()
|
||||
{
|
||||
is_activatable_ = false;
|
||||
@@ -258,7 +261,7 @@ bool AbstractViewItem::is_active() const
|
||||
std::unique_ptr<DropTargetInterface> view_item_drop_target(uiViewItemHandle *item_handle)
|
||||
{
|
||||
AbstractViewItem &item = reinterpret_cast<AbstractViewItem &>(*item_handle);
|
||||
return item.create_drop_target();
|
||||
return item.create_item_drop_target();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -226,6 +226,20 @@ AbstractGridView &AbstractGridViewItem::get_view() const
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
std::unique_ptr<DropTargetInterface> AbstractGridViewItem::create_item_drop_target()
|
||||
{
|
||||
return create_drop_target();
|
||||
}
|
||||
|
||||
std::unique_ptr<GridViewItemDropTarget> AbstractGridViewItem::create_drop_target()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GridViewItemDropTarget::GridViewItemDropTarget(AbstractGridView &view) : view_(view) {}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Helper for only adding layout items for grid items that are actually in view. 3 main functions:
|
||||
* - #is_item_visible(): Query if an item of a given index is visible in the view (others should be
|
||||
|
||||
@@ -78,6 +78,25 @@ void AbstractTreeView::foreach_item(ItemIterFn iter_fn, IterOptions options) con
|
||||
foreach_item_recursive(iter_fn, options);
|
||||
}
|
||||
|
||||
AbstractTreeViewItem *AbstractTreeView::find_hovered(const ARegion ®ion, const int2 &xy)
|
||||
{
|
||||
AbstractTreeViewItem *hovered_item = nullptr;
|
||||
foreach_item_recursive(
|
||||
[&](AbstractTreeViewItem &item) {
|
||||
if (hovered_item) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<rctf> win_rect = item.get_win_rect(region);
|
||||
if (win_rect && BLI_rctf_isect_y(&*win_rect, xy[1])) {
|
||||
hovered_item = &item;
|
||||
}
|
||||
},
|
||||
IterOptions::SkipCollapsed | IterOptions::SkipFiltered);
|
||||
|
||||
return hovered_item;
|
||||
}
|
||||
|
||||
void AbstractTreeView::set_min_rows(int min_rows)
|
||||
{
|
||||
min_rows_ = min_rows;
|
||||
@@ -229,6 +248,56 @@ void AbstractTreeView::change_state_delayed()
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
TreeViewItemDropTarget::TreeViewItemDropTarget(AbstractTreeView &view, DropBehavior behavior)
|
||||
: view_(view), behavior_(behavior)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<DropLocation> TreeViewItemDropTarget::choose_drop_location(
|
||||
const ARegion ®ion, const wmEvent &event) const
|
||||
{
|
||||
if (behavior_ == DropBehavior::Insert) {
|
||||
return DropLocation::Into;
|
||||
}
|
||||
|
||||
const AbstractTreeViewItem *hovered_item = view_.find_hovered(region, event.xy);
|
||||
if (!hovered_item) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<rctf> win_rect = hovered_item->get_win_rect(region);
|
||||
BLI_assert(win_rect.has_value());
|
||||
const float item_height = BLI_rctf_size_y(&*win_rect);
|
||||
|
||||
BLI_assert(ELEM(behavior_, DropBehavior::Reorder, DropBehavior::ReorderAndInsert));
|
||||
|
||||
const int segment_count =
|
||||
(behavior_ == DropBehavior::Reorder) ?
|
||||
/* Divide into upper (insert before) and lower (insert after) half. */
|
||||
2 :
|
||||
/* Upper (insert before), middle (insert into) and lower (insert after) third. */
|
||||
3;
|
||||
const float segment_height = item_height / segment_count;
|
||||
|
||||
if (event.xy[1] - win_rect->ymin > (item_height - segment_height)) {
|
||||
return DropLocation::Before;
|
||||
}
|
||||
if (event.xy[1] - win_rect->ymin <= segment_height) {
|
||||
if (behavior_ == DropBehavior::ReorderAndInsert && hovered_item->is_collapsible() &&
|
||||
!hovered_item->is_collapsed())
|
||||
{
|
||||
/* Special case: Dropping at the lower 3rd of an uncollapsed item should insert into it, not
|
||||
* after. */
|
||||
return DropLocation::Into;
|
||||
}
|
||||
return DropLocation::After;
|
||||
}
|
||||
|
||||
BLI_assert(behavior_ == DropBehavior::ReorderAndInsert);
|
||||
return DropLocation::Into;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void AbstractTreeViewItem::tree_row_click_fn(bContext * /*C*/, void *but_arg1, void * /*arg2*/)
|
||||
{
|
||||
uiButViewItem *item_but = (uiButViewItem *)but_arg1;
|
||||
@@ -388,11 +457,34 @@ bool AbstractTreeViewItem::matches_single(const AbstractTreeViewItem &other) con
|
||||
return label_ == other.label_;
|
||||
}
|
||||
|
||||
std::unique_ptr<DropTargetInterface> AbstractTreeViewItem::create_item_drop_target()
|
||||
{
|
||||
return create_drop_target();
|
||||
}
|
||||
|
||||
std::unique_ptr<TreeViewItemDropTarget> AbstractTreeViewItem::create_drop_target()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AbstractTreeView &AbstractTreeViewItem::get_tree_view() const
|
||||
{
|
||||
return dynamic_cast<AbstractTreeView &>(get_view());
|
||||
}
|
||||
|
||||
std::optional<rctf> AbstractTreeViewItem::get_win_rect(const ARegion ®ion) const
|
||||
{
|
||||
uiButViewItem *item_but = view_item_button();
|
||||
if (!item_but) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
rctf win_rect;
|
||||
ui_block_to_window_rctf(®ion, item_but->block, &win_rect, &item_but->rect);
|
||||
|
||||
return win_rect;
|
||||
}
|
||||
|
||||
int AbstractTreeViewItem::count_parents() const
|
||||
{
|
||||
int i = 0;
|
||||
@@ -499,11 +591,6 @@ bool AbstractTreeViewItem::matches(const AbstractViewItem &other) const
|
||||
return true;
|
||||
}
|
||||
|
||||
uiButViewItem *AbstractTreeViewItem::view_item_button() const
|
||||
{
|
||||
return view_item_but_;
|
||||
}
|
||||
|
||||
void AbstractTreeViewItem::change_state_delayed()
|
||||
{
|
||||
const std::optional<bool> should_be_active = this->should_be_active();
|
||||
|
||||
@@ -93,7 +93,7 @@ class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
|
||||
/** Add drag support for catalog items. */
|
||||
std::unique_ptr<ui::AbstractViewItemDragController> create_drag_controller() const override;
|
||||
/** Add dropping support for catalog items. */
|
||||
std::unique_ptr<ui::AbstractViewItemDropTarget> create_drop_target() override;
|
||||
std::unique_ptr<ui::TreeViewItemDropTarget> create_drop_target() override;
|
||||
};
|
||||
|
||||
class AssetCatalogDragController : public ui::AbstractViewItemDragController {
|
||||
@@ -108,15 +108,15 @@ class AssetCatalogDragController : public ui::AbstractViewItemDragController {
|
||||
void on_drag_start() override;
|
||||
};
|
||||
|
||||
class AssetCatalogDropTarget : public ui::AbstractViewItemDropTarget {
|
||||
class AssetCatalogDropTarget : public ui::TreeViewItemDropTarget {
|
||||
AssetCatalogTreeItem &catalog_item_;
|
||||
|
||||
public:
|
||||
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;
|
||||
bool on_drop(bContext *C, const wmDrag &drag) const override;
|
||||
std::string drop_tooltip(const ui::DragInfo &drag_info) const override;
|
||||
bool on_drop(bContext *C, const ui::DragInfo &drag_info) const override;
|
||||
|
||||
::AssetLibrary &get_asset_library() const;
|
||||
|
||||
@@ -149,29 +149,29 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
|
||||
|
||||
void build_row(uiLayout &row) override;
|
||||
|
||||
struct DropTarget : public ui::AbstractViewItemDropTarget {
|
||||
struct DropTarget : public ui::TreeViewItemDropTarget {
|
||||
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(bContext *C, const wmDrag &drag) const override;
|
||||
std::string drop_tooltip(const ui::DragInfo &drag_info) const override;
|
||||
bool on_drop(bContext *C, const ui::DragInfo &drag_info) const override;
|
||||
};
|
||||
|
||||
std::unique_ptr<ui::AbstractViewItemDropTarget> create_drop_target() override;
|
||||
std::unique_ptr<ui::TreeViewItemDropTarget> create_drop_target() override;
|
||||
};
|
||||
|
||||
class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
|
||||
using BasicTreeViewItem::BasicTreeViewItem;
|
||||
|
||||
struct DropTarget : public ui::AbstractViewItemDropTarget {
|
||||
struct DropTarget : public ui::TreeViewItemDropTarget {
|
||||
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(bContext *C, const wmDrag &drag) const override;
|
||||
std::string drop_tooltip(const ui::DragInfo &drag_info) const override;
|
||||
bool on_drop(bContext *C, const ui::DragInfo &drag_info) const override;
|
||||
};
|
||||
|
||||
std::unique_ptr<ui::AbstractViewItemDropTarget> create_drop_target() override;
|
||||
std::unique_ptr<ui::TreeViewItemDropTarget> create_drop_target() override;
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
@@ -342,7 +342,7 @@ bool AssetCatalogTreeViewItem::rename(StringRefNull new_name)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<ui::AbstractViewItemDropTarget> AssetCatalogTreeViewItem::create_drop_target()
|
||||
std::unique_ptr<ui::TreeViewItemDropTarget> AssetCatalogTreeViewItem::create_drop_target()
|
||||
{
|
||||
return std::make_unique<AssetCatalogDropTarget>(
|
||||
static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_);
|
||||
@@ -359,7 +359,7 @@ std::unique_ptr<ui::AbstractViewItemDragController> AssetCatalogTreeViewItem::
|
||||
|
||||
AssetCatalogDropTarget::AssetCatalogDropTarget(AssetCatalogTreeView &tree_view,
|
||||
AssetCatalogTreeItem &catalog_item)
|
||||
: ui::AbstractViewItemDropTarget(tree_view), catalog_item_(catalog_item)
|
||||
: ui::TreeViewItemDropTarget(tree_view), catalog_item_(catalog_item)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -385,18 +385,19 @@ bool AssetCatalogDropTarget::can_drop(const wmDrag &drag, const char **r_disable
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (drag.type == WM_DRAG_ASSET_LIST) {
|
||||
return has_droppable_asset(drag, r_disabled_hint);
|
||||
|
||||
if (drag.type == WM_DRAG_ASSET_LIST && has_droppable_asset(drag, r_disabled_hint)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string AssetCatalogDropTarget::drop_tooltip(const wmDrag &drag) const
|
||||
std::string AssetCatalogDropTarget::drop_tooltip(const ui::DragInfo &drag_info) const
|
||||
{
|
||||
if (drag.type == WM_DRAG_ASSET_CATALOG) {
|
||||
return drop_tooltip_asset_catalog(drag);
|
||||
if (drag_info.drag_data.type == WM_DRAG_ASSET_CATALOG) {
|
||||
return drop_tooltip_asset_catalog(drag_info.drag_data);
|
||||
}
|
||||
return drop_tooltip_asset_list(drag);
|
||||
return drop_tooltip_asset_list(drag_info.drag_data);
|
||||
}
|
||||
|
||||
std::string AssetCatalogDropTarget::drop_tooltip_asset_catalog(const wmDrag &drag) const
|
||||
@@ -432,15 +433,15 @@ std::string AssetCatalogDropTarget::drop_tooltip_asset_list(const wmDrag &drag)
|
||||
return basic_tip;
|
||||
}
|
||||
|
||||
bool AssetCatalogDropTarget::on_drop(bContext *C, const wmDrag &drag) const
|
||||
bool AssetCatalogDropTarget::on_drop(bContext *C, const ui::DragInfo &drag) const
|
||||
{
|
||||
if (drag.type == WM_DRAG_ASSET_CATALOG) {
|
||||
if (drag.drag_data.type == WM_DRAG_ASSET_CATALOG) {
|
||||
return drop_asset_catalog_into_catalog(
|
||||
drag, get_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
|
||||
drag.drag_data, get_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
|
||||
}
|
||||
return drop_assets_into_catalog(C,
|
||||
get_view<AssetCatalogTreeView>(),
|
||||
drag,
|
||||
drag.drag_data,
|
||||
catalog_item_.get_catalog_id(),
|
||||
catalog_item_.get_simple_name());
|
||||
}
|
||||
@@ -582,14 +583,14 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
|
||||
RNA_string_set(props, "parent_path", nullptr);
|
||||
}
|
||||
|
||||
std::unique_ptr<ui::AbstractViewItemDropTarget> AssetCatalogTreeViewAllItem::create_drop_target()
|
||||
std::unique_ptr<ui::TreeViewItemDropTarget> AssetCatalogTreeViewAllItem::create_drop_target()
|
||||
{
|
||||
return std::make_unique<AssetCatalogTreeViewAllItem::DropTarget>(
|
||||
static_cast<AssetCatalogTreeView &>(get_tree_view()));
|
||||
}
|
||||
|
||||
AssetCatalogTreeViewAllItem::DropTarget::DropTarget(AssetCatalogTreeView &tree_view)
|
||||
: ui::AbstractViewItemDropTarget(tree_view)
|
||||
: ui::TreeViewItemDropTarget(tree_view)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -613,21 +614,23 @@ bool AssetCatalogTreeViewAllItem::DropTarget::can_drop(const wmDrag &drag,
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string AssetCatalogTreeViewAllItem::DropTarget::drop_tooltip(const wmDrag &drag) const
|
||||
std::string AssetCatalogTreeViewAllItem::DropTarget::drop_tooltip(
|
||||
const ui::DragInfo &drag_info) const
|
||||
{
|
||||
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
|
||||
BLI_assert(drag_info.drag_data.type == WM_DRAG_ASSET_CATALOG);
|
||||
const AssetCatalog *drag_catalog = AssetCatalogDropTarget::get_drag_catalog(
|
||||
drag, *get_view<AssetCatalogTreeView>().asset_library_);
|
||||
drag_info.drag_data, *get_view<AssetCatalogTreeView>().asset_library_);
|
||||
|
||||
return fmt::format(TIP_("Move catalog {} to the top level of the tree"),
|
||||
std::string_view(drag_catalog->path.name()));
|
||||
}
|
||||
|
||||
bool AssetCatalogTreeViewAllItem::DropTarget::on_drop(bContext * /*C*/, const wmDrag &drag) const
|
||||
bool AssetCatalogTreeViewAllItem::DropTarget::on_drop(bContext * /*C*/,
|
||||
const ui::DragInfo &drag) const
|
||||
{
|
||||
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
|
||||
BLI_assert(drag.drag_data.type == WM_DRAG_ASSET_CATALOG);
|
||||
return AssetCatalogDropTarget::drop_asset_catalog_into_catalog(
|
||||
drag,
|
||||
drag.drag_data,
|
||||
get_view<AssetCatalogTreeView>(),
|
||||
/* No value to drop into the root level. */
|
||||
std::nullopt);
|
||||
@@ -635,7 +638,7 @@ bool AssetCatalogTreeViewAllItem::DropTarget::on_drop(bContext * /*C*/, const wm
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
std::unique_ptr<ui::AbstractViewItemDropTarget> AssetCatalogTreeViewUnassignedItem::
|
||||
std::unique_ptr<ui::TreeViewItemDropTarget> AssetCatalogTreeViewUnassignedItem::
|
||||
create_drop_target()
|
||||
{
|
||||
return std::make_unique<AssetCatalogTreeViewUnassignedItem::DropTarget>(
|
||||
@@ -643,7 +646,7 @@ std::unique_ptr<ui::AbstractViewItemDropTarget> AssetCatalogTreeViewUnassignedIt
|
||||
}
|
||||
|
||||
AssetCatalogTreeViewUnassignedItem::DropTarget::DropTarget(AssetCatalogTreeView &tree_view)
|
||||
: ui::AbstractViewItemDropTarget(tree_view)
|
||||
: ui::TreeViewItemDropTarget(tree_view)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -656,20 +659,22 @@ bool AssetCatalogTreeViewUnassignedItem::DropTarget::can_drop(const wmDrag &drag
|
||||
return AssetCatalogDropTarget::has_droppable_asset(drag, r_disabled_hint);
|
||||
}
|
||||
|
||||
std::string AssetCatalogTreeViewUnassignedItem::DropTarget::drop_tooltip(const wmDrag &drag) const
|
||||
std::string AssetCatalogTreeViewUnassignedItem::DropTarget::drop_tooltip(
|
||||
const ui::DragInfo &drag_info) const
|
||||
{
|
||||
const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
|
||||
const ListBase *asset_drags = WM_drag_asset_list_get(&drag_info.drag_data);
|
||||
const bool is_multiple_assets = !BLI_listbase_is_single(asset_drags);
|
||||
|
||||
return is_multiple_assets ? TIP_("Move assets out of any catalog") :
|
||||
TIP_("Move asset out of any catalog");
|
||||
}
|
||||
|
||||
bool AssetCatalogTreeViewUnassignedItem::DropTarget::on_drop(bContext *C, const wmDrag &drag) const
|
||||
bool AssetCatalogTreeViewUnassignedItem::DropTarget::on_drop(bContext *C,
|
||||
const ui::DragInfo &drag) const
|
||||
{
|
||||
/* Assign to nil catalog ID. */
|
||||
return AssetCatalogDropTarget::drop_assets_into_catalog(
|
||||
C, get_view<AssetCatalogTreeView>(), drag, CatalogID{});
|
||||
C, get_view<AssetCatalogTreeView>(), drag.drag_data, CatalogID{});
|
||||
}
|
||||
|
||||
} // namespace blender::ed::asset_browser
|
||||
|
||||
Reference in New Issue
Block a user