tag UNUSED() for operator exec() and invoke() functions.
[blender.git] / source / blender / editors / metaball / mball_edit.c
1 /**
2  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <string.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_blenlib.h"
36 #include "BLI_math.h"
37 #include "BLI_rand.h"
38
39 #include "DNA_meta_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_scene_types.h"
42
43 #include "RNA_define.h"
44 #include "RNA_access.h"
45
46 #include "BKE_depsgraph.h"
47 #include "BKE_context.h"
48 #include "BKE_mball.h"
49
50 #include "ED_screen.h"
51 #include "ED_view3d.h"
52 #include "ED_transform.h"
53 #include "ED_util.h"
54
55 #include "WM_api.h"
56 #include "WM_types.h"
57
58 /* This function is used to free all MetaElems from MetaBall */
59 void free_editMball(Object *obedit)
60 {
61         MetaBall *mb = (MetaBall*)obedit->data;
62
63         mb->editelems= NULL;
64         mb->lastelem= NULL;
65 }
66
67 /* This function is called, when MetaBall Object is
68  * switched from object mode to edit mode */
69 void make_editMball(Object *obedit)
70 {
71         MetaBall *mb = (MetaBall*)obedit->data;
72         MetaElem *ml;/*, *newml;*/
73
74         ml= mb->elems.first;
75         
76         while(ml) {
77                 if(ml->flag & SELECT) mb->lastelem = ml;
78                 ml= ml->next;
79         }
80
81         mb->editelems = &mb->elems;
82 }
83
84 /* This function is called, when MetaBall Object switched from
85  * edit mode to object mode. List od MetaElements is copied
86  * from object->data->edit_elems to object->data->elems. */
87 void load_editMball(Object *obedit)
88 {
89 }
90
91 /* Add metaelem primitive to metaball object (which is in edit mode) */
92 MetaElem *add_metaball_primitive(bContext *C, float mat[4][4], int type, int newname)
93 {
94         Object *obedit= CTX_data_edit_object(C);
95         MetaBall *mball = (MetaBall*)obedit->data;
96         MetaElem *ml;
97
98         if(!obedit) return NULL;
99
100         /* Deselect all existing metaelems */
101         ml= mball->editelems->first;
102         while(ml) {
103                 ml->flag &= ~SELECT;
104                 ml= ml->next;
105         }
106         
107         ml= add_metaball_element(mball, type);
108         copy_v3_v3(&ml->x, mat[3]);
109
110         ml->flag |= SELECT;
111         mball->lastelem= ml;
112         return ml;
113 }
114
115 /***************************** Select/Deselect operator *****************************/
116
117 /* Select or deselect all MetaElements */
118 static int select_all_exec(bContext *C, wmOperator *op)
119 {
120         //Scene *scene= CTX_data_scene(C);
121         Object *obedit= CTX_data_edit_object(C);
122         MetaBall *mb = (MetaBall*)obedit->data;
123         MetaElem *ml;
124         int action = RNA_enum_get(op->ptr, "action");
125
126         ml= mb->editelems->first;
127         if(ml) {
128                 if (action == SEL_TOGGLE) {
129                         action = SEL_SELECT;
130                         while(ml) {
131                                 if(ml->flag & SELECT) {
132                                         action = SEL_DESELECT;
133                                         break;
134                                 }
135                                 ml= ml->next;
136                         }
137                 }
138
139                 ml= mb->editelems->first;
140                 while(ml) {
141                         switch (action) {
142                         case SEL_SELECT:
143                                 ml->flag |= SELECT;
144                                 break;
145                         case SEL_DESELECT:
146                                 ml->flag &= ~SELECT;
147                                 break;
148                         case SEL_INVERT:
149                                 ml->flag ^= SELECT;
150                                 break;
151                         }
152                         ml= ml->next;
153                 }
154                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
155         }
156
157         return OPERATOR_FINISHED;
158 }
159
160 void MBALL_OT_select_all(wmOperatorType *ot)
161 {
162         /* identifiers */
163         ot->name= "Select or Deselect All";
164         ot->description= "Change selection of all meta elements";
165         ot->idname= "MBALL_OT_select_all";
166
167         /* callback functions */
168         ot->exec= select_all_exec;
169         ot->poll= ED_operator_editmball;
170
171         /* flags */
172         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
173
174         WM_operator_properties_select_all(ot);
175 }
176
177 /***************************** Select inverse operator *****************************/
178
179 /* Invert metaball selection */
180 static int select_inverse_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
181 {
182         Object *obedit= CTX_data_edit_object(C);
183         MetaBall *mb = (MetaBall*)obedit->data;
184         MetaElem *ml;
185         
186         ml= mb->editelems->first;
187         if(ml) {
188                 while(ml) {
189                         if(ml->flag & SELECT)
190                                 ml->flag &= ~SELECT;
191                         else
192                                 ml->flag |= SELECT;
193                         ml= ml->next;
194                 }
195                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
196         }
197         
198         return OPERATOR_FINISHED;
199 }
200
201 void MBALL_OT_select_inverse_metaelems(wmOperatorType *ot)
202 {
203         /* identifiers */
204         ot->name= "Inverse";
205         ot->description= "Select inverse of (un)selected metaelements";
206         ot->idname= "MBALL_OT_select_inverse_metaelems";
207
208         /* callback functions */
209         ot->exec= select_inverse_metaelems_exec;
210         ot->poll= ED_operator_editmball;
211
212         /* flags */
213         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
214 }
215
216 /***************************** Select random operator *****************************/
217
218 /* Random metaball selection */
219 static int select_random_metaelems_exec(bContext *C, wmOperator *op)
220 {
221         Object *obedit= CTX_data_edit_object(C);
222         MetaBall *mb = (MetaBall*)obedit->data;
223         MetaElem *ml;
224         float percent= RNA_float_get(op->ptr, "percent");
225         
226         if(percent == 0.0)
227                 return OPERATOR_CANCELLED;
228         
229         ml= mb->editelems->first;
230         BLI_srand( BLI_rand() );        /* Random seed */
231         
232         /* Stupid version of random selection. Should be improved. */
233         while(ml) {
234                 if(BLI_frand() < percent)
235                         ml->flag |= SELECT;
236                 else
237                         ml->flag &= ~SELECT;
238                 ml= ml->next;
239         }
240         
241         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
242         
243         return OPERATOR_FINISHED;
244 }
245
246
247 void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot)
248 {
249         /* identifiers */
250         ot->name= "Random...";
251         ot->description= "Randomly select metaelements";
252         ot->idname= "MBALL_OT_select_random_metaelems";
253         
254         /* callback functions */
255         ot->exec= select_random_metaelems_exec;
256         ot->invoke= WM_operator_props_popup;
257         ot->poll= ED_operator_editmball;
258         
259         /* flags */
260         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
261         
262         /* properties */
263         RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "Percentage of metaelems to select randomly.", 0.0001f, 1.0f);
264 }
265
266 /***************************** Duplicate operator *****************************/
267
268 /* Duplicate selected MetaElements */
269 static int duplicate_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
270 {
271         Object *obedit= CTX_data_edit_object(C);
272         MetaBall *mb = (MetaBall*)obedit->data;
273         MetaElem *ml, *newml;
274         
275         ml= mb->editelems->last;
276         if(ml) {
277                 while(ml) {
278                         if(ml->flag & SELECT) {
279                                 newml= MEM_dupallocN(ml);
280                                 BLI_addtail(mb->editelems, newml);
281                                 mb->lastelem= newml;
282                                 ml->flag &= ~SELECT;
283                         }
284                         ml= ml->prev;
285                 }
286                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
287                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
288         }
289
290         return OPERATOR_FINISHED;
291 }
292
293 static int duplicate_metaelems_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
294 {
295         int retv= duplicate_metaelems_exec(C, op);
296         
297         if (retv == OPERATOR_FINISHED) {
298                 RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
299                 WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
300         }
301         
302         return retv;
303 }
304
305
306 void MBALL_OT_duplicate_metaelems(wmOperatorType *ot)
307 {
308         /* identifiers */
309         ot->name= "Duplicate";
310         ot->description= "Delete selected metaelement(s)";
311         ot->idname= "MBALL_OT_duplicate_metaelems";
312
313         /* callback functions */
314         ot->exec= duplicate_metaelems_exec;
315         ot->invoke= duplicate_metaelems_invoke;
316         ot->poll= ED_operator_editmball;
317
318         /* flags */
319         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
320         
321         /* to give to transform */
322         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
323 }
324
325 /***************************** Delete operator *****************************/
326
327 /* Delete all selected MetaElems (not MetaBall) */
328 static int delete_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
329 {
330         Object *obedit= CTX_data_edit_object(C);
331         MetaBall *mb= (MetaBall*)obedit->data;
332         MetaElem *ml, *next;
333         
334         ml= mb->editelems->first;
335         if(ml) {
336                 while(ml) {
337                         next= ml->next;
338                         if(ml->flag & SELECT) {
339                                 if(mb->lastelem==ml) mb->lastelem= NULL;
340                                 BLI_remlink(mb->editelems, ml);
341                                 MEM_freeN(ml);
342                         }
343                         ml= next;
344                 }
345                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
346                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
347         }
348
349         return OPERATOR_FINISHED;
350 }
351
352 void MBALL_OT_delete_metaelems(wmOperatorType *ot)
353 {
354         /* identifiers */
355         ot->name= "Delete";
356         ot->description= "Delete selected metaelement(s)";
357         ot->idname= "MBALL_OT_delete_metaelems";
358
359         /* callback functions */
360         ot->exec= delete_metaelems_exec;
361         ot->poll= ED_operator_editmball;
362
363         /* flags */
364         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
365 }
366
367 /***************************** Hide operator *****************************/
368
369 /* Hide selected MetaElems */
370 static int hide_metaelems_exec(bContext *C, wmOperator *op)
371 {
372         Object *obedit= CTX_data_edit_object(C);
373         MetaBall *mb= (MetaBall*)obedit->data;
374         MetaElem *ml;
375         int hide_unselected= RNA_boolean_get(op->ptr, "unselected");
376
377         ml= mb->editelems->first;
378
379         if(ml) {
380                 /* Hide unselected metaelems */
381                 if(hide_unselected) {
382                         while(ml){
383                                 if(!(ml->flag & SELECT))
384                                         ml->flag |= MB_HIDE;
385                                 ml= ml->next;
386                         }
387                 /* Hide selected metaelems */   
388                 } else {
389                         while(ml){
390                                 if(ml->flag & SELECT)
391                                         ml->flag |= MB_HIDE;
392                                 ml= ml->next;
393                         }
394                 }
395                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
396                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
397         }
398
399         return OPERATOR_FINISHED;
400 }
401
402 void MBALL_OT_hide_metaelems(wmOperatorType *ot)
403 {
404         /* identifiers */
405         ot->name= "Hide";
406         ot->description= "Hide (un)selected metaelement(s)";
407         ot->idname= "MBALL_OT_hide_metaelems";
408
409         /* callback functions */
410         ot->exec= hide_metaelems_exec;
411         ot->poll= ED_operator_editmball;
412
413         /* flags */
414         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
415         
416         /* props */
417         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
418 }
419
420 /***************************** Unhide operator *****************************/
421
422 /* Unhide all edited MetaElems */
423 static int reveal_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
424 {
425         Object *obedit= CTX_data_edit_object(C);
426         MetaBall *mb= (MetaBall*)obedit->data;
427         MetaElem *ml;
428
429         ml= mb->editelems->first;
430
431         if(ml) {
432                 while(ml) {
433                         ml->flag &= ~MB_HIDE;
434                         ml= ml->next;
435                 }
436                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
437                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
438         }
439         
440         return OPERATOR_FINISHED;
441 }
442
443 void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
444 {
445         /* identifiers */
446         ot->name= "Reveal";
447         ot->description= "Reveal all hidden metaelements";
448         ot->idname= "MBALL_OT_reveal_metaelems";
449         
450         /* callback functions */
451         ot->exec= reveal_metaelems_exec;
452         ot->poll= ED_operator_editmball;
453         
454         /* flags */
455         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
456 }
457
458 /* Select MetaElement with mouse click (user can select radius circle or
459  * stiffness circle) */
460 int mouse_mball(bContext *C, short mval[2], int extend)
461 {
462         static MetaElem *startelem=NULL;
463         Object *obedit= CTX_data_edit_object(C);
464         ViewContext vc;
465         MetaBall *mb = (MetaBall*)obedit->data;
466         MetaElem *ml, *act=NULL;
467         int a, hits;
468         unsigned int buffer[4*MAXPICKBUF];
469         rcti rect;
470
471         view3d_set_viewcontext(C, &vc);
472
473         rect.xmin= mval[0]-12;
474         rect.xmax= mval[0]+12;
475         rect.ymin= mval[1]-12;
476         rect.ymax= mval[1]+12;
477
478         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
479
480         /* does startelem exist? */
481         ml= mb->editelems->first;
482         while(ml) {
483                 if(ml==startelem) break;
484                 ml= ml->next;
485         }
486
487         if(ml==NULL) startelem= mb->editelems->first;
488         
489         if(hits>0) {
490                 ml= startelem;
491                 while(ml) {
492                         for(a=0; a<hits; a++) {
493                                 /* index converted for gl stuff */
494                                 if(ml->selcol1==buffer[ 4 * a + 3 ]){
495                                         ml->flag |= MB_SCALE_RAD;
496                                         act= ml;
497                                 }
498                                 if(ml->selcol2==buffer[ 4 * a + 3 ]){
499                                         ml->flag &= ~MB_SCALE_RAD;
500                                         act= ml;
501                                 }
502                         }
503                         if(act) break;
504                         ml= ml->next;
505                         if(ml==NULL) ml= mb->editelems->first;
506                         if(ml==startelem) break;
507                 }
508                 
509                 /* When some metaelem was found, then it is necessary to select or
510                  * deselet it. */
511                 if(act) {
512                         if(extend==0) {
513                                 /* Deselect all existing metaelems */
514                                 ml= mb->editelems->first;
515                                 while(ml) {
516                                         ml->flag &= ~SELECT;
517                                         ml= ml->next;
518                                 }
519                                 /* Select only metaelem clicked on */
520                                 act->flag |= SELECT;
521                         }
522                         else {
523                                 if(act->flag & SELECT)
524                                         act->flag &= ~SELECT;
525                                 else
526                                         act->flag |= SELECT;
527                         }
528                         mb->lastelem= act;
529                         
530                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
531
532                         return 1;
533                 }
534         }
535
536         return 0;
537 }
538
539
540 /*  ************* undo for MetaBalls ************* */
541
542 /* free all MetaElems from ListBase */
543 static void freeMetaElemlist(ListBase *lb)
544 {
545         MetaElem *ml, *next;
546
547         if(lb==NULL) return;
548
549         ml= lb->first;
550         while(ml){
551                 next= ml->next;
552                 BLI_remlink(lb, ml);
553                 MEM_freeN(ml);
554                 ml= next;
555         }
556
557         lb->first= lb->last= NULL;
558 }
559
560
561 static void undoMball_to_editMball(void *lbu, void *lbe)
562 {
563         ListBase *lb= lbu;
564         ListBase *editelems= lbe;
565         MetaElem *ml, *newml;
566         
567         freeMetaElemlist(editelems);
568
569         /* copy 'undo' MetaElems to 'edit' MetaElems */
570         ml= lb->first;
571         while(ml){
572                 newml= MEM_dupallocN(ml);
573                 BLI_addtail(editelems, newml);
574                 ml= ml->next;
575         }
576         
577 }
578
579 static void *editMball_to_undoMball(void *lbe)
580 {
581         ListBase *editelems= lbe;
582         ListBase *lb;
583         MetaElem *ml, *newml;
584
585         /* allocate memory for undo ListBase */
586         lb= MEM_callocN(sizeof(ListBase), "listbase undo");
587         lb->first= lb->last= NULL;
588         
589         /* copy contents of current ListBase to the undo ListBase */
590         ml= editelems->first;
591         while(ml){
592                 newml= MEM_dupallocN(ml);
593                 BLI_addtail(lb, newml);
594                 ml= ml->next;
595         }
596         
597         return lb;
598 }
599
600 /* free undo ListBase of MetaElems */
601 static void free_undoMball(void *lbv)
602 {
603         ListBase *lb= lbv;
604         
605         freeMetaElemlist(lb);
606         MEM_freeN(lb);
607 }
608
609 ListBase *metaball_get_editelems(Object *ob)
610 {
611         if(ob && ob->type==OB_MBALL) {
612                 struct MetaBall *mb= (struct MetaBall*)ob->data;
613                 return mb->editelems;
614         }
615         return NULL;
616 }
617
618
619 static void *get_data(bContext *C)
620 {
621         Object *obedit= CTX_data_edit_object(C);
622         return metaball_get_editelems(obedit);
623 }
624
625 /* this is undo system for MetaBalls */
626 void undo_push_mball(bContext *C, char *name)
627 {
628         undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
629 }
630