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