Merge branch 'master' into blender2.8
[blender.git] / source / blender / python / bmesh / bmesh_py_ops.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_ops.c
27  *  \ingroup pybmesh
28  *
29  * This file defines the 'bmesh.ops' module.
30  * Operators from 'opdefines' are wrapped.
31  */
32
33 #include <Python.h>
34
35 #include "BLI_utildefines.h"
36 #include "BLI_dynstr.h"
37
38 #include "MEM_guardedalloc.h"
39
40
41 #include "bmesh.h"
42
43 #include "bmesh_py_ops_call.h"
44 #include "bmesh_py_ops.h"  /* own include */
45
46 /* bmesh operator 'bmesh.ops.*' callable types
47  * ******************************************* */
48 static PyTypeObject bmesh_op_Type;
49
50 static PyObject *bpy_bmesh_op_CreatePyObject(const char *opname)
51 {
52         BPy_BMeshOpFunc *self = PyObject_New(BPy_BMeshOpFunc, &bmesh_op_Type);
53
54         self->opname = opname;
55
56         return (PyObject *)self;
57 }
58
59 static PyObject *bpy_bmesh_op_repr(BPy_BMeshOpFunc *self)
60 {
61         return PyUnicode_FromFormat("<%.200s bmesh.ops.%.200s()>",
62                                     Py_TYPE(self)->tp_name,
63                                     self->opname);
64 }
65
66
67 /* methods
68  * ======= */
69
70
71 /* __doc__
72  * ------- */
73
74 static char *bmp_slots_as_args(const BMOSlotType slot_types[BMO_OP_MAX_SLOTS], const bool is_out)
75 {
76         DynStr *dyn_str = BLI_dynstr_new();
77         char *ret;
78
79         int i = 0;
80
81         while (*slot_types[i].name) {
82                 /* cut off '.out' by using a string size arg */
83                 const int name_len = is_out ?
84                         (strchr(slot_types[i].name, '.') - slot_types[i].name) :
85                         sizeof(slot_types[i].name);
86                 const char *value = "<Unknown>";
87                 switch (slot_types[i].type) {
88                         case BMO_OP_SLOT_BOOL:          value = "False"; break;
89                         case BMO_OP_SLOT_INT:           value = "0"; break;
90                         case BMO_OP_SLOT_FLT:           value = "0.0"; break;
91                         case BMO_OP_SLOT_PTR:           value = "None"; break;
92                         case BMO_OP_SLOT_MAT:           value = "Matrix()"; break;
93                         case BMO_OP_SLOT_VEC:           value = "Vector()"; break;
94                         case BMO_OP_SLOT_ELEMENT_BUF:   value =
95                              (slot_types[i].subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) ? "None" : "[]"; break;
96                         case BMO_OP_SLOT_MAPPING:       value = "{}"; break;
97                 }
98                 BLI_dynstr_appendf(dyn_str, i ? ", %.*s=%s" : "%.*s=%s", name_len, slot_types[i].name, value);
99                 i++;
100         }
101
102         ret = BLI_dynstr_get_cstring(dyn_str);
103         BLI_dynstr_free(dyn_str);
104         return ret;
105 }
106
107 static PyObject *bpy_bmesh_op_doc_get(BPy_BMeshOpFunc *self, void *UNUSED(closure))
108 {
109         PyObject *ret;
110         char *slot_in;
111         char *slot_out;
112         int i;
113
114         i = BMO_opcode_from_opname(self->opname);
115
116         slot_in  = bmp_slots_as_args(bmo_opdefines[i]->slot_types_in, false);
117         slot_out = bmp_slots_as_args(bmo_opdefines[i]->slot_types_out, true);
118
119         ret = PyUnicode_FromFormat("%.200s bmesh.ops.%.200s(bmesh, %s)\n  -> dict(%s)",
120                                    Py_TYPE(self)->tp_name,
121                                    self->opname, slot_in, slot_out);
122
123         MEM_freeN(slot_in);
124         MEM_freeN(slot_out);
125
126         return ret;
127 }
128
129 static PyGetSetDef bpy_bmesh_op_getseters[] = {
130         {(char *)"__doc__", (getter)bpy_bmesh_op_doc_get, (setter)NULL, NULL, NULL},
131         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
132 };
133
134
135 /* Types
136  * ===== */
137
138 static PyTypeObject bmesh_op_Type = {
139         PyVarObject_HEAD_INIT(NULL, 0)
140         "BMeshOpFunc",              /* tp_name */
141         sizeof(BPy_BMeshOpFunc),    /* tp_basicsize */
142         0,                          /* tp_itemsize */
143         /* methods */
144         NULL,                       /* tp_dealloc */
145         NULL,                       /* printfunc tp_print; */
146         NULL,                       /* getattrfunc tp_getattr; */
147         NULL,                       /* setattrfunc tp_setattr; */
148         NULL,                       /* tp_compare */ /* DEPRECATED in python 3.0! */
149         (reprfunc) bpy_bmesh_op_repr, /* tp_repr */
150
151         /* Method suites for standard classes */
152
153         NULL,                       /* PyNumberMethods *tp_as_number; */
154         NULL,                       /* PySequenceMethods *tp_as_sequence; */
155         NULL,                       /* PyMappingMethods *tp_as_mapping; */
156
157         /* More standard operations (here for binary compatibility) */
158
159         NULL,                       /* hashfunc tp_hash; */
160         (ternaryfunc)BPy_BMO_call,  /* ternaryfunc tp_call; */
161         NULL,                       /* reprfunc tp_str; */
162
163         /* will only use these if this is a subtype of a py class */
164         NULL,                       /* getattrofunc tp_getattro; */
165         NULL,                       /* setattrofunc tp_setattro; */
166
167         /* Functions to access object as input/output buffer */
168         NULL,                       /* PyBufferProcs *tp_as_buffer; */
169
170         /*** Flags to define presence of optional/expanded features ***/
171         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
172
173         NULL,                       /*  char *tp_doc;  Documentation string */
174         /*** Assigned meaning in release 2.0 ***/
175         /* call function for all accessible objects */
176         NULL,                       /* traverseproc tp_traverse; */
177
178         /* delete references to contained objects */
179         NULL,                       /* inquiry tp_clear; */
180
181         /***  Assigned meaning in release 2.1 ***/
182         /*** rich comparisons ***/
183         NULL,                       /* richcmpfunc tp_richcompare; */
184
185         /***  weak reference enabler ***/
186         0,
187         /*** Added in release 2.2 ***/
188         /*   Iterators */
189         NULL,                       /* getiterfunc tp_iter; */
190         NULL,                       /* iternextfunc tp_iternext; */
191
192         /*** Attribute descriptor and subclassing stuff ***/
193         NULL,                       /* struct PyMethodDef *tp_methods; */
194         NULL,                       /* struct PyMemberDef *tp_members; */
195         bpy_bmesh_op_getseters,     /* struct PyGetSetDef *tp_getset; */
196         NULL,                       /* struct _typeobject *tp_base; */
197         NULL,                       /* PyObject *tp_dict; */
198         NULL,                       /* descrgetfunc tp_descr_get; */
199         NULL,                       /* descrsetfunc tp_descr_set; */
200         0,                          /* long tp_dictoffset; */
201         NULL,                       /* initproc tp_init; */
202         NULL,                       /* allocfunc tp_alloc; */
203         NULL,                       /* newfunc tp_new; */
204         /*  Low-level free-memory routine */
205         NULL,                       /* freefunc tp_free;  */
206         /* For PyObject_IS_GC */
207         NULL,                       /* inquiry tp_is_gc;  */
208         NULL,                       /* PyObject *tp_bases; */
209         /* method resolution order */
210         NULL,                       /* PyObject *tp_mro;  */
211         NULL,                       /* PyObject *tp_cache; */
212         NULL,                       /* PyObject *tp_subclasses; */
213         NULL,                       /* PyObject *tp_weaklist; */
214         NULL
215 };
216
217
218 /* bmesh fake module 'bmesh.ops'
219  * ***************************** */
220
221 static PyObject *bpy_bmesh_ops_fakemod_getattro(PyObject *UNUSED(self), PyObject *pyname)
222 {
223         const char *opname = _PyUnicode_AsString(pyname);
224
225         if (BMO_opcode_from_opname(opname) != -1) {
226                 return bpy_bmesh_op_CreatePyObject(opname);
227         }
228         else {
229                 PyErr_Format(PyExc_AttributeError,
230                              "BMeshOpsModule: operator \"%.200s\" doesn't exist",
231                              opname);
232                 return NULL;
233         }
234 }
235
236 static PyObject *bpy_bmesh_ops_fakemod_dir(PyObject *UNUSED(self))
237 {
238         const unsigned int tot = bmo_opdefines_total;
239         unsigned int i;
240         PyObject *ret;
241
242         ret = PyList_New(bmo_opdefines_total);
243
244         for (i = 0; i < tot; i++) {
245                 PyList_SET_ITEM(ret, i, PyUnicode_FromString(bmo_opdefines[i]->opname));
246         }
247
248         return ret;
249 }
250
251 static struct PyMethodDef bpy_bmesh_ops_fakemod_methods[] = {
252         {"__dir__", (PyCFunction)bpy_bmesh_ops_fakemod_dir, METH_NOARGS, NULL},
253         {NULL, NULL, 0, NULL}
254 };
255
256 static PyTypeObject bmesh_ops_fakemod_Type = {
257         PyVarObject_HEAD_INIT(NULL, 0)
258         "BMeshOpsModule",           /* tp_name */
259         0,                          /* tp_basicsize */
260         0,                          /* tp_itemsize */
261         /* methods */
262         NULL,                       /* tp_dealloc */
263         NULL,                       /* printfunc tp_print; */
264         NULL,                       /* getattrfunc tp_getattr; */
265         NULL,                       /* setattrfunc tp_setattr; */
266         NULL,                       /* tp_compare */ /* DEPRECATED in python 3.0! */
267         NULL,                       /* tp_repr */
268
269         /* Method suites for standard classes */
270
271         NULL,                       /* PyNumberMethods *tp_as_number; */
272         NULL,                       /* PySequenceMethods *tp_as_sequence; */
273         NULL,                       /* PyMappingMethods *tp_as_mapping; */
274
275         /* More standard operations (here for binary compatibility) */
276
277         NULL,                       /* hashfunc tp_hash; */
278         NULL,                       /* ternaryfunc tp_call; */
279         NULL,                       /* reprfunc tp_str; */
280
281         /* will only use these if this is a subtype of a py class */
282         bpy_bmesh_ops_fakemod_getattro,    /* getattrofunc tp_getattro; */
283         NULL,                       /* setattrofunc tp_setattro; */
284
285         /* Functions to access object as input/output buffer */
286         NULL,                       /* PyBufferProcs *tp_as_buffer; */
287
288         /*** Flags to define presence of optional/expanded features ***/
289         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
290
291         NULL,                       /*  char *tp_doc;  Documentation string */
292         /*** Assigned meaning in release 2.0 ***/
293         /* call function for all accessible objects */
294         NULL,                       /* traverseproc tp_traverse; */
295
296         /* delete references to contained objects */
297         NULL,                       /* inquiry tp_clear; */
298
299         /***  Assigned meaning in release 2.1 ***/
300         /*** rich comparisons ***/
301         NULL, /* subclassed */          /* richcmpfunc tp_richcompare; */
302
303         /***  weak reference enabler ***/
304         0,
305         /*** Added in release 2.2 ***/
306         /*   Iterators */
307         NULL,                       /* getiterfunc tp_iter; */
308         NULL,                       /* iternextfunc tp_iternext; */
309
310         /*** Attribute descriptor and subclassing stuff ***/
311         bpy_bmesh_ops_fakemod_methods,  /* struct PyMethodDef *tp_methods; */
312         NULL,                       /* struct PyMemberDef *tp_members; */
313         NULL,                       /* struct PyGetSetDef *tp_getset; */
314         NULL,                       /* struct _typeobject *tp_base; */
315         NULL,                       /* PyObject *tp_dict; */
316         NULL,                       /* descrgetfunc tp_descr_get; */
317         NULL,                       /* descrsetfunc tp_descr_set; */
318         0,                          /* long tp_dictoffset; */
319         NULL,                       /* initproc tp_init; */
320         NULL,                       /* allocfunc tp_alloc; */
321         NULL,                       /* newfunc tp_new; */
322         /*  Low-level free-memory routine */
323         NULL,                       /* freefunc tp_free;  */
324         /* For PyObject_IS_GC */
325         NULL,                       /* inquiry tp_is_gc;  */
326         NULL,                       /* PyObject *tp_bases; */
327         /* method resolution order */
328         NULL,                       /* PyObject *tp_mro;  */
329         NULL,                       /* PyObject *tp_cache; */
330         NULL,                       /* PyObject *tp_subclasses; */
331         NULL,                       /* PyObject *tp_weaklist; */
332         NULL
333 };
334
335 PyObject *BPyInit_bmesh_ops(void)
336 {
337         PyObject *submodule;
338
339         if (PyType_Ready(&bmesh_ops_fakemod_Type) < 0)
340                 return NULL;
341
342         if (PyType_Ready(&bmesh_op_Type) < 0)
343                 return NULL;
344
345         submodule = PyObject_New(PyObject, &bmesh_ops_fakemod_Type);
346
347         /* prevent further creation of instances */
348         bmesh_ops_fakemod_Type.tp_init = NULL;
349         bmesh_ops_fakemod_Type.tp_new = NULL;
350
351         return submodule;
352 }