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