1 /* SPDX-FileCopyrightText: 2023 Blender Authors
3 * SPDX-License-Identifier: GPL-2.0-or-later */
6 * \ingroup pythonintern
8 * Runtime defined icons.
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. */
25 bpy_app_icons_new_triangles_doc
,
26 ".. function:: new_triangles(range, coords, colors)\n"
28 " Create a new icon from triangle geometry.\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"
38 static PyObject
*bpy_app_icons_new_triangles(PyObject
* /*self*/, PyObject
*args
, PyObject
*kw
)
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()
54 if (!_PyArg_ParseTupleAndKeywordsFast(
55 args
, kw
, &_parser
, &coords_range
[0], &coords_range
[1], &py_coords
, &py_colors
))
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");
66 if (PyBytes_GET_SIZE(py_colors
) != 2 * coords_len
) {
67 PyErr_SetString(PyExc_ValueError
, "colors must be twice size of coords");
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
;
86 const int icon_id
= BKE_icon_geom_ensure(geom
);
87 return PyLong_FromLong(icon_id
);
92 bpy_app_icons_new_triangles_from_file_doc
,
93 ".. function:: new_triangles_from_file(filepath)\n"
95 " Create a new icon from triangle geometry.\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"
101 static PyObject
*bpy_app_icons_new_triangles_from_file(PyObject
* /*self*/,
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",
115 if (!_PyArg_ParseTupleAndKeywordsFast(
116 args
, kw
, &_parser
, PyC_ParseUnicodeAsBytesAndSize
, &filepath_data
))
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");
128 const int icon_id
= BKE_icon_geom_ensure(geom
);
129 return PyLong_FromLong(icon_id
);
134 bpy_app_icons_release_doc
,
135 ".. function:: release(icon_id)\n"
137 " Release the icon.\n");
138 static PyObject
*bpy_app_icons_release(PyObject
* /*self*/, PyObject
*args
, PyObject
*kw
)
141 static const char *_keywords
[] = {"icon_id", nullptr};
142 static _PyArg_Parser _parser
= {
143 PY_ARG_PARSER_HEAD_COMPAT()
149 if (!_PyArg_ParseTupleAndKeywordsFast(args
, kw
, &_parser
, &icon_id
)) {
153 if (!BKE_icon_delete_unmanaged(icon_id
)) {
154 PyErr_SetString(PyExc_ValueError
, "invalid icon_id");
160 #if (defined(__GNUC__) && !defined(__clang__))
161 # pragma GCC diagnostic push
162 # pragma GCC diagnostic ignored "-Wcast-function-type"
165 static PyMethodDef M_AppIcons_methods
[] = {
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
},
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
185 static PyModuleDef M_AppIcons_module_def
= {
186 /*m_base*/ PyModuleDef_HEAD_INIT
,
187 /*m_name*/ "bpy.app.icons",
190 /*m_methods*/ M_AppIcons_methods
,
192 /*m_traverse*/ 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
);