Refactor: Clarify code around scheduling composite nodes
[blender.git] / source / blender / python / intern / bpy_app_icons.cc
blob003535686c4cf6b16ece5c365aa9537eacb16a2a
1 /* SPDX-FileCopyrightText: 2023 Blender Authors
3 * SPDX-License-Identifier: GPL-2.0-or-later */
5 /** \file
6 * \ingroup pythonintern
8 * Runtime defined icons.
9 */
11 #include <Python.h>
13 #include "MEM_guardedalloc.h"
15 #include "BKE_icons.h"
17 #include "../generic/py_capi_utils.hh"
18 #include "../generic/python_compat.hh"
20 #include "bpy_app_icons.hh"
22 /* We may want to load direct from file. */
23 PyDoc_STRVAR(
24 /* Wrap. */
25 bpy_app_icons_new_triangles_doc,
26 ".. function:: new_triangles(range, coords, colors)\n"
27 "\n"
28 " Create a new icon from triangle geometry.\n"
29 "\n"
30 " :arg range: Pair of ints.\n"
31 " :type range: tuple[int, int]\n"
32 " :arg coords: Sequence of bytes (6 floats for one triangle) for (X, Y) coordinates.\n"
33 " :type coords: bytes\n"
34 " :arg colors: Sequence of bytes (12 for one triangles) for RGBA.\n"
35 " :type colors: bytes\n"
36 " :return: Unique icon value (pass to interface ``icon_value`` argument).\n"
37 " :rtype: int\n");
38 static PyObject *bpy_app_icons_new_triangles(PyObject * /*self*/, PyObject *args, PyObject *kw)
40 /* bytes */
41 uchar coords_range[2];
42 PyObject *py_coords, *py_colors;
44 static const char *_keywords[] = {"range", "coords", "colors", nullptr};
45 static _PyArg_Parser _parser = {
46 PY_ARG_PARSER_HEAD_COMPAT()
47 "(BB)" /* `range` */
48 "S" /* `coords` */
49 "S" /* `colors` */
50 ":new_triangles",
51 _keywords,
52 nullptr,
54 if (!_PyArg_ParseTupleAndKeywordsFast(
55 args, kw, &_parser, &coords_range[0], &coords_range[1], &py_coords, &py_colors))
57 return nullptr;
60 const int coords_len = PyBytes_GET_SIZE(py_coords);
61 const int tris_len = coords_len / 6;
62 if (tris_len * 6 != coords_len) {
63 PyErr_SetString(PyExc_ValueError, "coords must be multiple of 6");
64 return nullptr;
66 if (PyBytes_GET_SIZE(py_colors) != 2 * coords_len) {
67 PyErr_SetString(PyExc_ValueError, "colors must be twice size of coords");
68 return nullptr;
71 const int coords_size = sizeof(uchar[2]) * tris_len * 3;
72 const int colors_size = sizeof(uchar[4]) * tris_len * 3;
73 uchar(*coords)[2] = static_cast<uchar(*)[2]>(MEM_mallocN(coords_size, __func__));
74 uchar(*colors)[4] = static_cast<uchar(*)[4]>(MEM_mallocN(colors_size, __func__));
76 memcpy(coords, PyBytes_AS_STRING(py_coords), coords_size);
77 memcpy(colors, PyBytes_AS_STRING(py_colors), colors_size);
79 Icon_Geom *geom = static_cast<Icon_Geom *>(MEM_mallocN(sizeof(*geom), __func__));
80 geom->coords_len = tris_len;
81 geom->coords_range[0] = coords_range[0];
82 geom->coords_range[1] = coords_range[1];
83 geom->coords = coords;
84 geom->colors = colors;
85 geom->icon_id = 0;
86 const int icon_id = BKE_icon_geom_ensure(geom);
87 return PyLong_FromLong(icon_id);
90 PyDoc_STRVAR(
91 /* Wrap. */
92 bpy_app_icons_new_triangles_from_file_doc,
93 ".. function:: new_triangles_from_file(filepath)\n"
94 "\n"
95 " Create a new icon from triangle geometry.\n"
96 "\n"
97 " :arg filepath: File path.\n"
98 " :type filepath: str | bytes.\n"
99 " :return: Unique icon value (pass to interface ``icon_value`` argument).\n"
100 " :rtype: int\n");
101 static PyObject *bpy_app_icons_new_triangles_from_file(PyObject * /*self*/,
102 PyObject *args,
103 PyObject *kw)
105 PyC_UnicodeAsBytesAndSize_Data filepath_data = {nullptr};
107 static const char *_keywords[] = {"filepath", nullptr};
108 static _PyArg_Parser _parser = {
109 PY_ARG_PARSER_HEAD_COMPAT()
110 "O&" /* `filepath` */
111 ":new_triangles_from_file",
112 _keywords,
113 nullptr,
115 if (!_PyArg_ParseTupleAndKeywordsFast(
116 args, kw, &_parser, PyC_ParseUnicodeAsBytesAndSize, &filepath_data))
118 return nullptr;
121 Icon_Geom *geom = BKE_icon_geom_from_file(filepath_data.value);
122 Py_XDECREF(filepath_data.value_coerce);
124 if (geom == nullptr) {
125 PyErr_SetString(PyExc_ValueError, "Unable to load from file");
126 return nullptr;
128 const int icon_id = BKE_icon_geom_ensure(geom);
129 return PyLong_FromLong(icon_id);
132 PyDoc_STRVAR(
133 /* Wrap. */
134 bpy_app_icons_release_doc,
135 ".. function:: release(icon_id)\n"
136 "\n"
137 " Release the icon.\n");
138 static PyObject *bpy_app_icons_release(PyObject * /*self*/, PyObject *args, PyObject *kw)
140 int icon_id;
141 static const char *_keywords[] = {"icon_id", nullptr};
142 static _PyArg_Parser _parser = {
143 PY_ARG_PARSER_HEAD_COMPAT()
144 "i" /* `icon_id` */
145 ":release",
146 _keywords,
147 nullptr,
149 if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &icon_id)) {
150 return nullptr;
153 if (!BKE_icon_delete_unmanaged(icon_id)) {
154 PyErr_SetString(PyExc_ValueError, "invalid icon_id");
155 return nullptr;
157 Py_RETURN_NONE;
160 #if (defined(__GNUC__) && !defined(__clang__))
161 # pragma GCC diagnostic push
162 # pragma GCC diagnostic ignored "-Wcast-function-type"
163 #endif
165 static PyMethodDef M_AppIcons_methods[] = {
166 {"new_triangles",
167 (PyCFunction)bpy_app_icons_new_triangles,
168 METH_VARARGS | METH_KEYWORDS,
169 bpy_app_icons_new_triangles_doc},
170 {"new_triangles_from_file",
171 (PyCFunction)bpy_app_icons_new_triangles_from_file,
172 METH_VARARGS | METH_KEYWORDS,
173 bpy_app_icons_new_triangles_from_file_doc},
174 {"release",
175 (PyCFunction)bpy_app_icons_release,
176 METH_VARARGS | METH_KEYWORDS,
177 bpy_app_icons_release_doc},
178 {nullptr, nullptr, 0, nullptr},
181 #if (defined(__GNUC__) && !defined(__clang__))
182 # pragma GCC diagnostic pop
183 #endif
185 static PyModuleDef M_AppIcons_module_def = {
186 /*m_base*/ PyModuleDef_HEAD_INIT,
187 /*m_name*/ "bpy.app.icons",
188 /*m_doc*/ nullptr,
189 /*m_size*/ 0,
190 /*m_methods*/ M_AppIcons_methods,
191 /*m_slots*/ nullptr,
192 /*m_traverse*/ nullptr,
193 /*m_clear*/ nullptr,
194 /*m_free*/ nullptr,
197 PyObject *BPY_app_icons_module()
199 PyObject *sys_modules = PyImport_GetModuleDict();
201 PyObject *mod = PyModule_Create(&M_AppIcons_module_def);
203 PyDict_SetItem(sys_modules, PyModule_GetNameObject(mod), mod);
205 return mod;