bmesh py api: finished todo - editable select_history
authorCampbell Barton <ideasman42@gmail.com>
Wed, 14 Mar 2012 04:46:12 +0000 (04:46 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 14 Mar 2012 04:46:12 +0000 (04:46 +0000)
eg:
  bm.select_history = vert, face, edge

  bm.select_history.add(edge)

doc/python_api/rst/include__bmesh.rst
doc/python_api/sphinx_doc_gen.py
source/blender/bmesh/intern/bmesh_marking.c
source/blender/bmesh/intern/bmesh_marking.h
source/blender/python/bmesh/bmesh_py_select.c
source/blender/python/bmesh/bmesh_py_select.h
source/blender/python/bmesh/bmesh_py_types.c
source/blender/python/bmesh/bmesh_py_types.h
source/blender/python/bmesh/bmesh_py_utils.c

index 1c702275f6272b09dc7f73993af4604bf50e05e5..2481c4a739cefec1ab8a42d3df3aee24cc33c5ca 100644 (file)
@@ -33,7 +33,6 @@ For an overview of BMesh data types and how they reference each other see:
 .. todo::
 
    * add access to BMesh **walkers**
-   * add access selection history (readonly access done)
    * add a way to re-tessellate an editmode bmesh.
 
 
index 49193ad8f22ac212ea7280cc5461d6d31f0100ef..b15fcd9303b1f42a89a4d2635d9a4c7710b096c6 100644 (file)
@@ -94,12 +94,13 @@ def handle_args():
         usage=SCRIPT_HELP_MSG
     )
 
-    # optional arguments
+    # optional arguments    
     parser.add_argument("-o", "--output",
                         dest="output_dir",
                         type=str,
                         default=SCRIPT_DIR,
-                        help="Path of the API docs (default=<script dir>)",
+                        # XXX, THIS ISNT WORKING, EXAMPLE SCRIPTS WILL NOT BE FOUND
+                        help="Path of the API docs (default=<script dir>).",
                         required=False)
 
     parser.add_argument("-B", "--sphinx-build",
index 4108d00fe7af141826b8cf5998015e02396269a2..89bce16f2ca5694005e6c142b75b493a056b0e2f 100644 (file)
@@ -720,14 +720,18 @@ void BM_select_history_clear(BMesh *bm)
        bm->selected.first = bm->selected.last = NULL;
 }
 
+void BM_select_history_store_notest(BMesh *bm, BMElem *ele)
+{
+       BMEditSelection *ese = (BMEditSelection *) MEM_callocN(sizeof(BMEditSelection), "BMEdit Selection");
+       ese->htype = ((BMHeader *)ele)->htype;
+       ese->ele = ele;
+       BLI_addtail(&(bm->selected), ese);
+}
+
 void BM_select_history_store(BMesh *bm, BMElem *ele)
 {
-       BMEditSelection *ese;
        if (!BM_select_history_check(bm, ele)) {
-               ese = (BMEditSelection *) MEM_callocN(sizeof(BMEditSelection), "BMEdit Selection");
-               ese->htype = ((BMHeader *)ele)->htype;
-               ese->ele = ele;
-               BLI_addtail(&(bm->selected), ese);
+               BM_select_history_store_notest(bm, ele);
        }
 }
 
index 8e4a4ab7d660c162e98fd0c90613324238ba40dc..f0e81b1dd9f4e84ab404603a6a8a4023dd36870c 100644 (file)
@@ -71,6 +71,7 @@ void BM_editselection_plane(BMesh *bm, float r_plane[3], BMEditSelection *ese);
 
 int  BM_select_history_check(BMesh *bm, const BMElem *ele);
 int  BM_select_history_remove(BMesh *bm, BMElem *ele);
+void BM_select_history_store_notest(BMesh *bm, BMElem *ele);
 void BM_select_history_store(BMesh *bm, BMElem *ele);
 void BM_select_history_validate(BMesh *bm);
 void BM_select_history_clear(BMesh *em);
index cd6145709e075fb9ecd405f9c66d5ed10c061b34..a9fb5b2b018eaa8dc906cf99721bd43c9f2b19b3 100644 (file)
@@ -28,6 +28,9 @@
  *
  * This file defines the types for 'BMesh.select_history'
  * sequence and iterator.
+ *
+ * select_history is very loosely based on pytons set() type,
+ * since items can only exist once. however they do have an order.
  */
 
 #include <Python.h>
@@ -93,6 +96,37 @@ static PyObject *bpy_bmeditselseq_clear(BPy_BMEditSelSeq *self)
        Py_RETURN_NONE;
 }
 
