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