manual merge trunk -r 23037
[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->description= "Select items using lasso selection.";
760         ot->idname= "VIEW3D_OT_select_lasso";
761         
762         ot->invoke= WM_gesture_lasso_invoke;
763         ot->modal= WM_gesture_lasso_modal;
764         ot->exec= view3d_lasso_select_exec;
765         ot->poll= WM_operator_winactive;
766         
767         /* flags */
768         ot->flag= OPTYPE_UNDO;
769         
770         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
771         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items.");
772 }
773
774
775 /* ************************************************* */
776
777 #if 0
778 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
779 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
780 {
781         Base *base;
782         unsigned int *bufmin,*bufmax;
783         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
784         unsigned int retval=0;
785         
786         base= LASTBASE;
787         if(base==0) return 0;
788         maxob= base->selcol;
789
790         aantal= (size-1)/2;
791         rc= 0;
792
793         dirvec[0][0]= 1;
794         dirvec[0][1]= 0;
795         dirvec[1][0]= 0;
796         dirvec[1][1]= -size;
797         dirvec[2][0]= -1;
798         dirvec[2][1]= 0;
799         dirvec[3][0]= 0;
800         dirvec[3][1]= size;
801
802         bufmin= buf;
803         bufmax= buf+ size*size;
804         buf+= aantal*size+ aantal;
805
806         for(tel=1;tel<=size;tel++) {
807
808                 for(a=0;a<2;a++) {
809                         for(b=0;b<tel;b++) {
810
811                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
812                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
813                                 
814                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
815
816                                 if(buf<bufmin || buf>=bufmax) return retval;
817                         }
818                         rc++;
819                         rc &= 3;
820                 }
821         }
822         return retval;
823 }
824 #endif
825
826 /* ************************** mouse select ************************* */
827
828
829 /* The max number of menu items in an object select menu */
830 #define SEL_MENU_SIZE   22
831
832 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
833 {
834         Base *base;
835         
836         for(base= FIRSTBASE; base; base= base->next) {
837                 if (base->flag & SELECT) {
838                         if(b!=base) {
839                                 ED_base_object_select(base, BA_DESELECT);
840                         }
841                 }
842         }
843 }
844
845 static Base *mouse_select_menu(ViewContext *vc, unsigned int *buffer, int hits, short *mval)
846 {
847         Scene *scene= vc->scene;
848         View3D *v3d= vc->v3d;
849         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
850         Base *base;
851         short baseCount = 0;
852         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       /* max ob name = 22 */
853         char str[32];
854         
855         for(base=FIRSTBASE; base; base= base->next) {
856                 if (BASE_SELECTABLE(v3d, base)) {
857                         baseList[baseCount] = NULL;
858                         
859                         /* two selection methods, the CTRL select uses max dist of 15 */
860                         if(buffer) {
861                                 int a;
862                                 for(a=0; a<hits; a++) {
863                                         /* index was converted */
864                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
865                                 }
866                         }
867                         else {
868                                 int temp, dist=15;
869                                 
870                                 project_short(vc->ar, base->object->obmat[3], &base->sx);
871                                 
872                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
873                                 if(temp<dist ) baseList[baseCount] = base;
874                         }
875                         
876                         if(baseList[baseCount]) {
877                                 if (baseCount < SEL_MENU_SIZE) {
878                                         baseList[baseCount] = base;
879                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        /* max ob name == 22 */
880                                                         strcat(menuText, str);
881                                                         baseCount++;
882                                 }
883                         }
884                 }
885         }
886
887         if(baseCount<=1) return baseList[0];
888         else {
889                 baseCount = -1; // XXX = pupmenu(menuText);
890                 
891                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
892                         return baseList[baseCount-1];
893                 }
894                 else return NULL;
895         }
896 }
897
898 /* we want a select buffer with bones, if there are... */
899 /* so check three selection levels and compare */
900 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, short *mval)
901 {
902         rcti rect;
903         int offs;
904         short a, hits15, hits9=0, hits5=0;
905         short has_bones15=0, has_bones9=0, has_bones5=0;
906         
907         BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
908         hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
909         if(hits15>0) {
910                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
911                 
912                 offs= 4*hits15;
913                 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
914                 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
915                 if(hits9>0) {
916                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
917                         
918                         offs+= 4*hits9;
919                         BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
920                         hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
921                         if(hits5>0) {
922                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
923                         }
924                 }
925                 
926                 if(has_bones5) {
927                         offs= 4*hits15 + 4*hits9;
928                         memcpy(buffer, buffer+offs, 4*offs);
929                         return hits5;
930                 }
931                 if(has_bones9) {
932                         offs= 4*hits15;
933                         memcpy(buffer, buffer+offs, 4*offs);
934                         return hits9;
935                 }
936                 if(has_bones15) {
937                         return hits15;
938                 }
939                 
940                 if(hits5>0) {
941                         offs= 4*hits15 + 4*hits9;
942                         memcpy(buffer, buffer+offs, 4*offs);
943                         return hits5;
944                 }
945                 if(hits9>0) {
946                         offs= 4*hits15;
947                         memcpy(buffer, buffer+offs, 4*offs);
948                         return hits9;
949                 }
950                 return hits15;
951         }
952         
953         return 0;
954 }
955
956
957 /* mval is region coords */
958 static void mouse_select(bContext *C, short *mval, short extend, short obcenter)
959 {
960         ViewContext vc;
961         ARegion *ar= CTX_wm_region(C);
962         View3D *v3d= CTX_wm_view3d(C);
963         Scene *scene= CTX_data_scene(C);
964         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
965         unsigned int buffer[4*MAXPICKBUF];
966         int temp, a, dist=100;
967         short hits;
968         
969         /* setup view context for argument to callbacks */
970         view3d_set_viewcontext(C, &vc);
971         
972         /* always start list from basact in wire mode */
973         startbase=  FIRSTBASE;
974         if(BASACT && BASACT->next) startbase= BASACT->next;
975         
976         /* This block uses the control key to make the object selected by its center point rather then its contents */
977         /* XXX later on, in editmode do not activate */
978         if(vc.obedit==NULL && obcenter) {
979                 
980                 /* note; shift+alt goes to group-flush-selecting */
981                 /* XXX solve */
982                 if(0) 
983                         basact= mouse_select_menu(&vc, NULL, 0, mval);
984                 else {
985                         base= startbase;
986                         while(base) {
987                                 if (BASE_SELECTABLE(v3d, base)) {
988                                         project_short(ar, base->object->obmat[3], &base->sx);
989                                         
990                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
991                                         if(base==BASACT) temp+=10;
992                                         if(temp<dist ) {
993                                                 
994                                                 dist= temp;
995                                                 basact= base;
996                                         }
997                                 }
998                                 base= base->next;
999                                 
1000                                 if(base==0) base= FIRSTBASE;
1001                                 if(base==startbase) break;
1002                         }
1003                 }
1004         }
1005         else {
1006                 /* if objects have posemode set, the bones are in the same selection buffer */
1007                 
1008                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1009                 
1010                 if(hits>0) {
1011                         int has_bones= 0;
1012                         
1013                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1014
1015                         /* note; shift+alt goes to group-flush-selecting */
1016                         if(has_bones==0 && 0) 
1017                                 basact= mouse_select_menu(&vc, buffer, hits, mval);
1018                         else {
1019                                 static short lastmval[2]={-100, -100};
1020                                 int donearest= 0;
1021                                 
1022                                 /* define if we use solid nearest select or not */
1023                                 if(v3d->drawtype>OB_WIRE) {
1024                                         donearest= 1;
1025                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1026                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
1027                                                         donearest= 0;
1028                                         }
1029                                 }
1030                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1031                                 
1032                                 if(donearest) {
1033                                         unsigned int min= 0xFFFFFFFF;
1034                                         int selcol= 0, notcol=0;
1035                                         
1036
1037                                         if(has_bones) {
1038                                                 /* we skip non-bone hits */
1039                                                 for(a=0; a<hits; a++) {
1040                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1041                                                                 min= buffer[4*a+1];
1042                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1043                                                         }
1044                                                 }
1045                                         }
1046                                         else {
1047                                                 /* only exclude active object when it is selected... */
1048                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1049                                         
1050                                                 for(a=0; a<hits; a++) {
1051                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1052                                                                 min= buffer[4*a+1];
1053                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1054                                                         }
1055                                                 }
1056                                         }
1057
1058                                         base= FIRSTBASE;
1059                                         while(base) {
1060                                                 if(base->lay & v3d->lay) {
1061                                                         if(base->selcol==selcol) break;
1062                                                 }
1063                                                 base= base->next;
1064                                         }
1065                                         if(base) basact= base;
1066                                 }
1067                                 else {
1068                                         
1069                                         base= startbase;
1070                                         while(base) {
1071                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
1072                                                  * with an un-selectable choice */
1073                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1074                                                         base=base->next;
1075                                                         if(base==NULL) base= FIRSTBASE;
1076                                                         if(base==startbase) break;
1077                                                 }
1078                                         
1079                                                 if(base->lay & v3d->lay) {
1080                                                         for(a=0; a<hits; a++) {
1081                                                                 if(has_bones) {
1082                                                                         /* skip non-bone objects */
1083                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1084                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1085                                                                                         basact= base;
1086                                                                         }
1087                                                                 }
1088                                                                 else {
1089                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1090                                                                                 basact= base;
1091                                                                 }
1092                                                         }
1093                                                 }
1094                                                 
1095                                                 if(basact) break;
1096                                                 
1097                                                 base= base->next;
1098                                                 if(base==NULL) base= FIRSTBASE;
1099                                                 if(base==startbase) break;
1100                                         }
1101                                 }
1102                         }
1103                         
1104                         if(has_bones && basact) {
1105                                 if(ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) {     /* then bone is found */
1106                                 
1107                                         /* we make the armature selected: 
1108                                            not-selected active object in posemode won't work well for tools */
1109                                         basact->flag|= SELECT;
1110                                         basact->object->flag= basact->flag;
1111                                         
1112                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1113                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1114                                         
1115                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1116                                         if(basact->object->mode & OB_MODE_WEIGHT_PAINT) {
1117                                                 /* prevent activating */
1118                                                 basact= NULL;
1119                                         }
1120
1121                                 }
1122                                 /* prevent bone selecting to pass on to object selecting */
1123                                 if(basact==BASACT)
1124                                         basact= NULL;
1125                         }
1126                 }
1127         }
1128         
1129         /* so, do we have something selected? */
1130         if(basact) {
1131                 
1132                 if(vc.obedit) {
1133                         /* only do select */
1134                         deselectall_except(scene, basact);
1135                         ED_base_object_select(basact, BA_SELECT);
1136                 }
1137                 /* also prevent making it active on mouse selection */
1138                 else if (BASE_SELECTABLE(v3d, basact)) {
1139
1140                         oldbasact= BASACT;
1141                         
1142                         if(!extend) {
1143                                 deselectall_except(scene, basact);
1144                                 ED_base_object_select(basact, BA_SELECT);
1145                         }
1146                         else if(0) {
1147                                 // XXX select_all_from_groups(basact);
1148                         }
1149                         else {
1150                                 if(basact->flag & SELECT) {
1151                                         if(basact==oldbasact)
1152                                                 ED_base_object_select(basact, BA_DESELECT);
1153                                 }
1154                                 else ED_base_object_select(basact, BA_SELECT);
1155                         }
1156
1157                         if(oldbasact != basact) {
1158                                 ED_base_object_activate(C, basact); /* adds notifier */
1159                         }
1160
1161                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1162                 }
1163         }
1164 }
1165
1166 /* ********************  border and circle ************************************** */
1167
1168
1169 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1170 {
1171         int radsq= rad*rad;
1172         float v1[2], v2[2], v3[2];
1173         
1174         /* check points in circle itself */
1175         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1176         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1177         
1178         /* pointdistline */
1179         v3[0]= centx;
1180         v3[1]= centy;
1181         v1[0]= x1;
1182         v1[1]= y1;
1183         v2[0]= x2;
1184         v2[1]= y2;
1185         
1186         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1187         
1188         return 0;
1189 }
1190
1191 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1192 {
1193         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1194
1195         if (BLI_in_rcti(data->rect, x, y)) {
1196                 if (bp) {
1197                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1198                 } else {
1199                         if (G.f & G_HIDDENHANDLES) {
1200                                 /* can only be beztindex==0 here since handles are hidden */
1201                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1202                         } else {
1203                                 if (beztindex==0) {
1204                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1205                                 } else if (beztindex==1) {
1206                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1207                                 } else {
1208                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1209                                 }
1210                         }
1211                 }
1212         }
1213 }
1214 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select)
1215 {
1216         struct { ViewContext vc; rcti *rect; int select; } data;
1217         
1218         data.vc= *vc;
1219         data.rect = rect;
1220         data.select = select;
1221
1222         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1223 }
1224
1225 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1226 {
1227         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1228
1229         if (BLI_in_rcti(data->rect, x, y)) {
1230                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1231         }
1232 }
1233 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select)
1234 {
1235         struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1236
1237         data.vc= *vc;
1238         data.rect = rect;
1239         data.select = select;
1240
1241         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1242 }
1243
1244 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1245 {
1246         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1247
1248         if (BLI_in_rcti(data->rect, x, y)) {
1249                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1250         }
1251 }
1252 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1253 {
1254         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1255
1256         if(EM_check_backbuf(em_solidoffs+index)) {
1257                 if (data->pass==0) {
1258                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1259                                 EM_select_edge(eed, data->select);
1260                                 data->done = 1;
1261                         }
1262                 } else {
1263                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1264                                 EM_select_edge(eed, data->select);
1265                         }
1266                 }
1267         }
1268 }
1269 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1270 {
1271         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1272
1273         if (BLI_in_rcti(data->rect, x, y)) {
1274                 EM_select_face_fgon(data->vc.em, efa, data->select);
1275         }
1276 }
1277 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
1278 {
1279         struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1280         ToolSettings *ts= vc->scene->toolsettings;
1281         int bbsel;
1282         
1283         data.vc= *vc;
1284         data.rect = rect;
1285         data.select = select;
1286         data.pass = 0;
1287         data.done = 0;
1288
1289         bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1290
1291         if(ts->selectmode & SCE_SELECT_VERTEX) {
1292                 if (bbsel) {
1293                         EM_backbuf_checkAndSelectVerts(vc->em, select);
1294                 } else {
1295                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1296                 }
1297         }
1298         if(ts->selectmode & SCE_SELECT_EDGE) {
1299                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1300
1301                 data.pass = 0;
1302                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1303
1304                 if (data.done==0) {
1305                         data.pass = 1;
1306                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1307                 }
1308         }
1309         
1310         if(ts->selectmode & SCE_SELECT_FACE) {
1311                 if(bbsel) {
1312                         EM_backbuf_checkAndSelectFaces(vc->em, select);
1313                 } else {
1314                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1315                 }
1316         }
1317         
1318         EM_free_backbuf();
1319                 
1320         EM_selectmode_flush(vc->em);
1321 }
1322
1323 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1324 {
1325         ViewContext vc;
1326         Scene *scene= CTX_data_scene(C);
1327         ScrArea *sa= CTX_wm_area(C);
1328         View3D *v3d= sa->spacedata.first;
1329         Object *obedit= CTX_data_edit_object(C);
1330         Object *obact= CTX_data_active_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 && (paint_facesel_test(OBACT))) {
1350 // XXX          face_borderselect();
1351                 return OPERATOR_FINISHED;
1352         }
1353         else if(obedit==NULL && (obact && obact->mode & OB_MODE_PARTICLE_EDIT)) {
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_GEOM|ND_SELECT, obedit->data);
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                         MetaBall *mb = (MetaBall*)obedit->data;
1371                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1372                         
1373                         ml= mb->editelems->first;
1374                         
1375                         while(ml) {
1376                                 for(a=0; a<hits; a++) {
1377                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1378                                                 ml->flag |= MB_SCALE_RAD;
1379                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1380                                                 else ml->flag &= ~SELECT;
1381                                                 break;
1382                                         }
1383                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1384                                                 ml->flag &= ~MB_SCALE_RAD;
1385                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1386                                                 else ml->flag &= ~SELECT;
1387                                                 break;
1388                                         }
1389                                 }
1390                                 ml= ml->next;
1391                         }
1392                 }
1393                 else if(obedit->type==OB_ARMATURE) {
1394                         bArmature *arm= obedit->data;
1395                         EditBone *ebone;
1396                         
1397                         /* clear flag we use to detect point was affected */
1398                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1399                                 ebone->flag &= ~BONE_DONE;
1400                         
1401                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1402                         
1403                         /* first we only check points inside the border */
1404                         for (a=0; a<hits; a++){
1405                                 index = buffer[(4*a)+3];
1406                                 if (index!=-1) {
1407                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1408                                         if (index & BONESEL_TIP) {
1409                                                 ebone->flag |= BONE_DONE;
1410                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1411                                                 else ebone->flag &= ~BONE_TIPSEL;
1412                                         }
1413                                         
1414                                         if (index & BONESEL_ROOT) {
1415                                                 ebone->flag |= BONE_DONE;
1416                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1417                                                 else ebone->flag &= ~BONE_ROOTSEL;
1418                                         }
1419                                 }
1420                         }
1421                         
1422                         /* now we have to flush tag from parents... */
1423                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1424                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1425                                         if(ebone->parent->flag & BONE_DONE)
1426                                                 ebone->flag |= BONE_DONE;
1427                                 }
1428                         }
1429                         
1430                         /* only select/deselect entire bones when no points where in the rect */
1431                         for (a=0; a<hits; a++){
1432                                 index = buffer[(4*a)+3];
1433                                 if (index!=-1) {
1434                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1435                                         if (index & BONESEL_BONE) {
1436                                                 if(!(ebone->flag & BONE_DONE)) {
1437                                                         if (val==LEFTMOUSE)
1438                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1439                                                         else
1440                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1441                                                 }
1442                                         }
1443                                 }
1444                         }
1445                         
1446                         ED_armature_sync_selection(arm->edbo);
1447                 }
1448                 else if(obedit->type==OB_LATTICE) {
1449                         do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
1450                 }
1451         }
1452         else {  /* no editmode, unified for bones and objects */
1453                 Bone *bone;
1454                 Object *ob= OBACT;
1455                 unsigned int *vbuffer=NULL; /* selection buffer */
1456                 unsigned int *col;                      /* color in buffer      */
1457                 short selecting = 0;
1458                 int bone_only;
1459                 int totobj= MAXPICKBUF; // XXX solve later
1460                 
1461                 if((ob) && (ob->mode & OB_MODE_POSE))
1462                         bone_only= 1;
1463                 else
1464                         bone_only= 0;
1465                 
1466                 if (val==LEFTMOUSE)
1467                         selecting = 1;
1468                 
1469                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1470                 vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1471                 hits= view3d_opengl_select(&vc, vbuffer, 4*(totobj+MAXPICKBUF), &rect);
1472                 /*
1473                 LOGIC NOTES (theeth):
1474                 The buffer and ListBase have the same relative order, which makes the selection
1475                 very simple. Loop through both data sets at the same time, if the color
1476                 is the same as the object, we have a hit and can move to the next color
1477                 and object pair, if not, just move to the next object,
1478                 keeping the same color until we have a hit.
1479
1480                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1481                 does it incorrectly.
1482                 */
1483
1484                 if (hits>0) { /* no need to loop if there's no hit */
1485                         base= FIRSTBASE;
1486                         col = vbuffer + 3;
1487                         
1488                         while(base && hits) {
1489                                 Base *next = base->next;
1490                                 if(base->lay & v3d->lay) {
1491                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1492                                                 
1493                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1494                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1495                                                         if(bone) {
1496                                                                 if(selecting) {
1497                                                                         bone->flag |= BONE_SELECTED;
1498 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1499                                                                 }
1500                                                                 else {
1501                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1502 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1503                                                                 }
1504                                                         }
1505                                                 }
1506                                                 else if(!bone_only) {
1507                                                         if (selecting)
1508                                                                 ED_base_object_select(base, BA_SELECT);
1509                                                         else
1510                                                                 ED_base_object_select(base, BA_DESELECT);
1511                                                 }
1512
1513                                                 col+=4; /* next color */
1514                                                 hits--;
1515                                                 if(hits==0) break;
1516                                         }
1517                                 }
1518                                 
1519                                 base= next;
1520                         }
1521
1522                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1523
1524                 }
1525                 MEM_freeN(vbuffer);
1526         }
1527         return OPERATOR_FINISHED;
1528
1529
1530
1531 /* *****************Selection Operators******************* */
1532
1533 /* ****** Border Select ****** */
1534 void VIEW3D_OT_select_border(wmOperatorType *ot)
1535 {
1536         /* identifiers */
1537         ot->name= "Border Select";
1538         ot->description= "Select items using border selection.";
1539         ot->idname= "VIEW3D_OT_select_border";
1540         
1541         /* api callbacks */
1542         ot->invoke= WM_border_select_invoke;
1543         ot->exec= view3d_borderselect_exec;
1544         ot->modal= WM_border_select_modal;
1545         
1546         ot->poll= ED_operator_view3d_active;
1547         
1548         /* flags */
1549         ot->flag= OPTYPE_UNDO;
1550         
1551         /* rna */
1552         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1553         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1554         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1555         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1556         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1557
1558         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first.");
1559 }
1560
1561 /* ****** Mouse Select ****** */
1562
1563
1564 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1565 {
1566         Object *obedit= CTX_data_edit_object(C);
1567         Object *obact= CTX_data_active_object(C);
1568         short extend= RNA_boolean_get(op->ptr, "extend");
1569
1570         view3d_operator_needs_opengl(C);
1571         
1572         if(obedit) {
1573                 if(obedit->type==OB_MESH)
1574                         mouse_mesh(C, event->mval, extend);
1575                 else if(obedit->type==OB_ARMATURE)
1576                         mouse_armature(C, event->mval, extend);
1577                 else if(obedit->type==OB_LATTICE)
1578                         mouse_lattice(C, event->mval, extend);
1579                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1580                         mouse_nurb(C, event->mval, extend);
1581                 else if(obedit->type==OB_MBALL)
1582                         mouse_mball(C, event->mval, extend);
1583                         
1584         }
1585         else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT)
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->description= "Activate/select item(s).";
1599         ot->idname= "VIEW3D_OT_select";
1600         
1601         /* api callbacks */
1602         ot->invoke= view3d_select_invoke;
1603         ot->poll= ED_operator_view3d_active;
1604         
1605         /* flags */
1606         ot->flag= OPTYPE_UNDO;
1607         
1608         /* properties */
1609         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first.");
1610 }
1611
1612
1613 /* -------------------- circle select --------------------------------------------- */
1614
1615 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1616 {
1617         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1618         int mx = x - data->mval[0], my = y - data->mval[1];
1619         float r = sqrt(mx*mx + my*my);
1620
1621         if (r<=data->radius) {
1622                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1623         }
1624 }
1625 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1626 {
1627         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1628
1629         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1630                 EM_select_edge(eed, data->select);
1631         }
1632 }
1633 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1634 {
1635         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1636         int mx = x - data->mval[0], my = y - data->mval[1];
1637         float r = sqrt(mx*mx + my*my);
1638         
1639         if (r<=data->radius) {
1640                 EM_select_face_fgon(data->vc->em, efa, data->select);
1641         }
1642 }
1643
1644 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1645 {
1646         ToolSettings *ts= vc->scene->toolsettings;
1647         int bbsel;
1648         Object *ob= vc->obact;
1649         
1650         if(vc->obedit==NULL && paint_facesel_test(ob)) {
1651                 Mesh *me = ob?ob->data:NULL;
1652
1653                 if (me) {
1654                         em_vertoffs= me->totface+1;     /* max index array */
1655
1656                         bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1657                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1658                         EM_free_backbuf();
1659
1660 // XXX                  object_tface_flags_changed(OBACT, 0);
1661                 }
1662         }
1663         else {
1664                 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1665                 
1666                 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1667                 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1668
1669                 data.select = selecting;
1670                 data.mval[0] = mval[0];
1671                 data.mval[1] = mval[1];
1672                 data.radius = rad;
1673
1674                 if(ts->selectmode & SCE_SELECT_VERTEX) {
1675                         if(bbsel) {
1676                                 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1677                         } else {
1678                                 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1679                         }
1680                 }
1681
1682                 if(ts->selectmode & SCE_SELECT_EDGE) {
1683                         if (bbsel) {
1684                                 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1685                         } else {
1686                                 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1687                         }
1688                 }
1689                 
1690                 if(ts->selectmode & SCE_SELECT_FACE) {
1691                         if(bbsel) {
1692                                 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1693                         } else {
1694                                 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1695                         }
1696                 }
1697
1698                 EM_free_backbuf();
1699                 EM_selectmode_flush(vc->em);
1700         }
1701 }
1702
1703
1704 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1705 {
1706         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1707         int mx = x - data->mval[0], my = y - data->mval[1];
1708         float r = sqrt(mx*mx + my*my);
1709
1710         if (r<=data->radius) {
1711                 if (bp) {
1712                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1713                 } else {
1714                         if (beztindex==0) {
1715                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1716                         } else if (beztindex==1) {
1717                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1718                         } else {
1719                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1720                         }
1721                 }
1722         }
1723 }
1724 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1725 {
1726         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1727
1728         /* set vc-> edit data */
1729         
1730         data.select = selecting;
1731         data.mval[0] = mval[0];
1732         data.mval[1] = mval[1];
1733         data.radius = rad;
1734
1735         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1736 }
1737
1738
1739 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1740 {
1741         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1742         int mx = x - data->mval[0], my = y - data->mval[1];
1743         float r = sqrt(mx*mx + my*my);
1744
1745         if (r<=data->radius) {
1746                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1747         }
1748 }
1749 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1750 {
1751         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1752
1753         /* set vc-> edit data */
1754         
1755         data.select = selecting;
1756         data.mval[0] = mval[0];
1757         data.mval[1] = mval[1];
1758         data.radius = rad;
1759
1760         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1761 }
1762
1763 /** Callbacks for circle selection in Editmode */
1764
1765 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad) 
1766 {
1767         switch(vc->obedit->type) {              
1768         case OB_MESH:
1769                 mesh_circle_select(vc, selecting, mval, rad);
1770                 break;
1771         case OB_CURVE:
1772         case OB_SURF:
1773                 nurbscurve_circle_select(vc, selecting, mval, rad);
1774                 break;
1775         case OB_LATTICE:
1776                 lattice_circle_select(vc, selecting, mval, rad);
1777                 break;
1778         default:
1779                 return;
1780         }
1781 }
1782
1783 /* not a real operator, only for circle test */
1784 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
1785 {
1786         ScrArea *sa= CTX_wm_area(C);
1787         ARegion *ar= CTX_wm_region(C);
1788         Scene *scene= CTX_data_scene(C);
1789         Object *obact= CTX_data_active_object(C);
1790         View3D *v3d= sa->spacedata.first;
1791         int x= RNA_int_get(op->ptr, "x");
1792         int y= RNA_int_get(op->ptr, "y");
1793         int radius= RNA_int_get(op->ptr, "radius");
1794         
1795         if(CTX_data_edit_object(C) || (obact && obact->mode & OB_MODE_PARTICLE_EDIT)) {
1796                 ViewContext vc;
1797                 short mval[2], selecting;
1798                 
1799                 view3d_operator_needs_opengl(C);
1800                 
1801                 view3d_set_viewcontext(C, &vc);
1802                 mval[0]= x;
1803                 mval[1]= y;
1804                 selecting= LEFTMOUSE==RNA_int_get(op->ptr, "event_type"); // XXX solve
1805
1806                 if(CTX_data_edit_object(C)) {
1807                         obedit_circle_select(&vc, selecting, mval, (float)radius);
1808                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
1809                 }
1810                 else
1811                         return PE_circle_select(C, selecting, mval, (float)radius);
1812         }
1813         else {
1814                 Base *base;
1815                 
1816                 for(base= FIRSTBASE; base; base= base->next) {
1817                         if(base->lay & v3d->lay) {
1818                                 project_short(ar, base->object->obmat[3], &base->sx);
1819                                 if(base->sx!=IS_CLIPPED) {
1820                                         int dx= base->sx-x;
1821                                         int dy= base->sy-y;
1822                                         if( dx*dx + dy*dy < radius*radius)
1823                                                 ED_base_object_select(base, BA_SELECT);
1824                                 }
1825                         }
1826                 }
1827                 
1828                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1829         }
1830         
1831         return OPERATOR_FINISHED;
1832 }
1833
1834 void VIEW3D_OT_select_circle(wmOperatorType *ot)
1835 {
1836         ot->name= "Circle Select";
1837         ot->description= "Select items using circle selection.";
1838         ot->idname= "VIEW3D_OT_select_circle";
1839         
1840         ot->invoke= WM_gesture_circle_invoke;
1841         ot->modal= WM_gesture_circle_modal;
1842         ot->exec= view3d_circle_select_exec;
1843         ot->poll= ED_operator_view3d_active;
1844         
1845         /* flags */
1846         ot->flag= OPTYPE_UNDO;
1847         
1848         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1849         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1850         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1851         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1852 }