+PyDoc_STRVAR(bpy_bmeditselseq_add_doc,
+".. method:: add(element)\n"
+"\n"
+"   Add an element to the selection history (no action taken if its already added).\n"
+);
+static PyObject *bpy_bmeditselseq_add(BPy_BMEditSelSeq *self, BPy_BMElem *value)
+{
+       BPY_BM_CHECK_OBJ(self);
+
+       if ((BPy_BMVert_Check(value) ||
+            BPy_BMEdge_Check(value) ||
+            BPy_BMFace_Check(value)) == FALSE)
+       {
+               PyErr_Format(PyExc_TypeError,
+                            "Expected a BMVert/BMedge/BMFace not a %.200s", Py_TYPE(value)->tp_name);
+               return NULL;
+       }
+
+       BPY_BM_CHECK_OBJ(value);
+
+       if (self->bm != value->bm)      {
+               PyErr_SetString(PyExc_ValueError,
+                               "Element is not from this mesh");
+               return NULL;
+       }
+
+       BM_select_history_store(self->bm, value->ele)
+
+       Py_RETURN_NONE;
+}
+
 PyDoc_STRVAR(bpy_bmeditselseq_remove_doc,
 ".. method:: remove(element)\n"
 "\n"
@@ -127,6 +161,8 @@ static PyObject *bpy_bmeditselseq_remove(BPy_BMEditSelSeq *self, BPy_BMElem *val
 static struct PyMethodDef bpy_bmeditselseq_methods[] = {
     {"validate", (PyCFunction)bpy_bmeditselseq_validate, METH_NOARGS, bpy_bmeditselseq_validate_doc},
     {"clear",    (PyCFunction)bpy_bmeditselseq_clear,    METH_NOARGS, bpy_bmeditselseq_clear_doc},
+
+    {"add",      (PyCFunction)bpy_bmeditselseq_add,      METH_O,      bpy_bmeditselseq_add_doc},
     {"remove",   (PyCFunction)bpy_bmeditselseq_remove,   METH_O,      bpy_bmeditselseq_remove_doc},
     {NULL, NULL, 0, NULL}
 };
@@ -381,3 +417,38 @@ void BPy_BM_init_select_types(void)
        PyType_Ready(&BPy_BMEditSelSeq_Type);
        PyType_Ready(&BPy_BMEditSelIter_Type);
 }
+
+
+/* utility function */
+
+/**
+ * \note doesnt actually check selection.
+ */
+int BPy_BMEditSel_Assign(BPy_BMesh *self, PyObject *value)
+{
+       BMesh *bm;
+       Py_ssize_t value_len;
+       Py_ssize_t i;
+       BMElem **value_array = NULL;
+
+       BPY_BM_CHECK_INT(self);
+
+       bm = self->bm;
+
+       value_array = BPy_BMElem_PySeq_As_Array(&bm, value, 0, PY_SSIZE_T_MAX,
+                                               &value_len, BM_VERT | BM_EDGE | BM_FACE,
+                                               TRUE, TRUE, "BMesh.select_history = value");
+
+       if (value_array == NULL) {
+               return -1;
+       }
+
+       BM_select_history_clear(bm);
+
+       for (i = 0; i < value_len; i++) {
+               BM_select_history_store_notest(bm, value_array[i]);
+       }
+
+       PyMem_FREE(value_array);
+       return 0;
+}
index d1bfcdcb6b3d20c2700153f8b66fac9986d1ef5b..3992dbe1ffed96fab319a4e38011ff6a8421aebf 100644 (file)
@@ -30,6 +30,8 @@
 #ifndef __BMESH_PY_SELECT_H__
 #define __BMESH_PY_SELECT_H__
 
+struct BPy_BMesh;
+
 extern PyTypeObject BPy_BMEditSelSeq_Type;
 extern PyTypeObject BPy_BMEditSelIter_Type;
 
@@ -51,5 +53,6 @@ void BPy_BM_init_select_types(void);
 
 PyObject *BPy_BMEditSel_CreatePyObject(BMesh *bm);
 PyObject *BPy_BMEditSelIter_CreatePyObject(BMesh *bm);
+int       BPy_BMEditSel_Assign(struct BPy_BMesh *self, PyObject *value);
 
 #endif /* __BMESH_PY_SELECT_H__ */
index 6d4d1b20e7b447756a0f6795cf8e83c75f1836f2..313761db5e24877667f2ead51ce6d5b21ea8fc04 100644 (file)
@@ -302,12 +302,11 @@ static PyObject *bpy_bmesh_select_history_get(BPy_BMesh *self)
        return BPy_BMEditSel_CreatePyObject(self->bm);
 }
 
