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