680fda35f2bed6079dfa0ba394fa433b4582c723
[blender.git] / source / blender / editors / curve / editcurve_select.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): John Roper
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/curve/editcurve_select.c
29  *  \ingroup edcurve
30  */
31
32 #include "DNA_object_types.h"
33 #include "DNA_scene_types.h"
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_bitmap.h"
38 #include "BLI_math.h"
39 #include "BLI_rand.h"
40
41
42 #include "BKE_context.h"
43 #include "BKE_curve.h"
44 #include "BKE_fcurve.h"
45 #include "BKE_report.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49
50 #include "ED_screen.h"
51 #include "ED_types.h"
52 #include "ED_view3d.h"
53 #include "ED_curve.h"
54
55 #include "curve_intern.h"
56
57
58 #include "RNA_access.h"
59 #include "RNA_define.h"
60
61
62 /* returns 1 in case (de)selection was successful */
63 bool select_beztriple(BezTriple *bezt, bool selstatus, short flag, eVisible_Types hidden)
64 {
65         if ((bezt->hide == 0) || (hidden == HIDDEN)) {
66                 if (selstatus == SELECT) { /* selects */
67                         bezt->f1 |= flag;
68                         bezt->f2 |= flag;
69                         bezt->f3 |= flag;
70                         return true;
71                 }
72                 else { /* deselects */
73                         bezt->f1 &= ~flag;
74                         bezt->f2 &= ~flag;
75                         bezt->f3 &= ~flag;
76                         return true;
77                 }
78         }
79
80         return false;
81 }
82
83 /* returns 1 in case (de)selection was successful */
84 bool select_bpoint(BPoint *bp, bool selstatus, short flag, bool hidden)
85 {
86         if ((bp->hide == 0) || (hidden == 1)) {
87                 if (selstatus == SELECT) {
88                         bp->f1 |= flag;
89                         return true;
90                 }
91                 else {
92                         bp->f1 &= ~flag;
93                         return true;
94                 }
95         }
96
97         return false;
98 }
99
100 static bool swap_selection_beztriple(BezTriple *bezt)
101 {
102         if (bezt->f2 & SELECT)
103                 return select_beztriple(bezt, DESELECT, SELECT, VISIBLE);
104         else
105                 return select_beztriple(bezt, SELECT, SELECT, VISIBLE);
106 }
107
108 static bool swap_selection_bpoint(BPoint *bp)
109 {
110         if (bp->f1 & SELECT)
111                 return select_bpoint(bp, DESELECT, SELECT, VISIBLE);
112         else
113                 return select_bpoint(bp, SELECT, SELECT, VISIBLE);
114 }
115
116 bool ED_curve_nurb_select_check(Curve *cu, Nurb *nu)
117 {
118         if (nu->type == CU_BEZIER) {
119                 BezTriple *bezt;
120                 int i;
121
122                 for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
123                         if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
124                                 return true;
125                         }
126                 }
127         }
128         else {
129                 BPoint *bp;
130                 int i;
131
132                 for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
133                         if (bp->f1 & SELECT) {
134                                 return true;
135                         }
136                 }
137         }
138         return false;
139 }
140
141 int ED_curve_nurb_select_count(Curve *cu, Nurb *nu)
142 {
143         int sel = 0;
144
145         if (nu->type == CU_BEZIER) {
146                 BezTriple *bezt;
147                 int i;
148
149                 for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
150                         if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
151                                 return sel++;
152                         }
153                 }
154         }
155         else {
156                 BPoint *bp;
157                 int i;
158
159                 for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
160                         if (bp->f1 & SELECT) {
161                                 return sel++;
162                         }
163                 }
164         }
165
166         return sel;
167 }
168
169 void ED_curve_nurb_select_all(Nurb *nu)
170 {
171         int i;
172
173         if (nu->bezt) {
174                 BezTriple *bezt;
175                 for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
176                         if (bezt->hide == 0) {
177                                 BEZT_SEL_ALL(bezt);
178                         }
179                 }
180         }
181         else if (nu->bp) {
182                 BPoint *bp;
183                 for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
184                         if (bp->hide == 0) {
185                                 bp->f1 |= SELECT;
186                         }
187                 }
188         }
189 }
190
191 void ED_curve_select_all(EditNurb *editnurb)
192 {
193         Nurb *nu;
194         for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
195                 ED_curve_nurb_select_all(nu);
196         }
197 }
198
199 void ED_curve_nurb_deselect_all(Nurb *nu)
200 {
201         int i;
202
203         if (nu->bezt) {
204                 BezTriple *bezt;
205                 for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
206                         BEZT_DESEL_ALL(bezt);
207                 }
208         }
209         else if (nu->bp) {
210                 BPoint *bp;
211                 for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
212                         bp->f1 &= ~SELECT;
213                 }
214         }
215 }
216
217 bool ED_curve_select_check(Curve *cu, struct EditNurb *editnurb)
218 {
219         Nurb *nu;
220
221         for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
222                 if (ED_curve_nurb_select_check(cu, nu)) {
223                         return true;
224                 }
225         }
226
227         return false;
228 }
229
230 void ED_curve_deselect_all(EditNurb *editnurb)
231 {
232         Nurb *nu;
233
234         for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
235                 ED_curve_nurb_deselect_all(nu);
236         }
237 }
238
239 void ED_curve_select_swap(EditNurb *editnurb, bool hide_handles)
240 {
241         Nurb *nu;
242         BPoint *bp;
243         BezTriple *bezt;
244         int a;
245
246         for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
247                 if (nu->type == CU_BEZIER) {
248                         bezt = nu->bezt;
249                         a = nu->pntsu;
250                         while (a--) {
251                                 if (bezt->hide == 0) {
252                                         bezt->f2 ^= SELECT; /* always do the center point */
253                                         if (!hide_handles) {
254                                                 bezt->f1 ^= SELECT;
255                                                 bezt->f3 ^= SELECT;
256                                         }
257                                 }
258                                 bezt++;
259                         }
260                 }
261                 else {
262                         bp = nu->bp;
263                         a = nu->pntsu * nu->pntsv;
264                         while (a--) {
265                                 swap_selection_bpoint(bp);
266                                 bp++;
267                         }
268                 }
269         }
270 }
271
272 /**
273  * \param next: -1/1 for prev/next
274  * \param cont: when true select continuously
275  * \param selstatus: inverts behavior
276  */
277 static void select_adjacent_cp(
278         ListBase *editnurb, short next,
279         const bool cont, const bool selstatus)
280 {
281         Nurb *nu;
282         BezTriple *bezt;
283         BPoint *bp;
284         int a;
285         bool lastsel = false;
286
287         if (next == 0) return;
288
289         for (nu = editnurb->first; nu; nu = nu->next) {
290                 lastsel = false;
291                 if (nu->type == CU_BEZIER) {
292                         a = nu->pntsu;
293                         bezt = nu->bezt;
294                         if (next < 0) bezt = &nu->bezt[a - 1];
295                         while (a--) {
296                                 if (a - abs(next) < 0) break;
297                                 if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) {
298                                         bezt += next;
299                                         if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) {
300                                                 short sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
301                                                 if ((sel == 1) && (cont == 0)) lastsel = true;
302                                         }
303                                 }
304                                 else {
305                                         bezt += next;
306                                         lastsel = false;
307                                 }
308                                 /* move around in zigzag way so that we go through each */
309                                 bezt -= (next - next / abs(next));
310                         }
311                 }
312                 else {
313                         a = nu->pntsu * nu->pntsv;
314                         bp = nu->bp;
315                         if (next < 0) bp = &nu->bp[a - 1];
316                         while (a--) {
317                                 if (a - abs(next) < 0) break;
318                                 if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) {
319                                         bp += next;
320                                         if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) {
321                                                 short sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
322                                                 if ((sel == 1) && (cont == 0)) lastsel = true;
323                                         }
324                                 }
325                                 else {
326                                         bp += next;
327                                         lastsel = false;
328                                 }
329                                 /* move around in zigzag way so that we go through each */
330                                 bp -= (next - next / abs(next));
331                         }
332                 }
333         }
334 }
335
336 /**************** select start/end operators **************/
337
338 /* (de)selects first or last of visible part of each Nurb depending on selFirst
339  * selFirst: defines the end of which to select
340  * doswap: defines if selection state of each first/last control point is swapped
341  * selstatus: selection status in case doswap is false
342  */
343 static void selectend_nurb(Object *obedit, eEndPoint_Types selfirst, bool doswap, bool selstatus)
344 {
345         ListBase *editnurb = object_editcurve_get(obedit);
346         Nurb *nu;
347         BPoint *bp;
348         BezTriple *bezt;
349         Curve *cu;
350         int a;
351
352         if (obedit == NULL) return;
353
354         cu = (Curve *)obedit->data;
355         cu->actvert = CU_ACT_NONE;
356
357         for (nu = editnurb->first; nu; nu = nu->next) {
358                 if (nu->type == CU_BEZIER) {
359                         a = nu->pntsu;
360
361                         /* which point? */
362                         if (selfirst == LAST) { /* select last */
363                                 bezt = &nu->bezt[a - 1];
364                         }
365                         else { /* select first */
366                                 bezt = nu->bezt;
367                         }
368
369                         while (a--) {
370                                 bool sel;
371                                 if (doswap) sel = swap_selection_beztriple(bezt);
372                                 else sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
373
374                                 if (sel == true) break;
375                         }
376                 }
377                 else {
378                         a = nu->pntsu * nu->pntsv;
379
380                         /* which point? */
381                         if (selfirst == LAST) { /* select last */
382                                 bp = &nu->bp[a - 1];
383                         }
384                         else { /* select first */
385                                 bp = nu->bp;
386                         }
387
388                         while (a--) {
389                                 if (bp->hide == 0) {
390                                         bool sel;
391                                         if (doswap) sel = swap_selection_bpoint(bp);
392                                         else sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
393
394                                         if (sel == true) break;
395                                 }
396                         }
397                 }
398         }
399 }
400
401 static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op))
402 {
403         Object *obedit = CTX_data_edit_object(C);
404
405         selectend_nurb(obedit, FIRST, true, DESELECT);
406         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
407         BKE_curve_nurb_vert_active_validate(obedit->data);
408
409         return OPERATOR_FINISHED;
410 }
411
412 void CURVE_OT_de_select_first(wmOperatorType *ot)
413 {
414         /* identifiers */
415         ot->name = "(De)select First";
416         ot->idname = "CURVE_OT_de_select_first";
417         ot->description = "(De)select first of visible part of each NURBS";
418
419         /* api cfirstbacks */
420         ot->exec = de_select_first_exec;
421         ot->poll = ED_operator_editcurve;
422
423         /* flags */
424         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
425 }
426
427 static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op))
428 {
429         Object *obedit = CTX_data_edit_object(C);
430
431         selectend_nurb(obedit, LAST, true, DESELECT);
432         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
433         BKE_curve_nurb_vert_active_validate(obedit->data);
434
435         return OPERATOR_FINISHED;
436 }
437
438 void CURVE_OT_de_select_last(wmOperatorType *ot)
439 {
440         /* identifiers */
441         ot->name = "(De)select Last";
442         ot->idname = "CURVE_OT_de_select_last";
443         ot->description = "(De)select last of visible part of each NURBS";
444
445         /* api clastbacks */
446         ot->exec = de_select_last_exec;
447         ot->poll = ED_operator_editcurve;
448
449         /* flags */
450         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
451 }
452
453 static int de_select_all_exec(bContext *C, wmOperator *op)
454 {
455         Object *obedit = CTX_data_edit_object(C);
456         Curve *cu = obedit->data;
457         int action = RNA_enum_get(op->ptr, "action");
458
459         if (action == SEL_TOGGLE) {
460                 action = SEL_SELECT;
461                 if (ED_curve_select_check(cu, cu->editnurb)) {
462                         action = SEL_DESELECT;
463                 }
464         }
465
466         switch (action) {
467                 case SEL_SELECT:
468                         ED_curve_select_all(cu->editnurb);
469                         break;
470                 case SEL_DESELECT:
471                         ED_curve_deselect_all(cu->editnurb);
472                         break;
473                 case SEL_INVERT:
474                         ED_curve_select_swap(cu->editnurb, (cu->drawflag & CU_HIDE_HANDLES) != 0);
475                         break;
476         }
477
478         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
479         BKE_curve_nurb_vert_active_validate(cu);
480
481         return OPERATOR_FINISHED;
482 }
483
484 void CURVE_OT_select_all(wmOperatorType *ot)
485 {
486         /* identifiers */
487         ot->name = "(De)select All";
488         ot->idname = "CURVE_OT_select_all";
489         ot->description = "(De)select all control points";
490
491         /* api callbacks */
492         ot->exec = de_select_all_exec;
493         ot->poll = ED_operator_editsurfcurve;
494
495         /* flags */
496         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
497
498         /* properties */
499         WM_operator_properties_select_all(ot);
500 }
501
502
503
504 /***************** select linked operator ******************/
505
506 static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
507 {
508         Object *obedit = CTX_data_edit_object(C);
509         Curve *cu = (Curve *)obedit->data;
510         EditNurb *editnurb = cu->editnurb;
511         ListBase *nurbs = &editnurb->nurbs;
512         Nurb *nu;
513
514         for (nu = nurbs->first; nu; nu = nu->next) {
515                 if (ED_curve_nurb_select_check(cu, nu)) {
516                         ED_curve_nurb_select_all(nu);
517                 }
518         }
519
520         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
521
522         return OPERATOR_FINISHED;
523 }
524
525 static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
526 {
527         return select_linked_exec(C, op);
528 }
529
530 void CURVE_OT_select_linked(wmOperatorType *ot)
531 {
532         /* identifiers */
533         ot->name = "Select Linked All";
534         ot->idname = "CURVE_OT_select_linked";
535         ot->description = "Select all control points linked to active one";
536
537         /* api callbacks */
538         ot->exec = select_linked_exec;
539         ot->invoke = select_linked_invoke;
540         ot->poll = ED_operator_editsurfcurve;
541
542         /* flags */
543         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
544
545         /* properties */
546 }
547
548
549 /***************** select linked pick operator ******************/
550
551 static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
552 {
553         Object *obedit = CTX_data_edit_object(C);
554         ViewContext vc;
555         Nurb *nu;
556         BezTriple *bezt;
557         BPoint *bp;
558         int a;
559         const bool select = !RNA_boolean_get(op->ptr, "deselect");
560
561         view3d_operator_needs_opengl(C);
562         view3d_set_viewcontext(C, &vc);
563
564         if (!ED_curve_pick_vert(&vc, 1, event->mval, &nu, &bezt, &bp, NULL)) {
565                 return OPERATOR_CANCELLED;
566         }
567
568         if (bezt) {
569                 a = nu->pntsu;
570                 bezt = nu->bezt;
571                 while (a--) {
572                         select_beztriple(bezt, select, SELECT, VISIBLE);
573                         bezt++;
574                 }
575         }
576         else if (bp) {
577                 a = nu->pntsu * nu->pntsv;
578                 bp = nu->bp;
579                 while (a--) {
580                         select_bpoint(bp, select, SELECT, VISIBLE);
581                         bp++;
582                 }
583         }
584
585         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
586         if (!select) {
587                 BKE_curve_nurb_vert_active_validate(obedit->data);
588         }
589
590         return OPERATOR_FINISHED;
591 }
592
593 void CURVE_OT_select_linked_pick(wmOperatorType *ot)
594 {
595         /* identifiers */
596         ot->name = "Select Linked";
597         ot->idname = "CURVE_OT_select_linked_pick";
598         ot->description = "Select all control points linked to already selected ones";
599
600         /* api callbacks */
601         ot->invoke = select_linked_pick_invoke;
602         ot->poll = ED_operator_editsurfcurve_region_view3d;
603
604         /* flags */
605         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
606
607         /* properties */
608         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked control points rather than selecting them");
609 }
610
611 /***************** select row operator **********************/
612
613 static int select_row_exec(bContext *C, wmOperator *UNUSED(op))
614 {
615         Object *obedit = CTX_data_edit_object(C);
616         Curve *cu = obedit->data;
617         ListBase *editnurb = object_editcurve_get(obedit);
618         static BPoint *last = NULL;
619         static int direction = 0;
620         Nurb *nu = NULL;
621         BPoint *bp = NULL;
622         int u = 0, v = 0, a, b;
623
624         if (!BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bp))
625                 return OPERATOR_CANCELLED;
626
627         if (last == bp) {
628                 direction = 1 - direction;
629                 BKE_nurbList_flag_set(editnurb, 0);
630         }
631         last = bp;
632
633         u = cu->actvert % nu->pntsu;
634         v = cu->actvert / nu->pntsu;
635         bp = nu->bp;
636         for (a = 0; a < nu->pntsv; a++) {
637                 for (b = 0; b < nu->pntsu; b++, bp++) {
638                         if (direction) {
639                                 if (a == v) select_bpoint(bp, SELECT, SELECT, VISIBLE);
640                         }
641                         else {
642                                 if (b == u) select_bpoint(bp, SELECT, SELECT, VISIBLE);
643                         }
644                 }
645         }
646
647         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
648
649         return OPERATOR_FINISHED;
650 }
651
652 void CURVE_OT_select_row(wmOperatorType *ot)
653 {
654         /* identifiers */
655         ot->name = "Select Control Point Row";
656         ot->idname = "CURVE_OT_select_row";
657         ot->description = "Select a row of control points including active one";
658
659         /* api callbacks */
660         ot->exec = select_row_exec;
661         ot->poll = ED_operator_editsurf;
662
663         /* flags */
664         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
665 }
666
667 /***************** select next operator **********************/
668
669 static int select_next_exec(bContext *C, wmOperator *UNUSED(op))
670 {
671         Object *obedit = CTX_data_edit_object(C);
672         ListBase *editnurb = object_editcurve_get(obedit);
673
674         select_adjacent_cp(editnurb, 1, 0, SELECT);
675         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
676
677         return OPERATOR_FINISHED;
678 }
679
680 void CURVE_OT_select_next(wmOperatorType *ot)
681 {
682         /* identifiers */
683         ot->name = "Select Next";
684         ot->idname = "CURVE_OT_select_next";
685         ot->description = "Select control points following already selected ones along the curves";
686
687         /* api callbacks */
688         ot->exec = select_next_exec;
689         ot->poll = ED_operator_editcurve;
690
691         /* flags */
692         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
693 }
694
695 /***************** select previous operator **********************/
696
697 static int select_previous_exec(bContext *C, wmOperator *UNUSED(op))
698 {
699         Object *obedit = CTX_data_edit_object(C);
700         ListBase *editnurb = object_editcurve_get(obedit);
701
702         select_adjacent_cp(editnurb, -1, 0, SELECT);
703         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
704
705         return OPERATOR_FINISHED;
706 }
707
708 void CURVE_OT_select_previous(wmOperatorType *ot)
709 {
710         /* identifiers */
711         ot->name = "Select Previous";
712         ot->idname = "CURVE_OT_select_previous";
713         ot->description = "Select control points preceding already selected ones along the curves";
714
715         /* api callbacks */
716         ot->exec = select_previous_exec;
717         ot->poll = ED_operator_editcurve;
718
719         /* flags */
720         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
721 }
722
723 /***************** select more operator **********************/
724
725 static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
726 {
727         Object *obedit = CTX_data_edit_object(C);
728         ListBase *editnurb = object_editcurve_get(obedit);
729         Nurb *nu;
730         BPoint *bp, *tempbp;
731         int a;
732         short sel = 0;
733
734         /* note that NURBS surface is a special case because we mimic */
735         /* the behavior of "select more" of mesh tools.       */
736         /* The algorithm is designed to work in planar cases so it    */
737         /* may not be optimal always (example: end of NURBS sphere)   */
738         if (obedit->type == OB_SURF) {
739                 for (nu = editnurb->first; nu; nu = nu->next) {
740                         BLI_bitmap *selbpoints;
741                         a = nu->pntsu * nu->pntsv;
742                         bp = nu->bp;
743                         selbpoints = BLI_BITMAP_NEW(a, "selectlist");
744                         while (a > 0) {
745                                 if ((!BLI_BITMAP_TEST(selbpoints, a)) && (bp->hide == 0) && (bp->f1 & SELECT)) {
746                                         /* upper control point */
747                                         if (a % nu->pntsu != 0) {
748                                                 tempbp = bp - 1;
749                                                 if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
750                                         }
751
752                                         /* left control point. select only if it is not selected already */
753                                         if (a - nu->pntsu > 0) {
754                                                 sel = 0;
755                                                 tempbp = bp + nu->pntsu;
756                                                 if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
757                                                 /* make sure selected bpoint is discarded */
758                                                 if (sel == 1) BLI_BITMAP_ENABLE(selbpoints, a - nu->pntsu);
759                                         }
760
761                                         /* right control point */
762                                         if (a + nu->pntsu < nu->pntsu * nu->pntsv) {
763                                                 tempbp = bp - nu->pntsu;
764                                                 if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
765                                         }
766
767                                         /* lower control point. skip next bp in case selection was made */
768                                         if (a % nu->pntsu != 1) {
769                                                 sel = 0;
770                                                 tempbp = bp + 1;
771                                                 if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
772                                                 if (sel) {
773                                                         bp++;
774                                                         a--;
775                                                 }
776                                         }
777                                 }
778
779                                 bp++;
780                                 a--;
781                         }
782
783                         MEM_freeN(selbpoints);
784                 }
785         }
786         else {
787                 select_adjacent_cp(editnurb, 1, 0, SELECT);
788                 select_adjacent_cp(editnurb, -1, 0, SELECT);
789         }
790
791         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
792
793         return OPERATOR_FINISHED;
794 }
795
796 void CURVE_OT_select_more(wmOperatorType *ot)
797 {
798         /* identifiers */
799         ot->name = "Select More";
800         ot->idname = "CURVE_OT_select_more";
801         ot->description = "Select control points directly linked to already selected ones";
802
803         /* api callbacks */
804         ot->exec = select_more_exec;
805         ot->poll = ED_operator_editsurfcurve;
806
807         /* flags */
808         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
809 }
810
811 /******************** select less operator *****************/
812
813 /* basic method: deselect if control point doesn't have all neighbors selected */
814 static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
815 {
816         Object *obedit = CTX_data_edit_object(C);
817         ListBase *editnurb = object_editcurve_get(obedit);
818         Nurb *nu;
819         BPoint *bp;
820         BezTriple *bezt;
821         int a;
822         int sel = 0;
823         short lastsel = false;
824
825         if (obedit->type == OB_SURF) {
826                 for (nu = editnurb->first; nu; nu = nu->next) {
827                         BLI_bitmap *selbpoints;
828                         a = nu->pntsu * nu->pntsv;
829                         bp = nu->bp;
830                         selbpoints = BLI_BITMAP_NEW(a, "selectlist");
831                         while (a--) {
832                                 if ((bp->hide == 0) && (bp->f1 & SELECT)) {
833                                         sel = 0;
834
835                                         /* check if neighbors have been selected */
836                                         /* edges of surface are an exception */
837                                         if ((a + 1) % nu->pntsu == 0) {
838                                                 sel++;
839                                         }
840                                         else {
841                                                 bp--;
842                                                 if (BLI_BITMAP_TEST(selbpoints, a + 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
843                                                 bp++;
844                                         }
845
846                                         if ((a + 1) % nu->pntsu == 1) {
847                                                 sel++;
848                                         }
849                                         else {
850                                                 bp++;
851                                                 if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
852                                                 bp--;
853                                         }
854
855                                         if (a + 1 > nu->pntsu * nu->pntsv - nu->pntsu) {
856                                                 sel++;
857                                         }
858                                         else {
859                                                 bp -= nu->pntsu;
860                                                 if (BLI_BITMAP_TEST(selbpoints, a + nu->pntsu) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
861                                                 bp += nu->pntsu;
862                                         }
863
864                                         if (a < nu->pntsu) {
865                                                 sel++;
866                                         }
867                                         else {
868                                                 bp += nu->pntsu;
869                                                 if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
870                                                 bp -= nu->pntsu;
871                                         }
872
873                                         if (sel != 4) {
874                                                 select_bpoint(bp, DESELECT, SELECT, VISIBLE);
875                                                 BLI_BITMAP_ENABLE(selbpoints, a);
876                                         }
877                                 }
878                                 else {
879                                         lastsel = false;
880                                 }
881
882                                 bp++;
883                         }
884
885                         MEM_freeN(selbpoints);
886                 }
887         }
888         else {
889                 for (nu = editnurb->first; nu; nu = nu->next) {
890                         lastsel = false;
891                         /* check what type of curve/nurb it is */
892                         if (nu->type == CU_BEZIER) {
893                                 a = nu->pntsu;
894                                 bezt = nu->bezt;
895                                 while (a--) {
896                                         if ((bezt->hide == 0) && (bezt->f2 & SELECT)) {
897                                                 sel = (lastsel == 1);
898
899                                                 /* check if neighbors have been selected */
900                                                 /* first and last are exceptions */
901                                                 if (a == nu->pntsu - 1) {
902                                                         sel++;
903                                                 }
904                                                 else {
905                                                         bezt--;
906                                                         if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++;
907                                                         bezt++;
908                                                 }
909
910                                                 if (a == 0) {
911                                                         sel++;
912                                                 }
913                                                 else {
914                                                         bezt++;
915                                                         if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++;
916                                                         bezt--;
917                                                 }
918
919                                                 if (sel != 2) {
920                                                         select_beztriple(bezt, DESELECT, SELECT, VISIBLE);
921                                                         lastsel = true;
922                                                 }
923                                                 else {
924                                                         lastsel = false;
925                                                 }
926                                         }
927                                         else {
928                                                 lastsel = false;
929                                         }
930
931                                         bezt++;
932                                 }
933                         }
934                         else {
935                                 a = nu->pntsu * nu->pntsv;
936                                 bp = nu->bp;
937                                 while (a--) {
938                                         if ((lastsel == 0) && (bp->hide == 0) && (bp->f1 & SELECT)) {
939                                                 if (lastsel != 0) sel = 1;
940                                                 else sel = 0;
941
942                                                 /* first and last are exceptions */
943                                                 if (a == nu->pntsu * nu->pntsv - 1) {
944                                                         sel++;
945                                                 }
946                                                 else {
947                                                         bp--;
948                                                         if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
949                                                         bp++;
950                                                 }
951
952                                                 if (a == 0) {
953                                                         sel++;
954                                                 }
955                                                 else {
956                                                         bp++;
957                                                         if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
958                                                         bp--;
959                                                 }
960
961                                                 if (sel != 2) {
962                                                         select_bpoint(bp, DESELECT, SELECT, VISIBLE);
963                                                         lastsel = true;
964                                                 }
965                                                 else {
966                                                         lastsel = false;
967                                                 }
968                                         }
969                                         else {
970                                                 lastsel = false;
971                                         }
972
973                                         bp++;
974                                 }
975                         }
976                 }
977         }
978
979         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
980         BKE_curve_nurb_vert_active_validate(obedit->data);
981
982         return OPERATOR_FINISHED;
983 }
984
985 void CURVE_OT_select_less(wmOperatorType *ot)
986 {
987         /* identifiers */
988         ot->name = "Select Less";
989         ot->idname = "CURVE_OT_select_less";
990         ot->description = "Reduce current selection by deselecting boundary elements";
991
992         /* api callbacks */
993         ot->exec = select_less_exec;
994         ot->poll = ED_operator_editsurfcurve;
995
996         /* flags */
997         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
998 }
999
1000 /********************** select random *********************/
1001
1002 static void curve_select_random(ListBase *editnurb, float randfac, bool select)
1003 {
1004         Nurb *nu;
1005         BezTriple *bezt;
1006         BPoint *bp;
1007         int a;
1008
1009         for (nu = editnurb->first; nu; nu = nu->next) {
1010                 if (nu->type == CU_BEZIER) {
1011                         bezt = nu->bezt;
1012                         a = nu->pntsu;
1013                         while (a--) {
1014                                 if (!bezt->hide) {
1015                                         if (BLI_frand() < randfac) {
1016                                                 select_beztriple(bezt, select, SELECT, VISIBLE);
1017                                         }
1018                                 }
1019                                 bezt++;
1020                         }
1021                 }
1022                 else {
1023                         bp = nu->bp;
1024                         a = nu->pntsu * nu->pntsv;
1025
1026                         while (a--) {
1027                                 if (!bp->hide) {
1028                                         if (BLI_frand() < randfac) {
1029                                                 select_bpoint(bp, select, SELECT, VISIBLE);
1030                                         }
1031                                 }
1032                                 bp++;
1033                         }
1034                 }
1035         }
1036 }
1037
1038 static int curve_select_random_exec(bContext *C, wmOperator *op)
1039 {
1040         Object *obedit = CTX_data_edit_object(C);
1041         ListBase *editnurb = object_editcurve_get(obedit);
1042         const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
1043         const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
1044
1045         curve_select_random(editnurb, randfac, select);
1046         BKE_curve_nurb_vert_active_validate(obedit->data);
1047
1048         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1049
1050         return OPERATOR_FINISHED;
1051 }
1052
1053 void CURVE_OT_select_random(wmOperatorType *ot)
1054 {
1055         /* identifiers */
1056         ot->name = "Select Random";
1057         ot->idname = "CURVE_OT_select_random";
1058         ot->description = "Randomly select some control points";
1059
1060         /* api callbacks */
1061         ot->exec = curve_select_random_exec;
1062         ot->poll = ED_operator_editsurfcurve;
1063
1064         /* flags */
1065         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1066
1067         /* properties */
1068         RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
1069                                  "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f);
1070         WM_operator_properties_select_action_simple(ot, SEL_SELECT);
1071 }
1072
1073 /********************* every nth number of point *******************/
1074
1075 static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth, int skip, int offset)
1076 {
1077         int a, start;
1078
1079         start = bezt - nu->bezt;
1080         a = nu->pntsu;
1081         bezt = &nu->bezt[a - 1];
1082
1083         while (a--) {
1084                 const int depth = abs(start - a);
1085                 if ((offset + depth) % (skip + nth) >= skip) {
1086                         select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
1087                 }
1088
1089                 bezt--;
1090         }
1091 }
1092
1093 static void select_nth_bp(Nurb *nu, BPoint *bp, int nth, int skip, int offset)
1094 {
1095         int a, startrow, startpnt;
1096         int row, pnt;
1097
1098         startrow = (bp - nu->bp) / nu->pntsu;
1099         startpnt = (bp - nu->bp) % nu->pntsu;
1100
1101         a = nu->pntsu * nu->pntsv;
1102         bp = &nu->bp[a - 1];
1103         row = nu->pntsv - 1;
1104         pnt = nu->pntsu - 1;
1105
1106         while (a--) {
1107                 const int depth = abs(pnt - startpnt) + abs(row - startrow);
1108                 if ((offset + depth) % (skip + nth) >= skip) {
1109                         select_bpoint(bp, DESELECT, SELECT, HIDDEN);
1110                 }
1111
1112                 pnt--;
1113                 if (pnt < 0) {
1114                         pnt = nu->pntsu - 1;
1115                         row--;
1116                 }
1117
1118                 bp--;
1119         }
1120 }
1121
1122 bool ED_curve_select_nth(Curve *cu, int nth, int skip, int offset)
1123 {
1124         Nurb *nu = NULL;
1125         void *vert = NULL;
1126
1127         if (!BKE_curve_nurb_vert_active_get(cu, &nu, &vert))
1128                 return false;
1129
1130         if (nu->bezt) {
1131                 select_nth_bezt(nu, vert, nth, skip, offset);
1132         }
1133         else {
1134                 select_nth_bp(nu, vert, nth, skip, offset);
1135         }
1136
1137         return true;
1138 }
1139
1140 static int select_nth_exec(bContext *C, wmOperator *op)
1141 {
1142         Object *obedit = CTX_data_edit_object(C);
1143         const int nth = RNA_int_get(op->ptr, "nth") - 1;
1144         const int skip = RNA_int_get(op->ptr, "skip");
1145         int offset = RNA_int_get(op->ptr, "offset");
1146
1147         /* so input of offset zero ends up being (nth - 1) */
1148         offset = mod_i(offset, nth + skip);
1149
1150         if (!ED_curve_select_nth(obedit->data, nth, skip, offset)) {
1151                 if (obedit->type == OB_SURF) {
1152                         BKE_report(op->reports, RPT_ERROR, "Surface has not got active point");
1153                 }
1154                 else {
1155                         BKE_report(op->reports, RPT_ERROR, "Curve has not got active point");
1156                 }
1157
1158                 return OPERATOR_CANCELLED;
1159         }
1160
1161         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1162
1163         return OPERATOR_FINISHED;
1164 }
1165
1166 void CURVE_OT_select_nth(wmOperatorType *ot)
1167 {
1168         /* identifiers */
1169         ot->name = "Checker Deselect";
1170         ot->description = "Deselect every other vertex";
1171         ot->idname = "CURVE_OT_select_nth";
1172
1173         /* api callbacks */
1174         ot->exec = select_nth_exec;
1175         ot->poll = ED_operator_editsurfcurve;
1176
1177         /* flags */
1178         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1179
1180         RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
1181         RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100);
1182         RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100);
1183 }
1184
1185
1186 /* -------------------------------------------------------------------- */
1187 /* Select Similar */
1188
1189 /** \name Select Similar
1190  * \{ */
1191
1192 enum {
1193         SIM_CMP_EQ = 0,
1194         SIM_CMP_GT,
1195         SIM_CMP_LT,
1196 };
1197
1198 static EnumPropertyItem curve_prop_similar_compare_types[] = {
1199         {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
1200         {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
1201         {SIM_CMP_LT, "LESS", 0, "Less", ""},
1202
1203         {0, NULL, 0, NULL, NULL}
1204 };
1205
1206 enum {
1207         SIMCURHAND_TYPE = 0,
1208         SIMCURHAND_RADIUS,
1209         SIMCURHAND_WEIGHT,
1210         SIMCURHAND_DIRECTION,
1211 };
1212
1213 static EnumPropertyItem curve_prop_similar_types[] = {
1214         {SIMCURHAND_TYPE, "TYPE", 0, "Type", ""},
1215         {SIMCURHAND_RADIUS, "RADIUS", 0, "Radius", ""},
1216         {SIMCURHAND_WEIGHT, "WEIGHT", 0, "Weight", ""},
1217         {SIMCURHAND_DIRECTION, "DIRECTION", 0, "Direction", ""},
1218         {0, NULL, 0, NULL, NULL}
1219 };
1220
1221 static int curve_select_similar_cmp_fl(const float delta, const float thresh, const int compare)
1222 {
1223         switch (compare) {
1224                 case SIM_CMP_EQ:
1225                         return (fabsf(delta) <= thresh);
1226                 case SIM_CMP_GT:
1227                         return ((delta + thresh) >= 0.0f);
1228                 case SIM_CMP_LT:
1229                         return ((delta - thresh) <= 0.0f);
1230                 default:
1231                         BLI_assert(0);
1232                         return 0;
1233         }
1234 }
1235
1236
1237 static void curve_select_similar_direction__bezt(Nurb *nu, const float dir_ref[3], float angle_cos)
1238 {
1239         BezTriple *bezt;
1240         int i;
1241
1242         for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
1243                 if (!bezt->hide) {
1244                         float dir[3];
1245                         BKE_nurb_bezt_calc_normal(nu, bezt, dir);
1246                         if (fabsf(dot_v3v3(dir_ref, dir)) >= angle_cos) {
1247                                 select_beztriple(bezt, SELECT, SELECT, VISIBLE);
1248                         }
1249                 }
1250         }
1251 }
1252
1253 static void curve_select_similar_direction__bp(Nurb *nu, const float dir_ref[3], float angle_cos)
1254 {
1255         BPoint *bp;
1256         int i;
1257
1258         for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
1259                 if (!bp->hide) {
1260                         float dir[3];
1261                         BKE_nurb_bpoint_calc_normal(nu, bp, dir);
1262                         if (fabsf(dot_v3v3(dir_ref, dir)) >= angle_cos) {
1263                                 select_bpoint(bp, SELECT, SELECT, VISIBLE);
1264                         }
1265                 }
1266         }
1267 }
1268
1269 static bool curve_select_similar_direction(ListBase *editnurb, Curve *cu, float thresh)
1270 {
1271         Nurb *nu, *act_nu;
1272         void *act_vert;
1273         float dir[3];
1274         float angle_cos;
1275
1276         if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert)) {
1277                 return false;
1278         }
1279
1280         if (act_nu->type == CU_BEZIER) {
1281                 BKE_nurb_bezt_calc_normal(act_nu, act_vert, dir);
1282         }
1283         else {
1284                 BKE_nurb_bpoint_calc_normal(act_nu, act_vert, dir);
1285         }
1286
1287         /* map 0-1 to radians, 'cos' for comparison */
1288         angle_cos = cosf(thresh * M_PI_2);
1289
1290         for (nu = editnurb->first; nu; nu = nu->next) {
1291                 if (nu->type == CU_BEZIER) {
1292                         curve_select_similar_direction__bezt(nu, dir, angle_cos);
1293                 }
1294                 else {
1295                         curve_select_similar_direction__bp(nu, dir, angle_cos);
1296                 }
1297         }
1298
1299         return true;
1300 }
1301
1302 static void curve_select_similar_radius__bezt(Nurb *nu, float radius_ref, int compare, float thresh)
1303 {
1304         BezTriple *bezt;
1305         int i;
1306
1307         for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
1308                 if (!bezt->hide) {
1309                         if (curve_select_similar_cmp_fl(bezt->radius - radius_ref, thresh, compare)) {
1310                                 select_beztriple(bezt, SELECT, SELECT, VISIBLE);
1311                         }
1312                 }
1313         }
1314 }
1315
1316 static void curve_select_similar_radius__bp(Nurb *nu, float radius_ref, int compare, float thresh)
1317 {
1318         BPoint *bp;
1319         int i;
1320
1321         for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
1322                 if (!bp->hide) {
1323                         if (curve_select_similar_cmp_fl(bp->radius - radius_ref, thresh, compare)) {
1324                                 select_bpoint(bp, SELECT, SELECT, VISIBLE);
1325                         }
1326                 }
1327         }
1328 }
1329
1330 static bool curve_select_similar_radius(ListBase *editnurb, Curve *cu, float compare, float thresh)
1331 {
1332         Nurb *nu, *act_nu;
1333         void *act_vert;
1334         float radius_ref;
1335
1336         if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert)) {
1337                 return false;
1338         }
1339
1340         if (act_nu->type == CU_BEZIER) {
1341                 radius_ref = ((BezTriple *)act_vert)->radius;
1342         }
1343         else {
1344                 radius_ref = ((BPoint *)act_vert)->radius;
1345         }
1346
1347         /* make relative */
1348         thresh *= radius_ref;
1349
1350         for (nu = editnurb->first; nu; nu = nu->next) {
1351                 if (nu->type == CU_BEZIER) {
1352                         curve_select_similar_radius__bezt(nu, radius_ref, compare, thresh);
1353                 }
1354                 else {
1355                         curve_select_similar_radius__bp(nu, radius_ref, compare, thresh);
1356                 }
1357         }
1358
1359         return true;
1360 }
1361
1362 static void curve_select_similar_weight__bezt(Nurb *nu, float weight_ref, int compare, float thresh)
1363 {
1364         BezTriple *bezt;
1365         int i;
1366
1367         for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
1368                 if (!bezt->hide) {
1369                         if (curve_select_similar_cmp_fl(bezt->weight - weight_ref, thresh, compare)) {
1370                                 select_beztriple(bezt, SELECT, SELECT, VISIBLE);
1371                         }
1372                 }
1373         }
1374 }
1375
1376 static void curve_select_similar_weight__bp(Nurb *nu, float weight_ref, int compare, float thresh)
1377 {
1378         BPoint *bp;
1379         int i;
1380
1381         for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
1382                 if (!bp->hide) {
1383                         if (curve_select_similar_cmp_fl(bp->weight - weight_ref, thresh, compare)) {
1384                                 select_bpoint(bp, SELECT, SELECT, VISIBLE);
1385                         }
1386                 }
1387         }
1388 }
1389
1390 static bool curve_select_similar_weight(ListBase *editnurb, Curve *cu, float compare, float thresh)
1391 {
1392         Nurb *nu, *act_nu;
1393         void *act_vert;
1394         float weight_ref;
1395
1396         if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert))
1397                 return false;
1398
1399         if (act_nu->type == CU_BEZIER) {
1400                 weight_ref = ((BezTriple *)act_vert)->weight;
1401         }
1402         else {
1403                 weight_ref = ((BPoint *)act_vert)->weight;
1404         }
1405
1406         for (nu = editnurb->first; nu; nu = nu->next) {
1407                 if (nu->type == CU_BEZIER) {
1408                         curve_select_similar_weight__bezt(nu, weight_ref, compare, thresh);
1409                 }
1410                 else {
1411                         curve_select_similar_weight__bp(nu, weight_ref, compare, thresh);
1412                 }
1413         }
1414
1415         return true;
1416 }
1417
1418 static bool curve_select_similar_type(ListBase *editnurb, Curve *cu)
1419 {
1420         Nurb *nu, *act_nu;
1421         int type_ref;
1422
1423         /* Get active nurb type */
1424         act_nu = BKE_curve_nurb_active_get(cu);
1425
1426         if (!act_nu)
1427                 return false;
1428
1429         /* Get the active nurb type */
1430         type_ref = act_nu->type;
1431
1432         for (nu = editnurb->first; nu; nu = nu->next) {
1433                 if (nu->type == type_ref) {
1434                         ED_curve_nurb_select_all(nu);
1435                 }
1436         }
1437
1438         return true;
1439 }
1440
1441 static int curve_select_similar_exec(bContext *C, wmOperator *op)
1442 {
1443         Object *obedit = CTX_data_edit_object(C);
1444         Curve *cu = obedit->data;
1445         ListBase *editnurb = object_editcurve_get(obedit);
1446         bool changed = false;
1447
1448         /* Get props */
1449         const int type = RNA_enum_get(op->ptr, "type");
1450         const float thresh = RNA_float_get(op->ptr, "threshold");
1451         const int compare = RNA_enum_get(op->ptr, "compare");
1452
1453         switch (type) {
1454                 case SIMCURHAND_TYPE:
1455                         changed = curve_select_similar_type(editnurb, cu);
1456                         break;
1457                 case SIMCURHAND_RADIUS:
1458                         changed = curve_select_similar_radius(editnurb, cu, compare, thresh);
1459                         break;
1460                 case SIMCURHAND_WEIGHT:
1461                         changed = curve_select_similar_weight(editnurb, cu, compare, thresh);
1462                         break;
1463                 case SIMCURHAND_DIRECTION:
1464                         changed = curve_select_similar_direction(editnurb, cu, thresh);
1465                         break;
1466         }
1467
1468         if (changed) {
1469                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1470                 return OPERATOR_FINISHED;
1471         }
1472         else {
1473                 return OPERATOR_CANCELLED;
1474         }
1475 }
1476
1477 void CURVE_OT_select_similar(wmOperatorType *ot)
1478 {
1479         /* identifiers */
1480         ot->name = "Select Similar";
1481         ot->idname = "CURVE_OT_select_similar";
1482         ot->description = "Select similar curve points by property type";
1483
1484         /* api callbacks */
1485         ot->invoke = WM_menu_invoke;
1486         ot->exec = curve_select_similar_exec;
1487         ot->poll = ED_operator_editsurfcurve;
1488
1489         /* flags */
1490         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1491
1492         /* properties */
1493         ot->prop = RNA_def_enum(ot->srna, "type", curve_prop_similar_types, SIMCURHAND_WEIGHT, "Type", "");
1494         RNA_def_enum(ot->srna, "compare", curve_prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
1495         RNA_def_float(ot->srna, "threshold", 0.1, 0.0, FLT_MAX, "Threshold", "", 0.0, 100.0);
1496 }
1497
1498 /** \} */