-static int bpy_bmesh_select_history_set(BPy_BMesh *self, PyObject *UNUSED(value))
+static int bpy_bmesh_select_history_set(BPy_BMesh *self, PyObject *value)
 {
        BPY_BM_CHECK_INT(self);
 
-       PyErr_SetString(PyExc_NotImplementedError, "not yet functional");
-       return -1;
+       return BPy_BMEditSel_Assign(self, value);
 }
 
 /* Vert
@@ -1045,7 +1044,7 @@ static PyObject *bpy_bmvert_copy_from_vert_interp(BPy_BMVert *self, PyObject *ar
                Py_ssize_t vert_seq_len; /* always 2 */
 
                vert_array = BPy_BMElem_PySeq_As_Array(&bm, vert_seq, 2, 2,
-                                                      &vert_seq_len, &BPy_BMVert_Type,
+                                                      &vert_seq_len, BM_VERT,
                                                       TRUE, TRUE, "BMVert.copy_from_vert_interp(...)");
 
                if (vert_array == NULL) {
@@ -1532,7 +1531,7 @@ static PyObject *bpy_bmedgeseq_new(BPy_BMElemSeq *self, PyObject *args)
                }
 
                vert_array = BPy_BMElem_PySeq_As_Array(&bm, vert_seq, 2, 2,
-                                                      &vert_seq_len, &BPy_BMVert_Type,
+                                                      &vert_seq_len, BM_VERT,
                                                       TRUE, TRUE, "edges.new(...)");
 
                if (vert_array == NULL) {
@@ -1599,7 +1598,7 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args)
                }
 
                vert_array = BPy_BMElem_PySeq_As_Array(&bm, vert_seq, 3, PY_SSIZE_T_MAX,
-                                                      &vert_seq_len, &BPy_BMVert_Type,
+                                                      &vert_seq_len, BM_VERT,
                                                       TRUE, TRUE, "faces.new(...)");
 
                if (vert_array == NULL) {
@@ -1821,7 +1820,7 @@ static PyObject *bpy_bmedgeseq_get(BPy_BMElemSeq *self, PyObject *args)
                PyObject *ret = NULL;
 
                vert_array = BPy_BMElem_PySeq_As_Array(&bm, vert_seq, 2, 2,
-                                                      &vert_seq_len, &BPy_BMVert_Type,
+                                                      &vert_seq_len, BM_VERT,
                                                       TRUE, TRUE, "edges.get(...)");
 
                if (vert_array == NULL) {
@@ -1863,7 +1862,7 @@ static PyObject *bpy_bmfaceseq_get(BPy_BMElemSeq *self, PyObject *args)
                PyObject *ret = NULL;
 
                vert_array = BPy_BMElem_PySeq_As_Array(&bm, vert_seq, 1, PY_SSIZE_T_MAX,
-                                                      &vert_seq_len, &BPy_BMVert_Type,
+                                                      &vert_seq_len, BM_VERT,
                                                       TRUE, TRUE, "faces.get(...)");
 
                if (vert_array == NULL) {
@@ -2849,7 +2848,7 @@ void bpy_bm_generic_invalidate(BPy_BMGeneric *self)
  * The 'bm_r' value is assigned when empty, and used when set.
  */
 void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
-                                PyTypeObject *type,
+                                const char htype,
                                 const char do_unique_check, const char do_bm_check,
                                 const char *error_prefix)
 {
@@ -2883,16 +2882,16 @@ void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_
                for (i = 0; i < seq_len; i++) {
                        item = (BPy_BMElem *)PySequence_Fast_GET_ITEM(seq_fast, i);
 
-                       if (Py_TYPE(item) != type) {
+                       if (!BPy_BMElem_CheckHType(Py_TYPE(item), htype)) {
                                PyErr_Format(PyExc_TypeError,
-                                            "%s: expected '%.200s', not '%.200s'",
-                                            error_prefix, type->tp_name, Py_TYPE(item)->tp_name);
+                                            "%s: expected %.200s, not '%.200s'",
+                                            error_prefix, BPy_BMElem_StringFromHType(htype), Py_TYPE(item)->tp_name);
                                goto err_cleanup;
                        }
                        else if (!BPY_BM_IS_VALID(item)) {
                                PyErr_Format(PyExc_TypeError,
                                             "%s: %d %s has been removed",
-                                            error_prefix, i, type->tp_name);
+                                            error_prefix, i, Py_TYPE(item)->tp_name);
                                goto err_cleanup;
                        }
                        /* trick so we can ensure all items have the same mesh,
@@ -2900,7 +2899,7 @@ void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_
                        else if (do_bm_check && (bm  && bm != item->bm)) {
                                PyErr_Format(PyExc_ValueError,
                                             "%s: %d %s is from another mesh",
-                                            error_prefix, i, type->tp_name);
+                                            error_prefix, i, BPy_BMElem_StringFromHType(htype));
                                goto err_cleanup;
                        }
 
@@ -2929,8 +2928,8 @@ void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_
 
                        if (ok == FALSE) {
                                PyErr_Format(PyExc_ValueError,
-                                            "%s: found the same %s used multiple times",
-                                            error_prefix, type->tp_name);
+                                            "%s: found the same %.200s used multiple times",
+                                            error_prefix, BPy_BMElem_StringFromHType(htype));
                                goto err_cleanup;
                        }
                }
@@ -2958,3 +2957,30 @@ PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_
 
        return ret;
 }
+
+int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype)
+{
+       return (((htype & BM_VERT) && (type == &BPy_BMVert_Type)) ||
+               ((htype & BM_EDGE) && (type == &BPy_BMEdge_Type)) ||
+               ((htype & BM_FACE) && (type == &BPy_BMFace_Type)) ||
+               ((htype & BM_LOOP) && (type == &BPy_BMLoop_Type)));
+}
+
+/**
+ * Use for error strings only, not thread safe,
+ *
+ * \return a sting like '(BMVert/BMEdge/BMFace/BMLoop)'
+ */
+char *BPy_BMElem_StringFromHType(const char htype)
+{
+       /* zero to ensure string is always NULL terminated */
+       static char ret[32];
+       char *ret_ptr = ret;
+       if (htype & BM_VERT) ret_ptr += sprintf(ret_ptr, "/%s", BPy_BMVert_Type.tp_name);
+       if (htype & BM_EDGE) ret_ptr += sprintf(ret_ptr, "/%s", BPy_BMEdge_Type.tp_name);
+       if (htype & BM_FACE) ret_ptr += sprintf(ret_ptr, "/%s", BPy_BMFace_Type.tp_name);
+       if (htype & BM_LOOP) ret_ptr += sprintf(ret_ptr, "/%s", BPy_BMLoop_Type.tp_name);
+       ret[0]   = '(';
+       *ret_ptr = ')';
+       return ret;
+}
index b5b96002cccfc1d2dfc1a7eabe2aedd0f6b7dfb7..452c8b2103fe9240f06d27be3cf92cd3e495c723 100644 (file)
@@ -139,11 +139,13 @@ int  bpy_bm_generic_valid_check(BPy_BMGeneric *self);
 void bpy_bm_generic_invalidate(BPy_BMGeneric *self);
 
 void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
-                                PyTypeObject *type,
+                                const char htype,
                                 const char do_unique_check, const char do_bm_check,
                                 const char *error_prefix);
 
 PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len);
+int       BPy_BMElem_CheckHType(PyTypeObject *type, const char htype);
+char     *BPy_BMElem_StringFromHType(const char htype);
 
 
 #define BPY_BM_CHECK_OBJ(obj) if (UNLIKELY(bpy_bm_generic_valid_check((BPy_BMGeneric *)obj) == -1)) { return NULL; } (void)0
index a41d5e7f766d235869bf0252adba1132a8af5fd2..736802c7f603152ca4dc7459b46197e032cbd424 100644 (file)
@@ -238,7 +238,7 @@ static PyObject *bpy_bm_utils_vert_separate(PyObject *UNUSED(self), PyObject *ar
        bm = py_vert->bm;
 
        edge_array = BPy_BMElem_PySeq_As_Array(&bm, edge_seq, 0, PY_SSIZE_T_MAX,
-                                              &edge_array_len, &BPy_BMEdge_Type,
+                                              &edge_array_len, BM_EDGE,
                                               TRUE, TRUE, "vert_separate(...)");
 
        if (edge_array == NULL) {
@@ -460,7 +460,7 @@ static PyObject *bpy_bm_utils_face_join(PyObject *UNUSED(self), PyObject *value)
        BMFace *f_new;
 
        face_array = BPy_BMElem_PySeq_As_Array(&bm, value, 2, PY_SSIZE_T_MAX,
-                                              &face_seq_len, &BPy_BMFace_Type,
+                                              &face_seq_len, BM_FACE,
                                               TRUE, TRUE, "face_join(...)");
 
        if (face_array == NULL) {