Blender V5.0
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 "ANIM_action.hh"
17
19#include "interface_intern.hh"
21
24
31
32static void template_search_exec_fn(bContext *C, void *arg_template, void *item)
33{
34 TemplateSearch *template_search = static_cast<TemplateSearch *>(arg_template);
35 uiRNACollectionSearch *coll_search = &template_search->search_data;
36 StructRNA *type = RNA_property_pointer_type(&coll_search->target_ptr, coll_search->target_prop);
37
38 PointerRNA item_ptr = RNA_pointer_create_discrete(nullptr, type, item);
39 RNA_property_pointer_set(&coll_search->target_ptr, coll_search->target_prop, item_ptr, nullptr);
40 RNA_property_update(C, &coll_search->target_ptr, coll_search->target_prop);
41}
42
43static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_template)
44{
45 static TemplateSearch template_search;
46
47 /* arg_template is malloced, can be freed by parent button */
48 template_search = *((TemplateSearch *)arg_template);
49 PointerRNA active_ptr = RNA_property_pointer_get(&template_search.search_data.target_ptr,
50 template_search.search_data.target_prop);
51
53 region,
55 &template_search,
57 active_ptr.data,
58 nullptr,
59 template_search.preview_rows,
60 template_search.preview_cols,
61 1.0f);
62}
63
65 uiLayout *layout,
66 uiBlock *block,
67 TemplateSearch &template_search,
68 const bool editable,
69 const bool live_icon)
70{
71 const StringRef ui_description = RNA_property_ui_description(
72 template_search.search_data.target_prop);
73
75 layout,
76 block,
77 &template_search.search_data.target_ptr,
78 template_search.search_data.target_prop,
80 MEM_new<TemplateSearch>(__func__, template_search),
81 ui_description,
82 template_search.use_previews,
83 editable,
84 live_icon,
87}
88
90 PointerRNA *active_ptr,
91 const StructRNA *type)
92{
93 /* Skip text button without an active item. */
94 if (active_ptr->data == nullptr) {
95 return;
96 }
97
98 int iconid = ICON_NONE;
99
100 PropertyRNA *name_prop;
101 if (type == &RNA_ActionSlot) {
102 name_prop = RNA_struct_find_property(active_ptr, "name_display");
103 /* Also show an icon for the data-block type that each slot is intended for. */
104 blender::animrig::Slot &slot = reinterpret_cast<ActionSlot *>(active_ptr->data)->wrap();
105 iconid = UI_icon_from_idcode(slot.idtype);
106 }
107 else {
108 name_prop = RNA_struct_name_property(type);
109 }
110
111 const int width = template_search_textbut_width(active_ptr, name_prop);
112 const int height = template_search_textbut_height();
113 uiDefAutoButR(block, active_ptr, name_prop, 0, "", iconid, 0, 0, width, height);
114}
115
117 uiBlock *block,
118 const char *const operator_name,
119 const blender::wm::OpCallContext opcontext,
120 const int icon,
121 const bool editable,
122 const std::optional<StringRefNull> button_text = {})
123{
124 if (!operator_name) {
125 return;
126 }
127
128 uiBut *but;
129 if (button_text) {
130 const int button_width = std::max(
131 UI_fontstyle_string_width(UI_FSTYLE_WIDGET, button_text->c_str()) + int(UI_UNIT_X * 1.5f),
132 UI_UNIT_X * 5);
133
134 but = uiDefIconTextButO(block,
136 operator_name,
137 opcontext,
138 icon,
139 *button_text,
140 0,
141 0,
142 button_width,
143 UI_UNIT_Y,
144 std::nullopt);
145 }
146 else {
147 but = uiDefIconButO(block,
149 operator_name,
150 opcontext,
151 icon,
152 0,
153 0,
154 UI_UNIT_X,
155 UI_UNIT_Y,
156 std::nullopt);
157 }
158
159 if (!editable) {
161 }
162}
163
165 uiLayout *layout,
166 TemplateSearch &template_search,
167 const char *newop,
168 const char *unlinkop,
169 const std::optional<StringRef> text)
170{
171 uiBlock *block = layout->block();
172 uiRNACollectionSearch *search_data = &template_search.search_data;
173 const StructRNA *type = RNA_property_pointer_type(&search_data->target_ptr,
174 search_data->target_prop);
175 const bool editable = RNA_property_editable(&search_data->target_ptr, search_data->target_prop);
176 PointerRNA active_ptr = RNA_property_pointer_get(&search_data->target_ptr,
177 search_data->target_prop);
178
179 if (active_ptr.type) {
180 /* can only get correct type when there is an active item */
181 type = active_ptr.type;
182 }
183
184 uiLayout *row = &layout->row(true);
186
187 uiLayout *decorator_layout = nullptr;
188 if (text && !text->is_empty()) {
189 /* Add label respecting the separated layout property split state. */
190 decorator_layout = uiItemL_respect_property_split(row, *text, ICON_NONE);
191 }
192
193 template_search_add_button_searchmenu(C, row, block, template_search, editable, false);
194 template_search_add_button_name(block, &active_ptr, type);
195
196 /* For Blender 4.4, the "New" button is only shown on Action Slot selectors.
197 * Blender 4.5 may have this enabled for all uses of this template, in which
198 * case this type-specific code will be removed. */
199 const bool may_show_new_button = (type == &RNA_ActionSlot);
200 if (may_show_new_button && !active_ptr.data) {
202 newop,
204 ICON_ADD,
205 editable,
206 IFACE_("New"));
207 }
208 else {
210 block, newop, blender::wm::OpCallContext::InvokeDefault, ICON_DUPLICATE, editable);
212 block, unlinkop, blender::wm::OpCallContext::InvokeRegionWin, ICON_X, editable);
213 }
214
215 UI_block_align_end(block);
216
217 if (decorator_layout) {
218 decorator_layout->decorator(nullptr, "", RNA_NO_INDEX);
219 }
220}
221
223 PropertyRNA *targetprop,
224 PointerRNA *searchptr,
225 const char *const searchpropname)
226{
227 PropertyRNA *searchprop;
228
229 if (searchptr && !searchptr->data) {
230 searchptr = nullptr;
231 }
232
233 if (!searchptr && !searchpropname) {
234 /* both nullptr means we don't use a custom rna collection to search in */
235 }
236 else if (!searchptr && searchpropname) {
237 RNA_warning("searchpropname defined (%s) but searchptr is missing", searchpropname);
238 }
239 else if (searchptr && !searchpropname) {
240 RNA_warning("searchptr defined (%s) but searchpropname is missing",
241 RNA_struct_identifier(searchptr->type));
242 }
243 else if (!(searchprop = RNA_struct_find_property(searchptr, searchpropname))) {
244 RNA_warning("search collection property not found: %s.%s",
245 RNA_struct_identifier(searchptr->type),
246 searchpropname);
247 }
248 else if (RNA_property_type(searchprop) != PROP_COLLECTION) {
249 RNA_warning("search collection property is not a collection type: %s.%s",
250 RNA_struct_identifier(searchptr->type),
251 searchpropname);
252 }
253 /* check if searchprop has same type as targetprop */
254 else if (RNA_property_pointer_type(searchptr, searchprop) !=
255 RNA_property_pointer_type(targetptr, targetprop))
256 {
257 RNA_warning("search collection items from %s.%s are not of type %s",
258 RNA_struct_identifier(searchptr->type),
259 searchpropname,
260 RNA_struct_identifier(RNA_property_pointer_type(targetptr, targetprop)));
261 }
262 else {
263 return searchprop;
264 }
265
266 return nullptr;
267}
268
269static bool template_search_setup(TemplateSearch &template_search,
271 const StringRefNull propname,
272 PointerRNA *searchptr,
273 const char *const searchpropname)
274{
275 template_search = {};
276 PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str());
277
278 if (!prop || RNA_property_type(prop) != PROP_POINTER) {
280 "pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
281 return false;
282 }
283 PropertyRNA *searchprop = template_search_get_searchprop(ptr, prop, searchptr, searchpropname);
284
285 template_search.search_data.target_ptr = *ptr;
286 template_search.search_data.target_prop = prop;
287 template_search.search_data.search_ptr = *searchptr;
288 template_search.search_data.search_prop = searchprop;
289
290 return true;
291}
292
294 const bContext *C,
296 const StringRefNull propname,
297 PointerRNA *searchptr,
298 const char *searchpropname,
299 const char *newop,
300 const char *unlinkop,
301 const std::optional<StringRef> text)
302{
303 TemplateSearch template_search;
304 if (template_search_setup(template_search, ptr, propname, searchptr, searchpropname)) {
305 template_search_buttons(C, layout, template_search, newop, unlinkop, text);
306 }
307}
308
310 bContext *C,
312 const StringRefNull propname,
313 PointerRNA *searchptr,
314 const char *searchpropname,
315 const char *newop,
316 const char *unlinkop,
317 const int rows,
318 const int cols,
319 const std::optional<StringRef> text)
320{
321 TemplateSearch template_search;
322 if (template_search_setup(template_search, ptr, propname, searchptr, searchpropname)) {
323 template_search.use_previews = true;
324 template_search.preview_rows = rows;
325 template_search.preview_cols = cols;
326
327 template_search_buttons(C, layout, template_search, newop, unlinkop, text);
328 }
329}
Functions and classes to work with Actions.
#define IFACE_(msgid)
#define RNA_warning(format,...)
@ PROP_POINTER
Definition RNA_types.hh:167
@ PROP_COLLECTION
Definition RNA_types.hh:168
#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
@ UI_BUT_DISABLED
void UI_but_drawflag_enable(uiBut *but, int flag)
uiBut * uiDefIconTextButO(uiBlock *block, ButType type, blender::StringRefNull, blender::wm::OpCallContext opcontext, int icon, blender::StringRef str, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
uiBut * uiDefIconButO(uiBlock *block, ButType type, blender::StringRefNull opname, blender::wm::OpCallContext opcontext, int icon, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
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)
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
void UI_block_align_end(uiBlock *block)
int UI_icon_from_idcode(int idcode)
uiLayout * uiItemL_respect_property_split(uiLayout *layout, blender::StringRef text, int icon)
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_operator(uiBlock *block, const char *const operator_name, const blender::wm::OpCallContext opcontext, const int icon, const bool editable, const std::optional< StringRefNull > button_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)
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)
float wrap(float value, float max, float min)
Definition node_math.h:103
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
void decorator(PointerRNA *ptr, PropertyRNA *prop, int index)
uiBlock * block() const
uiLayout & row(bool align)
PointerRNA * ptr
Definition wm_files.cc:4238