code cleanup: rename BKE_tessmesh -> BKE_editmesh, rename EditDerivedBMesh.tc ->...
[blender-staging.git] / source / blender / python / bmesh / bmesh_py_types_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) 2012 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Campbell Barton
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/python/bmesh/bmesh_py_types_select.c
27  *  \ingroup pybmesh
28  *
29  * This file defines the types for 'BMesh.select_history'
30  * sequence and iterator.
31  *
32  * select_history is very loosely based on pythons set() type,
33  * since items can only exist once. however they do have an order.
34  */
35
36 #include <Python.h>
37
38 #include "BLI_utildefines.h"
39 #include "BLI_listbase.h"
40
41 #include "bmesh.h"
42
43 #include "bmesh_py_types.h"
44 #include "bmesh_py_types_select.h"
45
46 #include "BKE_editmesh.h"
47
48 #include "DNA_mesh_types.h"
49
50 #include "../generic/py_capi_utils.h"
51
52 #include "bmesh_py_api.h" /* own include */
53
54 PyDoc_STRVAR(bpy_bmeditselseq_active_doc,
55 "The last selected element or None (read-only).\n\n:type: :class:`BMVert`, :class:`BMEdge` or :class:`BMFace`"
56 );
57 static PyObject *bpy_bmeditselseq_active_get(BPy_BMEditSelSeq *self, void *UNUSED(closure))
58 {
59         BMEditSelection *ese;
60         BPY_BM_CHECK_OBJ(self);
61
62         if ((ese = self->bm->selected.last)) {
63                 return BPy_BMElem_CreatePyObject(self->bm, &ese->ele->head);
64         }
65         else {
66                 Py_RETURN_NONE;
67         }
68 }
69
70 static PyGetSetDef bpy_bmeditselseq_getseters[] = {
71         {(char *)"active", (getter)bpy_bmeditselseq_active_get, (setter)NULL, (char *)bpy_bmeditselseq_active_doc, NULL},
72         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
73 };
74
75 PyDoc_STRVAR(bpy_bmeditselseq_validate_doc,
76 ".. method:: validate()\n"
77 "\n"
78 "   Ensures all elements in the selection history are selected.\n"
79 );
80 static PyObject *bpy_bmeditselseq_validate(BPy_BMEditSelSeq *self)
81 {
82         BPY_BM_CHECK_OBJ(self);
83         BM_select_history_validate(self->bm);
84         Py_RETURN_NONE;
85 }
86
87 PyDoc_STRVAR(bpy_bmeditselseq_clear_doc,
88 ".. method:: clear()\n"
89 "\n"
90 "   Empties the selection history.\n"
91 );
92 static PyObject *bpy_bmeditselseq_clear(BPy_BMEditSelSeq *self)
93 {
94         BPY_BM_CHECK_OBJ(self);
95         BM_select_history_clear(self->bm);
96         Py_RETURN_NONE;
97 }
98
99 PyDoc_STRVAR(bpy_bmeditselseq_add_doc,
100 ".. method:: add(element)\n"
101 "\n"
102 "   Add an element to the selection history (no action taken if its already added).\n"
103 );
104 static PyObject *bpy_bmeditselseq_add(BPy_BMEditSelSeq *self, BPy_BMElem *value)
105 {
106         BPY_BM_CHECK_OBJ(self);
107
108         if ((BPy_BMVert_Check(value) ||
109              BPy_BMEdge_Check(value) ||
110              BPy_BMFace_Check(value)) == false)
111         {
112                 PyErr_Format(PyExc_TypeError,
113                              "Expected a BMVert/BMedge/BMFace not a %.200s", Py_TYPE(value)->tp_name);
114                 return NULL;
115         }
116
117         BPY_BM_CHECK_SOURCE_OBJ(value, self->bm, "select_history.add()");
118
119         BM_select_history_store(self->bm, value->ele);
120
121         Py_RETURN_NONE;
122 }
123
124 PyDoc_STRVAR(bpy_bmeditselseq_remove_doc,
125 ".. method:: remove(element)\n"
126 "\n"
127 "   Remove an element from the selection history.\n"
128 );
129 static PyObject *bpy_bmeditselseq_remove(BPy_BMEditSelSeq *self, BPy_BMElem *value)
130 {
131         BPY_BM_CHECK_OBJ(self);
132
133         if ((BPy_BMVert_Check(value) ||
134              BPy_BMEdge_Check(value) ||
135              BPy_BMFace_Check(value)) == false)
136         {
137                 PyErr_Format(PyExc_TypeError,
138                              "Expected a BMVert/BMedge/BMFace not a %.200s", Py_TYPE(value)->tp_name);
139                 return NULL;
140         }
141
142         BPY_BM_CHECK_SOURCE_OBJ(value, self->bm, "select_history.remove()");
143
144         if (BM_select_history_remove(self->bm, value->ele) == false) {
145                 PyErr_SetString(PyExc_ValueError,
146                                 "Element not found in selection history");
147                 return NULL;
148         }
149
150         Py_RETURN_NONE;
151 }
152
153 static struct PyMethodDef bpy_bmeditselseq_methods[] = {
154         {"validate", (PyCFunction)bpy_bmeditselseq_validate, METH_NOARGS, bpy_bmeditselseq_validate_doc},
155         {"clear",    (PyCFunction)bpy_bmeditselseq_clear,    METH_NOARGS, bpy_bmeditselseq_clear_doc},
156
157         {"add",      (PyCFunction)bpy_bmeditselseq_add,      METH_O,      bpy_bmeditselseq_add_doc},
158         {"remove",   (PyCFunction)bpy_bmeditselseq_remove,   METH_O,      bpy_bmeditselseq_remove_doc},
159         {NULL, NULL, 0, NULL}
160 };
161
162
163 /* Sequences
164  * ========= */
165
166 static Py_ssize_t bpy_bmeditselseq_length(BPy_BMEditSelSeq *self)
167 {
168         BPY_BM_CHECK_INT(self);
169
170         return BLI_countlist(&self->bm->selected);
171 }
172
173 static PyObject *bpy_bmeditselseq_subscript_int(BPy_BMEditSelSeq *self, int keynum)
174 {
175         BMEditSelection *ese;
176
177         BPY_BM_CHECK_OBJ(self);
178
179         if (keynum < 0) {
180                 ese = BLI_rfindlink(&self->bm->selected, -1 - keynum);
181         }
182         else {
183                 ese = BLI_findlink(&self->bm->selected, keynum);
184         }
185
186         if (ese) {
187                 return BPy_BMElem_CreatePyObject(self->bm, &ese->ele->head);
188         }
189         else {
190                 PyErr_Format(PyExc_IndexError,
191                              "BMElemSeq[index]: index %d out of range", keynum);
192                 return NULL;
193         }
194 }
195
196 static PyObject *bpy_bmeditselseq_subscript_slice(BPy_BMEditSelSeq *self, Py_ssize_t start, Py_ssize_t stop)
197 {
198         int count = 0;
199         bool ok;
200
201         PyObject *list;
202         PyObject *item;
203         BMEditSelection *ese;
204
205         BPY_BM_CHECK_OBJ(self);
206
207         list = PyList_New(0);
208
209         ese = self->bm->selected.first;
210
211         ok = (ese != NULL);
212
213         if (UNLIKELY(ok == false)) {
214                 return list;
215         }
216
217         /* first loop up-until the start */
218         for (ok = true; ok; ok = ((ese = ese->next) != NULL)) {
219                 if (count == start) {
220                         break;
221                 }
222                 count++;
223         }
224
225         /* add items until stop */
226         while ((ese = ese->next)) {
227                 item = BPy_BMElem_CreatePyObject(self->bm, &ese->ele->head);
228                 PyList_Append(list, item);
229                 Py_DECREF(item);
230
231                 count++;
232                 if (count == stop) {
233                         break;
234                 }
235         }
236
237         return list;
238 }
239
240 static PyObject *bpy_bmeditselseq_subscript(BPy_BMEditSelSeq *self, PyObject *key)
241 {
242         /* don't need error check here */
243         if (PyIndex_Check(key)) {
244                 Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
245                 if (i == -1 && PyErr_Occurred())
246                         return NULL;
247                 return bpy_bmeditselseq_subscript_int(self, i);
248         }
249         else if (PySlice_Check(key)) {
250                 PySliceObject *key_slice = (PySliceObject *)key;
251                 Py_ssize_t step = 1;
252
253                 if (key_slice->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
254                         return NULL;
255                 }
256                 else if (step != 1) {
257                         PyErr_SetString(PyExc_TypeError,
258                                         "BMElemSeq[slice]: slice steps not supported");
259                         return NULL;
260                 }
261                 else if (key_slice->start == Py_None && key_slice->stop == Py_None) {
262                         return bpy_bmeditselseq_subscript_slice(self, 0, PY_SSIZE_T_MAX);
263                 }
264                 else {
265                         Py_ssize_t start = 0, stop = PY_SSIZE_T_MAX;
266
267                         /* avoid PySlice_GetIndicesEx because it needs to know the length ahead of time. */
268                         if (key_slice->start != Py_None && !_PyEval_SliceIndex(key_slice->start, &start)) return NULL;
269                         if (key_slice->stop != Py_None && !_PyEval_SliceIndex(key_slice->stop, &stop))    return NULL;
270
271                         if (start < 0 || stop < 0) {
272                                 /* only get the length for negative values */
273                                 Py_ssize_t len = bpy_bmeditselseq_length(self);
274                                 if (start < 0) start += len;
275                                 if (stop  < 0) stop  += len;
276                         }
277
278                         if (stop - start <= 0) {
279                                 return PyList_New(0);
280                         }
281                         else {
282                                 return bpy_bmeditselseq_subscript_slice(self, start, stop);
283                         }
284                 }
285         }
286         else {
287                 PyErr_SetString(PyExc_AttributeError,
288                                 "BMElemSeq[key]: invalid key, key must be an int");
289                 return NULL;
290         }
291 }
292
293 static int bpy_bmeditselseq_contains(BPy_BMEditSelSeq *self, PyObject *value)
294 {
295         BPy_BMElem *value_bm_ele;
296
297         BPY_BM_CHECK_INT(self);
298
299         value_bm_ele = (BPy_BMElem *)value;
300         if (value_bm_ele->bm == self->bm) {
301                 return BM_select_history_check(self->bm, value_bm_ele->ele);
302         }
303
304         return 0;
305 }
306
307 static PySequenceMethods bpy_bmeditselseq_as_sequence = {
308         (lenfunc)bpy_bmeditselseq_length,            /* sq_length */
309         NULL,                                        /* sq_concat */
310         NULL,                                        /* sq_repeat */
311         (ssizeargfunc)bpy_bmeditselseq_subscript_int,/* sq_item */ /* Only set this so PySequence_Check() returns True */
312         NULL,                                        /* sq_slice */
313         (ssizeobjargproc)NULL,                       /* sq_ass_item */
314         NULL,                                        /* *was* sq_ass_slice */
315         (objobjproc)bpy_bmeditselseq_contains,       /* sq_contains */
316         (binaryfunc) NULL,                           /* sq_inplace_concat */
317         (ssizeargfunc) NULL,                         /* sq_inplace_repeat */
318 };
319
320 static PyMappingMethods bpy_bmeditselseq_as_mapping = {
321         (lenfunc)bpy_bmeditselseq_length,            /* mp_length */
322         (binaryfunc)bpy_bmeditselseq_subscript,      /* mp_subscript */
323         (objobjargproc)NULL,                         /* mp_ass_subscript */
324 };
325
326
327 /* Iterator
328  * -------- */
329
330 static PyObject *bpy_bmeditselseq_iter(BPy_BMEditSelSeq *self)
331 {
332         BPy_BMEditSelIter *py_iter;
333
334         BPY_BM_CHECK_OBJ(self);
335         py_iter = (BPy_BMEditSelIter *)BPy_BMEditSelIter_CreatePyObject(self->bm);
336         py_iter->ese = self->bm->selected.first;
337         return (PyObject *)py_iter;
338 }
339
340 static PyObject *bpy_bmeditseliter_next(BPy_BMEditSelIter *self)
341 {
342         BMEditSelection *ese = self->ese;
343         if (ese == NULL) {
344                 PyErr_SetString(PyExc_StopIteration,
345                                 "bpy_bmiter_next stop");
346                 return NULL;
347         }
348         else {
349                 self->ese = ese->next;
350                 return (PyObject *)BPy_BMElem_CreatePyObject(self->bm, &ese->ele->head);
351         }
352 }
353
354 PyTypeObject BPy_BMEditSelSeq_Type  = {{{0}}};
355 PyTypeObject BPy_BMEditSelIter_Type = {{{0}}};
356
357
358 PyObject *BPy_BMEditSel_CreatePyObject(BMesh *bm)
359 {
360         BPy_BMEditSelSeq *self = PyObject_New(BPy_BMEditSelSeq, &BPy_BMEditSelSeq_Type);
361         self->bm = bm;
362         /* caller must initialize 'iter' member */
363         return (PyObject *)self;
364 }
365
366 PyObject *BPy_BMEditSelIter_CreatePyObject(BMesh *bm)
367 {
368         BPy_BMEditSelIter *self = PyObject_New(BPy_BMEditSelIter, &BPy_BMEditSelIter_Type);
369         self->bm = bm;
370         /* caller must initialize 'iter' member */
371         return (PyObject *)self;
372 }
373
374 void BPy_BM_init_types_select(void)
375 {
376         BPy_BMEditSelSeq_Type.tp_basicsize     = sizeof(BPy_BMEditSelSeq);
377         BPy_BMEditSelIter_Type.tp_basicsize    = sizeof(BPy_BMEditSelIter);
378
379         BPy_BMEditSelSeq_Type.tp_name  = "BMEditSelSeq";
380         BPy_BMEditSelIter_Type.tp_name = "BMEditSelIter";
381
382         BPy_BMEditSelSeq_Type.tp_doc   = NULL; /* todo */
383         BPy_BMEditSelIter_Type.tp_doc  = NULL;
384
385         BPy_BMEditSelSeq_Type.tp_repr  = (reprfunc)NULL;
386         BPy_BMEditSelIter_Type.tp_repr = (reprfunc)NULL;
387
388         BPy_BMEditSelSeq_Type.tp_getset     = bpy_bmeditselseq_getseters;
389         BPy_BMEditSelIter_Type.tp_getset = NULL;
390
391         BPy_BMEditSelSeq_Type.tp_methods     = bpy_bmeditselseq_methods;
392         BPy_BMEditSelIter_Type.tp_methods = NULL;
393
394         BPy_BMEditSelSeq_Type.tp_as_sequence = &bpy_bmeditselseq_as_sequence;
395
396         BPy_BMEditSelSeq_Type.tp_as_mapping = &bpy_bmeditselseq_as_mapping;
397
398         BPy_BMEditSelSeq_Type.tp_iter = (getiterfunc)bpy_bmeditselseq_iter;
399
400         /* only 1 iteratir so far */
401         BPy_BMEditSelIter_Type.tp_iternext = (iternextfunc)bpy_bmeditseliter_next;
402
403         BPy_BMEditSelSeq_Type.tp_dealloc     = NULL; //(destructor)bpy_bmeditselseq_dealloc;
404         BPy_BMEditSelIter_Type.tp_dealloc = NULL; //(destructor)bpy_bmvert_dealloc;
405
406         BPy_BMEditSelSeq_Type.tp_flags     = Py_TPFLAGS_DEFAULT;
407         BPy_BMEditSelIter_Type.tp_flags    = Py_TPFLAGS_DEFAULT;
408
409         PyType_Ready(&BPy_BMEditSelSeq_Type);
410         PyType_Ready(&BPy_BMEditSelIter_Type);
411 }
412
413
414 /* utility function */
415
416 /**
417  * \note doesn't actually check selection.
418  */
419 int BPy_BMEditSel_Assign(BPy_BMesh *self, PyObject *value)
420 {
421         BMesh *bm;
422         Py_ssize_t value_len;
423         Py_ssize_t i;
424         BMElem **value_array = NULL;
425
426         BPY_BM_CHECK_INT(self);
427
428         bm = self->bm;
429
430         value_array = BPy_BMElem_PySeq_As_Array(&bm, value, 0, PY_SSIZE_T_MAX,
431                                                 &value_len, BM_VERT | BM_EDGE | BM_FACE,
432                                                 true, true, "BMesh.select_history = value");
433
434         if (value_array == NULL) {
435                 return -1;
436         }
437
438         BM_select_history_clear(bm);
439
440         for (i = 0; i < value_len; i++) {
441                 BM_select_history_store_notest(bm, value_array[i]);
442         }
443
444         PyMem_FREE(value_array);
445         return 0;
446 }