Blender V4.3
interface_region_menu_pie.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <cstdarg>
12#include <cstdlib>
13#include <cstring>
14
15#include "MEM_guardedalloc.h"
16
17#include "DNA_userdef_types.h"
18
19#include "BLI_blenlib.h"
20#include "BLI_time.h"
21#include "BLI_utildefines.h"
22
23#include "BKE_context.hh"
24#include "BKE_screen.hh"
25
26#include "WM_api.hh"
27#include "WM_types.hh"
28
29#include "RNA_access.hh"
30#include "RNA_path.hh"
31#include "RNA_prototypes.hh"
32
33#include "UI_interface.hh"
34
35#include "BLT_translation.hh"
36
37#include "interface_intern.hh"
39
40/* -------------------------------------------------------------------- */
44struct uiPieMenu {
45 uiBlock *pie_block; /* radial block of the pie menu (more could be added later) */
47 int mx, my;
48};
49
50static uiBlock *ui_block_func_PIE(bContext * /*C*/, uiPopupBlockHandle *handle, void *arg_pie)
51{
52 uiBlock *block;
53 uiPieMenu *pie = static_cast<uiPieMenu *>(arg_pie);
54 int minwidth, width, height;
55
56 minwidth = UI_MENU_WIDTH_MIN;
57 block = pie->pie_block;
58
59 /* in some cases we create the block before the region,
60 * so we set it delayed here if necessary */
61 if (BLI_findindex(&handle->region->uiblocks, block) == -1) {
62 UI_block_region_set(block, handle->region);
63 }
64
65 UI_block_layout_resolve(block, &width, &height);
66
69
70 block->minbounds = minwidth;
71 block->bounds = 1;
72 block->bounds_offset[0] = 0;
73 block->bounds_offset[1] = 0;
75
76 block->pie_data.pie_center_spawned[0] = pie->mx;
77 block->pie_data.pie_center_spawned[1] = pie->my;
78
79 return pie->pie_block;
80}
81
82static float ui_pie_menu_title_width(const char *name, int icon)
83{
84 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
85 return (UI_fontstyle_string_width(fstyle, name) + (UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f))));
86}
87
88uiPieMenu *UI_pie_menu_begin(bContext *C, const char *title, int icon, const wmEvent *event)
89{
90 const uiStyle *style = UI_style_get_dpi();
91 short event_type;
92
93 wmWindow *win = CTX_wm_window(C);
94
95 uiPieMenu *pie = MEM_cnew<uiPieMenu>(__func__);
96
97 pie->pie_block = UI_block_begin(C, nullptr, __func__, UI_EMBOSS);
98 /* may be useful later to allow spawning pies
99 * from old positions */
100 // pie->pie_block->flag |= UI_BLOCK_POPUP_MEMORY;
101 pie->pie_block->puphash = ui_popup_menu_hash(title);
103
104 /* if pie is spawned by a left click, release or click event,
105 * it is always assumed to be click style */
106 if (event->type == LEFTMOUSE || ELEM(event->val, KM_RELEASE, KM_CLICK)) {
110 }
111 else {
112 if (win->pie_event_type_last != EVENT_NONE) {
113 /* original pie key has been released, so don't propagate the event */
114 if (win->pie_event_type_lock == EVENT_NONE) {
115 event_type = EVENT_NONE;
117 }
118 else {
119 event_type = win->pie_event_type_last;
120 }
121 }
122 else {
123 event_type = event->type;
124 }
125
126 pie->pie_block->pie_data.event_type = event_type;
127 win->pie_event_type_lock = event_type;
128 }
129
130 pie->layout = UI_block_layout(
131 pie->pie_block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
132
133 /* NOTE: #wmEvent.xy is where we started dragging in case of #KM_CLICK_DRAG. */
134 pie->mx = event->xy[0];
135 pie->my = event->xy[1];
136
137 /* create title button */
138 if (title[0]) {
139 uiBut *but;
140 char titlestr[256];
141 int w;
142 if (icon) {
143 SNPRINTF(titlestr, " %s", title);
144 w = ui_pie_menu_title_width(titlestr, icon);
145 but = uiDefIconTextBut(pie->pie_block,
147 0,
148 icon,
149 titlestr,
150 0,
151 0,
152 w,
153 UI_UNIT_Y,
154 nullptr,
155 0.0,
156 0.0,
157 "");
158 }
159 else {
160 w = ui_pie_menu_title_width(title, 0);
161 but = uiDefBut(
162 pie->pie_block, UI_BTYPE_LABEL, 0, title, 0, 0, w, UI_UNIT_Y, nullptr, 0.0, 0.0, "");
163 }
164 /* do not align left */
165 but->drawflag &= ~UI_BUT_TEXT_LEFT;
166 pie->pie_block->pie_data.title = but->str.c_str();
167 pie->pie_block->pie_data.icon = icon;
168 }
169
170 return pie;
171}
172
174{
175 wmWindow *window = CTX_wm_window(C);
176
178 C, nullptr, nullptr, nullptr, ui_block_func_PIE, pie, nullptr, false);
179 menu->popup = true;
181
184
185 MEM_freeN(pie);
186}
187
189{
190 return pie->layout;
191}
192
193int UI_pie_menu_invoke(bContext *C, const char *idname, const wmEvent *event)
194{
195 uiPieMenu *pie;
196 uiLayout *layout;
197 MenuType *mt = WM_menutype_find(idname, true);
198
199 if (mt == nullptr) {
200 printf("%s: named menu \"%s\" not found\n", __func__, idname);
201 return OPERATOR_CANCELLED;
202 }
203
204 if (WM_menutype_poll(C, mt) == false) {
205 /* cancel but allow event to pass through, just like operators do */
207 }
208
209 pie = UI_pie_menu_begin(C, CTX_IFACE_(mt->translation_context, mt->label), ICON_NONE, event);
210 layout = UI_pie_menu_layout(pie);
211
212 UI_menutype_draw(C, mt, layout);
213
214 UI_pie_menu_end(C, pie);
215
216 return OPERATOR_INTERFACE;
217}
218
220 bContext *C, const char *title, const char *opname, const char *propname, const wmEvent *event)
221{
222 uiPieMenu *pie;
223 uiLayout *layout;
224
225 pie = UI_pie_menu_begin(C, IFACE_(title), ICON_NONE, event);
226 layout = UI_pie_menu_layout(pie);
227
228 layout = uiLayoutRadial(layout);
229 uiItemsEnumO(layout, opname, propname);
230
231 UI_pie_menu_end(C, pie);
232
233 return OPERATOR_INTERFACE;
234}
235
237 const char *title,
238 const char *path,
239 const wmEvent *event)
240{
241 PointerRNA r_ptr;
242 PropertyRNA *r_prop;
243 uiPieMenu *pie;
244 uiLayout *layout;
245
246 PointerRNA ctx_ptr = RNA_pointer_create(nullptr, &RNA_Context, C);
247
248 if (!RNA_path_resolve(&ctx_ptr, path, &r_ptr, &r_prop)) {
249 return OPERATOR_CANCELLED;
250 }
251
252 /* invalid property, only accept enums */
253 if (RNA_property_type(r_prop) != PROP_ENUM) {
254 BLI_assert(0);
255 return OPERATOR_CANCELLED;
256 }
257
258 pie = UI_pie_menu_begin(C, IFACE_(title), ICON_NONE, event);
259
260 layout = UI_pie_menu_layout(pie);
261
262 layout = uiLayoutRadial(layout);
263 uiItemFullR(layout, &r_ptr, r_prop, RNA_NO_INDEX, 0, UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
264
265 UI_pie_menu_end(C, pie);
266
267 return OPERATOR_INTERFACE;
268}
269
272/* -------------------------------------------------------------------- */
288 char title[UI_MAX_NAME_STR]; /* parent pie title, copied for level */
289 int icon; /* parent pie icon, copied for level */
290 int totitem; /* total count of *remaining* items */
291
292 /* needed for calling uiItemsFullEnumO_array again for new level */
294 const char *propname;
298};
299
303static void ui_pie_menu_level_invoke(bContext *C, void *argN, void *arg2)
304{
305 EnumPropertyItem *item_array = (EnumPropertyItem *)argN;
306 PieMenuLevelData *lvl = (PieMenuLevelData *)arg2;
307 wmWindow *win = CTX_wm_window(C);
308
309 uiPieMenu *pie = UI_pie_menu_begin(C, IFACE_(lvl->title), lvl->icon, win->eventstate);
310 uiLayout *layout = UI_pie_menu_layout(pie);
311
312 layout = uiLayoutRadial(layout);
313
315
317 /* So the context is passed to `itemf` functions (some need it). */
320
321 if (prop) {
323 lvl->ot,
324 ptr,
325 prop,
326 lvl->properties,
327 lvl->context,
328 lvl->flag,
329 item_array,
330 lvl->totitem);
331 }
332 else {
333 RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), lvl->propname);
334 }
335
336 UI_pie_menu_end(C, pie);
337}
338
341 const char *propname,
342 IDProperty *properties,
343 const EnumPropertyItem *items,
344 int totitem,
345 const wmOperatorCallContext context,
346 const eUI_Item_Flag flag)
347{
348 const int totitem_parent = PIE_MAX_ITEMS - 1;
349 const int totitem_remain = totitem - totitem_parent;
350 const size_t array_size = sizeof(EnumPropertyItem) * totitem_remain;
351
352 /* used as but->func_argN so freeing is handled elsewhere */
353 EnumPropertyItem *remaining = static_cast<EnumPropertyItem *>(
354 MEM_mallocN(array_size + sizeof(EnumPropertyItem), "pie_level_item_array"));
355 memcpy(remaining, items + totitem_parent, array_size);
356 /* A null terminating sentinel element is required. */
357 memset(&remaining[totitem_remain], 0, sizeof(EnumPropertyItem));
358
359 /* yuk, static... issue is we can't reliably free this without doing dangerous changes */
360 static PieMenuLevelData lvl;
361 STRNCPY(lvl.title, block->pie_data.title);
362 lvl.totitem = totitem_remain;
363 lvl.ot = ot;
364 lvl.propname = propname;
365 lvl.properties = properties;
366 lvl.context = context;
367 lvl.flag = flag;
368
369 /* add a 'more' menu entry */
370 uiBut *but = uiDefIconTextBut(block,
372 0,
373 ICON_PLUS,
374 "More",
375 0,
376 0,
377 UI_UNIT_X * 3,
378 UI_UNIT_Y,
379 nullptr,
380 0.0f,
381 0.0f,
382 "Show more items of this menu");
383 UI_but_funcN_set(but, ui_pie_menu_level_invoke, remaining, &lvl);
384}
385
386 /* Pie Menu Levels */
wmWindow * CTX_wm_window(const bContext *C)
#define BLI_assert(a)
Definition BLI_assert.h:50
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
#define ELEM(...)
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
@ OPERATOR_PASS_THROUGH
Read Guarded memory(de)allocation.
#define RNA_warning(format,...)
@ PROP_ENUM
Definition RNA_types.hh:69
#define UI_UNIT_Y
@ UI_EMBOSS
void UI_block_theme_style_set(uiBlock *block, char theme_style)
@ UI_BLOCK_NUMSELECT
@ UI_BLOCK_LOOP
@ UI_BLOCK_PIE_MENU
uiBut * uiDefBut(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
void uiItemsFullEnumO_items(uiLayout *layout, wmOperatorType *ot, const PointerRNA &ptr, PropertyRNA *prop, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, const EnumPropertyItem *item_array, int totitem, int active=-1)
uiLayout * UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, const uiStyle *style)
const uiStyle * UI_style_get_dpi()
void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, const char *name, int icon, const char *placeholder=nullptr)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, eUIEmbossType emboss)
uiBut * uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
@ UI_BLOCK_BOUNDS_PIE_CENTER
void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
@ UI_LAYOUT_VERTICAL
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
@ UI_LAYOUT_PIEMENU
@ UI_BLOCK_THEME_STYLE_POPUP
int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, char flag)
uiLayout * uiLayoutRadial(uiLayout *layout)
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
void UI_block_region_set(uiBlock *block, ARegion *region)
#define UI_FSTYLE_WIDGET
#define UI_UNIT_X
void UI_block_flag_enable(uiBlock *block, int flag)
@ UI_BTYPE_BUT
@ UI_BTYPE_LABEL
#define UI_MAX_NAME_STR
void UI_but_funcN_set(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2, uiButArgNFree func_argN_free_fn=MEM_freeN, uiButArgNCopy func_argN_copy_fn=MEM_dupallocN)
eUI_Item_Flag
@ UI_ITEM_R_EXPAND
@ WM_HANDLER_ACCEPT_DBL_CLICK
Definition WM_api.hh:466
@ KM_RELEASE
Definition WM_types.hh:285
@ KM_CLICK
Definition WM_types.hh:286
wmOperatorCallContext
Definition WM_types.hh:216
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
#define printf
#define RNA_NO_INDEX
uiPopupBlockHandle * ui_popup_block_create(bContext *C, ARegion *butregion, uiBut *but, uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func, void *arg, uiFreeArgFunc arg_free, bool can_refresh)
#define PIE_MAX_ITEMS
@ UI_PIE_CLICK_STYLE
#define UI_MENU_WIDTH_MIN
static float ui_pie_menu_title_width(const char *name, int icon)
int UI_pie_menu_invoke_from_operator_enum(bContext *C, const char *title, const char *opname, const char *propname, const wmEvent *event)
uiLayout * UI_pie_menu_layout(uiPieMenu *pie)
void ui_pie_menu_level_create(uiBlock *block, wmOperatorType *ot, const char *propname, IDProperty *properties, const EnumPropertyItem *items, int totitem, const wmOperatorCallContext context, const eUI_Item_Flag flag)
int UI_pie_menu_invoke_from_rna_enum(bContext *C, const char *title, const char *path, const wmEvent *event)
void UI_pie_menu_end(bContext *C, uiPieMenu *pie)
static uiBlock * ui_block_func_PIE(bContext *, uiPopupBlockHandle *handle, void *arg_pie)
int UI_pie_menu_invoke(bContext *C, const char *idname, const wmEvent *event)
uiPieMenu * UI_pie_menu_begin(bContext *C, const char *title, int icon, const wmEvent *event)
static void ui_pie_menu_level_invoke(bContext *C, void *argN, void *arg2)
uint ui_popup_menu_hash(const StringRef str)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
PropertyType RNA_property_type(PropertyRNA *prop)
const char * RNA_struct_identifier(const StructRNA *type)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
bool RNA_path_resolve(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:525
char label[BKE_ST_MAXNAME]
char translation_context[BKE_ST_MAXNAME]
float pie_center_spawned[2]
const char * title
wmOperatorCallContext context
char title[UI_MAX_NAME_STR]
StructRNA * type
Definition RNA_types.hh:41
PieMenuData pie_data
int bounds_offset[2]
eBlockBoundsCalc bounds_type
std::string str
short val
Definition WM_types.hh:724
short type
Definition WM_types.hh:722
struct wmEvent * eventstate
void WM_event_add_mousemove(wmWindow *win)
@ EVENT_NONE
@ LEFTMOUSE
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
MenuType * WM_menutype_find(const char *idname, bool quiet)
bool WM_menutype_poll(bContext *C, MenuType *mt)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
uint8_t flag
Definition wm_window.cc:138