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:
authorCampbell Barton <ideasman42@gmail.com>2018-12-13 11:05:11 +0300
committerCampbell Barton <ideasman42@gmail.com>2018-12-13 13:11:21 +0300
commitcef2a25518dd41beb5335e73e5b765926b1eb387 (patch)
treea7838346ba5e2618dd35ffd43f15976838bfc565 /source/blender/editors/armature/armature_select.c
parente79d7747d21f3d3079c759abe0f20a7904aded80 (diff)
Armature Edit Mode: improve box/lasso select
Mostly rewrite logic which now matches (de)select picking, share between both operators. - Support all selection operations (eSelectOp), fixes T59255. - Add function that selects using 'BONESEL_*' flags & eSelectOp. This avoids lasso & box select having to handle selection flushing. - Fix strange behavior with lasso where selecting a bone in a chain would only select the tip (from 2.7x).
Diffstat (limited to 'source/blender/editors/armature/armature_select.c')
-rw-r--r--source/blender/editors/armature/armature_select.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index d817fbf5229..830798fa737 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -732,6 +732,189 @@ bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, b
return false;
}
+/* -------------------------------------------------------------------- */
+/** \name Select Op From Tagged
+ *
+ * Implements #ED_armature_edit_select_op_from_tagged
+ * \{ */
+
+static bool armature_edit_select_op_apply(
+ bArmature *arm, EditBone *ebone, const eSelectOp sel_op, int is_ignore_flag, int is_inside_flag)
+{
+ BLI_assert(!(is_ignore_flag & ~(BONESEL_ROOT | BONESEL_TIP)));
+ BLI_assert(!(is_inside_flag & ~(BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE)));
+ BLI_assert(EBONE_VISIBLE(arm, ebone));
+ bool changed = false;
+ bool is_point_done = false;
+ int points_proj_tot = 0;
+ BLI_assert(ebone->flag == ebone->temp.i);
+ const int ebone_flag_prev = ebone->flag;
+
+ if ((is_ignore_flag & BONE_ROOTSEL) == 0) {
+ points_proj_tot++;
+ const bool is_select = ebone->flag & BONE_ROOTSEL;
+ const bool is_inside = is_inside_flag & BONESEL_ROOT;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+ SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_ROOTSEL);
+ }
+ }
+ is_point_done |= is_inside;
+ }
+
+ if ((is_ignore_flag & BONE_TIPSEL) == 0) {
+ points_proj_tot++;
+ const bool is_select = ebone->flag & BONE_TIPSEL;
+ const bool is_inside = is_inside_flag & BONESEL_TIP;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+ SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_TIPSEL);
+ }
+ }
+ is_point_done |= is_inside;
+ }
+
+ /* if one of points selected, we skip the bone itself */
+ if ((is_point_done == false) && (points_proj_tot == 2)) {
+ const bool is_select = ebone->flag & BONE_SELECTED;
+ {
+ const bool is_inside = is_inside_flag & BONESEL_BONE;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+ SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ }
+ }
+ }
+
+ changed = true;
+ }
+ changed |= is_point_done;
+
+ if (ebone_flag_prev != ebone->flag) {
+ ebone->temp.i = ebone->flag;
+ ebone->flag = ebone_flag_prev;
+ ebone->flag = ebone_flag_prev | BONE_DONE;
+ changed = true;
+ }
+
+ return changed;
+}
+
+/**
+ * Perform a selection operation on elements which have been 'touched', use for lasso & border select
+ * but can be used elsewhere too.
+ *
+ * Tagging is done via #EditBone.temp.i using: #BONESEL_ROOT, #BONESEL_TIP, #BONESEL_BONE
+ * And optionally ignoring end-points using the #BONESEL_ROOT, #BONESEL_TIP right shifted 16 bits.
+ * (used when the values are clipped outside the view).
+ *
+ * \param sel_op: #eSelectOp type.
+ *
+ * \note Visibility checks must be done by the caller.
+ */
+bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
+{
+ bool changed = false;
+
+ /* Initialize flags. */
+ {
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+
+ /* Flush the parent flag to this bone
+ * so we don't need to check the parent when adjusting the selection. */
+ if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
+ if (ebone->parent->flag & BONE_TIPSEL) {
+ ebone->flag |= BONE_ROOTSEL;
+ }
+ else {
+ ebone->flag &= ~BONE_ROOTSEL;
+ }
+
+ /* Flush the 'temp.i' flag. */
+ if (ebone->parent->temp.i & BONESEL_TIP) {
+ ebone->temp.i |= BONESEL_ROOT;
+ }
+ }
+ ebone->flag &= ~BONE_DONE;
+ }
+ }
+
+ /* Apply selection from bone selection flags. */
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.i != 0) {
+ int is_ignore_flag = ((ebone->temp.i << 16) & (BONESEL_ROOT | BONESEL_TIP));
+ int is_inside_flag = (ebone->temp.i & (BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE));
+
+ /* Use as previous bone flag from now on. */
+ ebone->temp.i = ebone->flag;
+
+ /* When there is a partial selection without both endpoints, only select an endpoint. */
+ if ((is_inside_flag & BONESEL_BONE) &&
+ (is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) &&
+ ((is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) != (BONESEL_ROOT | BONESEL_TIP)))
+ {
+ is_inside_flag &= ~BONESEL_BONE;
+ }
+
+ changed |= armature_edit_select_op_apply(arm, ebone, sel_op, is_ignore_flag, is_inside_flag);
+ }
+ }
+
+ if (changed) {
+ /* Cleanup flags. */
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->flag & BONE_DONE) {
+ SWAP(int, ebone->temp.i, ebone->flag);
+ ebone->flag |= BONE_DONE;
+ if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
+ if ((ebone->parent->flag & BONE_DONE) == 0) {
+ /* Checked below. */
+ ebone->parent->temp.i = ebone->parent->flag;
+ }
+ }
+ }
+ }
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->flag & BONE_DONE) {
+ if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
+ bool is_parent_tip_changed = (ebone->parent->flag & BONE_TIPSEL) != (ebone->parent->temp.i & BONE_TIPSEL);
+ if ((ebone->temp.i & BONE_ROOTSEL) == 0) {
+ if ((ebone->flag & BONE_ROOTSEL) != 0) {
+ ebone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+ else {
+ if ((ebone->flag & BONE_ROOTSEL) == 0) {
+ ebone->parent->flag &= ~BONE_TIPSEL;
+
+ }
+ }
+
+
+ if (is_parent_tip_changed == false) {
+ /* Keep tip selected if the parent remains selected. */
+ if (ebone->parent->flag & BONE_SELECTED) {
+ ebone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+
+ }
+ ebone->flag &= ~BONE_DONE;
+ }
+ }
+
+ ED_armature_edit_sync_selection(arm->edbo);
+ ED_armature_edit_validate_active(arm);
+ }
+
+ return changed;
+}
+
+/** \} */
/* **************** Selections ******************/