[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [13137] trunk/blender/source/blender/src/ poselib.c: == PoseLib - Quick Search for Preview ==

Joshua Leung aligorith at gmail.com
Sat Jan 5 11:54:33 CET 2008


Revision: 13137
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=13137
Author:   aligorith
Date:     2008-01-05 11:54:33 +0100 (Sat, 05 Jan 2008)

Log Message:
-----------
== PoseLib - Quick Search for Preview ==

Now, when Previewing/Browsing poses with Ctrl-L, it is possible to type in part of a name to limit the poses which can get chosen to hone in on the poses you wish to apply more quickly. 
* The search is case insensitive, and doesn't look for complete matches (it will 'match' if the whole search-string is found). 
* Only basic text manipulation capabilities are available for editing the search string (i.e.  backspace, del, home, end, move text-cursor forward ->, move text-cursor backwards <-).
* Pose browsing using the Scroll-Wheel and Page up/down can be used to browse through the matches
* View manipulation is only possible with MMB, as numpad keys are used for search-string input.

In the process, I've recoded the preview function to be more modular. It's now split up more, like the Transform core.

Modified Paths:
--------------
    trunk/blender/source/blender/src/poselib.c

Modified: trunk/blender/source/blender/src/poselib.c
===================================================================
--- trunk/blender/source/blender/src/poselib.c	2008-01-05 10:01:05 UTC (rev 13136)
+++ trunk/blender/source/blender/src/poselib.c	2008-01-05 10:54:33 UTC (rev 13137)
@@ -515,6 +515,49 @@
 
 /* ************************************************************* */
 
+/* Simple struct for storing settings/data for use during PoseLib preview */
+typedef struct tPoseLib_PreviewData {
+	ListBase backups;		/* tPoseLib_Backup structs for restoring poses */
+	ListBase searchp;		/* LinkData structs storing list of poses which match the current search-string */
+	
+	Object *ob;				/* object to work on */
+	bArmature *arm;			/* object's armature data */
+	bPose *pose;			/* object's pose */
+	bAction *act;			/* poselib to use */
+	TimeMarker *marker;		/* 'active' pose */
+	
+	short state;			/* state of main loop */
+	short redraw;			/* redraw/update settings during main loop */
+	short firsttime;		/* first loop... (no restore) */
+	
+	int selcount;			/* number of selected elements to work on */
+	int totcount;			/* total number of elements to work on */
+	
+	char headerstr[200];	/* Info-text to print in header */
+	
+	char searchstr[64];		/* (Part of) Name to search for to filter poses that get shown */
+	char searchold[64];		/* Previously set searchstr (from last loop run), so that we can detected when to rebuild searchp */
+	short search_cursor;	/* position of cursor in searchstr (cursor occurs before the item at the nominated index) */
+} tPoseLib_PreviewData;
+
+/* defines for tPoseLib_PreviewData->state values */
+enum {
+	PL_PREVIEW_ERROR = -1,
+	PL_PREVIEW_RUNNING,
+	PL_PREVIEW_CONFIRM,
+	PL_PREVIEW_CANCEL,
+	PL_PREVIEW_RUNONCE 
+};
+
+/* defines for tPoseLib_PreviewData->redraw values */
+enum {
+	PL_PREVIEW_NOREDRAW = 0,
+	PL_PREVIEW_REDRAWALL,
+	PL_PREVIEW_REDRAWHEADER,
+};
+
+/* ---------------------------- */
+
 /* simple struct for storing backup info */
 typedef struct tPoseLib_Backup {
 	struct tPoseLib_Backup *next, *prev;
@@ -524,41 +567,46 @@
 } tPoseLib_Backup;
 
 /* Makes a copy of the current pose for restoration purposes - doesn't do constraints currently */
-static void poselib_backup_posecopy (ListBase *backups, bPose *pose, bAction *act)
+static void poselib_backup_posecopy (tPoseLib_PreviewData *pld)
 {
 	bActionChannel *achan;
 	bPoseChannel *pchan;
 	
 	/* for each posechannel that has an actionchannel in */
-	for (achan= act->chanbase.first; achan; achan= achan->next) {
+	for (achan= pld->act->chanbase.first; achan; achan= achan->next) {
 		/* try to find posechannel */
-		pchan= get_pose_channel(pose, achan->name);
+		pchan= get_pose_channel(pld->pose, achan->name);
 		
 		/* backup data if available */
 		if (pchan) {
 			tPoseLib_Backup *plb;
 			
+			/* store backup */
 			plb= MEM_callocN(sizeof(tPoseLib_Backup), "tPoseLib_Backup");
 			
 			plb->pchan= pchan;
 			memcpy(&plb->olddata, plb->pchan, sizeof(bPoseChannel));
 			
-			BLI_addtail(backups, plb);
+			BLI_addtail(&pld->backups, plb);
+			
+			/* mark as being affected */
+			if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))
+				pld->selcount++;
+			pld->totcount++;
 		}
 	}
 }
 
 /* Restores original pose - doesn't do constraints currently */
