svn merge -r 21041:21243 https://svn.blender.org/svnroot/bf-blender/branches/blender2...
[blender.git] / source / blender / editors / space_view3d / view3d_select.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_curve_types.h"
37 #include "DNA_camera_types.h"
38 #include "DNA_lamp_types.h"
39 #include "DNA_meta_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_space_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_userdef_types.h"
47 #include "DNA_view3d_types.h"
48 #include "DNA_world_types.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "BLI_arithb.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_editVert.h"
55 #include "BLI_rand.h"
56
57 #include "BKE_action.h"
58 #include "BKE_context.h"
59 #include "BKE_depsgraph.h"
60 #include "BKE_object.h"
61 #include "BKE_global.h"
62 #include "BKE_scene.h"
63 #include "BKE_screen.h"
64 #include "BKE_utildefines.h"
65
66 #include "RE_pipeline.h"        // make_stars
67
68 #include "BIF_gl.h"
69 #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         ToolSettings *ts= vc->scene->toolsettings;
442         rcti rect;
443         int bbsel;
444         
445         lasso_select_boundbox(&rect, mcords, moves);
446         
447         /* set editmesh */
448         vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
449
450         data.vc= *vc;
451         data.rect = &rect;
452         data.mcords = mcords;
453         data.moves = moves;
454         data.select = select;
455         data.done = 0;
456         data.pass = 0;
457
458         bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
459         
460         if(ts->selectmode & SCE_SELECT_VERTEX) {
461                 if (bbsel) {
462                         EM_backbuf_checkAndSelectVerts(vc->em, select);
463                 } else {
464                         mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
465                 }
466         }
467         if(ts->selectmode & SCE_SELECT_EDGE) {
468                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
469
470                 data.pass = 0;
471                 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
472
473                 if (data.done==0) {
474                         data.pass = 1;
475                         mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
476                 }
477         }
478         
479         if(ts->selectmode & SCE_SELECT_FACE) {
480                 if (bbsel) {
481                         EM_backbuf_checkAndSelectFaces(vc->em, select);
482                 } else {
483                         mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
484                 }
485         }
486         
487         EM_free_backbuf();
488         EM_selectmode_flush(vc->em);    
489 }
490
491 #if 0
492 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
493 static void do_lasso_select_mesh_uv(short mcords[][2], short moves, short select)
494 {
495         EditFace *efa;
496         MTFace *tf;
497         int screenUV[2], nverts, i, ok = 1;
498         rcti rect;
499         
500         lasso_select_boundbox(&rect, mcords, moves);
501         
502         if (draw_uvs_face_check()) { /* Face Center Sel */
503                 float cent[2];
504                 ok = 0;
505                 for (efa= em->faces.first; efa; efa= efa->next) {
506                         /* assume not touched */
507                         efa->tmp.l = 0;
508                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
509                         if ((select) != (simaFaceSel_Check(efa, tf))) {
510                                 uv_center(tf->uv, cent, (void *)efa->v4);
511                                 uvco_to_areaco_noclip(cent, screenUV);
512                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
513                                         efa->tmp.l = ok = 1;
514                                 }
515                         }
516                 }
517                 /* (de)selects all tagged faces and deals with sticky modes */
518                 if (ok)
519                         uvface_setsel__internal(select);
520                 
521         } else { /* Vert Sel*/
522                 for (efa= em->faces.first; efa; efa= efa->next) {
523                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
524                         if (simaFaceDraw_Check(efa, tf)) {              
525                                 nverts= efa->v4? 4: 3;
526                                 for(i=0; i<nverts; i++) {
527                                         if ((select) != (simaUVSel_Check(efa, tf, i))) {
528                                                 uvco_to_areaco_noclip(tf->uv[i], screenUV);
529                                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
530                                                         if (select) {
531                                                                 simaUVSel_Set(efa, tf, i);
532                                                         } else {
533                                                                 simaUVSel_UnSet(efa, tf, i);
534                                                         }
535                                                 }
536                                         }
537                                 }
538                         }
539                 }
540         }
541         if (ok && G.sima->flag & SI_SYNC_UVSEL) {
542                 if (select) EM_select_flush(vc->em);
543                 else            EM_deselect_flush(vc->em);
544         }
545 }
546 #endif
547
548 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
549 {
550         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
551
552         if (lasso_inside(data->mcords, data->moves, x, y)) {
553                 if (bp) {
554                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
555                 } else {
556                         if (G.f & G_HIDDENHANDLES) {
557                                 /* can only be beztindex==0 here since handles are hidden */
558                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
559                         } else {
560                                 if (beztindex==0) {
561                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
562                                 } else if (beztindex==1) {
563                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
564                                 } else {
565                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
566                                 }
567                         }
568                 }
569         }
570 }
571
572 static void do_lasso_select_curve(ViewContext *vc, short mcords[][2], short moves, short select)
573 {
574         struct { short (*mcords)[2]; short moves; short select; } data;
575
576         /* set vc->editnurb */
577         data.mcords = mcords;
578         data.moves = moves;
579         data.select = select;
580
581         nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data);
582 }
583
584 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
585 {
586         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
587
588         if (lasso_inside(data->mcords, data->moves, x, y)) {
589                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
590         }
591 }
592 static void do_lasso_select_lattice(ViewContext *vc, short mcords[][2], short moves, short select)
593 {
594         struct { short (*mcords)[2]; short moves; short select; } data;
595
596         /* set editdata in vc */
597         data.mcords = mcords;
598         data.moves = moves;
599         data.select = select;
600
601         lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data);
602 }
603
604 static void do_lasso_select_armature(ViewContext *vc, short mcords[][2], short moves, short select)
605 {
606         bArmature *arm= vc->obedit->data;
607         EditBone *ebone;
608         float vec[3];
609         short sco1[2], sco2[2], didpoint;
610         
611         /* set editdata in vc */
612         
613         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
614
615                 VECCOPY(vec, ebone->head);
616                 Mat4MulVecfl(vc->obedit->obmat, vec);
617                 project_short(vc->ar, vec, sco1);
618                 VECCOPY(vec, ebone->tail);
619                 Mat4MulVecfl(vc->obedit->obmat, vec);
620                 project_short(vc->ar, vec, sco2);
621                 
622                 didpoint= 0;
623                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
624                         if(select) ebone->flag |= BONE_ROOTSEL;
625                         else ebone->flag &= ~BONE_ROOTSEL;
626                         didpoint= 1;
627                 }
628                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
629                    if(select) ebone->flag |= BONE_TIPSEL;
630                    else ebone->flag &= ~BONE_TIPSEL;
631                    didpoint= 1;
632                 }
633                 /* if one of points selected, we skip the bone itself */
634                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
635                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
636                         else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
637                 }
638         }
639 }
640
641 static void do_lasso_select_facemode(ViewContext *vc, short mcords[][2], short moves, short select)
642 {
643         Object *ob= vc->obact;
644         Mesh *me= ob?ob->data:NULL;
645         rcti rect;
646         
647         if(me==NULL || me->mtface==NULL) return;
648         if(me->totface==0) return;
649         
650         em_vertoffs= me->totface+1;     /* max index array */
651         
652         lasso_select_boundbox(&rect, mcords, moves);
653         EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
654         
655         EM_backbuf_checkAndSelectTFaces(me, select);
656         
657         EM_free_backbuf();
658         
659 // XXX  object_tface_flags_changed(ob, 0);
660 }
661
662 #if 0
663 static void do_lasso_select_node(short mcords[][2], short moves, short select)
664 {
665         SpaceNode *snode = sa->spacedata.first;
666         
667         bNode *node;
668         rcti rect;
669         short node_cent[2];
670         float node_centf[2];
671         
672         lasso_select_boundbox(&rect, mcords, moves);
673         
674         /* store selection in temp test flag */
675         for(node= snode->edittree->nodes.first; node; node= node->next) {
676                 
677                 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2;
678                 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2;
679                 
680                 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
681                 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
682                         if (select) {
683                                 node->flag |= SELECT;
684                         } else {
685                                 node->flag &= ~SELECT;
686                         }
687                 }
688         }
689         BIF_undo_push("Lasso select nodes");
690 }
691 #endif
692
693 void view3d_lasso_select(bContext *C, ViewContext *vc, short mcords[][2], short moves, short select)
694 {
695         if(vc->obedit==NULL) {
696                 if(FACESEL_PAINT_TEST)
697                         do_lasso_select_facemode(vc, mcords, moves, select);
698                 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
699                         ;
700                 else if(G.f & G_PARTICLEEDIT)
701                         PE_lasso_select(C, mcords, moves, select);
702                 else  
703                         do_lasso_select_objects(vc, mcords, moves, select);
704         }
705         else if(vc->obedit->type==OB_MESH) {
706                 do_lasso_select_mesh(vc, mcords, moves, select);
707         } else if(vc->obedit->type==OB_CURVE || vc->obedit->type==OB_SURF) 
708                 do_lasso_select_curve(vc, mcords, moves, select);
709         else if(vc->obedit->type==OB_LATTICE) 
710                 do_lasso_select_lattice(vc, mcords, moves, select);
711         else if(vc->obedit->type==OB_ARMATURE)
712                 do_lasso_select_armature(vc, mcords, moves, select);
713
714         BIF_undo_push("Lasso select");
715         
716 }
717
718 static EnumPropertyItem lasso_select_types[] = {
719         {0, "SELECT", 0, "Select", ""},
720         {1, "DESELECT", 0, "Deselect", ""},
721         {0, NULL, 0, NULL, NULL}
722 };
723
724
725 /* lasso operator gives properties, but since old code works
726    with short array we convert */
727 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
728 {
729         ViewContext vc;
730         int select, i= 0;
731         short mcords[1024][2];
732
733         RNA_BEGIN(op->ptr, itemptr, "path") {
734                 float loc[2];
735                 
736                 RNA_float_get_array(&itemptr, "loc", loc);
737                 mcords[i][0]= (short)loc[0];
738                 mcords[i][1]= (short)loc[1];
739                 i++;
740                 if(i>=1024) break;
741         }
742         RNA_END;
743         
744         if(i>1) {
745                 view3d_operator_needs_opengl(C);
746                 
747                 /* setup view context for argument to callbacks */
748                 view3d_set_viewcontext(C, &vc);
749                 
750                 select= RNA_enum_is_equal(op->ptr, "type", "SELECT");
751                 view3d_lasso_select(C, &vc, mcords, i, select);
752                 
753                 return OPERATOR_FINISHED;
754         }
755         return OPERATOR_PASS_THROUGH;
756 }
757
758 void VIEW3D_OT_select_lasso(wmOperatorType *ot)
759 {
760         ot->name= "Lasso Select";
761         ot->idname= "VIEW3D_OT_select_lasso";
762         
763         ot->invoke= WM_gesture_lasso_invoke;
764         ot->modal= WM_gesture_lasso_modal;
765         ot->exec= view3d_lasso_select_exec;
766         ot->poll= WM_operator_winactive;
767         
768         /* flags */
769         ot->flag= OPTYPE_UNDO;
770         
771         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
772         RNA_def_enum(ot->srna, "type", lasso_select_types, 0, "Type", "");
773 }
774
775
776 /* ************************************************* */
777
778 #if 0
779 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
780 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
781 {
782         Base *base;
783         unsigned int *bufmin,*bufmax;
784         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
785         unsigned int retval=0;
786         
787         base= LASTBASE;
788         if(base==0) return 0;
789         maxob= base->selcol;
790
791         aantal= (size-1)/2;
792         rc= 0;
793
794         dirvec[0][0]= 1;
795         dirvec[0][1]= 0;
796         dirvec[1][0]= 0;
797         dirvec[1][1]= -size;
798         dirvec[2][0]= -1;
799         dirvec[2][1]= 0;
800         dirvec[3][0]= 0;
801         dirvec[3][1]= size;
802
803         bufmin= buf;
804         bufmax= buf+ size*size;
805         buf+= aantal*size+ aantal;
806
807         for(tel=1;tel<=size;tel++) {
808
809                 for(a=0;a<2;a++) {
810                         for(b=0;b<tel;b++) {
811
812                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
813                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
814                                 
815                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
816
817                                 if(buf<bufmin || buf>=bufmax) return retval;
818                         }
819                         rc++;
820                         rc &= 3;
821                 }
822         }
823         return retval;
824 }
825 #endif
826
827 /* ************************** mouse select ************************* */
828
829
830 /* The max number of menu items in an object select menu */
831 #define SEL_MENU_SIZE   22
832
833 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
834 {
835         Base *base;
836         
837         for(base= FIRSTBASE; base; base= base->next) {
838                 if (base->flag & SELECT) {
839                         if(b!=base) {
840                                 ED_base_object_select(base, BA_DESELECT);
841                         }
842                 }
843         }
844 }
845
846 static Base *mouse_select_menu(ViewContext *vc, unsigned int *buffer, int hits, short *mval)
847 {
848         Scene *scene= vc->scene;
849         View3D *v3d= vc->v3d;
850         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
851         Base *base;
852         short baseCount = 0;
853         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       /* max ob name = 22 */
854         char str[32];
855         
856         for(base=FIRSTBASE; base; base= base->next) {
857                 if (BASE_SELECTABLE(v3d, base)) {
858                         baseList[baseCount] = NULL;
859                         
860                         /* two selection methods, the CTRL select uses max dist of 15 */
861                         if(buffer) {
862                                 int a;
863                                 for(a=0; a<hits; a++) {
864                                         /* index was converted */
865                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
866                                 }
867                         }
868                         else {
869                                 int temp, dist=15;
870                                 
871                                 project_short(vc->ar, base->object->obmat[3], &base->sx);
872                                 
873                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
874                                 if(temp<dist ) baseList[baseCount] = base;
875                         }
876                         
877                         if(baseList[baseCount]) {
878                                 if (baseCount < SEL_MENU_SIZE) {
879                                         baseList[baseCount] = base;
880                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        /* max ob name == 22 */
881                                                         strcat(menuText, str);
882                                                         baseCount++;
883                                 }
884                         }
885                 }
886         }
887
888         if(baseCount<=1) return baseList[0];
889         else {
890                 baseCount = -1; // XXX = pupmenu(menuText);
891                 
892                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
893                         return baseList[baseCount-1];
894                 }
895                 else return NULL;
896         }
897 }
898
899 /* we want a select buffer with bones, if there are... */
900 /* so check three selection levels and compare */
901 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, short *mval)
902 {
903         rcti rect;
904         int offs;
905         short a, hits15, hits9=0, hits5=0;
906         short has_bones15=0, has_bones9=0, has_bones5=0;
907         
908         BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
909         hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
910         if(hits15>0) {
911                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
912                 
913                 offs= 4*hits15;
914                 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
915                 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
916                 if(hits9>0) {
917                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
918                         
919                         offs+= 4*hits9;
920                         BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
921                         hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
922                         if(hits5>0) {
923                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
924                         }
925                 }
926                 
927                 if(has_bones5) {
928                         offs= 4*hits15 + 4*hits9;
929                         memcpy(buffer, buffer+offs, 4*offs);
930                         return hits5;
931                 }
932                 if(has_bones9) {
933                         offs= 4*hits15;
934                         memcpy(buffer, buffer+offs, 4*offs);
935                         return hits9;
936                 }
937                 if(has_bones15) {
938                         return hits15;
939                 }
940                 
941                 if(hits5>0) {
942                         offs= 4*hits15 + 4*hits9;
943                         memcpy(buffer, buffer+offs, 4*offs);
944                         return hits5;
945                 }
946                 if(hits9>0) {
947                         offs= 4*hits15;
948                         memcpy(buffer, buffer+offs, 4*offs);
949                         return hits9;
950                 }
951                 return hits15;
952         }
953         
954         return 0;
955 }
956
957
958 /* mval is region coords */
959 static void mouse_select(bContext *C, short *mval, short extend, short obcenter)
960 {
961         ViewContext vc;
962         ARegion *ar= CTX_wm_region(C);
963         View3D *v3d= CTX_wm_view3d(C);
964         Scene *scene= CTX_data_scene(C);
965         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
966         unsigned int buffer[4*MAXPICKBUF];
967         int temp, a, dist=100;
968         short hits;
969         
970         /* setup view context for argument to callbacks */
971         view3d_set_viewcontext(C, &vc);
972         
973         /* always start list from basact in wire mode */
974         startbase=  FIRSTBASE;
975         if(BASACT && BASACT->next) startbase= BASACT->next;
976         
977         /* This block uses the control key to make the object selected by its center point rather then its contents */
978         /* XXX later on, in editmode do not activate */
979         if(vc.obedit==NULL && obcenter) {
980                 
981                 /* note; shift+alt goes to group-flush-selecting */
982                 /* XXX solve */
983                 if(0) 
984                         basact= mouse_select_menu(&vc, NULL, 0, mval);
985                 else {
986                         base= startbase;
987                         while(base) {
988                                 if (BASE_SELECTABLE(v3d, base)) {
989                                         project_short(ar, base->object->obmat[3], &base->sx);
990                                         
991                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
992                                         if(base==BASACT) temp+=10;
993                                         if(temp<dist ) {
994                                                 
995                                                 dist= temp;
996                                                 basact= base;
997                                         }
998                                 }
999                                 base= base->next;
1000                                 
1001                                 if(base==0) base= FIRSTBASE;
1002                                 if(base==startbase) break;
1003                         }
1004                 }
1005         }
1006         else {
1007                 /* if objects have posemode set, the bones are in the same selection buffer */
1008                 
1009                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1010                 
1011                 if(hits>0) {
1012                         int has_bones= 0;
1013                         
1014                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1015
1016                         /* note; shift+alt goes to group-flush-selecting */
1017                         if(has_bones==0 && 0) 
1018                                 basact= mouse_select_menu(&vc, buffer, hits, mval);
1019                         else {
1020                                 static short lastmval[2]={-100, -100};
1021                                 int donearest= 0;
1022                                 
1023                                 /* define if we use solid nearest select or not */
1024                                 if(v3d->drawtype>OB_WIRE) {
1025                                         donearest= 1;
1026                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1027                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
1028                                                         donearest= 0;
1029                                         }
1030                                 }
1031                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1032                                 
1033                                 if(donearest) {
1034                                         unsigned int min= 0xFFFFFFFF;
1035                                         int selcol= 0, notcol=0;
1036                                         
1037
1038                                         if(has_bones) {
1039                                                 /* we skip non-bone hits */
1040                                                 for(a=0; a<hits; a++) {
1041                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1042                                                                 min= buffer[4*a+1];
1043                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1044                                                         }
1045                                                 }
1046                                         }
1047                                         else {
1048                                                 /* only exclude active object when it is selected... */
1049                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1050                                         
1051                                                 for(a=0; a<hits; a++) {
1052                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1053                                                                 min= buffer[4*a+1];
1054                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1055                                                         }
1056                                                 }
1057                                         }
1058
1059                                         base= FIRSTBASE;
1060                                         while(base) {
1061                                                 if(base->lay & v3d->lay) {
1062                                                         if(base->selcol==selcol) break;
1063                                                 }
1064                                                 base= base->next;
1065                                         }
1066                                         if(base) basact= base;
1067                                 }
1068                                 else {
1069                                         
1070                                         base= startbase;
1071                                         while(base) {
1072                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
1073                                                  * with an un-selectable choice */
1074                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1075                                                         base=base->next;
1076                                                         if(base==NULL) base= FIRSTBASE;
1077                                                         if(base==startbase) break;
1078                                                 }
1079                                         
1080                                                 if(base->lay & v3d->lay) {
1081                                                         for(a=0; a<hits; a++) {
1082                                                                 if(has_bones) {
1083                                                                         /* skip non-bone objects */
1084                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1085                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1086                                                                                         basact= base;
1087                                                                         }
1088                                                                 }
1089                                                                 else {
1090                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1091                                                                                 basact= base;
1092                                                                 }
1093                                                         }
1094                                                 }
1095                                                 
1096                                                 if(basact) break;
1097                                                 
1098                                                 base= base->next;
1099                                                 if(base==NULL) base= FIRSTBASE;
1100                                                 if(base==startbase) break;
1101                                         }
1102                                 }
1103                         }
1104                         
1105                         if(has_bones && basact) {
1106                                 if(ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) {     /* then bone is found */
1107                                 
1108                                         /* we make the armature selected: 
1109                                            not-selected active object in posemode won't work well for tools */
1110                                         basact->flag|= SELECT;
1111                                         basact->object->flag= basact->flag;
1112                                         
1113                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1114                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1115                                         
1116                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1117                                         if(G.f & G_WEIGHTPAINT) {
1118                                                 /* prevent activating */
1119                                                 basact= NULL;
1120                                         }
1121
1122                                 }
1123                                 /* prevent bone selecting to pass on to object selecting */
1124                                 if(basact==BASACT)
1125                                         basact= NULL;
1126                         }
1127                 }
1128         }
1129         
1130         /* so, do we have something selected? */
1131         if(basact) {
1132                 
1133                 if(vc.obedit) {
1134                         /* only do select */
1135                         deselectall_except(scene, basact);
1136                         ED_base_object_select(basact, BA_SELECT);
1137                 }
1138                 /* also prevent making it active on mouse selection */
1139                 else if (BASE_SELECTABLE(v3d, basact)) {
1140
1141                         oldbasact= BASACT;
1142                         
1143                         if(!extend) {
1144                                 deselectall_except(scene, basact);
1145                                 ED_base_object_select(basact, BA_SELECT);
1146                         }
1147                         else if(0) {
1148                                 // XXX select_all_from_groups(basact);
1149                         }
1150                         else {
1151                                 if(basact->flag & SELECT) {
1152                                         if(basact==oldbasact)
1153                                                 ED_base_object_select(basact, BA_DESELECT);
1154                                 }
1155                                 else ED_base_object_select(basact, BA_SELECT);
1156                         }
1157
1158                         if(oldbasact != basact) {
1159                                 ED_base_object_activate(C, basact); /* adds notifier */
1160                         }
1161
1162                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1163                 }
1164         }
1165 }
1166
1167 /* ********************  border and circle ************************************** */
1168
1169
1170 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1171 {
1172         int radsq= rad*rad;
1173         float v1[2], v2[2], v3[2];
1174         
1175         /* check points in circle itself */
1176         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1177         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1178         
1179         /* pointdistline */
1180         v3[0]= centx;
1181         v3[1]= centy;
1182         v1[0]= x1;
1183         v1[1]= y1;
1184         v2[0]= x2;
1185         v2[1]= y2;
1186         
1187         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1188         
1189         return 0;
1190 }
1191
1192 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1193 {
1194         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1195
1196         if (BLI_in_rcti(data->rect, x, y)) {
1197                 if (bp) {
1198                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1199                 } else {
1200                         if (G.f & G_HIDDENHANDLES) {
1201                                 /* can only be beztindex==0 here since handles are hidden */
1202                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1203                         } else {
1204                                 if (beztindex==0) {
1205                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1206                                 } else if (beztindex==1) {
1207                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1208                                 } else {
1209                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1210                                 }
1211                         }
1212                 }
1213         }
1214 }
1215 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select)
1216 {
1217         struct { ViewContext vc; rcti *rect; int select; } data;
1218         
1219         data.vc= *vc;
1220         data.rect = rect;
1221         data.select = select;
1222
1223         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1224 }
1225
1226 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1227 {
1228         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1229
1230         if (BLI_in_rcti(data->rect, x, y)) {
1231                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1232         }
1233 }
1234 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select)
1235 {
1236         struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1237
1238         data.vc= *vc;
1239         data.rect = rect;
1240         data.select = select;
1241
1242         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1243 }
1244
1245 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1246 {
1247         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1248
1249         if (BLI_in_rcti(data->rect, x, y)) {
1250                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1251         }
1252 }
1253 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1254 {
1255         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1256
1257         if(EM_check_backbuf(em_solidoffs+index)) {
1258                 if (data->pass==0) {
1259                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1260                                 EM_select_edge(eed, data->select);
1261                                 data->done = 1;
1262                         }
1263                 } else {
1264                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1265                                 EM_select_edge(eed, data->select);
1266                         }
1267                 }
1268         }
1269 }
1270 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1271 {
1272         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1273
1274         if (BLI_in_rcti(data->rect, x, y)) {
1275                 EM_select_face_fgon(data->vc.em, efa, data->select);
1276         }
1277 }
1278 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
1279 {
1280         struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1281         ToolSettings *ts= vc->scene->toolsettings;
1282         int bbsel;
1283         
1284         data.vc= *vc;
1285         data.rect = rect;
1286         data.select = select;
1287         data.pass = 0;
1288         data.done = 0;
1289
1290         bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1291
1292         if(ts->selectmode & SCE_SELECT_VERTEX) {
1293                 if (bbsel) {
1294                         EM_backbuf_checkAndSelectVerts(vc->em, select);
1295                 } else {
1296                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1297                 }
1298         }
1299         if(ts->selectmode & SCE_SELECT_EDGE) {
1300                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1301
1302                 data.pass = 0;
1303                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1304
1305                 if (data.done==0) {
1306                         data.pass = 1;
1307                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1308                 }
1309         }
1310         
1311         if(ts->selectmode & SCE_SELECT_FACE) {
1312                 if(bbsel) {
1313                         EM_backbuf_checkAndSelectFaces(vc->em, select);
1314                 } else {
1315                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1316                 }
1317         }
1318         
1319         EM_free_backbuf();
1320                 
1321         EM_selectmode_flush(vc->em);
1322 }
1323
1324 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1325 {
1326         ViewContext vc;
1327         Scene *scene= CTX_data_scene(C);
1328         ScrArea *sa= CTX_wm_area(C);
1329         View3D *v3d= sa->spacedata.first;
1330         Object *obedit= CTX_data_edit_object(C);
1331         rcti rect;
1332         Base *base;
1333         MetaElem *ml;
1334         unsigned int buffer[4*MAXPICKBUF];
1335         int a, index;
1336         short hits, val;
1337
1338         view3d_operator_needs_opengl(C);
1339         
1340         /* setup view context for argument to callbacks */
1341         view3d_set_viewcontext(C, &vc);
1342         
1343         val= RNA_int_get(op->ptr, "event_type");
1344         rect.xmin= RNA_int_get(op->ptr, "xmin");
1345         rect.ymin= RNA_int_get(op->ptr, "ymin");
1346         rect.xmax= RNA_int_get(op->ptr, "xmax");
1347         rect.ymax= RNA_int_get(op->ptr, "ymax");
1348         
1349         if(obedit==NULL && (FACESEL_PAINT_TEST)) {
1350 // XXX          face_borderselect();
1351                 return OPERATOR_FINISHED;
1352         }
1353         else if(obedit==NULL && (G.f & G_PARTICLEEDIT)) {
1354                 return PE_border_select(C, &rect, (val==LEFTMOUSE));
1355         }
1356         
1357         if(obedit) {
1358                 if(obedit->type==OB_MESH) {
1359                         Mesh *me= obedit->data;
1360                         vc.em= me->edit_mesh;
1361                         do_mesh_box_select(&vc, &rect, (val==LEFTMOUSE));
1362 //                      if (EM_texFaceCheck())
1363                         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1364                         
1365                 }
1366                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1367                         do_nurbs_box_select(&vc, &rect, val==LEFTMOUSE);
1368                 }
1369                 else if(obedit->type==OB_MBALL) {
1370                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1371                         
1372                         ml= NULL; // XXX editelems.first;
1373                         
1374                         while(ml) {
1375                                 for(a=0; a<hits; a++) {
1376                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1377                                                 ml->flag |= MB_SCALE_RAD;
1378                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1379                                                 else ml->flag &= ~SELECT;
1380                                                 break;
1381                                         }
1382                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1383                                                 ml->flag &= ~MB_SCALE_RAD;
1384                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1385                                                 else ml->flag &= ~SELECT;
1386                                                 break;
1387                                         }
1388                                 }
1389                                 ml= ml->next;
1390                         }
1391                 }
1392                 else if(obedit->type==OB_ARMATURE) {
1393                         bArmature *arm= obedit->data;
1394                         EditBone *ebone;
1395                         
1396                         /* clear flag we use to detect point was affected */
1397                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1398                                 ebone->flag &= ~BONE_DONE;
1399                         
1400                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1401                         
1402                         /* first we only check points inside the border */
1403                         for (a=0; a<hits; a++){
1404                                 index = buffer[(4*a)+3];
1405                                 if (index!=-1) {
1406                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1407                                         if (index & BONESEL_TIP) {
1408                                                 ebone->flag |= BONE_DONE;
1409                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1410                                                 else ebone->flag &= ~BONE_TIPSEL;
1411                                         }
1412                                         
1413                                         if (index & BONESEL_ROOT) {
1414                                                 ebone->flag |= BONE_DONE;
1415                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1416                                                 else ebone->flag &= ~BONE_ROOTSEL;
1417                                         }
1418                                 }
1419                         }
1420                         
1421                         /* now we have to flush tag from parents... */
1422                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1423                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1424                                         if(ebone->parent->flag & BONE_DONE)
1425                                                 ebone->flag |= BONE_DONE;
1426                                 }
1427                         }
1428                         
1429                         /* only select/deselect entire bones when no points where in the rect */
1430                         for (a=0; a<hits; a++){
1431                                 index = buffer[(4*a)+3];
1432                                 if (index!=-1) {
1433                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1434                                         if (index & BONESEL_BONE) {
1435                                                 if(!(ebone->flag & BONE_DONE)) {
1436                                                         if (val==LEFTMOUSE)
1437                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1438                                                         else
1439                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1440                                                 }
1441                                         }
1442                                 }
1443                         }
1444                         
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 static EnumPropertyItem prop_select_types[] = {
1531         {0, "EXCLUSIVE", 0, "Exclusive", ""},
1532         {1, "EXTEND", 0, "Extend", ""},
1533         {0, NULL, 0, NULL, NULL}
1534 };
1535
1536 /* ****** Border Select ****** */
1537 void VIEW3D_OT_select_border(wmOperatorType *ot)
1538 {
1539         /* identifiers */
1540         ot->name= "Border Select";
1541         ot->idname= "VIEW3D_OT_select_border";
1542         
1543         /* api callbacks */
1544         ot->invoke= WM_border_select_invoke;
1545         ot->exec= view3d_borderselect_exec;
1546         ot->modal= WM_border_select_modal;
1547         
1548         ot->poll= ED_operator_view3d_active;
1549         
1550         /* flags */
1551         ot->flag= OPTYPE_UNDO;
1552         
1553         /* rna */
1554         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1555         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1556         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1557         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1558         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1559
1560         RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
1561 }
1562
1563 /* ****** Mouse Select ****** */
1564
1565
1566 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1567 {
1568         Object *obedit= CTX_data_edit_object(C);
1569         short extend= RNA_enum_is_equal(op->ptr, "type", "EXTEND");
1570
1571         view3d_operator_needs_opengl(C);
1572         
1573         if(obedit) {
1574                 if(obedit->type==OB_MESH)
1575                         mouse_mesh(C, event->mval, extend);
1576                 else if(obedit->type==OB_ARMATURE)
1577                         mouse_armature(C, event->mval, extend);
1578                 else if(obedit->type==OB_LATTICE)
1579                         mouse_lattice(C, event->mval, extend);
1580                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1581                         mouse_nurb(C, event->mval, extend);
1582                         
1583         }
1584         else if(G.f & G_PARTICLEEDIT)
1585                 PE_mouse_particles(C, event->mval, extend);
1586         else 
1587                 mouse_select(C, event->mval, extend, 0);
1588
1589         /* allowing tweaks */
1590         return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
1591 }
1592
1593 void VIEW3D_OT_select(wmOperatorType *ot)
1594 {
1595         /* identifiers */
1596         ot->name= "Activate/Select";
1597         ot->idname= "VIEW3D_OT_select";
1598         
1599         /* api callbacks */
1600         ot->invoke= view3d_select_invoke;
1601         ot->poll= ED_operator_view3d_active;
1602         
1603         /* flags */
1604         ot->flag= OPTYPE_UNDO;
1605         
1606         /* properties */
1607         RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
1608 }
1609
1610
1611 /* -------------------- circle select --------------------------------------------- */
1612
1613 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1614 {
1615         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1616         int mx = x - data->mval[0], my = y - data->mval[1];
1617         float r = sqrt(mx*mx + my*my);
1618
1619         if (r<=data->radius) {
1620                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1621         }
1622 }
1623 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1624 {
1625         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1626
1627         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1628                 EM_select_edge(eed, data->select);
1629         }
1630 }
1631 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1632 {
1633         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1634         int mx = x - data->mval[0], my = y - data->mval[1];
1635         float r = sqrt(mx*mx + my*my);
1636         
1637         if (r<=data->radius) {
1638                 EM_select_face_fgon(data->vc->em, efa, data->select);
1639         }
1640 }
1641
1642 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1643 {
1644         ToolSettings *ts= vc->scene->toolsettings;
1645         int bbsel;
1646         
1647         if(vc->obedit==NULL && (FACESEL_PAINT_TEST)) {
1648                 Object *ob= vc->obact;
1649                 Mesh *me = ob?ob->data:NULL;
1650
1651                 if (me) {
1652                         em_vertoffs= me->totface+1;     /* max index array */
1653
1654                         bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1655                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1656                         EM_free_backbuf();
1657
1658 // XXX                  object_tface_flags_changed(OBACT, 0);
1659                 }
1660         }
1661         else {
1662                 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1663                 
1664                 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1665                 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1666
1667                 data.select = selecting;
1668                 data.mval[0] = mval[0];
1669                 data.mval[1] = mval[1];
1670                 data.radius = rad;
1671
1672                 if(ts->selectmode & SCE_SELECT_VERTEX) {
1673                         if(bbsel) {
1674                                 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1675                         } else {
1676                                 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1677                         }
1678                 }
1679
1680                 if(ts->selectmode & SCE_SELECT_EDGE) {
1681                         if (bbsel) {
1682                                 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1683                         } else {
1684                                 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1685                         }
1686                 }
1687                 
1688                 if(ts->selectmode & SCE_SELECT_FACE) {
1689                         if(bbsel) {
1690                                 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1691                         } else {
1692                                 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1693                         }
1694                 }
1695
1696                 EM_free_backbuf();
1697                 EM_selectmode_flush(vc->em);
1698         }
1699 }
1700
1701
1702 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1703 {
1704         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1705         int mx = x - data->mval[0], my = y - data->mval[1];
1706         float r = sqrt(mx*mx + my*my);
1707
1708         if (r<=data->radius) {
1709                 if (bp) {
1710                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1711                 } else {
1712                         if (beztindex==0) {
1713                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1714                         } else if (beztindex==1) {
1715                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1716                         } else {
1717                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1718                         }
1719                 }
1720         }
1721 }
1722 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1723 {
1724         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1725
1726         /* set vc-> edit data */
1727         
1728         data.select = selecting;
1729         data.mval[0] = mval[0];
1730         data.mval[1] = mval[1];
1731         data.radius = rad;
1732
1733         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1734 }
1735
1736
1737 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1738 {
1739         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1740         int mx = x - data->mval[0], my = y - data->mval[1];
1741         float r = sqrt(mx*mx + my*my);
1742
1743         if (r<=data->radius) {
1744                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1745         }
1746 }
1747 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1748 {
1749         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1750
1751         /* set vc-> edit data */
1752         
1753         data.select = selecting;
1754         data.mval[0] = mval[0];
1755         data.mval[1] = mval[1];
1756         data.radius = rad;
1757
1758         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1759 }
1760
1761 /** Callbacks for circle selection in Editmode */
1762
1763 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad) 
1764 {
1765         switch(vc->obedit->type) {              
1766         case OB_MESH:
1767                 mesh_circle_select(vc, selecting, mval, rad);
1768                 break;
1769         case OB_CURVE:
1770         case OB_SURF:
1771                 nurbscurve_circle_select(vc, selecting, mval, rad);
1772                 break;
1773         case OB_LATTICE:
1774                 lattice_circle_select(vc, selecting, mval, rad);
1775                 break;
1776         default:
1777                 return;
1778         }
1779 }
1780
1781 /* not a real operator, only for circle test */
1782 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
1783 {
1784         ScrArea *sa= CTX_wm_area(C);
1785         ARegion *ar= CTX_wm_region(C);
1786         Scene *scene= CTX_data_scene(C);
1787         View3D *v3d= sa->spacedata.first;
1788         int x= RNA_int_get(op->ptr, "x");
1789         int y= RNA_int_get(op->ptr, "y");
1790         int radius= RNA_int_get(op->ptr, "radius");
1791         
1792         if(CTX_data_edit_object(C) || (G.f & G_PARTICLEEDIT)) {
1793                 ViewContext vc;
1794                 short mval[2], selecting;
1795                 
1796                 view3d_operator_needs_opengl(C);
1797                 
1798                 view3d_set_viewcontext(C, &vc);
1799                 mval[0]= x;
1800                 mval[1]= y;
1801                 selecting= LEFTMOUSE==RNA_int_get(op->ptr, "event_type"); // XXX solve
1802
1803                 if(CTX_data_edit_object(C))
1804                         obedit_circle_select(&vc, selecting, mval, (float)radius);
1805                 else
1806                         return PE_circle_select(C, selecting, mval, (float)radius);
1807         }
1808         else {
1809                 Base *base;
1810                 
1811                 for(base= FIRSTBASE; base; base= base->next) {
1812                         if(base->lay & v3d->lay) {
1813                                 project_short(ar, base->object->obmat[3], &base->sx);
1814                                 if(base->sx!=IS_CLIPPED) {
1815                                         int dx= base->sx-x;
1816                                         int dy= base->sy-y;
1817                                         if( dx*dx + dy*dy < radius*radius)
1818                                                 ED_base_object_select(base, BA_SELECT);
1819                                 }
1820                         }
1821                 }
1822                 
1823                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1824         }
1825         
1826         return OPERATOR_FINISHED;
1827 }
1828
1829 void VIEW3D_OT_select_circle(wmOperatorType *ot)
1830 {
1831         ot->name= "Circle Select";
1832         ot->idname= "VIEW3D_OT_select_circle";
1833         
1834         ot->invoke= WM_gesture_circle_invoke;
1835         ot->modal= WM_gesture_circle_modal;
1836         ot->exec= view3d_circle_select_exec;
1837         ot->poll= ED_operator_view3d_active;
1838         
1839         /* flags */
1840         ot->flag= OPTYPE_UNDO;
1841         
1842         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1843         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1844         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1845         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1846 }