GPv3: Drag & drop reordering & inserting in the layer tree UI
Note: Change applies to Grease Pencil 3.0 only (experimental feature). Enables use of drag & drop to reorder grease pencil layers through the layer tree UI, as well as inserting layers into groups. This is an intuitive and often requested method of managing such data-structures. Visual feedback should be improved still, and the gap between items be removed, to reduce flickering while dragging. These are general improvements for tree views however which should be done separately. There is no support yet for dragging layer groups, this requires further changes in the internal grease pencil APIs. #109825 introduced the necessary drag & drop support for tree views, #109824 prepared the internal grease pencil API for it. Pull Request: https://projects.blender.org/blender/blender/pulls/109826
This commit is contained in:
committed by
Julian Eisel
parent
3757ec7ee8
commit
d31a0e8393
@@ -21,6 +21,7 @@ set(INC
|
||||
../../render
|
||||
../../windowmanager
|
||||
../../../../intern/ghost
|
||||
../../../../extern/fmtlib/include
|
||||
../../bmesh
|
||||
# RNA_prototypes.h
|
||||
${CMAKE_BINARY_DIR}/source/blender/makesrna
|
||||
|
||||
@@ -18,10 +18,133 @@
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace blender::ui::greasepencil {
|
||||
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
class LayerTreeView : public AbstractTreeView {
|
||||
public:
|
||||
explicit LayerTreeView(GreasePencil &grease_pencil) : grease_pencil_(grease_pencil) {}
|
||||
|
||||
void build_tree() override;
|
||||
|
||||
private:
|
||||
void build_tree_node_recursive(TreeViewOrItem &parent, TreeNode &node);
|
||||
GreasePencil &grease_pencil_;
|
||||
};
|
||||
|
||||
class LayerNodeDropTarget : public TreeViewItemDropTarget {
|
||||
TreeNode &drop_tree_node_;
|
||||
|
||||
public:
|
||||
LayerNodeDropTarget(AbstractTreeView &view, TreeNode &drop_tree_node, DropBehavior behavior)
|
||||
: TreeViewItemDropTarget(view, behavior), drop_tree_node_(drop_tree_node)
|
||||
{
|
||||
}
|
||||
|
||||
bool can_drop(const wmDrag &drag, const char ** /*r_disabled_hint*/) const override
|
||||
{
|
||||
return drag.type == WM_DRAG_GREASE_PENCIL_LAYER;
|
||||
}
|
||||
|
||||
std::string drop_tooltip(const DragInfo &drag_info) const override
|
||||
{
|
||||
const wmDragGreasePencilLayer *drag_grease_pencil =
|
||||
static_cast<const wmDragGreasePencilLayer *>(drag_info.drag_data.poin);
|
||||
Layer &drag_layer = drag_grease_pencil->layer->wrap();
|
||||
|
||||
std::string_view drag_name = drag_layer.name();
|
||||
std::string_view drop_name = drop_tree_node_.name;
|
||||
|
||||
switch (drag_info.drop_location) {
|
||||
case DropLocation::Into:
|
||||
return fmt::format(TIP_("Move layer {} into {}"), drag_name, drop_name);
|
||||
case DropLocation::Before:
|
||||
return fmt::format(TIP_("Move layer {} above {}"), drag_name, drop_name);
|
||||
case DropLocation::After:
|
||||
return fmt::format(TIP_("Move layer {} below {}"), drag_name, drop_name);
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
bool on_drop(struct bContext * /*C*/, const DragInfo &drag_info) const override
|
||||
{
|
||||
const wmDragGreasePencilLayer *drag_grease_pencil =
|
||||
static_cast<const wmDragGreasePencilLayer *>(drag_info.drag_data.poin);
|
||||
Layer &drag_layer = drag_grease_pencil->layer->wrap();
|
||||
|
||||
LayerGroup &drag_parent = drag_layer.parent_group();
|
||||
LayerGroup *drop_parent_group = drop_tree_node_.parent_group();
|
||||
if (!drop_parent_group) {
|
||||
/* Root node is not added to the tree view, so there should never be a drop target for this.
|
||||
*/
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (drag_info.drop_location) {
|
||||
case DropLocation::Into: {
|
||||
BLI_assert_msg(drop_tree_node_.is_group(),
|
||||
"Inserting should not be possible for layers, only for groups, because "
|
||||
"only groups use DropBehavior::Reorder_and_Insert");
|
||||
|
||||
LayerGroup &drop_group = drop_tree_node_.as_group_for_write();
|
||||
drag_parent.unlink_node(&drag_layer.as_node());
|
||||
drop_group.add_layer(&drag_layer);
|
||||
return true;
|
||||
}
|
||||
case DropLocation::Before:
|
||||
drag_parent.unlink_node(&drag_layer.as_node());
|
||||
/* Draw order is inverted, so inserting before means inserting below. */
|
||||
drop_parent_group->add_layer_after(&drag_layer, &drop_tree_node_);
|
||||
return true;
|
||||
case DropLocation::After:
|
||||
drag_parent.unlink_node(&drag_layer.as_node());
|
||||
/* Draw order is inverted, so inserting after means inserting above. */
|
||||
drop_parent_group->add_layer_before(&drag_layer, &drop_tree_node_);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class LayerViewItemDragController : public AbstractViewItemDragController {
|
||||
GreasePencil &grease_pencil_;
|
||||
Layer &dragged_layer_;
|
||||
|
||||
public:
|
||||
LayerViewItemDragController(LayerTreeView &tree_view, GreasePencil &grease_pencil, Layer &layer)
|
||||
: AbstractViewItemDragController(tree_view),
|
||||
grease_pencil_(grease_pencil),
|
||||
dragged_layer_(layer)
|
||||
{
|
||||
}
|
||||
|
||||
eWM_DragDataType get_drag_type() const override
|
||||
{
|
||||
return WM_DRAG_GREASE_PENCIL_LAYER;
|
||||
}
|
||||
|
||||
void *create_drag_data() const override
|
||||
{
|
||||
wmDragGreasePencilLayer *drag_data = MEM_new<wmDragGreasePencilLayer>(__func__);
|
||||
drag_data->layer = &dragged_layer_;
|
||||
return drag_data;
|
||||
}
|
||||
|
||||
void on_drag_start() override
|
||||
{
|
||||
grease_pencil_.set_active_layer(&dragged_layer_);
|
||||
}
|
||||
};
|
||||
|
||||
class LayerViewItem : public AbstractTreeViewItem {
|
||||
public:
|
||||
LayerViewItem(GreasePencil &grease_pencil, Layer &layer)
|
||||
@@ -74,6 +197,18 @@ class LayerViewItem : public AbstractTreeViewItem {
|
||||
return layer_.name();
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractViewItemDragController> create_drag_controller() const override
|
||||
{
|
||||
return std::make_unique<LayerViewItemDragController>(
|
||||
static_cast<LayerTreeView &>(get_tree_view()), grease_pencil_, layer_);
|
||||
}
|
||||
|
||||
std::unique_ptr<TreeViewItemDropTarget> create_drop_target() override
|
||||
{
|
||||
return std::make_unique<LayerNodeDropTarget>(
|
||||
get_tree_view(), layer_.as_node(), DropBehavior::Reorder);
|
||||
}
|
||||
|
||||
private:
|
||||
GreasePencil &grease_pencil_;
|
||||
Layer &layer_;
|
||||
@@ -137,6 +272,12 @@ class LayerGroupViewItem : public AbstractTreeViewItem {
|
||||
return group_.name();
|
||||
}
|
||||
|
||||
std::unique_ptr<TreeViewItemDropTarget> create_drop_target() override
|
||||
{
|
||||
return std::make_unique<LayerNodeDropTarget>(
|
||||
get_tree_view(), group_.as_node(), DropBehavior::ReorderAndInsert);
|
||||
}
|
||||
|
||||
private:
|
||||
GreasePencil &grease_pencil_;
|
||||
LayerGroup &group_;
|
||||
@@ -160,17 +301,6 @@ class LayerGroupViewItem : public AbstractTreeViewItem {
|
||||
}
|
||||
};
|
||||
|
||||
class LayerTreeView : public AbstractTreeView {
|
||||
public:
|
||||
explicit LayerTreeView(GreasePencil &grease_pencil) : grease_pencil_(grease_pencil) {}
|
||||
|
||||
void build_tree() override;
|
||||
|
||||
private:
|
||||
void build_tree_node_recursive(TreeViewOrItem &parent, TreeNode &node);
|
||||
GreasePencil &grease_pencil_;
|
||||
};
|
||||
|
||||
void LayerTreeView::build_tree_node_recursive(TreeViewOrItem &parent, TreeNode &node)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
@@ -1088,6 +1088,7 @@ typedef enum eWM_DragDataType {
|
||||
WM_DRAG_COLOR,
|
||||
WM_DRAG_DATASTACK,
|
||||
WM_DRAG_ASSET_CATALOG,
|
||||
WM_DRAG_GREASE_PENCIL_LAYER,
|
||||
} eWM_DragDataType;
|
||||
|
||||
typedef enum eWM_DragFlags {
|
||||
@@ -1146,6 +1147,10 @@ typedef struct wmDragPath {
|
||||
int file_type; /* eFileSel_File_Types */
|
||||
} wmDragPath;
|
||||
|
||||
typedef struct wmDragGreasePencilLayer {
|
||||
struct GreasePencilLayer *layer;
|
||||
} wmDragGreasePencilLayer;
|
||||
|
||||
typedef char *(*WMDropboxTooltipFunc)(struct bContext *,
|
||||
struct wmDrag *,
|
||||
const int xy[2],
|
||||
|
||||
@@ -201,6 +201,7 @@ wmDrag *WM_drag_data_create(
|
||||
WM_drag_add_local_ID(drag, static_cast<ID *>(poin), nullptr);
|
||||
}
|
||||
break;
|
||||
case WM_DRAG_GREASE_PENCIL_LAYER:
|
||||
case WM_DRAG_ASSET:
|
||||
case WM_DRAG_ASSET_CATALOG:
|
||||
/* Move ownership of poin to wmDrag. */
|
||||
|
||||
Reference in New Issue
Block a user