-static void poselib_backup_restore (ListBase *backups)
+static void poselib_backup_restore (tPoseLib_PreviewData *pld)
 {
 	tPoseLib_Backup *plb;
 	
-	for (plb= backups->first; plb; plb= plb->next) {
+	for (plb= pld->backups.first; plb; plb= plb->next) {
 		memcpy(plb->pchan, &plb->olddata, sizeof(bPoseChannel));
 	}
 }
 
-
 /* ---------------------------- */
 
 /* Applies the appropriate stored pose from the pose-library to the current pose
@@ -566,15 +614,20 @@
  *	- gets the string to print in the header
  * 	- this code is based on the code for extract_pose_from_action in blenkernel/action.c
  */
-static void poselib_apply_pose (Object *ob, TimeMarker *marker, char headerstr[])
+static void poselib_apply_pose (tPoseLib_PreviewData *pld)
 {
-	bPose *pose= ob->pose;
+	bPose *pose= pld->pose;
 	bPoseChannel *pchan;
-	bAction *act= ob->poselib;
+	bAction *act= pld->act;
 	bActionChannel *achan;
 	IpoCurve *icu;
-	int frame= marker->frame;
+	int frame;
 	
+	if (pld->marker)
+		frame= pld->marker->frame;
+	else
+		return;	
+	
 	/* start applying - only those channels which have a key at this point in time! */
 	for (achan= act->chanbase.first; achan; achan= achan->next) {
 		short found= 0;
@@ -600,13 +653,18 @@
 			if (found) {
 				pchan= get_pose_channel(pose, achan->name);
 				
-				if ( (pchan) && (pchan->bone) && 
-					 (pchan->bone->flag & (BONE_SELECTED|BONE_ACTIVE)) ) 
-				{
-					/* Evaluates and sets the internal ipo values	*/
-					calc_ipo(achan->ipo, frame);
-					/* This call also sets the pchan flags */
-					execute_action_ipo(achan, pchan);
+				if (pchan) {	
+					short ok;
+					
+					ok= (pchan->bone) ? (pchan->bone->flag & (BONE_SELECTED|BONE_ACTIVE)) : 0;
+					ok= (ok || pld->selcount) ? 1 : 0; 
+					
+					if (ok) {
+						/* Evaluates and sets the internal ipo values	*/
+						calc_ipo(achan->ipo, frame);
+						/* This call also sets the pchan flags */
+						execute_action_ipo(achan, pchan);
+					}
 				}
 			}
 		}
@@ -620,21 +678,22 @@
 }
 
 /* Auto-keys/tags bones affected by the pose used from the poselib */
-static void poselib_keytag_pose (Object *ob)
+static void poselib_keytag_pose (tPoseLib_PreviewData *pld)
 {
+	bPose *pose= pld->pose;
 	bPoseChannel *pchan;
-	bAction *act= ob->poselib;
+	bAction *act= pld->act;
 	bActionChannel *achan;
 	
 	/* start tagging/keying */
 	for (achan= act->chanbase.first; achan; achan= achan->next) {
 		/* only for selected action channels */
 		if (achan->flag & ACHAN_SELECTED) {
-			pchan= get_pose_channel(ob->pose, achan->name);
+			pchan= get_pose_channel(pose, achan->name);
 			
 			if (pchan) {
 				if (G.flags & G_RECORDKEYS) {
-					ID *id= &ob->id;
+					ID *id= &pld->ob->id;
 					
 					/* Set keys on pose */
 					if (pchan->flag & POSE_ROT) {
@@ -673,216 +732,361 @@
 /* This helper function is called during poselib_preview_poses to find the 
  * pose to preview next (after a change event)
  */
-static TimeMarker *poselib_preview_get_next (bAction *act, TimeMarker *current, int step)
+static void poselib_preview_get_next (tPoseLib_PreviewData *pld, int step)
 {
-	if (step) {
-		TimeMarker *marker, *next;
-		
-		/* Loop through the markers in a cyclic fashion, incrementing/decrementing step as appropriate 
-		 * until step == 0. At this point, marker should be the correct marker.
-		 */
-		if (step > 0) {
-			for (marker=current; marker && step; marker=next, step--)
-				next= (marker->next) ? marker->next : act->markers.first;
+	if ((pld->marker) && (step)) {
+		/* search-string dictates a special approach */
+		if (pld->searchstr[0]) {
+			TimeMarker *marker;
+			LinkData *ld, *ldn, *ldc;
+			
+			/* free and rebuild if needed (i.e. if search-str changed) */
+			if (strcmp(pld->searchstr, pld->searchold)) {
+				/* free list of temporary search matches */
+				BLI_freelistN(&pld->searchp);
+				
+				/* generate a new list of search matches */
+				for (marker= pld->act->markers.first; marker; marker= marker->next) {
+					/* does the name partially match? 
+					 * 	- don't worry about case, to make it easier for users to quickly input a name (or 
+					 *	  part of one), which is the whole point of this feature
+					 */
+					if (BLI_strcasestr(marker->name, pld->searchstr)) {
+						/* make link-data to store reference to it */
+						ld= MEM_callocN(sizeof(LinkData), "PoseMatch");
+						ld->data= marker;
+						BLI_addtail(&pld->searchp, ld);
+					}
+				}
+				
+				/* set current marker to NULL (so that we start from first) */
+				pld->marker= NULL;
+			}
+			
+			/* check if any matches */
+			if (pld->searchp.first == NULL) { 
+				pld->marker= NULL;
+				return;
+			}
+			
+			/* find first match */
+			for (ldc= pld->searchp.first; ldc; ldc= ldc->next) {
+				if (ldc->data == pld->marker)
+					break;
+			}
+			if (ldc == NULL)
+				ldc= pld->searchp.first;
+				
+			/* Loop through the matches in a cyclic fashion, incrementing/decrementing step as appropriate 
+			 * until step == 0. At this point, marker should be the correct marker.
+			 */
+			if (step > 0) {
+				for (ld=ldc; ld && step; ld=ldn, step--)
+					ldn= (ld->next) ? ld->next : pld->searchp.first;
+			}
+			else {
+				for (ld=ldc; ld && step; ld=ldn, step++)
+					ldn= (ld->prev) ? ld->prev : pld->searchp.last;
+			}
+			
+			/* set marker */
+			if (ld)
+				pld->marker= ld->data;
 		}
 		else {
-			for (marker=current; marker && step; marker=next, step++)
-				next= (marker->prev) ? marker->prev : act->markers.last;
+			TimeMarker *marker, *next;
+			
+			/* Loop through the markers in a cyclic fashion, incrementing/decrementing step as appropriate 
+			 * until step == 0. At this point, marker should be the correct marker.
+			 */
+			if (step > 0) {
+				for (marker=pld->marker; marker && step; marker=next, step--)
+					next= (marker->next) ? marker->next : pld->act->markers.first;
+			}
+			else {
+				for (marker=pld->marker; marker && step; marker=next, step++)
+					next= (marker->prev) ? marker->prev : pld->act->markers.last;
+			}
+			
+			/* it should be fairly impossible for marker to be NULL */
+			if (marker)
+				pld->marker= marker;
 		}
+	}
+}
+
+/* specially handle events for searching */
+static void poselib_preview_handle_search (tPoseLib_PreviewData *pld, unsigned short event, char ascii)
+{
+	if (ascii) {
+		/* character to add to the string */
+		short index= pld->search_cursor;
+		short len= (pld->searchstr[0]) ? strlen(pld->searchstr) : 0;
+		short i;
 		
-		/* don't go anywhere if for some reason an error occurred */
-		return (marker) ? marker : current;
+		if (len) {
+			for (i = len; i > index; i--)  
+				pld->searchstr[i]= pld->searchstr[i-1];
+		}
+		else
+			pld->searchstr[1]= 0;
+			
+		pld->searchstr[index]= ascii;
+		pld->search_cursor++;
+		
+		poselib_preview_get_next(pld, 1);
+		pld->redraw = PL_PREVIEW_REDRAWALL;
 	}
-	else
-		return current;
+	else {
+		/* some form of string manipulation */
+		switch (event) {
+			case BACKSPACEKEY:
+				if (pld->searchstr[0] && pld->search_cursor) {
+					short len= strlen(pld->searchstr);
+					short index= pld->search_cursor;
+					short i;
+					
+					for (i = index; i <= len; i++) 
+						pld->searchstr[i-1] = pld->searchstr[i];
+					
+					pld->search_cursor--;
+					

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list