soc-2008-mxcurioni: merged changes to revision 15705
[blender.git] / source / blender / src / editaction_gpencil.c
1 /**
2  * $Id: editaction_gpencil.c 14881 2008-05-18 10:41:42Z aligorith $
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008, Blender Foundation
21  * This is a new part of Blender
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27  
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <math.h>
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BMF_Api.h"
41
42 #include "BLI_arithb.h"
43 #include "BLI_blenlib.h"
44
45 #include "DNA_listBase.h"
46 #include "DNA_action_types.h"
47 #include "DNA_gpencil_types.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_screen_types.h"
50 #include "DNA_space_types.h"
51 #include "DNA_userdef_types.h"
52 #include "DNA_view3d_types.h"
53 #include "DNA_view2d_types.h"
54
55 #include "BKE_global.h"
56 #include "BKE_utildefines.h"
57 #include "BKE_blender.h"
58 #include "BKE_ipo.h"
59
60 #include "BIF_gl.h"
61 #include "BIF_glutil.h"
62 #include "BIF_butspace.h"
63 #include "BIF_graphics.h"
64 #include "BIF_interface.h"
65 #include "BIF_mywindow.h"
66 #include "BIF_resources.h"
67 #include "BIF_space.h"
68 #include "BIF_screen.h"
69 #include "BIF_toolbox.h"
70 #include "BIF_toets.h"
71
72 #include "BIF_editaction.h"
73 #include "BSE_editaction_types.h"
74
75 #include "BDR_gpencil.h"
76 #include "BIF_drawgpencil.h"
77
78 #include "BSE_drawipo.h"
79 #include "BSE_headerbuttons.h"
80 #include "BSE_time.h"
81 #include "BSE_view.h"
82
83 #include "blendef.h"
84 #include "butspace.h"
85
86 #include "PIL_time.h"                   /* sleep                                */
87 #include "mydevice.h"
88
89 /* ***************************************** */
90 /* NOTE ABOUT THIS FILE:
91  *      This file contains code for editing Grease Pencil data in the Action Editor
92  *      as a 'keyframes', so that a user can adjust the timing of Grease Pencil drawings.
93  *      Therefore, this file mostly contains functions for selecting Grease-Pencil frames.
94  */
95 /* ***************************************** */
96 /* Generics - Loopers */
97
98 /* Loops over the gp-frames for a gp-layer, and applies the given callback */
99 short gplayer_frames_looper (bGPDlayer *gpl, short (*gpf_cb)(bGPDframe *))
100 {
101         bGPDframe *gpf;
102         
103         /* error checker */
104         if (gpl == NULL)
105                 return 0;
106         
107         /* do loop */
108         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
109                 /* execute callback */
110                 if (gpf_cb(gpf))
111                         return 1;
112         }
113                 
114         /* nothing to return */
115         return 0;
116 }
117
118 /* ****************************************** */
119 /* Data Conversion Tools */
120
121 /* make a listing all the gp-frames in a layer as cfraelems */
122 void gplayer_make_cfra_list (bGPDlayer *gpl, ListBase *elems, short onlysel)
123 {
124         bGPDframe *gpf;
125         CfraElem *ce;
126         
127         /* error checking */
128         if (ELEM(NULL, gpl, elems))
129                 return;
130         
131         /* loop through gp-frames, adding */
132         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
133                 if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) {
134                         ce= MEM_callocN(sizeof(CfraElem), "CfraElem");
135                         
136                         ce->cfra= gpf->framenum;
137                         ce->sel= (gpf->flag & GP_FRAME_SELECT) ? 1 : 0;
138                         
139                         BLI_addtail(elems, ce);
140                 }
141         }
142 }
143
144 /* ***************************************** */
145 /* Selection Tools */
146
147 /* check if one of the frames in this layer is selected */
148 short is_gplayer_frame_selected (bGPDlayer *gpl)
149 {
150         bGPDframe *gpf;
151         
152         /* error checking */
153         if (gpl == NULL) 
154                 return 0;
155         
156         /* stop at the first one found */
157         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
158                 if (gpf->flag & GP_FRAME_SELECT)
159                         return 1;
160         }
161         
162         /* not found */
163         return 0;
164 }
165
166 /* helper function - select gp-frame based on SELECT_* mode */
167 static void gpframe_select (bGPDframe *gpf, short select_mode)
168 {
169         switch (select_mode) {
170                 case SELECT_ADD:
171                         gpf->flag |= GP_FRAME_SELECT;
172                         break;
173                 case SELECT_SUBTRACT:
174                         gpf->flag &= ~GP_FRAME_SELECT;
175                         break;
176                 case SELECT_INVERT:
177                         gpf->flag ^= GP_FRAME_SELECT;
178                         break;
179         }
180 }
181
182 /* set all/none/invert select (like above, but with SELECT_* modes) */
183 void select_gpencil_frames (bGPDlayer *gpl, short select_mode)
184 {
185         bGPDframe *gpf;
186         
187         /* error checking */
188         if (gpl == NULL) 
189                 return;
190                 
191         /* handle according to mode */
192         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
193                 gpframe_select(gpf, select_mode);
194         }
195 }
196
197 /* set all/none/invert select */
198 void set_gplayer_frame_selection (bGPDlayer *gpl, short mode)
199 {
200         /* error checking */
201         if (gpl == NULL) 
202                 return;
203                 
204         /* convert mode to select_mode */
205         switch (mode) {
206                 case 2:
207                         mode= SELECT_INVERT;
208                         break;
209                 case 1:
210                         mode= SELECT_ADD;
211                         break;
212                 case 0:
213                         mode= SELECT_SUBTRACT;
214                         break;
215                 default:
216                         return;
217         }
218         
219         /* now call the standard function */
220         select_gpencil_frames (gpl, mode);
221 }
222
223 void select_gpencil_frame (bGPDlayer *gpl, int selx, short select_mode)
224 {
225         bGPDframe *gpf;
226    
227         /* search through frames for a match */
228         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
229                 if (gpf->framenum == selx)
230                         gpframe_select(gpf, select_mode);
231         }
232 }
233
234 void borderselect_gplayer_frames (bGPDlayer *gpl, float min, float max, short select_mode)
235 {
236         bGPDframe *gpf;
237         
238         /* only select those frames which are in bounds */
239         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
240                 if (IN_RANGE(gpf->framenum, min, max))
241                         gpframe_select(gpf, select_mode);
242         }
243 }
244
245
246 /* De-selects or inverts the selection of Layers for a grease-pencil block
247  *      mode: 0 = default behaviour (select all), 1 = test if (de)select all, 2 = invert all 
248  */
249 void deselect_gpencil_layers (bGPdata *gpd, short mode)
250 {
251         ListBase act_data = {NULL, NULL};
252         bActListElem *ale;
253         int filter, sel=1;
254         
255         /* filter data */
256         filter= ACTFILTER_VISIBLE;
257         actdata_filter(&act_data, filter, gpd, ACTCONT_GPENCIL);
258         
259         /* See if we should be selecting or deselecting */
260         if (mode == 1) {
261                 for (ale= act_data.first; ale; ale= ale->next) {
262                         if (sel == 0) 
263                                 break;
264                         
265                         if (ale->flag & GP_LAYER_SELECT)
266                                 sel= 0;
267                 }
268         }
269         else
270                 sel= 0;
271                 
272         /* Now set the flags */
273         for (ale= act_data.first; ale; ale= ale->next) {
274                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
275                 
276                 if (mode == 2)
277                         gpl->flag ^= GP_LAYER_SELECT;
278                 else if (sel)
279                         gpl->flag |= GP_LAYER_SELECT;
280                 else
281                         gpl->flag &= ~GP_LAYER_SELECT;
282                         
283                 gpl->flag &= ~GP_LAYER_ACTIVE;
284         }
285         
286         /* Cleanup */
287         BLI_freelistN(&act_data);
288 }
289
290 /* ***************************************** */
291 /* Frame Editing Tools */
292
293 void delete_gpencil_layers (void)
294 {
295         ListBase act_data = {NULL, NULL};
296         bActListElem *ale, *next;
297         bGPdata *gpd;
298         void *data;
299         short datatype;
300         int filter;
301         
302         /* determine what type of data we are operating on */
303         data = get_action_context(&datatype);
304         if (data == NULL) return;
305         if (datatype != ACTCONT_GPENCIL) return;
306         gpd= (bGPdata *)data;
307         
308         /* filter data */
309         filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_CHANNELS | ACTFILTER_SEL);
310         actdata_filter(&act_data, filter, data, datatype);
311         
312         /* clean up grease-pencil layers */
313         for (ale= act_data.first; ale; ale= next) {
314                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
315                 next= ale->next;
316                 
317                 /* free layer and its data */
318                 if (SEL_GPL(gpl)) {
319                         free_gpencil_frames(gpl);
320                         BLI_freelinkN(&gpd->layers, gpl);
321                 }
322                 
323                 /* free temp memory */
324                 BLI_freelinkN(&act_data, ale);
325         }
326         
327         BIF_undo_push("Delete GPencil Layers");
328         allspace(REDRAWVIEW3D, 0);
329         allqueue(REDRAWACTION, 0);
330 }
331
332 /* Delete selected frames */
333 void delete_gplayer_frames (bGPDlayer *gpl)
334 {
335         bGPDframe *gpf, *gpfn;
336         
337         /* error checking */
338         if (gpl == NULL)
339                 return;
340                 
341         /* check for frames to delete */
342         for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
343                 gpfn= gpf->next;
344                 
345                 if (gpf->flag & GP_FRAME_SELECT)
346                         gpencil_layer_delframe(gpl, gpf);
347         }
348 }
349
350 /* Duplicate selected frames from given gp-layer */
351 void duplicate_gplayer_frames (bGPDlayer *gpl)
352 {
353         bGPDframe *gpf, *gpfn;
354         
355         /* error checking */
356         if (gpl == NULL)
357                 return;
358         
359         /* duplicate selected frames  */
360         for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
361                 gpfn= gpf->next;
362                 
363                 /* duplicate this frame */
364                 if (gpf->flag & GP_FRAME_SELECT) {
365                         bGPDframe *gpfd; 
366                         bGPDstroke *gps;
367                         
368                         /* duplicate frame, and deselect self */
369                         gpfd= MEM_dupallocN(gpf);
370                         gpf->flag &= ~GP_FRAME_SELECT;
371                         
372                         /* duplicate list of strokes too */
373                         duplicatelist(&gpfd->strokes, &gpf->strokes);
374                         
375                         /* dupalloc only makes another copy of mem, but doesn't adjust pointers */
376                         for (gps= gpfd->strokes.first; gps; gps= gps->next) {
377                                 gps->points= MEM_dupallocN(gps->points);
378                         }
379                         
380                         BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
381                 }
382         }
383 }
384
385 /* -------------------------------------- */
386 /* Snap Tools */
387
388 static short snap_gpf_nearest (bGPDframe *gpf)
389 {
390         if (gpf->flag & GP_FRAME_SELECT)
391                 gpf->framenum= (int)(floor(gpf->framenum+0.5));
392         return 0;
393 }
394
395 static short snap_gpf_nearestsec (bGPDframe *gpf)
396 {
397         float secf = FPS;
398         if (gpf->flag & GP_FRAME_SELECT)
399                 gpf->framenum= (int)(floor(gpf->framenum/secf + 0.5f) * secf);
400         return 0;
401 }
402
403 static short snap_gpf_cframe (bGPDframe *gpf)
404 {
405         if (gpf->flag & GP_FRAME_SELECT)
406                 gpf->framenum= (int)CFRA;
407         return 0;
408 }
409
410 static short snap_gpf_nearmarker (bGPDframe *gpf)
411 {
412         if (gpf->flag & GP_FRAME_SELECT)
413                 gpf->framenum= (int)find_nearest_marker_time(gpf->framenum);
414         return 0;
415 }
416
417
418 /* snap selected frames to ... */
419 void snap_gplayer_frames (bGPDlayer *gpl, short mode)
420 {
421         switch (mode) {
422                 case 1: /* snap to nearest frame */
423                         gplayer_frames_looper(gpl, snap_gpf_nearest);
424                         break;
425                 case 2: /* snap to current frame */
426                         gplayer_frames_looper(gpl, snap_gpf_cframe);
427                         break;
428                 case 3: /* snap to nearest marker */
429                         gplayer_frames_looper(gpl, snap_gpf_nearmarker);
430                         break;
431                 case 4: /* snap to nearest second */
432                         gplayer_frames_looper(gpl, snap_gpf_nearestsec);
433                         break;
434                 default: /* just in case */
435                         gplayer_frames_looper(gpl, snap_gpf_nearest);
436                         break;
437         }
438 }
439
440 /* -------------------------------------- */
441 /* Mirror Tools */
442
443 static short mirror_gpf_cframe (bGPDframe *gpf)
444 {
445         float diff;
446         
447         if (gpf->flag & GP_FRAME_SELECT) {
448                 diff= ((float)CFRA - gpf->framenum);
449                 gpf->framenum= ((float)CFRA + diff);
450         }
451         
452         return 0;
453 }
454
455 static short mirror_gpf_yaxis (bGPDframe *gpf)
456 {
457         float diff;
458         
459         if (gpf->flag & GP_FRAME_SELECT) {
460                 diff= (0.0f - gpf->framenum);
461                 gpf->framenum= (0.0f + diff);
462         }
463         
464         return 0;
465 }
466
467 static short mirror_gpf_xaxis (bGPDframe *gpf)
468 {
469         float diff;
470         
471         if (gpf->flag & GP_FRAME_SELECT) {
472                 diff= (0.0f - gpf->framenum);
473                 gpf->framenum= (0.0f + diff);
474         }
475         
476         return 0;
477 }
478
479 static short mirror_gpf_marker (bGPDframe *gpf)
480 {
481         static TimeMarker *marker;
482         static short initialised = 0;
483         float diff;
484         
485         /* In order for this mirror function to work without
486          * any extra arguments being added, we use the case
487          * of bezt==NULL to denote that we should find the 
488          * marker to mirror over. The static pointer is safe
489          * to use this way, as it will be set to null after 
490          * each cycle in which this is called.
491          */
492         
493         if (gpf) {
494                 /* mirroring time */
495                 if ((gpf->flag & GP_FRAME_SELECT) && (marker)) {
496                         diff= (marker->frame - gpf->framenum);
497                         gpf->framenum= (marker->frame + diff);
498                 }
499         }
500         else {
501                 /* initialisation time */
502                 if (initialised) {
503                         /* reset everything for safety */
504                         marker = NULL;
505                         initialised = 0;
506                 }
507                 else {
508                         /* try to find a marker */
509                         for (marker= G.scene->markers.first; marker; marker=marker->next) {
510                                 if (marker->flag & SELECT) {
511                                         initialised = 1;
512                                         break;
513                                 }
514                         }
515                         
516                         if (initialised == 0) 
517                                 marker = NULL;
518                 }
519         }
520         
521         return 0;
522 }
523
524
525 /* mirror selected gp-frames on... */
526 void mirror_gplayer_frames (bGPDlayer *gpl, short mode)
527 {
528         switch (mode) {
529                 case 1: /* mirror over current frame */
530                         gplayer_frames_looper(gpl, mirror_gpf_cframe);
531                         break;
532                 case 2: /* mirror over frame 0 */
533                         gplayer_frames_looper(gpl, mirror_gpf_yaxis);
534                         break;
535                 case 3: /* mirror over value 0 */
536                         gplayer_frames_looper(gpl, mirror_gpf_xaxis);
537                         break;
538                 case 4: /* mirror over marker */
539                         mirror_gpf_marker(NULL);
540                         gplayer_frames_looper(gpl, mirror_gpf_marker);
541                         mirror_gpf_marker(NULL);
542                         break;
543                 default: /* just in case */
544                         gplayer_frames_looper(gpl, mirror_gpf_yaxis);
545                         break;
546         }
547 }
548
549 /* ***************************************** */