Blender V4.5
interface_template_search.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_string_ref.hh"
10
11#include "RNA_access.hh"
12#include "RNA_prototypes.hh"
13
14#include "BLT_translation.hh"
15
16#include "UI_interface.hh"
17#include "interface_intern.hh"
19
22
29
30static void template_search_exec_fn(bContext *C, void *arg_template, void *item)
31{
32 TemplateSearch *template_search = static_cast<TemplateSearch *>(arg_template);
33 uiRNACollectionSearch *coll_search = &template_search->search_data;
34 StructRNA *type = RNA_property_pointer_type(&coll_search->target_ptr, coll_search->target_prop);
35
36 PointerRNA item_ptr = RNA_pointer_create_discrete(nullptr, type, item);
37 RNA_property_pointer_set(&coll_search->target_ptr, coll_search->target_prop, item_ptr, nullptr);
38 RNA_property_update(C, &coll_search->target_ptr, coll_search->target_prop);
39}
40
41static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_template)
42{
43 static TemplateSearch template_search;
44
45 /* arg_template is malloced, can be freed by parent button */
46 template_search = *((TemplateSearch *)arg_template);
47 PointerRNA active_ptr = RNA_property_pointer_get(&template_search.search_data.target_ptr,
48 template_search.search_data.target_prop);
49
51 region,
53 &template_search,
55 active_ptr.data,
56 nullptr,
57 template_search.preview_rows,
58 template_search.preview_cols,
59 1.0f);
60}
61
63 uiLayout *layout,
64 uiBlock *block,
65 TemplateSearch &template_search,
66 const bool editable,
67 const bool live_icon)
68{
69 const StringRef ui_description = RNA_property_ui_description(
70 template_search.search_data.target_prop);
71
73 layout,
74 block,
75 &template_search.search_data.target_ptr,
76 template_search.search_data.target_prop,
78 MEM_new<TemplateSearch>(__func__, template_search),
79 ui_description,
80 template_search.use_previews,
81 editable,
82 live_icon,
85}
86
88 PointerRNA *active_ptr,
89 const StructRNA *type)
90{
91 /* Skip text button without an active item. */
92 if (active_ptr->data == nullptr) {
93 return;
94 }
95
96 PropertyRNA *name_prop;
97 if (type == &RNA_ActionSlot) {
98 name_prop = RNA_struct_find_property(active_ptr, "name_display");
99 }
100 else {
101 name_prop = RNA_struct_name_property(type);
102 }
103
104 const int width = template_search_textbut_width(active_ptr, name_prop);
105 const int height = template_search_textbut_height();
106 uiDefAutoButR(block, active_ptr, name_prop, 0, "", ICON_NONE, 0, 0, width, height);
107}
108
110 uiBlock *block,
111 const char *const operator_name,
112 const wmOperatorCallContext opcontext,
113 const int icon,
114 const bool editable,
115 const std::optional<StringRefNull> button_text = {})
116{
117 if (!operator_name) {
118 return;
119 }
120
121 uiBut *but;
122 if (button_text) {
123 const int button_width = std::max(
124 UI_fontstyle_string_width(UI_FSTYLE_WIDGET, button_text->c_str()) + int(UI_UNIT_X * 1.5f),
125 UI_UNIT_X * 5);
126
127 but = uiDefIconTextButO(block,
129 operator_name,
130 opcontext,
131 icon,
132 *button_text,
133 0,
134 0,
135 button_width,
136 UI_UNIT_Y,
137 std::nullopt);
138 }
139 else {
140 but = uiDefIconButO(block,
142 operator_name,
143 opcontext,
144 icon,
145 0,
146 0,
147 UI_UNIT_X,
148 UI_UNIT_Y,
149 std::nullopt);
150 }
151
152 if (!editable) {
154 }
155}
156
158 uiLayout *layout,
159 TemplateSearch &template_search,
160 const char *newop,
161 const char *unlinkop,
162 const std::optional<StringRef> text)
163{
164 uiBlock *block = uiLayoutGetBlock(layout);
165 uiRNACollectionSearch *search_data = &template_search.search_data;
166 const StructRNA *type = RNA_property_pointer_type(&search_data->target_ptr,
167 search_data->target_prop);
168 const bool editable = RNA_property_editable(&search_data->target_ptr, search_data->target_prop);
169 PointerRNA active_ptr = RNA_property_pointer_get(&search_data->target_ptr,
170 search_data->target_prop);
171
172 if (active_ptr.type) {
173 /* can only get correct type when there is an active item */
174 type = active_ptr.type;
175 }
176
177 uiLayout *row = &layout->row(true);
179
180 uiLayout *decorator_layout = nullptr;
181 if (text && !text->is_empty()) {
182 /* Add label respecting the separated layout property split state. */
183 decorator_layout = uiItemL_respect_property_split(row, *text, ICON_NONE);
184 }
185
186 template_search_add_button_searchmenu(C, row, block, template_search, editable, false);
187 template_search_add_button_name(block, &active_ptr, type);
188
189 /* For Blender 4.4, the "New" button is only shown on Action Slot selectors.
190 * Blender 4.5 may have this enabled for all uses of this template, in which
191 * case this type-specific code will be removed. */
192 const bool may_show_new_button = (type == &RNA_ActionSlot);
193 if (may_show_new_button && !active_ptr.data) {
195 block, newop, WM_OP_INVOKE_DEFAULT, ICON_ADD, editable, IFACE_("New"));
196 }
197 else {
199 block, newop, WM_OP_INVOKE_DEFAULT, ICON_DUPLICATE, editable);
201 block, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, editable);
202 }
203
204 UI_block_align_end(block);
205
206 if (decorator_layout) {
207 uiItemDecoratorR(decorator_layout, nullptr, "", RNA_NO_INDEX);
208 }
209}
210
212 PropertyRNA *targetprop,
213 PointerRNA *searchptr,
214 const char *const searchpropname)
215{
216 PropertyRNA *searchprop;
217
218 if (searchptr && !searchptr->data) {
219 searchptr = nullptr;
220 }
221
222 if (!searchptr && !searchpropname) {
223 /* both nullptr means we don't use a custom rna collection to search in */
224 }
225 else if (!searchptr && searchpropname) {
226 RNA_warning("searchpropname defined (%s) but searchptr is missing", searchpropname);
227 }
228 else if (searchptr && !searchpropname) {
229 RNA_warning("searchptr defined (%s) but searchpropname is missing",
230 RNA_struct_identifier(searchptr->type));
231 }
232 else if (!(searchprop = RNA_struct_find_property(searchptr, searchpropname))) {
233 RNA_warning("search collection property not found: %s.%s",
234 RNA_struct_identifier(searchptr->type),
235 searchpropname);
236 }
237 else if (RNA_property_type(searchprop) != PROP_COLLECTION) {
238 RNA_warning("search collection property is not a collection type: %s.%s",
239 RNA_struct_identifier(searchptr->type),
240 searchpropname);
241 }
242 /* check if searchprop has same type as targetprop */
243 else if (RNA_property_pointer_type(searchptr, searchprop) !=
244 RNA_property_pointer_type(targetptr, targetprop))
245 {
246 RNA_warning("search collection items from %s.%s are not of type %s",
247 RNA_struct_identifier(searchptr->type),
248 searchpropname,
249 RNA_struct_identifier(RNA_property_pointer_type(targetptr, targetprop)));
250 }
251 else {
252 return searchprop;
253 }
254
255 return nullptr;
256}
257
258static bool template_search_setup(TemplateSearch &template_search,
260 const StringRefNull propname,
261 PointerRNA *searchptr,
262 const char *const searchpropname)
263{
264 template_search = {};
265 PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str());
266
267 if (!prop || RNA_property_type(prop) != PROP_POINTER) {
269 "pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
270 return false;
271 }
272 PropertyRNA *searchprop = template_search_get_searchprop(ptr, prop, searchptr, searchpropname);
273
274 template_search.search_data.target_ptr = *ptr;
275 template_search.search_data.target_prop = prop;
276 template_search.search_data.search_ptr = *searchptr;
277 template_search.search_data.search_prop = searchprop;
278
279 return true;
280}
281
283 const bContext *C,
285 const StringRefNull propname,
286 PointerRNA *searchptr,
287 const char *searchpropname,
288 const char *newop,
289 const char *unlinkop,
290 const std::optional<StringRef> text)
291{
292 TemplateSearch template_search;
293 if (template_search_setup(template_search, ptr, propname, searchptr, searchpropname)) {
294 template_search_buttons(C, layout, template_search, newop, unlinkop, text);
295 }
296}
297
299 bContext *C,
301 const StringRefNull propname,
302 PointerRNA *searchptr,
303 const char *searchpropname,
304 const char *newop,
305 const char *unlinkop,
306 const int rows,
307 const int cols,
308 const std::optional<StringRef> text)
309{
310 TemplateSearch template_search;
311 if (template_search_setup(template_search, ptr, propname, searchptr, searchpropname)) {
312 template_search.use_previews = true;
313 template_search.preview_rows = rows;
314 template_search.preview_cols = cols;
315
316 template_search_buttons(C, layout, template_search, newop, unlinkop, text);
317 }
318}
#define IFACE_(msgid)
#define RNA_warning(format,...)
@ PROP_POINTER
Definition RNA_types.hh:155
@ PROP_COLLECTION
Definition RNA_types.hh:156
#define C
Definition RandGen.cpp:29
void * but_func_argN_copy(const void *argN)
void but_func_argN_free(void *argN)
#define UI_UNIT_Y
void UI_but_drawflag_enable(uiBut *but, int flag)
uiBut * uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int index, std::optional< blender::StringRef > name, int icon, int x, int y, int width, int height)
uiBut * uiDefIconButO(uiBlock *block, int type, blender::StringRefNull opname, wmOperatorCallContext opcontext, int icon, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
void UI_block_align_begin(uiBlock *block)
int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
#define UI_FSTYLE_WIDGET
#define UI_UNIT_X
@ UI_BTYPE_BUT
@ UI_BUT_DISABLED
uiBut * uiDefIconTextButO(uiBlock *block, int type, blender::StringRefNull, wmOperatorCallContext opcontext, int icon, blender::StringRef str, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
void UI_block_align_end(uiBlock *block)
void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, std::optional< blender::StringRefNull > propname, int index)
uiLayout * uiItemL_respect_property_split(uiLayout *layout, blender::StringRef text, int icon)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
wmOperatorCallContext
Definition WM_types.hh:236
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:239
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
constexpr const char * c_str() const
#define RNA_NO_INDEX
void ui_rna_collection_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first)
static void template_search_buttons(const bContext *C, uiLayout *layout, TemplateSearch &template_search, const char *newop, const char *unlinkop, const std::optional< StringRef > text)
static uiBlock * template_search_menu(bContext *C, ARegion *region, void *arg_template)
static void template_search_exec_fn(bContext *C, void *arg_template, void *item)
static bool template_search_setup(TemplateSearch &template_search, PointerRNA *ptr, const StringRefNull propname, PointerRNA *searchptr, const char *const searchpropname)
void uiTemplateSearchPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const StringRefNull propname, PointerRNA *searchptr, const char *searchpropname, const char *newop, const char *unlinkop, const int rows, const int cols, const std::optional< StringRef > text)
static void template_search_add_button_searchmenu(const bContext *C, uiLayout *layout, uiBlock *block, TemplateSearch &template_search, const bool editable, const bool live_icon)
static void template_search_add_button_name(uiBlock *block, PointerRNA *active_ptr, const StructRNA *type)
static PropertyRNA * template_search_get_searchprop(PointerRNA *targetptr, PropertyRNA *targetprop, PointerRNA *searchptr, const char *const searchpropname)
static void template_search_add_button_operator(uiBlock *block, const char *const operator_name, const wmOperatorCallContext opcontext, const int icon, const bool editable, const std::optional< StringRefNull > button_text={})
void uiTemplateSearch(uiLayout *layout, const bContext *C, PointerRNA *ptr, const StringRefNull propname, PointerRNA *searchptr, const char *searchpropname, const char *newop, const char *unlinkop, const std::optional< StringRef > text)
void template_add_button_search_menu(const bContext *C, uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, uiBlockCreateFunc block_func, void *block_argN, const std::optional< blender::StringRef > tip, const bool use_previews, const bool editable, const bool live_icon, uiButArgNFree func_argN_free_fn, uiButArgNCopy func_argN_copy_fn)
int template_search_textbut_height()
int template_search_textbut_width(PointerRNA *ptr, PropertyRNA *name_prop)
uiBlock * template_common_search_menu(const bContext *C, ARegion *region, uiButSearchUpdateFn search_update_fn, void *search_arg, uiButHandleFunc search_exec_fn, void *active_item, uiButSearchTooltipFn item_tooltip_fn, const int preview_rows, const int preview_cols, float scale)
const char * RNA_property_ui_description(const PropertyRNA *prop)
StructRNA * RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
PropertyType RNA_property_type(PropertyRNA *prop)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_struct_identifier(const StructRNA *type)
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
PropertyRNA * RNA_struct_name_property(const StructRNA *type)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
StructRNA * type
Definition RNA_types.hh:52
void * data
Definition RNA_types.hh:53
uiRNACollectionSearch search_data
uiLayout & row(bool align)
PointerRNA * ptr
Definition wm_files.cc:4226