Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <eiseljulian@gmail.com>2017-03-10 17:03:06 +0300
committerJulian Eisel <eiseljulian@gmail.com>2017-03-10 17:24:53 +0300
commit8e303aae255be2ef45d5818af046de7c22312aa4 (patch)
tree115b700e7b797645a6796dabcc2eae4ac51ed66f
parentb3bb4a6936313a1358428ab95b0df96c93c9cd34 (diff)
Support drag & drop of collections across multiple hierarchy levels
Two issues are remaining, they'll be fixed separately: * Graphical feedback when dragging within the master collection is wrong * There's some bug where collections swap places instead, Dalai will investigate
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c37
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h4
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c115
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c75
4 files changed, 104 insertions, 127 deletions
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 0ba60b21aa7..0b119b5d247 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1520,34 +1520,14 @@ static void outliner_draw_tree_element(
}
}
-/**
- * Count how many visible childs (and open grandchilds, great-grandchilds, ...) \a te has.
- */
-static int outliner_count_visible_childs(const SpaceOops *soops, const TreeElement *te)
-{
- TreeStoreElem *tselem = TREESTORE(te);
- int current_count = 0;
-
- if (TSELEM_OPEN(tselem, soops)) {
- for (TreeElement *te_child = te->subtree.first; te_child; te_child = te_child->next) {
- current_count += outliner_count_visible_childs(soops, te_child);
- current_count++;
- }
- }
-
- return current_count;
-}
-
-static void outliner_draw_tree_element_floating(const SpaceOops *soops, const ARegion *ar,
- const TreeElement *te_floating)
+static void outliner_draw_tree_element_floating(
+ const ARegion *ar, const TreeElement *te_floating)
{
const TreeElement *te_insert = te_floating->drag_data->insert_handle;
- const ListBase *lb_parent = te_floating->parent ? &te_floating->parent->subtree : &soops->tree;
- const TreeElement *te_insert_fallback = te_insert ? te_insert : lb_parent->first;
const int line_width = 2;
unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT);
- int coord_y = (te_insert ? te_insert->ys : (te_insert_fallback->ys + UI_UNIT_Y)) - (int)(line_width * 0.5f);
+ int coord_y = te_insert->ys;
unsigned char col[4];
if (te_insert == te_floating) {
@@ -1555,15 +1535,14 @@ static void outliner_draw_tree_element_floating(const SpaceOops *soops, const AR
return;
}
- if (te_insert) {
- coord_y -= UI_UNIT_Y * outliner_count_visible_childs(soops, te_insert);
- }
-
UI_GetThemeColorShade4ubv(TH_BACK, -40, col);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
glEnable(GL_BLEND);
- if (!te_insert || (te_floating->drag_data->insert_type == TE_INSERT_AFTER)) {
+ if (ELEM(te_floating->drag_data->insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) {
+ if (te_floating->drag_data->insert_type == TE_INSERT_BEFORE) {
+ coord_y += UI_UNIT_Y;
+ }
immUniformColor4ubv(col);
glLineWidth(line_width);
@@ -1793,7 +1772,7 @@ static void outliner_draw_tree(
startx, &starty, te_edit, &te_floating);
}
if (te_floating) {
- outliner_draw_tree_element_floating(soops, ar, te_floating);
+ outliner_draw_tree_element_floating(ar, te_floating);
}
if (has_restrict_icons) {
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 4cee0e44fca..cad34c96db4 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -50,7 +50,7 @@ struct wmKeyConfig;
typedef enum TreeElementInsertType {
- /* no INSERT_BEFORE needed for now */
+ TE_INSERT_BEFORE,
TE_INSERT_AFTER,
TE_INSERT_INTO,
} TreeElementInsertType;
@@ -91,7 +91,7 @@ typedef struct TreeElement {
struct {
TreeElementInsertType insert_type;
- /* the element after which we may insert the dragged one (NULL to insert at top) */
+ /* the element before/after/into which we may insert the dragged one (NULL to insert at top) */
struct TreeElement *insert_handle;
} *drag_data;
} TreeElement;
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 3db0b6ffa08..6fc088e0f48 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -52,11 +52,6 @@ enum {
OUTLINER_ITEM_DRAG_CONFIRM,
};
-typedef struct OutlinerItemDrag {
- TreeElement *dragged_te;
- int init_mouse_xy[2];
-} OutlinerItemDrag;
-
static int outliner_item_drag_drop_poll(bContext *C)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -67,70 +62,69 @@ static int outliner_item_drag_drop_poll(bContext *C)
static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event)
{
+ /* note: using EVT_TWEAK_ events to trigger dragging is fine,
+ * it sends coordinates from where dragging was started */
const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
return outliner_find_item_at_y(soops, &soops->tree, my);
}
-static OutlinerItemDrag *outliner_item_drag_data_create(TreeElement *dragged_te, const int mouse_xy[2])
-{
- OutlinerItemDrag *drag_data = MEM_mallocN(sizeof(*drag_data), __func__);
-
- drag_data->dragged_te = dragged_te;
- copy_v2_v2_int(drag_data->init_mouse_xy, mouse_xy);
-
- return drag_data;
-}
-
-static void outliner_item_drag_end(OutlinerItemDrag *op_drag_data)
+static void outliner_item_drag_end(TreeElement *dragged_te)
{
- MEM_SAFE_FREE(op_drag_data->dragged_te->drag_data);
- MEM_freeN(op_drag_data);
+ MEM_SAFE_FREE(dragged_te->drag_data);
}
-static void outliner_item_drag_handle(ARegion *ar, const wmEvent *event, OutlinerItemDrag *op_drag_data)
+static void outliner_item_drag_handle(
+ SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged)
{
- TreeElement *dragged_te = op_drag_data->dragged_te;
- const int delta_mouse_y = event->y - op_drag_data->init_mouse_xy[1];
- const int cmp_coord = (int)UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
- const float margin = UI_UNIT_Y * (1.0f / 3);
-
- /* by default we don't change the item position */
- dragged_te->drag_data->insert_handle = dragged_te;
-
- if (delta_mouse_y > 0) {
- for (TreeElement *te = dragged_te->prev; te && (cmp_coord >= (te->ys + margin)); te = te->prev) {
- if (cmp_coord > (te->ys + (2 * margin))) {
- dragged_te->drag_data->insert_type = TE_INSERT_AFTER;
- /* will be NULL if we want to insert as first element */
- dragged_te->drag_data->insert_handle = te->prev;
+ TreeStoreElem *tselem_dragged = TREESTORE(te_dragged);
+ TreeElement *insert_handle;
+ float view_mval[2];
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+ insert_handle = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
+
+ te_dragged->drag_data->insert_handle = NULL;
+ if (insert_handle) {
+ TreeStoreElem *tselem_handle = TREESTORE(insert_handle);
+ if (tselem_handle->type == tselem_dragged->type) {
+ const float margin = UI_UNIT_Y * (1.0f / 4);
+
+ te_dragged->drag_data->insert_handle = insert_handle;
+ if (view_mval[1] < (insert_handle->ys + margin)) {
+ te_dragged->drag_data->insert_type = TE_INSERT_AFTER;
+ }
+ else if (view_mval[1] > (insert_handle->ys + (2 * margin))) {
+ te_dragged->drag_data->insert_type = TE_INSERT_BEFORE;
}
else {
- dragged_te->drag_data->insert_type = TE_INSERT_INTO;
- dragged_te->drag_data->insert_handle = te;
+ te_dragged->drag_data->insert_type = TE_INSERT_INTO;
}
}
}
else {
- for (TreeElement *te = dragged_te->next; te && (cmp_coord <= (te->ys + UI_UNIT_Y - margin)); te = te->next) {
- if (cmp_coord < (te->ys + margin)) {
- dragged_te->drag_data->insert_type = TE_INSERT_AFTER;
- dragged_te->drag_data->insert_handle = te;
- BLI_assert(te->prev != NULL);
- }
- else {
- dragged_te->drag_data->insert_type = TE_INSERT_INTO;
- dragged_te->drag_data->insert_handle = te;
- }
+ TreeElement *first = soops->tree.first;
+ TreeElement *last = soops->tree.last;
+
+ /* mouse doesn't hover any item (ignoring x axis), so it's either above list bounds or below. */
+ if (view_mval[1] < last->ys) {
+ te_dragged->drag_data->insert_handle = last;
+ te_dragged->drag_data->insert_type = TE_INSERT_AFTER;
+ }
+ else if (view_mval[1] > (first->ys + UI_UNIT_Y)) {
+ te_dragged->drag_data->insert_handle = first;
+ te_dragged->drag_data->insert_type = TE_INSERT_BEFORE;
+ }
+ else {
+ BLI_assert(0);
}
}
}
-static bool outliner_item_drag_drop_apply(const Scene *scene, OutlinerItemDrag *op_drag_data)
+static bool outliner_item_drag_drop_apply(const Scene *scene, TreeElement *dragged_te)
{
- TreeElement *dragged_te = op_drag_data->dragged_te;
- TreeElement *insert_after = dragged_te->drag_data->insert_handle;
+ TreeElement *insert_handle = dragged_te->drag_data->insert_handle;
- if (insert_after == dragged_te) {
+ if (insert_handle == dragged_te) {
/* No need to do anything */
return false;
}
@@ -138,8 +132,8 @@ static bool outliner_item_drag_drop_apply(const Scene *scene, OutlinerItemDrag *
if (dragged_te->reinsert) {
/* Not sure yet what the best way to handle reordering elements of different types
* (and stored in different lists). For collection display mode this is enough. */
- if (!insert_after || (insert_after->reinsert == dragged_te->reinsert)) {
- dragged_te->reinsert(scene, dragged_te, insert_after, dragged_te->drag_data->insert_type);
+ if (!insert_handle || (insert_handle->reinsert == dragged_te->reinsert)) {
+ dragged_te->reinsert(scene, dragged_te, insert_handle, dragged_te->drag_data->insert_type);
}
}
@@ -150,7 +144,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
- OutlinerItemDrag *op_drag_data = op->customdata;
+ TreeElement *te_dragged = op->customdata;
int retval = OPERATOR_RUNNING_MODAL;
bool redraw = false;
bool skip_rebuild = true;
@@ -158,7 +152,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
switch (event->type) {
case EVT_MODAL_MAP:
if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) {
- outliner_item_drag_drop_apply(CTX_data_scene(C), op_drag_data);
+ outliner_item_drag_drop_apply(CTX_data_scene(C), te_dragged);
skip_rebuild = false;
retval = OPERATOR_FINISHED;
}
@@ -169,11 +163,11 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
BLI_assert(0);
}
WM_event_add_mousemove(C); /* update highlight */
- outliner_item_drag_end(op_drag_data);
+ outliner_item_drag_end(te_dragged);
redraw = true;
break;
case MOUSEMOVE:
- outliner_item_drag_handle(ar, event, op_drag_data);
+ outliner_item_drag_handle(soops, ar, event, te_dragged);
redraw = true;
break;
}
@@ -192,17 +186,16 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmE
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
- TreeElement *te = outliner_item_drag_element_find(soops, ar, event);
+ TreeElement *te_dragged = outliner_item_drag_element_find(soops, ar, event);
- if (!te) {
+ if (!te_dragged) {
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
}
-
- op->customdata = outliner_item_drag_data_create(te, &event->x);
- te->drag_data = MEM_callocN(sizeof(*te->drag_data), __func__);
+ op->customdata = te_dragged;
+ te_dragged->drag_data = MEM_callocN(sizeof(*te_dragged->drag_data), __func__);
/* by default we don't change the item position */
- te->drag_data->insert_handle = te;
+ te_dragged->drag_data->insert_handle = te_dragged;
/* unset highlighted tree element, dragged one will be highlighted instead */
outliner_set_flag(&soops->tree, TSE_HIGHLIGHTED, false);
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 1273a9fd1f6..e8abef263eb 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -1287,55 +1287,60 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
}
}
-static void outliner_layer_collections_reorder(const Scene *scene, TreeElement *insert_element, TreeElement *insert_handle,
- TreeElementInsertType action)
+static void outliner_layer_collections_reorder(
+ const Scene *scene, TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
{
- LayerCollection *lc_src = insert_element->directdata;
- LayerCollection *lc_dst = insert_handle ? insert_handle->directdata : NULL;
-
- if (action == TE_INSERT_AFTER) {
- if (lc_dst == NULL) {
- /* It needs a LayerCollection to use as reference,
- * specially now that we are to allow insert in collections
- * that don't belong to the same hierarchical level */
- TODO_LAYER_OPERATORS;
- /* BKE_layer_collection_move_after(scene, sc_dst, sc_src); */
- }
- else {
- BKE_layer_collection_move_below(scene, lc_dst, lc_src);
- }
+ LayerCollection *lc_insert = insert_element->directdata;
+ LayerCollection *lc_handle = insert_handle->directdata;
+
+ if (action == TE_INSERT_BEFORE) {
+ BKE_layer_collection_move_above(scene, lc_handle, lc_insert);
+ }
+ else if (action == TE_INSERT_AFTER) {
+ BKE_layer_collection_move_below(scene, lc_handle, lc_insert);
}
else if (action == TE_INSERT_INTO) {
- BKE_layer_collection_move_into(scene, lc_dst, lc_src);
+ BKE_layer_collection_move_into(scene, lc_insert, lc_handle);
+ }
+ else {
+ BLI_assert(0);
}
}
-static void outliner_scene_collections_reorder(const Scene *scene, TreeElement *insert_element, TreeElement *insert_handle,
- TreeElementInsertType action)
+static void outliner_scene_collections_reorder(
+ const Scene *scene, TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
{
- SceneCollection *sc_src = insert_element->directdata;
- SceneCollection *sc_dst = insert_handle ? insert_handle->directdata : NULL;
-
- if (action == TE_INSERT_AFTER) {
- if (sc_dst == NULL) {
- /* It needs a SceneCollection to use as reference,
- * specially now that we are to allow insert in collections
- * that don't belong to the same hierarchical level */
- TODO_LAYER_OPERATORS;
- /* BKE_collection_move_after(scene, sc_dst, sc_src); */
+ SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc_insert = insert_element->directdata;
+ SceneCollection *sc_handle = insert_handle->directdata;
+
+ if (sc_handle == sc_master) {
+ /* exception: Can't insert before/after master selection, has to be one of its childs */
+ if (action == TE_INSERT_BEFORE) {
+ sc_handle = sc_master->scene_collections.first;
}
- else {
- BKE_collection_move_below(scene, sc_dst, sc_src);
+ else if (action == TE_INSERT_AFTER) {
+ sc_handle = sc_master->scene_collections.last;
}
}
+
+ if (action == TE_INSERT_BEFORE) {
+ BKE_collection_move_above(scene, sc_handle, sc_insert);
+ }
+ else if (action == TE_INSERT_AFTER) {
+ BKE_collection_move_below(scene, sc_handle, sc_insert);
+ }
else if (action == TE_INSERT_INTO) {
- BKE_collection_move_into(scene, sc_dst, sc_src);
+ BKE_collection_move_into(scene, sc_handle, sc_insert);
+ }
+ else {
+ BLI_assert(0);
}
}
-static void outliner_add_layer_collections_recursive(SpaceOops *soops, ListBase *tree, Scene *scene,
- ListBase *layer_collections, TreeElement *parent_ten,
- int *io_collection_counter)
+static void outliner_add_layer_collections_recursive(
+ SpaceOops *soops, ListBase *tree, Scene *scene, ListBase *layer_collections, TreeElement *parent_ten,
+ int *io_collection_counter)
{
for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) {
TreeElement *ten = outliner_add_element(soops, tree, scene, parent_ten, TSE_LAYER_COLLECTION,