From d31a0e83936dfe1ff039b248b2c28f5fc56e0d64 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 11 Jul 2023 15:05:17 +0200 Subject: [PATCH] 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 --- .../blender/editors/interface/CMakeLists.txt | 1 + ...rface_template_grease_pencil_layer_tree.cc | 152 ++++++++++++++++-- source/blender/windowmanager/WM_types.h | 5 + .../windowmanager/intern/wm_dragdrop.cc | 1 + 4 files changed, 148 insertions(+), 11 deletions(-) diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 438aa0ece10..d7f08a3472f 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -21,6 +21,7 @@ set(INC ../../render ../../windowmanager ../../../../intern/ghost + ../../../../extern/fmtlib/include ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/interface/interface_template_grease_pencil_layer_tree.cc b/source/blender/editors/interface/interface_template_grease_pencil_layer_tree.cc index 4f40998ec09..e6f07f8e468 100644 --- a/source/blender/editors/interface/interface_template_grease_pencil_layer_tree.cc +++ b/source/blender/editors/interface/interface_template_grease_pencil_layer_tree.cc @@ -18,10 +18,133 @@ #include "RNA_access.h" #include "RNA_prototypes.h" +#include + 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(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(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(__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 create_drag_controller() const override + { + return std::make_unique( + static_cast(get_tree_view()), grease_pencil_, layer_); + } + + std::unique_ptr create_drop_target() override + { + return std::make_unique( + 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 create_drop_target() override + { + return std::make_unique( + 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; diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 3843a6ed565..16c04f8f959 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -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], diff --git a/source/blender/windowmanager/intern/wm_dragdrop.cc b/source/blender/windowmanager/intern/wm_dragdrop.cc index 5d204973f93..b6c64a5a8ad 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.cc +++ b/source/blender/windowmanager/intern/wm_dragdrop.cc @@ -201,6 +201,7 @@ wmDrag *WM_drag_data_create( WM_drag_add_local_ID(drag, static_cast(poin), nullptr); } break; + case WM_DRAG_GREASE_PENCIL_LAYER: case WM_DRAG_ASSET: case WM_DRAG_ASSET_CATALOG: /* Move ownership of poin to wmDrag. */