diff options
author | Campbell Barton <ideasman42@gmail.com> | 2012-02-29 18:05:03 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2012-02-29 18:05:03 +0400 |
commit | 17ee9f77c527db544f041e886ef65e569e63d5f5 (patch) | |
tree | c1285b8f4f9cf7592e01dabffc44cb1bb33e63b3 /source | |
parent | a3a6f304038932f13225c1346742c63e15afba7d (diff) |
bmesh py api - initial support for selection history.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/python/bmesh/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/python/bmesh/bmesh_py_api.c | 3 | ||||
-rw-r--r-- | source/blender/python/bmesh/bmesh_py_select.c | 312 | ||||
-rw-r--r-- | source/blender/python/bmesh/bmesh_py_select.h | 55 | ||||
-rw-r--r-- | source/blender/python/bmesh/bmesh_py_types.c | 23 |
5 files changed, 394 insertions, 1 deletions
diff --git a/source/blender/python/bmesh/CMakeLists.txt b/source/blender/python/bmesh/CMakeLists.txt index 2823254c5c2..2b5a58171b6 100644 --- a/source/blender/python/bmesh/CMakeLists.txt +++ b/source/blender/python/bmesh/CMakeLists.txt @@ -33,10 +33,12 @@ set(INC_SYS set(SRC bmesh_py_api.c + bmesh_py_select.c bmesh_py_types.c bmesh_py_utils.c bmesh_py_api.h + bmesh_py_select.h bmesh_py_types.h bmesh_py_utils.h ) diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c index 96604e7337d..b6064c452fe 100644 --- a/source/blender/python/bmesh/bmesh_py_api.c +++ b/source/blender/python/bmesh/bmesh_py_api.c @@ -35,6 +35,7 @@ #include "bmesh_py_types.h" #include "bmesh_py_utils.h" +#include "bmesh_py_select.h" #include "BLI_utildefines.h" @@ -96,6 +97,8 @@ PyObject *BPyInit_bmesh(void) PyObject *sys_modules = PySys_GetObject("modules"); /* not pretty */ BPy_BM_init_types(); + BPy_BM_init_select_types(); + mod = PyModule_Create(&BPy_BM_module_def); diff --git a/source/blender/python/bmesh/bmesh_py_select.c b/source/blender/python/bmesh/bmesh_py_select.c new file mode 100644 index 00000000000..5630b4ac712 --- /dev/null +++ b/source/blender/python/bmesh/bmesh_py_select.c @@ -0,0 +1,312 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/bmesh/bmesh_py_api.c + * \ingroup pybmesh + * + * This file defines the 'bmesh' module. + */ + +#include <Python.h> + +#include "bmesh.h" + +#include "bmesh_py_types.h" +#include "bmesh_py_select.h" + +#include "BLI_utildefines.h" +#include "BLI_listbase.h" + +#include "BKE_tessmesh.h" + +#include "DNA_mesh_types.h" + +#include "../generic/py_capi_utils.h" + +#include "bmesh_py_api.h" /* own include */ + +static PyGetSetDef bpy_bmeditselseq_getseters[] = { + // {(char *)"verts", (getter)bpy_bmeditselseq_get, (setter)NULL, (char *)bpy_bmesh_verts_doc, (void *)BM_VERTS_OF_MESH}, + + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +static struct PyMethodDef bpy_bmeditselseq_methods[] = { + // {"select_flush_mode", (PyCFunction)bpy_bmesh_select_flush_mode, METH_NOARGS, bpy_bmesh_select_flush_mode_doc}, + {NULL, NULL, 0, NULL} +}; + + +/* Sequences + * ========= */ + +static Py_ssize_t bpy_bmeditselseq_length(BPy_BMEditSelSeq *self) +{ + BPY_BM_CHECK_INT(self); + + return BLI_countlist(&self->bm->selected); +} + +static PyObject *bpy_bmeditselseq_subscript_int(BPy_BMEditSelSeq *self, int keynum) +{ + BPY_BM_CHECK_OBJ(self); + + if (keynum < 0) keynum += bpy_bmeditselseq_length(self); /* only get length on negative value, may loop entire seq */ + if (keynum >= 0) { + BMEditSelection *ese = BLI_findlink(&self->bm->selected, keynum); + if (ese) { + return BPy_BMElem_CreatePyObject(self->bm, &ese->ele->head); + } + } + + PyErr_Format(PyExc_IndexError, + "BMElemSeq[index]: index %d out of range", keynum); + return NULL; +} + +static PyObject *bpy_bmeditselseq_subscript_slice(BPy_BMEditSelSeq *self, Py_ssize_t start, Py_ssize_t stop) +{ + int count = 0; + int ok; + + PyObject *list; + PyObject *item; + BMEditSelection *ese; + + BPY_BM_CHECK_OBJ(self); + + list = PyList_New(0); + + ese = self->bm->selected.first; + + ok = (ese != NULL); + + if (UNLIKELY(ok == FALSE)) { + return list; + } + + /* first loop up-until the start */ + for (ok = TRUE; ok; ok = ((ese = ese->next) != NULL)) { + if (count == start) { + break; + } + count++; + } + + /* add items until stop */ + while ((ese = ese->next)) { + item = BPy_BMElem_CreatePyObject(self->bm, &ese->ele->head); + PyList_Append(list, item); + Py_DECREF(item); + + count++; + if (count == stop) { + break; + } + } + + return list; +} + +static PyObject *bpy_bmeditselseq_subscript(BPy_BMEditSelSeq *self, PyObject *key) +{ + /* dont need error check here */ + if (PyIndex_Check(key)) { + Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + return bpy_bmeditselseq_subscript_int(self, i); + } + else if (PySlice_Check(key)) { + PySliceObject *key_slice = (PySliceObject *)key; + Py_ssize_t step = 1; + + if (key_slice->step != Py_None && !_PyEval_SliceIndex(key, &step)) { + return NULL; + } + else if (step != 1) { + PyErr_SetString(PyExc_TypeError, + "BMElemSeq[slice]: slice steps not supported"); + return NULL; + } + else if (key_slice->start == Py_None && key_slice->stop == Py_None) { + return bpy_bmeditselseq_subscript_slice(self, 0, PY_SSIZE_T_MAX); + } + else { + Py_ssize_t start = 0, stop = PY_SSIZE_T_MAX; + + /* avoid PySlice_GetIndicesEx because it needs to know the length ahead of time. */ + if (key_slice->start != Py_None && !_PyEval_SliceIndex(key_slice->start, &start)) return NULL; + if (key_slice->stop != Py_None && !_PyEval_SliceIndex(key_slice->stop, &stop)) return NULL; + + if (start < 0 || stop < 0) { + /* only get the length for negative values */ + Py_ssize_t len = bpy_bmeditselseq_length(self); + if (start < 0) start += len; + if (stop < 0) start += len; + } + + if (stop - start <= 0) { + return PyList_New(0); + } + else { + return bpy_bmeditselseq_subscript_slice(self, start, stop); + } + } + } + else { + PyErr_SetString(PyExc_AttributeError, + "BMElemSeq[key]: invalid key, key must be an int"); + return NULL; + } +} + +static int bpy_bmeditselseq_contains(BPy_BMEditSelSeq *self, PyObject *value) +{ + BPy_BMElem *value_bm_ele; + + BPY_BM_CHECK_INT(self); + + value_bm_ele = (BPy_BMElem *)value; + if (value_bm_ele->bm == self->bm) { + BMEditSelection *ese_test; + BMElem *ele; + + ele = value_bm_ele->ele; + for (ese_test = self->bm->selected.first; ese_test; ese_test = ese_test->next) { + if (ele == ese_test->ele) { + return 1; + } + } + } + + return 0; +} + +static PySequenceMethods bpy_bmeditselseq_as_sequence = { + (lenfunc)bpy_bmeditselseq_length, /* sq_length */ + NULL, /* sq_concat */ + NULL, /* sq_repeat */ + (ssizeargfunc)bpy_bmeditselseq_subscript_int, /* sq_item */ /* Only set this so PySequence_Check() returns True */ + NULL, /* sq_slice */ + (ssizeobjargproc)NULL, /* sq_ass_item */ + NULL, /* *was* sq_ass_slice */ + (objobjproc)bpy_bmeditselseq_contains, /* sq_contains */ + (binaryfunc) NULL, /* sq_inplace_concat */ + (ssizeargfunc) NULL, /* sq_inplace_repeat */ +}; + +static PyMappingMethods bpy_bmeditselseq_as_mapping = { + (lenfunc)bpy_bmeditselseq_length, /* mp_length */ + (binaryfunc)bpy_bmeditselseq_subscript, /* mp_subscript */ + (objobjargproc)NULL, /* mp_ass_subscript */ +}; + + +/* Iterator + * -------- */ + +static PyObject *bpy_bmeditselseq_iter(BPy_BMEditSelSeq *self) +{ + BPy_BMEditSelIter *py_iter; + + BPY_BM_CHECK_OBJ(self); + py_iter = (BPy_BMEditSelIter *)BPy_BMEditSelIter_CreatePyObject(self->bm); + py_iter->ese = self->bm->selected.first; + return (PyObject *)py_iter; +} + +static PyObject *bpy_bmeditseliter_next(BPy_BMEditSelIter *self) +{ + BMEditSelection *ese = self->ese; + if (ese == NULL) { + PyErr_SetString(PyExc_StopIteration, + "bpy_bmiter_next stop"); + return NULL; + } + else { + self->ese = ese->next; + return (PyObject *)BPy_BMElem_CreatePyObject(self->bm, &ese->ele->head); + } +} + +PyTypeObject BPy_BMEditSelSeq_Type = {{{0}}}; +PyTypeObject BPy_BMEditSelIter_Type = {{{0}}}; + + +PyObject *BPy_BMEditSel_CreatePyObject(BMesh *bm) +{ + BPy_BMEditSelSeq *self = PyObject_New(BPy_BMEditSelSeq, &BPy_BMEditSelSeq_Type); + self->bm = bm; + /* caller must initialize 'iter' member */ + return (PyObject *)self; +} + +PyObject *BPy_BMEditSelIter_CreatePyObject(BMesh *bm) +{ + BPy_BMEditSelIter *self = PyObject_New(BPy_BMEditSelIter, &BPy_BMEditSelIter_Type); + self->bm = bm; + /* caller must initialize 'iter' member */ + return (PyObject *)self; +} + +void BPy_BM_init_select_types(void) +{ + BPy_BMEditSelSeq_Type.tp_basicsize = sizeof(BPy_BMEditSelSeq); + BPy_BMEditSelIter_Type.tp_basicsize = sizeof(BPy_BMEditSelIter); + + BPy_BMEditSelSeq_Type.tp_name = "BMEditSelSeq"; + BPy_BMEditSelIter_Type.tp_name = "BMEditSelIter"; + + BPy_BMEditSelSeq_Type.tp_doc = NULL; // todo + BPy_BMEditSelIter_Type.tp_doc = NULL; + + BPy_BMEditSelSeq_Type.tp_repr = (reprfunc)NULL; + BPy_BMEditSelIter_Type.tp_repr = (reprfunc)NULL; + + BPy_BMEditSelSeq_Type.tp_getset = bpy_bmeditselseq_getseters; + BPy_BMEditSelIter_Type.tp_getset = NULL; + + BPy_BMEditSelSeq_Type.tp_methods = bpy_bmeditselseq_methods; + BPy_BMEditSelIter_Type.tp_methods = NULL; + + BPy_BMEditSelSeq_Type.tp_as_sequence = &bpy_bmeditselseq_as_sequence; + + BPy_BMEditSelSeq_Type.tp_as_mapping = &bpy_bmeditselseq_as_mapping; + + BPy_BMEditSelSeq_Type.tp_iter = (getiterfunc)bpy_bmeditselseq_iter; + + /* only 1 iteratir so far */ + BPy_BMEditSelIter_Type.tp_iternext = (iternextfunc)bpy_bmeditseliter_next; + + BPy_BMEditSelSeq_Type.tp_dealloc = NULL; //(destructor)bpy_bmeditselseq_dealloc; + BPy_BMEditSelIter_Type.tp_dealloc = NULL; //(destructor)bpy_bmvert_dealloc; + + BPy_BMEditSelSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT; + BPy_BMEditSelIter_Type.tp_flags = Py_TPFLAGS_DEFAULT; + + PyType_Ready(&BPy_BMEditSelSeq_Type); + PyType_Ready(&BPy_BMEditSelIter_Type); +} diff --git a/source/blender/python/bmesh/bmesh_py_select.h b/source/blender/python/bmesh/bmesh_py_select.h new file mode 100644 index 00000000000..d1bfcdcb6b3 --- /dev/null +++ b/source/blender/python/bmesh/bmesh_py_select.h @@ -0,0 +1,55 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/bmesh/bmesh_py_select.h + * \ingroup pybmesh + */ + +#ifndef __BMESH_PY_SELECT_H__ +#define __BMESH_PY_SELECT_H__ + +extern PyTypeObject BPy_BMEditSelSeq_Type; +extern PyTypeObject BPy_BMEditSelIter_Type; + +#define BPy_BMSelectHistory_Check(v) (Py_TYPE(v) == &BPy_BMEditSelSeq_Type) +#define BPy_BMSelectHistoryIter_Check(v) (Py_TYPE(v) == &BPy_BMEditSelIter_Type) + +typedef struct BPy_BMEditSelSeq { + PyObject_VAR_HEAD + struct BMesh *bm; /* keep first */ +} BPy_BMEditSelSeq; + +typedef struct BPy_BMEditSelIter { + PyObject_VAR_HEAD + struct BMesh *bm; /* keep first */ + struct BMEditSelection *ese; +} BPy_BMEditSelIter; + +void BPy_BM_init_select_types(void); + +PyObject *BPy_BMEditSel_CreatePyObject(BMesh *bm); +PyObject *BPy_BMEditSelIter_CreatePyObject(BMesh *bm); + +#endif /* __BMESH_PY_SELECT_H__ */ diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index dca2b4d229a..d0efb677a11 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -39,6 +39,7 @@ #include "../generic/py_capi_utils.h" +#include "bmesh_py_select.h" #include "bmesh_py_types.h" /* own include */ /* Common Flags @@ -277,6 +278,23 @@ static int bpy_bmesh_select_mode_set(BPy_BMesh *self, PyObject *value) } } +PyDoc_STRVAR(bpy_bmesh_select_history_doc, +"Sequence of selected items (the last is displayed as active).\n\n:type: :class:`BMEditSelSeq`" +); +static PyObject *bpy_bmesh_select_history_get(BPy_BMesh *self) +{ + BPY_BM_CHECK_OBJ(self); + + return BPy_BMEditSel_CreatePyObject(self->bm); +} + +static int bpy_bmesh_select_history_set(BPy_BMesh *self, PyObject *UNUSED(value)) +{ + BPY_BM_CHECK_INT(self); + + PyErr_SetString(PyExc_NotImplementedError, "not yet functional"); + return -1; +} /* Vert * ^^^^ */ @@ -459,6 +477,8 @@ static PyGetSetDef bpy_bmesh_getseters[] = { {(char *)"faces", (getter)bpy_bmelemseq_get, (setter)NULL, (char *)bpy_bmesh_faces_doc, (void *)BM_FACES_OF_MESH}, {(char *)"select_mode", (getter)bpy_bmesh_select_mode_get, (setter)bpy_bmesh_select_mode_set, (char *)bpy_bmesh_select_mode_doc, NULL}, + {(char *)"select_history", (getter)bpy_bmesh_select_history_get, (setter)bpy_bmesh_select_history_set, (char *)bpy_bmesh_select_history_doc, NULL}, + /* readonly checks */ {(char *)"is_valid", (getter)bpy_bm_is_valid_get, (setter)NULL, (char *)bpy_bm_is_valid_doc, NULL}, @@ -1873,7 +1893,6 @@ static PyObject *bpy_bmelemseq_subscript_slice(BPy_BMElemSeq *self, Py_ssize_t s /* first loop up-until the start */ for (ok = TRUE; ok; ok = (BM_iter_step(&iter) != NULL)) { - /* PointerRNA itemptr = rna_macro_iter.ptr; */ if (count == start) { break; } @@ -2343,6 +2362,8 @@ PyObject *BPyInit_bmesh_types(void) mod_type_add(submodule, BPy_BMLoop_Type); mod_type_add(submodule, BPy_BMElemSeq_Type); mod_type_add(submodule, BPy_BMIter_Type); + mod_type_add(submodule, BPy_BMEditSelSeq_Type); + mod_type_add(submodule, BPy_BMEditSelIter_Type); #undef mod_type_add |