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:
Diffstat (limited to 'source/blender/blenkernel/intern/key.c')
-rw-r--r--source/blender/blenkernel/intern/key.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 2dc615c19f9..5cca948cd49 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -2055,3 +2055,91 @@ void BKE_key_convert_from_offset(Object *ob, KeyBlock *kb, float (*ofs)[3])
}
}
}
+
+/* ==========================================================*/
+
+/** Move shape key from org_index to new_index. Safe, clamps index to valid range, updates reference keys,
+ * the object's active shape index, the 'frame' value in case of absolute keys, etc.
+ * Note indices are expected in real values (not 'fake' shapenr +1 ones).
+ *
+ * \param org_index if < 0, current object's active shape will be used as skey to move.
+ * \return true if something was done, else false.
+ */
+bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
+{
+ Key *key = BKE_key_from_object(ob);
+ KeyBlock *kb;
+ const int act_index = ob->shapenr - 1;
+ const int totkey = key->totkey;
+ int i;
+ bool rev, in_range = false;
+
+ if (org_index < 0) {
+ org_index = act_index;
+ }
+
+ CLAMP(new_index, 0, key->totkey - 1);
+ CLAMP(org_index, 0, key->totkey - 1);
+
+ if (new_index == org_index) {
+ return false;
+ }
+
+ rev = ((new_index - org_index) < 0) ? true : false;
+
+ /* We swap 'org' element with its previous/next neighbor (depending on direction of the move) repeatedly,
+ * until we reach final position.
+ * This allows us to only loop on the list once! */
+ for (kb = (rev ? key->block.last : key->block.first), i = (rev ? totkey - 1 : 0);
+ kb;
+ kb = (rev ? kb->prev : kb->next), rev ? i-- : i++)
+ {
+ if (i == org_index) {
+ in_range = true; /* Start list items swapping... */
+ }
+ else if (i == new_index) {
+ in_range = false; /* End list items swapping. */
+ }
+
+ if (in_range) {
+ KeyBlock *other_kb = rev ? kb->prev : kb->next;
+
+ /* Swap with previous/next list item. */
+ BLI_swaplinks(&key->block, kb, other_kb);
+
+ /* Swap absolute positions. */
+ SWAP(float, kb->pos, other_kb->pos);
+
+ kb = other_kb;
+ }
+
+ /* Adjust relative indices, this has to be done on the whole list! */
+ if (kb->relative == org_index) {
+ kb->relative = new_index;
+ }
+ else if (kb->relative < org_index && kb->relative >= new_index) {
+ /* remove after, insert before this index */
+ kb->relative++;
+ }
+ else if (kb->relative > org_index && kb->relative <= new_index) {
+ /* remove before, insert after this index */
+ kb->relative--;
+ }
+ }
+
+ /* Need to update active shape number if it's affected, same principle as for relative indices above. */
+ if (org_index == act_index) {
+ ob->shapenr = new_index + 1;
+ }
+ else if (act_index < org_index && act_index >= new_index) {
+ ob->shapenr++;
+ }
+ else if (act_index > org_index && act_index <= new_index) {
+ ob->shapenr--;
+ }
+
+ /* First key is always refkey, matches interface and BKE_key_sort */
+ key->refkey = key->block.first;
+
+ return true;
+}