NLA SoC: Merge from 2.5
[blender.git] / source / blender / editors / space_view3d / view3d_select.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_curve_types.h"
37 #include "DNA_camera_types.h"
38 #include "DNA_lamp_types.h"
39 #include "DNA_meta_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_space_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_userdef_types.h"
47 #include "DNA_view3d_types.h"
48 #include "DNA_world_types.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "BLI_arithb.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_editVert.h"
55 #include "BLI_rand.h"
56
57 #include "BKE_action.h"
58 #include "BKE_context.h"
59 #include "BKE_depsgraph.h"
60 #include "BKE_object.h"
61 #include "BKE_global.h"
62 #include "BKE_scene.h"
63 #include "BKE_screen.h"
64 #include "BKE_utildefines.h"
65
66 #include "RE_pipeline.h"        // make_stars
67
68 #include "BIF_gl.h"
69
70 #include "WM_api.h"
71 #include "WM_types.h"
72
73 #include "RNA_access.h"
74 #include "RNA_define.h"
75
76 #include "ED_armature.h"
77 #include "ED_curve.h"
78 #include "ED_particle.h"
79 #include "ED_mesh.h"
80 #include "ED_object.h"
81 #include "ED_retopo.h"
82 #include "ED_screen.h"
83 #include "ED_types.h"
84 #include "ED_util.h"
85
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                         ED_armature_sync_selection(arm->edbo);
1446                 }
1447                 else if(obedit->type==OB_LATTICE) {
1448                         do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
1449                 }
1450         }
1451         else {  /* no editmode, unified for bones and objects */
1452                 Bone *bone;
1453                 Object *ob= OBACT;
1454                 unsigned int *vbuffer=NULL; /* selection buffer */
1455                 unsigned int *col;                      /* color in buffer      */
1456                 short selecting = 0;
1457                 int bone_only;
1458                 int totobj= MAXPICKBUF; // XXX solve later
1459                 
1460                 if((ob) && (ob->flag & OB_POSEMODE))
1461                         bone_only= 1;
1462                 else
1463                         bone_only= 0;
1464                 
1465                 if (val==LEFTMOUSE)
1466                         selecting = 1;
1467                 
1468                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1469                 vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1470                 hits= view3d_opengl_select(&vc, vbuffer, 4*(totobj+MAXPICKBUF), &rect);
1471                 /*
1472                 LOGIC NOTES (theeth):
1473                 The buffer and ListBase have the same relative order, which makes the selection
1474                 very simple. Loop through both data sets at the same time, if the color
1475                 is the same as the object, we have a hit and can move to the next color
1476                 and object pair, if not, just move to the next object,
1477                 keeping the same color until we have a hit.
1478
1479                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1480                 does it incorrectly.
1481                 */
1482
1483                 if (hits>0) { /* no need to loop if there's no hit */
1484                         base= FIRSTBASE;
1485                         col = vbuffer + 3;
1486                         
1487                         while(base && hits) {
1488                                 Base *next = base->next;
1489                                 if(base->lay & v3d->lay) {
1490                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1491                                                 
1492                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1493                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1494                                                         if(bone) {
1495                                                                 if(selecting) {
1496                                                                         bone->flag |= BONE_SELECTED;
1497 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1498                                                                 }
1499                                                                 else {
1500                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1501 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1502                                                                 }
1503                                                         }
1504                                                 }
1505                                                 else if(!bone_only) {
1506                                                         if (selecting)
1507                                                                 ED_base_object_select(base, BA_SELECT);
1508                                                         else
1509                                                                 ED_base_object_select(base, BA_DESELECT);
1510                                                 }
1511
1512                                                 col+=4; /* next color */
1513                                                 hits--;
1514                                                 if(hits==0) break;
1515                                         }
1516                                 }
1517                                 
1518                                 base= next;
1519                         }
1520
1521                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1522
1523                 }
1524                 MEM_freeN(vbuffer);
1525         }
1526         return OPERATOR_FINISHED;
1527
1528
1529
1530 /* *****************Selection Operators******************* */
1531 static EnumPropertyItem prop_select_types[] = {
1532         {0, "EXCLUSIVE", 0, "Exclusive", ""},
1533         {1, "EXTEND", 0, "Extend", ""},
1534         {0, NULL, 0, NULL, NULL}
1535 };
1536
1537 /* ****** Border Select ****** */
1538 void VIEW3D_OT_select_border(wmOperatorType *ot)
1539 {
1540         /* identifiers */
1541         ot->name= "Border Select";
1542         ot->idname= "VIEW3D_OT_select_border";
1543         
1544         /* api callbacks */
1545         ot->invoke= WM_border_select_invoke;
1546         ot->exec= view3d_borderselect_exec;
1547         ot->modal= WM_border_select_modal;
1548         
1549         ot->poll= ED_operator_view3d_active;
1550         
1551         /* flags */
1552         ot->flag= OPTYPE_UNDO;
1553         
1554         /* rna */
1555         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1556         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1557         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1558         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1559         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1560
1561         RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
1562 }
1563
1564 /* ****** Mouse Select ****** */
1565
1566
1567 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1568 {
1569         Object *obedit= CTX_data_edit_object(C);
1570         short extend= RNA_enum_is_equal(op->ptr, "type", "EXTEND");
1571
1572         view3d_operator_needs_opengl(C);
1573         
1574         if(obedit) {
1575                 if(obedit->type==OB_MESH)
1576                         mouse_mesh(C, event->mval, extend);
1577                 else if(obedit->type==OB_ARMATURE)
1578                         mouse_armature(C, event->mval, extend);
1579                 else if(obedit->type==OB_LATTICE)
1580                         mouse_lattice(C, event->mval, extend);
1581                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1582                         mouse_nurb(C, event->mval, extend);
1583                         
1584         }
1585         else if(G.f & G_PARTICLEEDIT)
1586                 PE_mouse_particles(C, event->mval, extend);
1587         else 
1588                 mouse_select(C, event->mval, extend, 0);
1589
1590         /* allowing tweaks */
1591         return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
1592 }
1593
1594 void VIEW3D_OT_select(wmOperatorType *ot)
1595 {
1596         /* identifiers */
1597         ot->name= "Activate/Select";
1598         ot->idname= "VIEW3D_OT_select";
1599         
1600         /* api callbacks */
1601         ot->invoke= view3d_select_invoke;
1602         ot->poll= ED_operator_view3d_active;
1603         
1604         /* flags */
1605         ot->flag= OPTYPE_UNDO;
1606         
1607         /* properties */
1608         RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
1609 }
1610
1611
1612 /* -------------------- circle select --------------------------------------------- */
1613
1614 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1615 {
1616         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1617         int mx = x - data->mval[0], my = y - data->mval[1];
1618         float r = sqrt(mx*mx + my*my);
1619
1620         if (r<=data->radius) {
1621                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1622         }
1623 }
1624 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1625 {
1626         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1627
1628         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1629                 EM_select_edge(eed, data->select);
1630         }
1631 }
1632 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1633 {
1634         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1635         int mx = x - data->mval[0], my = y - data->mval[1];
1636         float r = sqrt(mx*mx + my*my);
1637         
1638         if (r<=data->radius) {
1639                 EM_select_face_fgon(data->vc->em, efa, data->select);
1640         }
1641 }
1642
1643 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1644 {
1645         ToolSettings *ts= vc->scene->toolsettings;
1646         int bbsel;
1647         
1648         if(vc->obedit==NULL && (FACESEL_PAINT_TEST)) {
1649                 Object *ob= vc->obact;
1650                 Mesh *me = ob?ob->data:NULL;
1651
1652                 if (me) {
1653                         em_vertoffs= me->totface+1;     /* max index array */
1654
1655                         bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1656                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1657                         EM_free_backbuf();
1658
1659 // XXX                  object_tface_flags_changed(OBACT, 0);
1660                 }
1661         }
1662         else {
1663                 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1664                 
1665                 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1666                 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1667
1668                 data.select = selecting;
1669                 data.mval[0] = mval[0];
1670                 data.mval[1] = mval[1];
1671                 data.radius = rad;
1672
1673                 if(ts->selectmode & SCE_SELECT_VERTEX) {
1674                         if(bbsel) {
1675                                 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1676                         } else {
1677                                 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1678                         }
1679                 }
1680
1681                 if(ts->selectmode & SCE_SELECT_EDGE) {
1682                         if (bbsel) {
1683                                 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1684                         } else {
1685                                 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1686                         }
1687                 }
1688                 
1689                 if(ts->selectmode & SCE_SELECT_FACE) {
1690                         if(bbsel) {
1691                                 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1692                         } else {
1693                                 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1694                         }
1695                 }
1696
1697                 EM_free_backbuf();
1698                 EM_selectmode_flush(vc->em);
1699         }
1700 }
1701
1702
1703 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1704 {
1705         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1706         int mx = x - data->mval[0], my = y - data->mval[1];
1707         float r = sqrt(mx*mx + my*my);
1708
1709         if (r<=data->radius) {
1710                 if (bp) {
1711                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1712                 } else {
1713                         if (beztindex==0) {
1714                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1715                         } else if (beztindex==1) {
1716                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1717                         } else {
1718                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1719                         }
1720                 }
1721         }
1722 }
1723 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1724 {
1725         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1726
1727         /* set vc-> edit data */
1728         
1729         data.select = selecting;
1730         data.mval[0] = mval[0];
1731         data.mval[1] = mval[1];
1732         data.radius = rad;
1733
1734         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1735 }
1736
1737
1738 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1739 {
1740         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1741         int mx = x - data->mval[0], my = y - data->mval[1];
1742         float r = sqrt(mx*mx + my*my);
1743
1744         if (r<=data->radius) {
1745                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1746         }
1747 }
1748 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1749 {
1750         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1751
1752         /* set vc-> edit data */
1753         
1754         data.select = selecting;
1755         data.mval[0] = mval[0];
1756         data.mval[1] = mval[1];
1757         data.radius = rad;
1758
1759         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1760 }
1761
1762 /** Callbacks for circle selection in Editmode */
1763
1764 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad) 
1765 {
1766         switch(vc->obedit->type) {              
1767         case OB_MESH:
1768                 mesh_circle_select(vc, selecting, mval, rad);
1769                 break;
1770         case OB_CURVE:
1771         case OB_SURF:
1772                 nurbscurve_circle_select(vc, selecting, mval, rad);
1773                 break;
1774         case OB_LATTICE:
1775                 lattice_circle_select(vc, selecting, mval, rad);
1776                 break;
1777         default:
1778                 return;
1779         }
1780 }
1781
1782 /* not a real operator, only for circle test */
1783 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
1784 {
1785         ScrArea *sa= CTX_wm_area(C);
1786         ARegion *ar= CTX_wm_region(C);
1787         Scene *scene= CTX_data_scene(C);
1788         View3D *v3d= sa->spacedata.first;
1789         int x= RNA_int_get(op->ptr, "x");
1790         int y= RNA_int_get(op->ptr, "y");
1791         int radius= RNA_int_get(op->ptr, "radius");
1792         
1793         if(CTX_data_edit_object(C) || (G.f & G_PARTICLEEDIT)) {
1794                 ViewContext vc;
1795                 short mval[2], selecting;
1796                 
1797                 view3d_operator_needs_opengl(C);
1798                 
1799                 view3d_set_viewcontext(C, &vc);
1800                 mval[0]= x;
1801                 mval[1]= y;
1802                 selecting= LEFTMOUSE==RNA_int_get(op->ptr, "event_type"); // XXX solve
1803
1804                 if(CTX_data_edit_object(C))
1805                         obedit_circle_select(&vc, selecting, mval, (float)radius);
1806                 else
1807                         return PE_circle_select(C, selecting, mval, (float)radius);
1808         }
1809         else {
1810                 Base *base;
1811                 
1812                 for(base= FIRSTBASE; base; base= base->next) {
1813                         if(base->lay & v3d->lay) {
1814                                 project_short(ar, base->object->obmat[3], &base->sx);
1815                                 if(base->sx!=IS_CLIPPED) {
1816                                         int dx= base->sx-x;
1817                                         int dy= base->sy-y;
1818                                         if( dx*dx + dy*dy < radius*radius)
1819                                                 ED_base_object_select(base, BA_SELECT);
1820                                 }
1821                         }
1822                 }
1823                 
1824                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1825         }
1826         
1827         return OPERATOR_FINISHED;
1828 }
1829
1830 void VIEW3D_OT_select_circle(wmOperatorType *ot)
1831 {
1832         ot->name= "Circle Select";
1833         ot->idname= "VIEW3D_OT_select_circle";
1834         
1835         ot->invoke= WM_gesture_circle_invoke;
1836         ot->modal= WM_gesture_circle_modal;
1837         ot->exec= view3d_circle_select_exec;
1838         ot->poll= ED_operator_view3d_active;
1839         
1840         /* flags */
1841         ot->flag= OPTYPE_UNDO;
1842         
1843         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1844         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1845         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1846         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1847 }