svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r22130:22205
[blender.git] / source / blender / editors / space_view3d / view3d_select.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_curve_types.h"
37 #include "DNA_camera_types.h"
38 #include "DNA_lamp_types.h"
39 #include "DNA_meta_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_space_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_userdef_types.h"
47 #include "DNA_view3d_types.h"
48 #include "DNA_world_types.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "BLI_arithb.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_editVert.h"
55 #include "BLI_rand.h"
56
57 #include "BKE_action.h"
58 #include "BKE_context.h"
59 #include "BKE_depsgraph.h"
60 #include "BKE_object.h"
61 #include "BKE_global.h"
62 #include "BKE_scene.h"
63 #include "BKE_screen.h"
64 #include "BKE_utildefines.h"
65
66 #include "RE_pipeline.h"        // make_stars
67
68 #include "BIF_gl.h"
69
70 #include "WM_api.h"
71 #include "WM_types.h"
72
73 #include "RNA_access.h"
74 #include "RNA_define.h"
75
76 #include "ED_armature.h"
77 #include "ED_curve.h"
78 #include "ED_particle.h"
79 #include "ED_mesh.h"
80 #include "ED_object.h"
81 #include "ED_retopo.h"
82 #include "ED_screen.h"
83 #include "ED_types.h"
84 #include "ED_util.h"
85 #include "ED_mball.h"
86
87 #include "UI_interface.h"
88 #include "UI_resources.h"
89 #include "UI_view2d.h"
90
91 #include "PIL_time.h" /* smoothview */
92
93 #include "view3d_intern.h"      // own include
94
95
96 void view3d_set_viewcontext(bContext *C, ViewContext *vc)
97 {
98         memset(vc, 0, sizeof(ViewContext));
99         vc->ar= CTX_wm_region(C);
100         vc->scene= CTX_data_scene(C);
101         vc->v3d= CTX_wm_view3d(C);
102         vc->rv3d= vc->ar->regiondata;
103         vc->obact= CTX_data_active_object(C);
104         vc->obedit= CTX_data_edit_object(C); 
105 }
106
107 void view3d_get_view_aligned_coordinate(ViewContext *vc, float *fp, short mval[2])
108 {
109         float dvec[3];
110         short mx, my;
111         
112         mx= mval[0];
113         my= mval[1];
114         
115         project_short_noclip(vc->ar, fp, mval);
116         
117         initgrabz(vc->rv3d, fp[0], fp[1], fp[2]);
118         
119         if(mval[0]!=IS_CLIPPED) {
120                 window_to_3d_delta(vc->ar, dvec, mval[0]-mx, mval[1]-my);
121                 VecSubf(fp, fp, dvec);
122         }
123 }
124
125 void view3d_get_transformation(ViewContext *vc, Object *ob, bglMats *mats)
126 {
127         float cpy[4][4];
128         int i, j;
129
130         Mat4MulMat4(cpy, ob->obmat, vc->rv3d->viewmat);
131
132         for(i = 0; i < 4; ++i) {
133                 for(j = 0; j < 4; ++j) {
134                         mats->projection[i*4+j] = vc->rv3d->winmat[i][j];
135                         mats->modelview[i*4+j] = cpy[i][j];
136                 }
137         }
138
139         mats->viewport[0] = vc->ar->winrct.xmin;
140         mats->viewport[1] = vc->ar->winrct.ymin;
141         mats->viewport[2] = vc->ar->winx;
142         mats->viewport[3] = vc->ar->winy;       
143 }
144
145 /* ********************** view3d_select: selection manipulations ********************* */
146
147 /* XXX to solve *************** */
148 static void BIF_undo_push() {}
149 /* XXX end ********************* */
150
151 /* local prototypes */
152
153 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
154 {
155         EditVert *eve;
156         int index= em_wireoffs;
157
158         for(eve= em->verts.first; eve; eve= eve->next, index++) {
159                 if(eve->h==0) {
160                         if(EM_check_backbuf(index)) {
161                                 eve->f = select?(eve->f|1):(eve->f&~1);
162                         }
163                 }
164         }
165 }
166
167 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
168 {
169         EditEdge *eed;
170         int index= em_solidoffs;
171
172         for(eed= em->edges.first; eed; eed= eed->next, index++) {
173                 if(eed->h==0) {
174                         if(EM_check_backbuf(index)) {
175                                 EM_select_edge(eed, select);
176                         }
177                 }
178         }
179 }
180
181 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
182 {
183         EditFace *efa;
184         int index= 1;
185
186         for(efa= em->faces.first; efa; efa= efa->next, index++) {
187                 if(efa->h==0) {
188                         if(EM_check_backbuf(index)) {
189                                 EM_select_face_fgon(em, efa, select);
190                         }
191                 }
192         }
193 }
194
195 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
196 {
197         MFace *mface = me->mface;
198         int a;
199
200         if (mface) {
201                 for(a=1; a<=me->totface; a++, mface++) {
202                         if(EM_check_backbuf(a)) {
203                                 mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL);
204                         }
205                 }
206         }
207 }
208
209 void arrows_move_cursor(unsigned short event)
210 {
211 #if 0
212         short mval[2];
213
214         getmouseco_sc(mval);
215
216         if(event==UPARROWKEY) {
217                 warp_pointer(mval[0], mval[1]+1);
218         } else if(event==DOWNARROWKEY) {
219                 warp_pointer(mval[0], mval[1]-1);
220         } else if(event==LEFTARROWKEY) {
221                 warp_pointer(mval[0]-1, mval[1]);
222         } else if(event==RIGHTARROWKEY) {
223                 warp_pointer(mval[0]+1, mval[1]);
224         }
225 #endif
226 }
227
228
229 /* *********************** GESTURE AND LASSO ******************* */
230
231 /* helper also for borderselect */
232 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
233 {
234         return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
235 }
236
237 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
238 {
239         int d1, d2, d3, d4;
240         
241         /* check points in rect */
242         if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
243         
244         /* check points completely out rect */
245         if(x1<rect->xmin && x2<rect->xmin) return 0;
246         if(x1>rect->xmax && x2>rect->xmax) return 0;
247         if(y1<rect->ymin && y2<rect->ymin) return 0;
248         if(y1>rect->ymax && y2>rect->ymax) return 0;
249         
250         /* simple check lines intersecting. */
251         d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
252         d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
253         d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
254         d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
255         
256         if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
257         if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
258         
259         return 1;
260 }
261
262
263 #define MOVES_GESTURE 50
264 #define MOVES_LASSO 500
265
266 int lasso_inside(short mcords[][2], short moves, short sx, short sy)
267 {
268         /* we do the angle rule, define that all added angles should be about zero or 2*PI */
269         float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
270         int a;
271         short *p1, *p2;
272         
273         if(sx==IS_CLIPPED)
274                 return 0;
275         
276         p1= mcords[moves-1];
277         p2= mcords[0];
278         
279         /* first vector */
280         fp1[0]= (float)(p1[0]-sx);
281         fp1[1]= (float)(p1[1]-sy);
282         len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
283         fp1[0]/= len;
284         fp1[1]/= len;
285         
286         for(a=0; a<moves; a++) {
287                 /* second vector */
288                 fp2[0]= (float)(p2[0]-sx);
289                 fp2[1]= (float)(p2[1]-sy);
290                 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
291                 fp2[0]/= len;
292                 fp2[1]/= len;
293                 
294                 /* dot and angle and cross */
295                 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
296                 ang= fabs(saacos(dot));
297
298                 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
299                 
300                 if(cross<0.0) angletot-= ang;
301                 else angletot+= ang;
302                 
303                 /* circulate */
304                 fp1[0]= fp2[0]; fp1[1]= fp2[1];
305                 p1= p2;
306                 p2= mcords[a+1];
307         }
308         
309         if( fabs(angletot) > 4.0 ) return 1;
310         return 0;
311 }
312
313 /* edge version for lasso select. we assume boundbox check was done */
314 int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
315 {
316         short v1[2], v2[2];
317         int a;
318
319         if(x0==IS_CLIPPED || x1==IS_CLIPPED)
320                 return 0;
321         
322         v1[0] = x0, v1[1] = y0;
323         v2[0] = x1, v2[1] = y1;
324
325         /* check points in lasso */
326         if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
327         if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
328         
329         /* no points in lasso, so we have to intersect with lasso edge */
330         
331         if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
332         for(a=0; a<moves-1; a++) {
333                 if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
334         }
335         
336         return 0;
337 }
338
339
340 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 
341    and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
342 */
343 static void do_lasso_select_pose(ViewContext *vc, short mcords[][2], short moves, short select)
344 {
345         Object *ob= vc->obact;
346         bPoseChannel *pchan;
347         float vec[3];
348         short sco1[2], sco2[2];
349         
350         if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
351         
352         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
353                 VECCOPY(vec, pchan->pose_head);
354                 Mat4MulVecfl(ob->obmat, vec);
355                 project_short(vc->ar, vec, sco1);
356                 VECCOPY(vec, pchan->pose_tail);
357                 Mat4MulVecfl(ob->obmat, vec);
358                 project_short(vc->ar, vec, sco2);
359                 
360                 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
361                         if(select) pchan->bone->flag |= BONE_SELECTED;
362                         else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
363                 }
364         }
365 }
366
367
368 static void do_lasso_select_objects(ViewContext *vc, short mcords[][2], short moves, short select)
369 {
370         Base *base;
371         
372         for(base= vc->scene->base.first; base; base= base->next) {
373                 if(base->lay & vc->v3d->lay) {
374                         project_short(vc->ar, base->object->obmat[3], &base->sx);
375                         if(lasso_inside(mcords, moves, base->sx, base->sy)) {
376                                 
377                                 if(select) ED_base_object_select(base, BA_SELECT);
378                                 else ED_base_object_select(base, BA_DESELECT);
379                                 base->object->flag= base->flag;
380                         }
381                         if(base->object->flag & OB_POSEMODE) {
382                                 do_lasso_select_pose(vc, mcords, moves, select);
383                         }
384                 }
385         }
386 }
387
388 void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
389 {
390         short a;
391         
392         rect->xmin= rect->xmax= mcords[0][0];
393         rect->ymin= rect->ymax= mcords[0][1];
394         
395         for(a=1; a<moves; a++) {
396                 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
397                 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
398                 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
399                 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
400         }
401 }
402
403 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
404 {
405         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
406
407         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
408                 eve->f = data->select?(eve->f|1):(eve->f&~1);
409         }
410 }
411 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
412 {
413         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
414
415         if (EM_check_backbuf(em_solidoffs+index)) {
416                 if (data->pass==0) {
417                         if (    edge_fully_inside_rect(data->rect, x0, y0, x1, y1)  &&
418                                         lasso_inside(data->mcords, data->moves, x0, y0) &&
419                                         lasso_inside(data->mcords, data->moves, x1, y1)) {
420                                 EM_select_edge(eed, data->select);
421                                 data->done = 1;
422                         }
423                 } else {
424                         if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
425                                 EM_select_edge(eed, data->select);
426                         }
427                 }
428         }
429 }
430 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
431 {
432         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
433
434         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
435                 EM_select_face_fgon(data->vc.em, efa, data->select);
436         }
437 }
438
439 static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves, short select)
440 {
441         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
442         ToolSettings *ts= vc->scene->toolsettings;
443         rcti rect;
444         int bbsel;
445         
446         lasso_select_boundbox(&rect, mcords, moves);
447         
448         /* set editmesh */
449         vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
450
451         data.vc= *vc;
452         data.rect = &rect;
453         data.mcords = mcords;
454         data.moves = moves;
455         data.select = select;
456         data.done = 0;
457         data.pass = 0;
458
459         bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
460         
461         if(ts->selectmode & SCE_SELECT_VERTEX) {
462                 if (bbsel) {
463                         EM_backbuf_checkAndSelectVerts(vc->em, select);
464                 } else {
465                         mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
466                 }
467         }
468         if(ts->selectmode & SCE_SELECT_EDGE) {
469                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
470
471                 data.pass = 0;
472                 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
473
474                 if (data.done==0) {
475                         data.pass = 1;
476                         mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
477                 }
478         }
479         
480         if(ts->selectmode & SCE_SELECT_FACE) {
481                 if (bbsel) {
482                         EM_backbuf_checkAndSelectFaces(vc->em, select);
483                 } else {
484                         mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
485                 }
486         }
487         
488         EM_free_backbuf();
489         EM_selectmode_flush(vc->em);    
490 }
491
492 #if 0
493 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
494 static void do_lasso_select_mesh_uv(short mcords[][2], short moves, short select)
495 {
496         EditFace *efa;
497         MTFace *tf;
498         int screenUV[2], nverts, i, ok = 1;
499         rcti rect;
500         
501         lasso_select_boundbox(&rect, mcords, moves);
502         
503         if (draw_uvs_face_check()) { /* Face Center Sel */
504                 float cent[2];
505                 ok = 0;
506                 for (efa= em->faces.first; efa; efa= efa->next) {
507                         /* assume not touched */
508                         efa->tmp.l = 0;
509                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
510                         if ((select) != (simaFaceSel_Check(efa, tf))) {
511                                 uv_center(tf->uv, cent, (void *)efa->v4);
512                                 uvco_to_areaco_noclip(cent, screenUV);
513                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
514                                         efa->tmp.l = ok = 1;
515                                 }
516                         }
517                 }
518                 /* (de)selects all tagged faces and deals with sticky modes */
519                 if (ok)
520                         uvface_setsel__internal(select);
521                 
522         } else { /* Vert Sel*/
523                 for (efa= em->faces.first; efa; efa= efa->next) {
524                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
525                         if (simaFaceDraw_Check(efa, tf)) {              
526                                 nverts= efa->v4? 4: 3;
527                                 for(i=0; i<nverts; i++) {
528                                         if ((select) != (simaUVSel_Check(efa, tf, i))) {
529                                                 uvco_to_areaco_noclip(tf->uv[i], screenUV);
530                                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
531                                                         if (select) {
532                                                                 simaUVSel_Set(efa, tf, i);
533                                                         } else {
534                                                                 simaUVSel_UnSet(efa, tf, i);
535                                                         }
536                                                 }
537                                         }
538                                 }
539                         }
540                 }
541         }
542         if (ok && G.sima->flag & SI_SYNC_UVSEL) {
543                 if (select) EM_select_flush(vc->em);
544                 else            EM_deselect_flush(vc->em);
545         }
546 }
547 #endif
548
549 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
550 {
551         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
552
553         if (lasso_inside(data->mcords, data->moves, x, y)) {
554                 if (bp) {
555                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
556                 } else {
557                         if (G.f & G_HIDDENHANDLES) {
558                                 /* can only be beztindex==0 here since handles are hidden */
559                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
560                         } else {
561                                 if (beztindex==0) {
562                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
563                                 } else if (beztindex==1) {
564                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
565                                 } else {
566                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
567                                 }
568                         }
569                 }
570         }
571 }
572
573 static void do_lasso_select_curve(ViewContext *vc, short mcords[][2], short moves, short select)
574 {
575         struct { short (*mcords)[2]; short moves; short select; } data;
576
577         /* set vc->editnurb */
578         data.mcords = mcords;
579         data.moves = moves;
580         data.select = select;
581
582         nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data);
583 }
584
585 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
586 {
587         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
588
589         if (lasso_inside(data->mcords, data->moves, x, y)) {
590                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
591         }
592 }
593 static void do_lasso_select_lattice(ViewContext *vc, short mcords[][2], short moves, short select)
594 {
595         struct { short (*mcords)[2]; short moves; short select; } data;
596
597         /* set editdata in vc */
598         data.mcords = mcords;
599         data.moves = moves;
600         data.select = select;
601
602         lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data);
603 }
604
605 static void do_lasso_select_armature(ViewContext *vc, short mcords[][2], short moves, short select)
606 {
607         bArmature *arm= vc->obedit->data;
608         EditBone *ebone;
609         float vec[3];
610         short sco1[2], sco2[2], didpoint;
611         
612         /* set editdata in vc */
613         
614         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
615
616                 VECCOPY(vec, ebone->head);
617                 Mat4MulVecfl(vc->obedit->obmat, vec);
618                 project_short(vc->ar, vec, sco1);
619                 VECCOPY(vec, ebone->tail);
620                 Mat4MulVecfl(vc->obedit->obmat, vec);
621                 project_short(vc->ar, vec, sco2);
622                 
623                 didpoint= 0;
624                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
625                         if(select) ebone->flag |= BONE_ROOTSEL;
626                         else ebone->flag &= ~BONE_ROOTSEL;
627                         didpoint= 1;
628                 }
629                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
630                    if(select) ebone->flag |= BONE_TIPSEL;
631                    else ebone->flag &= ~BONE_TIPSEL;
632                    didpoint= 1;
633                 }
634                 /* if one of points selected, we skip the bone itself */
635                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
636                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
637                         else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
638                 }
639         }
640 }
641
642 static void do_lasso_select_facemode(ViewContext *vc, short mcords[][2], short moves, short select)
643 {
644         Object *ob= vc->obact;
645         Mesh *me= ob?ob->data:NULL;
646         rcti rect;
647         
648         if(me==NULL || me->mtface==NULL) return;
649         if(me->totface==0) return;
650         
651         em_vertoffs= me->totface+1;     /* max index array */
652         
653         lasso_select_boundbox(&rect, mcords, moves);
654         EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
655         
656         EM_backbuf_checkAndSelectTFaces(me, select);
657         
658         EM_free_backbuf();
659         
660 // XXX  object_tface_flags_changed(ob, 0);
661 }
662
663 #if 0
664 static void do_lasso_select_node(short mcords[][2], short moves, short select)
665 {
666         SpaceNode *snode = sa->spacedata.first;
667         
668         bNode *node;
669         rcti rect;
670         short node_cent[2];
671         float node_centf[2];
672         
673         lasso_select_boundbox(&rect, mcords, moves);
674         
675         /* store selection in temp test flag */
676         for(node= snode->edittree->nodes.first; node; node= node->next) {
677                 
678                 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2;
679                 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2;
680                 
681                 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
682                 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
683                         if (select) {
684                                 node->flag |= SELECT;
685                         } else {
686                                 node->flag &= ~SELECT;
687                         }
688                 }
689         }
690         BIF_undo_push("Lasso select nodes");
691 }
692 #endif
693
694 void view3d_lasso_select(bContext *C, ViewContext *vc, short mcords[][2], short moves, short select)
695 {
696         if(vc->obedit==NULL) {
697                 if(FACESEL_PAINT_TEST)
698                         do_lasso_select_facemode(vc, mcords, moves, select);
699                 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
700                         ;
701                 else if(G.f & G_PARTICLEEDIT)
702                         PE_lasso_select(C, mcords, moves, select);
703                 else  
704                         do_lasso_select_objects(vc, mcords, moves, select);
705         }
706         else if(vc->obedit->type==OB_MESH) {
707                 do_lasso_select_mesh(vc, mcords, moves, select);
708         } else if(vc->obedit->type==OB_CURVE || vc->obedit->type==OB_SURF) 
709                 do_lasso_select_curve(vc, mcords, moves, select);
710         else if(vc->obedit->type==OB_LATTICE) 
711                 do_lasso_select_lattice(vc, mcords, moves, select);
712         else if(vc->obedit->type==OB_ARMATURE)
713                 do_lasso_select_armature(vc, mcords, moves, select);
714
715         BIF_undo_push("Lasso select");
716         
717 }
718
719
720 /* lasso operator gives properties, but since old code works
721    with short array we convert */
722 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
723 {
724         ViewContext vc;
725         int select, i= 0;
726         short mcords[1024][2];
727
728         RNA_BEGIN(op->ptr, itemptr, "path") {
729                 float loc[2];
730                 
731                 RNA_float_get_array(&itemptr, "loc", loc);
732                 mcords[i][0]= (short)loc[0];
733                 mcords[i][1]= (short)loc[1];
734                 i++;
735                 if(i>=1024) break;
736         }
737         RNA_END;
738         
739         if(i>1) {
740                 view3d_operator_needs_opengl(C);
741                 
742                 /* setup view context for argument to callbacks */
743                 view3d_set_viewcontext(C, &vc);
744                 
745                 select= !RNA_boolean_get(op->ptr, "deselect");
746                 view3d_lasso_select(C, &vc, mcords, i, select);
747                 
748                 return OPERATOR_FINISHED;
749         }
750         return OPERATOR_PASS_THROUGH;
751 }
752
753 void VIEW3D_OT_select_lasso(wmOperatorType *ot)
754 {
755         ot->name= "Lasso Select";
756         ot->idname= "VIEW3D_OT_select_lasso";
757         
758         ot->invoke= WM_gesture_lasso_invoke;
759         ot->modal= WM_gesture_lasso_modal;
760         ot->exec= view3d_lasso_select_exec;
761         ot->poll= WM_operator_winactive;
762         
763         /* flags */
764         ot->flag= OPTYPE_UNDO;
765         
766         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
767         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items.");
768 }
769
770
771 /* ************************************************* */
772
773 #if 0
774 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
775 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
776 {
777         Base *base;
778         unsigned int *bufmin,*bufmax;
779         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
780         unsigned int retval=0;
781         
782         base= LASTBASE;
783         if(base==0) return 0;
784         maxob= base->selcol;
785
786         aantal= (size-1)/2;
787         rc= 0;
788
789         dirvec[0][0]= 1;
790         dirvec[0][1]= 0;
791         dirvec[1][0]= 0;
792         dirvec[1][1]= -size;
793         dirvec[2][0]= -1;
794         dirvec[2][1]= 0;
795         dirvec[3][0]= 0;
796         dirvec[3][1]= size;
797
798         bufmin= buf;
799         bufmax= buf+ size*size;
800         buf+= aantal*size+ aantal;
801
802         for(tel=1;tel<=size;tel++) {
803
804                 for(a=0;a<2;a++) {
805                         for(b=0;b<tel;b++) {
806
807                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
808                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
809                                 
810                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
811
812                                 if(buf<bufmin || buf>=bufmax) return retval;
813                         }
814                         rc++;
815                         rc &= 3;
816                 }
817         }
818         return retval;
819 }
820 #endif
821
822 /* ************************** mouse select ************************* */
823
824
825 /* The max number of menu items in an object select menu */
826 #define SEL_MENU_SIZE   22
827
828 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
829 {
830         Base *base;
831         
832         for(base= FIRSTBASE; base; base= base->next) {
833                 if (base->flag & SELECT) {
834                         if(b!=base) {
835                                 ED_base_object_select(base, BA_DESELECT);
836                         }
837                 }
838         }
839 }
840
841 static Base *mouse_select_menu(ViewContext *vc, unsigned int *buffer, int hits, short *mval)
842 {
843         Scene *scene= vc->scene;
844         View3D *v3d= vc->v3d;
845         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
846         Base *base;
847         short baseCount = 0;
848         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       /* max ob name = 22 */
849         char str[32];
850         
851         for(base=FIRSTBASE; base; base= base->next) {
852                 if (BASE_SELECTABLE(v3d, base)) {
853                         baseList[baseCount] = NULL;
854                         
855                         /* two selection methods, the CTRL select uses max dist of 15 */
856                         if(buffer) {
857                                 int a;
858                                 for(a=0; a<hits; a++) {
859                                         /* index was converted */
860                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
861                                 }
862                         }
863                         else {
864                                 int temp, dist=15;
865                                 
866                                 project_short(vc->ar, base->object->obmat[3], &base->sx);
867                                 
868                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
869                                 if(temp<dist ) baseList[baseCount] = base;
870                         }
871                         
872                         if(baseList[baseCount]) {
873                                 if (baseCount < SEL_MENU_SIZE) {
874                                         baseList[baseCount] = base;
875                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        /* max ob name == 22 */
876                                                         strcat(menuText, str);
877                                                         baseCount++;
878                                 }
879                         }
880                 }
881         }
882
883         if(baseCount<=1) return baseList[0];
884         else {
885                 baseCount = -1; // XXX = pupmenu(menuText);
886                 
887                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
888                         return baseList[baseCount-1];
889                 }
890                 else return NULL;
891         }
892 }
893
894 /* we want a select buffer with bones, if there are... */
895 /* so check three selection levels and compare */
896 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, short *mval)
897 {
898         rcti rect;
899         int offs;
900         short a, hits15, hits9=0, hits5=0;
901         short has_bones15=0, has_bones9=0, has_bones5=0;
902         
903         BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
904         hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
905         if(hits15>0) {
906                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
907                 
908                 offs= 4*hits15;
909                 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
910                 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
911                 if(hits9>0) {
912                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
913                         
914                         offs+= 4*hits9;
915                         BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
916                         hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
917                         if(hits5>0) {
918                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
919                         }
920                 }
921                 
922                 if(has_bones5) {
923                         offs= 4*hits15 + 4*hits9;
924                         memcpy(buffer, buffer+offs, 4*offs);
925                         return hits5;
926                 }
927                 if(has_bones9) {
928                         offs= 4*hits15;
929                         memcpy(buffer, buffer+offs, 4*offs);
930                         return hits9;
931                 }
932                 if(has_bones15) {
933                         return hits15;
934                 }
935                 
936                 if(hits5>0) {
937                         offs= 4*hits15 + 4*hits9;
938                         memcpy(buffer, buffer+offs, 4*offs);
939                         return hits5;
940                 }
941                 if(hits9>0) {
942                         offs= 4*hits15;
943                         memcpy(buffer, buffer+offs, 4*offs);
944                         return hits9;
945                 }
946                 return hits15;
947         }
948         
949         return 0;
950 }
951
952
953 /* mval is region coords */
954 static void mouse_select(bContext *C, short *mval, short extend, short obcenter)
955 {
956         ViewContext vc;
957         ARegion *ar= CTX_wm_region(C);
958         View3D *v3d= CTX_wm_view3d(C);
959         Scene *scene= CTX_data_scene(C);
960         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
961         unsigned int buffer[4*MAXPICKBUF];
962         int temp, a, dist=100;
963         short hits;
964         
965         /* setup view context for argument to callbacks */
966         view3d_set_viewcontext(C, &vc);
967         
968         /* always start list from basact in wire mode */
969         startbase=  FIRSTBASE;
970         if(BASACT && BASACT->next) startbase= BASACT->next;
971         
972         /* This block uses the control key to make the object selected by its center point rather then its contents */
973         /* XXX later on, in editmode do not activate */
974         if(vc.obedit==NULL && obcenter) {
975                 
976                 /* note; shift+alt goes to group-flush-selecting */
977                 /* XXX solve */
978                 if(0) 
979                         basact= mouse_select_menu(&vc, NULL, 0, mval);
980                 else {
981                         base= startbase;
982                         while(base) {
983                                 if (BASE_SELECTABLE(v3d, base)) {
984                                         project_short(ar, base->object->obmat[3], &base->sx);
985                                         
986                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
987                                         if(base==BASACT) temp+=10;
988                                         if(temp<dist ) {
989                                                 
990                                                 dist= temp;
991                                                 basact= base;
992                                         }
993                                 }
994                                 base= base->next;
995                                 
996                                 if(base==0) base= FIRSTBASE;
997                                 if(base==startbase) break;
998                         }
999                 }
1000         }
1001         else {
1002                 /* if objects have posemode set, the bones are in the same selection buffer */
1003                 
1004                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1005                 
1006                 if(hits>0) {
1007                         int has_bones= 0;
1008                         
1009                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1010
1011                         /* note; shift+alt goes to group-flush-selecting */
1012                         if(has_bones==0 && 0) 
1013                                 basact= mouse_select_menu(&vc, buffer, hits, mval);
1014                         else {
1015                                 static short lastmval[2]={-100, -100};
1016                                 int donearest= 0;
1017                                 
1018                                 /* define if we use solid nearest select or not */
1019                                 if(v3d->drawtype>OB_WIRE) {
1020                                         donearest= 1;
1021                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1022                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
1023                                                         donearest= 0;
1024                                         }
1025                                 }
1026                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1027                                 
1028                                 if(donearest) {
1029                                         unsigned int min= 0xFFFFFFFF;
1030                                         int selcol= 0, notcol=0;
1031                                         
1032
1033                                         if(has_bones) {
1034                                                 /* we skip non-bone hits */
1035                                                 for(a=0; a<hits; a++) {
1036                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1037                                                                 min= buffer[4*a+1];
1038                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1039                                                         }
1040                                                 }
1041                                         }
1042                                         else {
1043                                                 /* only exclude active object when it is selected... */
1044                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1045                                         
1046                                                 for(a=0; a<hits; a++) {
1047                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1048                                                                 min= buffer[4*a+1];
1049                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1050                                                         }
1051                                                 }
1052                                         }
1053
1054                                         base= FIRSTBASE;
1055                                         while(base) {
1056                                                 if(base->lay & v3d->lay) {
1057                                                         if(base->selcol==selcol) break;
1058                                                 }
1059                                                 base= base->next;
1060                                         }
1061                                         if(base) basact= base;
1062                                 }
1063                                 else {
1064                                         
1065                                         base= startbase;
1066                                         while(base) {
1067                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
1068                                                  * with an un-selectable choice */
1069                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1070                                                         base=base->next;
1071                                                         if(base==NULL) base= FIRSTBASE;
1072                                                         if(base==startbase) break;
1073                                                 }
1074                                         
1075                                                 if(base->lay & v3d->lay) {
1076                                                         for(a=0; a<hits; a++) {
1077                                                                 if(has_bones) {
1078                                                                         /* skip non-bone objects */
1079                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1080                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1081                                                                                         basact= base;
1082                                                                         }
1083                                                                 }
1084                                                                 else {
1085                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1086                                                                                 basact= base;
1087                                                                 }
1088                                                         }
1089                                                 }
1090                                                 
1091                                                 if(basact) break;
1092                                                 
1093                                                 base= base->next;
1094                                                 if(base==NULL) base= FIRSTBASE;
1095                                                 if(base==startbase) break;
1096                                         }
1097                                 }
1098                         }
1099                         
1100                         if(has_bones && basact) {
1101                                 if(ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) {     /* then bone is found */
1102                                 
1103                                         /* we make the armature selected: 
1104                                            not-selected active object in posemode won't work well for tools */
1105                                         basact->flag|= SELECT;
1106                                         basact->object->flag= basact->flag;
1107                                         
1108                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1109                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1110                                         
1111                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1112                                         if(G.f & G_WEIGHTPAINT) {
1113                                                 /* prevent activating */
1114                                                 basact= NULL;
1115                                         }
1116
1117                                 }
1118                                 /* prevent bone selecting to pass on to object selecting */
1119                                 if(basact==BASACT)
1120                                         basact= NULL;
1121                         }
1122                 }
1123         }
1124         
1125         /* so, do we have something selected? */
1126         if(basact) {
1127                 
1128                 if(vc.obedit) {
1129                         /* only do select */
1130                         deselectall_except(scene, basact);
1131                         ED_base_object_select(basact, BA_SELECT);
1132                 }
1133                 /* also prevent making it active on mouse selection */
1134                 else if (BASE_SELECTABLE(v3d, basact)) {
1135
1136                         oldbasact= BASACT;
1137                         
1138                         if(!extend) {
1139                                 deselectall_except(scene, basact);
1140                                 ED_base_object_select(basact, BA_SELECT);
1141                         }
1142                         else if(0) {
1143                                 // XXX select_all_from_groups(basact);
1144                         }
1145                         else {
1146                                 if(basact->flag & SELECT) {
1147                                         if(basact==oldbasact)
1148                                                 ED_base_object_select(basact, BA_DESELECT);
1149                                 }
1150                                 else ED_base_object_select(basact, BA_SELECT);
1151                         }
1152
1153                         if(oldbasact != basact) {
1154                                 ED_base_object_activate(C, basact); /* adds notifier */
1155                         }
1156
1157                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1158                 }
1159         }
1160 }
1161
1162 /* ********************  border and circle ************************************** */
1163
1164
1165 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1166 {
1167         int radsq= rad*rad;
1168         float v1[2], v2[2], v3[2];
1169         
1170         /* check points in circle itself */
1171         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1172         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1173         
1174         /* pointdistline */
1175         v3[0]= centx;
1176         v3[1]= centy;
1177         v1[0]= x1;
1178         v1[1]= y1;
1179         v2[0]= x2;
1180         v2[1]= y2;
1181         
1182         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1183         
1184         return 0;
1185 }
1186
1187 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1188 {
1189         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1190
1191         if (BLI_in_rcti(data->rect, x, y)) {
1192                 if (bp) {
1193                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1194                 } else {
1195                         if (G.f & G_HIDDENHANDLES) {
1196                                 /* can only be beztindex==0 here since handles are hidden */
1197                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1198                         } else {
1199                                 if (beztindex==0) {
1200                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1201                                 } else if (beztindex==1) {
1202                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1203                                 } else {
1204                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1205                                 }
1206                         }
1207                 }
1208         }
1209 }
1210 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select)
1211 {
1212         struct { ViewContext vc; rcti *rect; int select; } data;
1213         
1214         data.vc= *vc;
1215         data.rect = rect;
1216         data.select = select;
1217
1218         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1219 }
1220
1221 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1222 {
1223         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1224
1225         if (BLI_in_rcti(data->rect, x, y)) {
1226                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1227         }
1228 }
1229 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select)
1230 {
1231         struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1232
1233         data.vc= *vc;
1234         data.rect = rect;
1235         data.select = select;
1236
1237         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1238 }
1239
1240 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1241 {
1242         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1243
1244         if (BLI_in_rcti(data->rect, x, y)) {
1245                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1246         }
1247 }
1248 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1249 {
1250         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1251
1252         if(EM_check_backbuf(em_solidoffs+index)) {
1253                 if (data->pass==0) {
1254                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1255                                 EM_select_edge(eed, data->select);
1256                                 data->done = 1;
1257                         }
1258                 } else {
1259                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1260                                 EM_select_edge(eed, data->select);
1261                         }
1262                 }
1263         }
1264 }
1265 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1266 {
1267         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1268
1269         if (BLI_in_rcti(data->rect, x, y)) {
1270                 EM_select_face_fgon(data->vc.em, efa, data->select);
1271         }
1272 }
1273 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
1274 {
1275         struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1276         ToolSettings *ts= vc->scene->toolsettings;
1277         int bbsel;
1278         
1279         data.vc= *vc;
1280         data.rect = rect;
1281         data.select = select;
1282         data.pass = 0;
1283         data.done = 0;
1284
1285         bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1286
1287         if(ts->selectmode & SCE_SELECT_VERTEX) {
1288                 if (bbsel) {
1289                         EM_backbuf_checkAndSelectVerts(vc->em, select);
1290                 } else {
1291                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1292                 }
1293         }
1294         if(ts->selectmode & SCE_SELECT_EDGE) {
1295                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1296
1297                 data.pass = 0;
1298                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1299
1300                 if (data.done==0) {
1301                         data.pass = 1;
1302                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1303                 }
1304         }
1305         
1306         if(ts->selectmode & SCE_SELECT_FACE) {
1307                 if(bbsel) {
1308                         EM_backbuf_checkAndSelectFaces(vc->em, select);
1309                 } else {
1310                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1311                 }
1312         }
1313         
1314         EM_free_backbuf();
1315                 
1316         EM_selectmode_flush(vc->em);
1317 }
1318
1319 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1320 {
1321         ViewContext vc;
1322         Scene *scene= CTX_data_scene(C);
1323         ScrArea *sa= CTX_wm_area(C);
1324         View3D *v3d= sa->spacedata.first;
1325         Object *obedit= CTX_data_edit_object(C);
1326         rcti rect;
1327         Base *base;
1328         MetaElem *ml;
1329         unsigned int buffer[4*MAXPICKBUF];
1330         int a, index;
1331         short hits, val;
1332
1333         view3d_operator_needs_opengl(C);
1334         
1335         /* setup view context for argument to callbacks */
1336         view3d_set_viewcontext(C, &vc);
1337         
1338         val= RNA_int_get(op->ptr, "event_type");
1339         rect.xmin= RNA_int_get(op->ptr, "xmin");
1340         rect.ymin= RNA_int_get(op->ptr, "ymin");
1341         rect.xmax= RNA_int_get(op->ptr, "xmax");
1342         rect.ymax= RNA_int_get(op->ptr, "ymax");
1343         
1344         if(obedit==NULL && (FACESEL_PAINT_TEST)) {
1345 // XXX          face_borderselect();
1346                 return OPERATOR_FINISHED;
1347         }
1348         else if(obedit==NULL && (G.f & G_PARTICLEEDIT)) {
1349                 return PE_border_select(C, &rect, (val==LEFTMOUSE));
1350         }
1351         
1352         if(obedit) {
1353                 if(obedit->type==OB_MESH) {
1354                         Mesh *me= obedit->data;
1355                         vc.em= me->edit_mesh;
1356                         do_mesh_box_select(&vc, &rect, (val==LEFTMOUSE));
1357 //                      if (EM_texFaceCheck())
1358                         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1359                         
1360                 }
1361                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1362                         do_nurbs_box_select(&vc, &rect, val==LEFTMOUSE);
1363                 }
1364                 else if(obedit->type==OB_MBALL) {
1365                         MetaBall *mb = (MetaBall*)obedit->data;
1366                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1367                         
1368                         ml= mb->editelems->first;
1369                         
1370                         while(ml) {
1371                                 for(a=0; a<hits; a++) {
1372                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1373                                                 ml->flag |= MB_SCALE_RAD;
1374                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1375                                                 else ml->flag &= ~SELECT;
1376                                                 break;
1377                                         }
1378                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1379                                                 ml->flag &= ~MB_SCALE_RAD;
1380                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1381                                                 else ml->flag &= ~SELECT;
1382                                                 break;
1383                                         }
1384                                 }
1385                                 ml= ml->next;
1386                         }
1387                 }
1388                 else if(obedit->type==OB_ARMATURE) {
1389                         bArmature *arm= obedit->data;
1390                         EditBone *ebone;
1391                         
1392                         /* clear flag we use to detect point was affected */
1393                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1394                                 ebone->flag &= ~BONE_DONE;
1395                         
1396                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1397                         
1398                         /* first we only check points inside the border */
1399                         for (a=0; a<hits; a++){
1400                                 index = buffer[(4*a)+3];
1401                                 if (index!=-1) {
1402                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1403                                         if (index & BONESEL_TIP) {
1404                                                 ebone->flag |= BONE_DONE;
1405                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1406                                                 else ebone->flag &= ~BONE_TIPSEL;
1407                                         }
1408                                         
1409                                         if (index & BONESEL_ROOT) {
1410                                                 ebone->flag |= BONE_DONE;
1411                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1412                                                 else ebone->flag &= ~BONE_ROOTSEL;
1413                                         }
1414                                 }
1415                         }
1416                         
1417                         /* now we have to flush tag from parents... */
1418                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1419                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1420                                         if(ebone->parent->flag & BONE_DONE)
1421                                                 ebone->flag |= BONE_DONE;
1422                                 }
1423                         }
1424                         
1425                         /* only select/deselect entire bones when no points where in the rect */
1426                         for (a=0; a<hits; a++){
1427                                 index = buffer[(4*a)+3];
1428                                 if (index!=-1) {
1429                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1430                                         if (index & BONESEL_BONE) {
1431                                                 if(!(ebone->flag & BONE_DONE)) {
1432                                                         if (val==LEFTMOUSE)
1433                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1434                                                         else
1435                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1436                                                 }
1437                                         }
1438                                 }
1439                         }
1440                         
1441                         ED_armature_sync_selection(arm->edbo);
1442                 }
1443                 else if(obedit->type==OB_LATTICE) {
1444                         do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
1445                 }
1446         }
1447         else {  /* no editmode, unified for bones and objects */
1448                 Bone *bone;
1449                 Object *ob= OBACT;
1450                 unsigned int *vbuffer=NULL; /* selection buffer */
1451                 unsigned int *col;                      /* color in buffer      */
1452                 short selecting = 0;
1453                 int bone_only;
1454                 int totobj= MAXPICKBUF; // XXX solve later
1455                 
1456                 if((ob) && (ob->flag & OB_POSEMODE))
1457                         bone_only= 1;
1458                 else
1459                         bone_only= 0;
1460                 
1461                 if (val==LEFTMOUSE)
1462                         selecting = 1;
1463                 
1464                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1465                 vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1466                 hits= view3d_opengl_select(&vc, vbuffer, 4*(totobj+MAXPICKBUF), &rect);
1467                 /*
1468                 LOGIC NOTES (theeth):
1469                 The buffer and ListBase have the same relative order, which makes the selection
1470                 very simple. Loop through both data sets at the same time, if the color
1471                 is the same as the object, we have a hit and can move to the next color
1472                 and object pair, if not, just move to the next object,
1473                 keeping the same color until we have a hit.
1474
1475                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1476                 does it incorrectly.
1477                 */
1478
1479                 if (hits>0) { /* no need to loop if there's no hit */
1480                         base= FIRSTBASE;
1481                         col = vbuffer + 3;
1482                         
1483                         while(base && hits) {
1484                                 Base *next = base->next;
1485                                 if(base->lay & v3d->lay) {
1486                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1487                                                 
1488                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1489                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1490                                                         if(bone) {
1491                                                                 if(selecting) {
1492                                                                         bone->flag |= BONE_SELECTED;
1493 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1494                                                                 }
1495                                                                 else {
1496                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1497 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1498                                                                 }
1499                                                         }
1500                                                 }
1501                                                 else if(!bone_only) {
1502                                                         if (selecting)
1503                                                                 ED_base_object_select(base, BA_SELECT);
1504                                                         else
1505                                                                 ED_base_object_select(base, BA_DESELECT);
1506                                                 }
1507
1508                                                 col+=4; /* next color */
1509                                                 hits--;
1510                                                 if(hits==0) break;
1511                                         }
1512                                 }
1513                                 
1514                                 base= next;
1515                         }
1516
1517                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1518
1519                 }
1520                 MEM_freeN(vbuffer);
1521         }
1522         return OPERATOR_FINISHED;
1523
1524
1525
1526 /* *****************Selection Operators******************* */
1527
1528 /* ****** Border Select ****** */
1529 void VIEW3D_OT_select_border(wmOperatorType *ot)
1530 {
1531         /* identifiers */
1532         ot->name= "Border Select";
1533         ot->idname= "VIEW3D_OT_select_border";
1534         
1535         /* api callbacks */
1536         ot->invoke= WM_border_select_invoke;
1537         ot->exec= view3d_borderselect_exec;
1538         ot->modal= WM_border_select_modal;
1539         
1540         ot->poll= ED_operator_view3d_active;
1541         
1542         /* flags */
1543         ot->flag= OPTYPE_UNDO;
1544         
1545         /* rna */
1546         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1547         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1548         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1549         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1550         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1551
1552         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first.");
1553 }
1554
1555 /* ****** Mouse Select ****** */
1556
1557
1558 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1559 {
1560         Object *obedit= CTX_data_edit_object(C);
1561         short extend= RNA_boolean_get(op->ptr, "extend");
1562
1563         view3d_operator_needs_opengl(C);
1564         
1565         if(obedit) {
1566                 if(obedit->type==OB_MESH)
1567                         mouse_mesh(C, event->mval, extend);
1568                 else if(obedit->type==OB_ARMATURE)
1569                         mouse_armature(C, event->mval, extend);
1570                 else if(obedit->type==OB_LATTICE)
1571                         mouse_lattice(C, event->mval, extend);
1572                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1573                         mouse_nurb(C, event->mval, extend);
1574                 else if(obedit->type==OB_MBALL)
1575                         mouse_mball(C, event->mval, extend);
1576                         
1577         }
1578         else if(G.f & G_PARTICLEEDIT)
1579                 PE_mouse_particles(C, event->mval, extend);
1580         else 
1581                 mouse_select(C, event->mval, extend, 0);
1582
1583         /* allowing tweaks */
1584         return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
1585 }
1586
1587 void VIEW3D_OT_select(wmOperatorType *ot)
1588 {
1589         /* identifiers */
1590         ot->name= "Activate/Select";
1591         ot->idname= "VIEW3D_OT_select";
1592         
1593         /* api callbacks */
1594         ot->invoke= view3d_select_invoke;
1595         ot->poll= ED_operator_view3d_active;
1596         
1597         /* flags */
1598         ot->flag= OPTYPE_UNDO;
1599         
1600         /* properties */
1601         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first.");
1602 }
1603
1604
1605 /* -------------------- circle select --------------------------------------------- */
1606
1607 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1608 {
1609         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1610         int mx = x - data->mval[0], my = y - data->mval[1];
1611         float r = sqrt(mx*mx + my*my);
1612
1613         if (r<=data->radius) {
1614                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1615         }
1616 }
1617 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1618 {
1619         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1620
1621         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1622                 EM_select_edge(eed, data->select);
1623         }
1624 }
1625 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1626 {
1627         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1628         int mx = x - data->mval[0], my = y - data->mval[1];
1629         float r = sqrt(mx*mx + my*my);
1630         
1631         if (r<=data->radius) {
1632                 EM_select_face_fgon(data->vc->em, efa, data->select);
1633         }
1634 }
1635
1636 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1637 {
1638         ToolSettings *ts= vc->scene->toolsettings;
1639         int bbsel;
1640         
1641         if(vc->obedit==NULL && (FACESEL_PAINT_TEST)) {
1642                 Object *ob= vc->obact;
1643                 Mesh *me = ob?ob->data:NULL;
1644
1645                 if (me) {
1646                         em_vertoffs= me->totface+1;     /* max index array */
1647
1648                         bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1649                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1650                         EM_free_backbuf();
1651
1652 // XXX                  object_tface_flags_changed(OBACT, 0);
1653                 }
1654         }
1655         else {
1656                 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1657                 
1658                 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1659                 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1660
1661                 data.select = selecting;
1662                 data.mval[0] = mval[0];
1663                 data.mval[1] = mval[1];
1664                 data.radius = rad;
1665
1666                 if(ts->selectmode & SCE_SELECT_VERTEX) {
1667                         if(bbsel) {
1668                                 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1669                         } else {
1670                                 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1671                         }
1672                 }
1673
1674                 if(ts->selectmode & SCE_SELECT_EDGE) {
1675                         if (bbsel) {
1676                                 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1677                         } else {
1678                                 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1679                         }
1680                 }
1681                 
1682                 if(ts->selectmode & SCE_SELECT_FACE) {
1683                         if(bbsel) {
1684                                 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1685                         } else {
1686                                 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1687                         }
1688                 }
1689
1690                 EM_free_backbuf();
1691                 EM_selectmode_flush(vc->em);
1692         }
1693 }
1694
1695
1696 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1697 {
1698         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1699         int mx = x - data->mval[0], my = y - data->mval[1];
1700         float r = sqrt(mx*mx + my*my);
1701
1702         if (r<=data->radius) {
1703                 if (bp) {
1704                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1705                 } else {
1706                         if (beztindex==0) {
1707                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1708                         } else if (beztindex==1) {
1709                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1710                         } else {
1711                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1712                         }
1713                 }
1714         }
1715 }
1716 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1717 {
1718         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1719
1720         /* set vc-> edit data */
1721         
1722         data.select = selecting;
1723         data.mval[0] = mval[0];
1724         data.mval[1] = mval[1];
1725         data.radius = rad;
1726
1727         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1728 }
1729
1730
1731 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1732 {
1733         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1734         int mx = x - data->mval[0], my = y - data->mval[1];
1735         float r = sqrt(mx*mx + my*my);
1736
1737         if (r<=data->radius) {
1738                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1739         }
1740 }
1741 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1742 {
1743         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1744
1745         /* set vc-> edit data */
1746         
1747         data.select = selecting;
1748         data.mval[0] = mval[0];
1749         data.mval[1] = mval[1];
1750         data.radius = rad;
1751
1752         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1753 }
1754
1755 /** Callbacks for circle selection in Editmode */
1756
1757 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad) 
1758 {
1759         switch(vc->obedit->type) {              
1760         case OB_MESH:
1761                 mesh_circle_select(vc, selecting, mval, rad);
1762                 break;
1763         case OB_CURVE:
1764         case OB_SURF:
1765                 nurbscurve_circle_select(vc, selecting, mval, rad);
1766                 break;
1767         case OB_LATTICE:
1768                 lattice_circle_select(vc, selecting, mval, rad);
1769                 break;
1770         default:
1771                 return;
1772         }
1773 }
1774
1775 /* not a real operator, only for circle test */
1776 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
1777 {
1778         ScrArea *sa= CTX_wm_area(C);
1779         ARegion *ar= CTX_wm_region(C);
1780         Scene *scene= CTX_data_scene(C);
1781         View3D *v3d= sa->spacedata.first;
1782         int x= RNA_int_get(op->ptr, "x");
1783         int y= RNA_int_get(op->ptr, "y");
1784         int radius= RNA_int_get(op->ptr, "radius");
1785         
1786         if(CTX_data_edit_object(C) || (G.f & G_PARTICLEEDIT)) {
1787                 ViewContext vc;
1788                 short mval[2], selecting;
1789                 
1790                 view3d_operator_needs_opengl(C);
1791                 
1792                 view3d_set_viewcontext(C, &vc);
1793                 mval[0]= x;
1794                 mval[1]= y;
1795                 selecting= LEFTMOUSE==RNA_int_get(op->ptr, "event_type"); // XXX solve
1796
1797                 if(CTX_data_edit_object(C))
1798                         obedit_circle_select(&vc, selecting, mval, (float)radius);
1799                 else
1800                         return PE_circle_select(C, selecting, mval, (float)radius);
1801         }
1802         else {
1803                 Base *base;
1804                 
1805                 for(base= FIRSTBASE; base; base= base->next) {
1806                         if(base->lay & v3d->lay) {
1807                                 project_short(ar, base->object->obmat[3], &base->sx);
1808                                 if(base->sx!=IS_CLIPPED) {
1809                                         int dx= base->sx-x;
1810                                         int dy= base->sy-y;
1811                                         if( dx*dx + dy*dy < radius*radius)
1812                                                 ED_base_object_select(base, BA_SELECT);
1813                                 }
1814                         }
1815                 }
1816                 
1817                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1818         }
1819         
1820         return OPERATOR_FINISHED;
1821 }
1822
1823 void VIEW3D_OT_select_circle(wmOperatorType *ot)
1824 {
1825         ot->name= "Circle Select";
1826         ot->idname= "VIEW3D_OT_select_circle";
1827         
1828         ot->invoke= WM_gesture_circle_invoke;
1829         ot->modal= WM_gesture_circle_modal;
1830         ot->exec= view3d_circle_select_exec;
1831         ot->poll= ED_operator_view3d_active;
1832         
1833         /* flags */
1834         ot->flag= OPTYPE_UNDO;
1835         
1836         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1837         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1838         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1839         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1840 }