Blender  V3.3
interface_region_menu_pie.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2008 Blender Foundation. All rights reserved. */
3 
10 #include <cstdarg>
11 #include <cstdlib>
12 #include <cstring>
13 
14 #include "MEM_guardedalloc.h"
15 
16 #include "DNA_userdef_types.h"
17 
18 #include "BLI_blenlib.h"
19 #include "BLI_utildefines.h"
20 
21 #include "PIL_time.h"
22 
23 #include "BKE_context.h"
24 #include "BKE_screen.h"
25 
26 #include "WM_api.h"
27 #include "WM_types.h"
28 
29 #include "RNA_access.h"
30 #include "RNA_path.h"
31 #include "RNA_prototypes.h"
32 
33 #include "UI_interface.h"
34 
35 #include "BLT_translation.h"
36 
37 #include "ED_screen.h"
38 
39 #include "interface_intern.h"
41 
42 /* -------------------------------------------------------------------- */
46 struct uiPieMenu {
47  uiBlock *block_radial; /* radial block of the pie menu (more could be added later) */
49  int mx, my;
50 };
51 
52 static uiBlock *ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handle, void *arg_pie)
53 {
54  uiBlock *block;
55  uiPieMenu *pie = static_cast<uiPieMenu *>(arg_pie);
56  int minwidth, width, height;
57 
58  minwidth = UI_MENU_WIDTH_MIN;
59  block = pie->block_radial;
60 
61  /* in some cases we create the block before the region,
62  * so we set it delayed here if necessary */
63  if (BLI_findindex(&handle->region->uiblocks, block) == -1) {
64  UI_block_region_set(block, handle->region);
65  }
66 
68 
71 
72  block->minbounds = minwidth;
73  block->bounds = 1;
74  block->bounds_offset[0] = 0;
75  block->bounds_offset[1] = 0;
77 
78  block->pie_data.pie_center_spawned[0] = pie->mx;
79  block->pie_data.pie_center_spawned[1] = pie->my;
80 
81  return pie->block_radial;
82 }
83 
84 static float ui_pie_menu_title_width(const char *name, int icon)
85 {
86  const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
87  return (UI_fontstyle_string_width(fstyle, name) + (UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f))));
88 }
89 
90 uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, const wmEvent *event)
91 {
92  const uiStyle *style = UI_style_get_dpi();
93  short event_type;
94 
95  wmWindow *win = CTX_wm_window(C);
96 
97  uiPieMenu *pie = MEM_cnew<uiPieMenu>(__func__);
98 
99  pie->block_radial = UI_block_begin(C, nullptr, __func__, UI_EMBOSS);
100  /* may be useful later to allow spawning pies
101  * from old positions */
102  /* pie->block_radial->flag |= UI_BLOCK_POPUP_MEMORY; */
103  pie->block_radial->puphash = ui_popup_menu_hash(title);
105 
106  /* if pie is spawned by a left click, release or click event,
107  * it is always assumed to be click style */
108  if (event->type == LEFTMOUSE || ELEM(event->val, KM_RELEASE, KM_CLICK)) {
112  }
113  else {
114  if (win->pie_event_type_last != EVENT_NONE) {
115  /* original pie key has been released, so don't propagate the event */
116  if (win->pie_event_type_lock == EVENT_NONE) {
117  event_type = EVENT_NONE;
119  }
120  else {
121  event_type = win->pie_event_type_last;
122  }
123  }
124  else {
125  event_type = event->type;
126  }
127 
128  pie->block_radial->pie_data.event_type = event_type;
129  win->pie_event_type_lock = event_type;
130  }
131 
132  pie->layout = UI_block_layout(
133  pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
134 
135  /* NOTE: #wmEvent.xy is where we started dragging in case of #KM_CLICK_DRAG. */
136  pie->mx = event->xy[0];
137  pie->my = event->xy[1];
138 
139  /* create title button */
140  if (title[0]) {
141  uiBut *but;
142  char titlestr[256];
143  int w;
144  if (icon) {
145  BLI_snprintf(titlestr, sizeof(titlestr), " %s", title);
146  w = ui_pie_menu_title_width(titlestr, icon);
147  but = uiDefIconTextBut(pie->block_radial,
149  0,
150  icon,
151  titlestr,
152  0,
153  0,
154  w,
155  UI_UNIT_Y,
156  nullptr,
157  0.0,
158  0.0,
159  0,
160  0,
161  "");
162  }
163  else {
164  w = ui_pie_menu_title_width(title, 0);
165  but = uiDefBut(pie->block_radial,
167  0,
168  title,
169  0,
170  0,
171  w,
172  UI_UNIT_Y,
173  nullptr,
174  0.0,
175  0.0,
176  0,
177  0,
178  "");
179  }
180  /* do not align left */
181  but->drawflag &= ~UI_BUT_TEXT_LEFT;
182  pie->block_radial->pie_data.title = but->str;
183  pie->block_radial->pie_data.icon = icon;
184  }
185 
186  return pie;
187 }
188 
190 {
191  wmWindow *window = CTX_wm_window(C);
192  uiPopupBlockHandle *menu;
193 
194  menu = ui_popup_block_create(C, nullptr, nullptr, nullptr, ui_block_func_PIE, pie, nullptr);
195  menu->popup = true;
197 
199  WM_event_add_mousemove(window);
200 
201  MEM_freeN(pie);
202 }
203 
205 {
206  return pie->layout;
207 }
208 
209 int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *event)
210 {
211  uiPieMenu *pie;
212  uiLayout *layout;
213  MenuType *mt = WM_menutype_find(idname, true);
214 
215  if (mt == nullptr) {
216  printf("%s: named menu \"%s\" not found\n", __func__, idname);
217  return OPERATOR_CANCELLED;
218  }
219 
220  if (WM_menutype_poll(C, mt) == false) {
221  /* cancel but allow event to pass through, just like operators do */
223  }
224 
225  pie = UI_pie_menu_begin(C, IFACE_(mt->label), ICON_NONE, event);
226  layout = UI_pie_menu_layout(pie);
227 
228  UI_menutype_draw(C, mt, layout);
229 
230  UI_pie_menu_end(C, pie);
231 
232  return OPERATOR_INTERFACE;
233 }
234 
236  const char *title,
237  const char *opname,
238  const char *propname,
239  const wmEvent *event)
240 {
241  uiPieMenu *pie;
242  uiLayout *layout;
243 
244  pie = UI_pie_menu_begin(C, IFACE_(title), ICON_NONE, event);
245  layout = UI_pie_menu_layout(pie);
246 
247  layout = uiLayoutRadial(layout);
248  uiItemsEnumO(layout, opname, propname);
249 
250  UI_pie_menu_end(C, pie);
251 
252  return OPERATOR_INTERFACE;
253 }
254 
256  const char *title,
257  const char *path,
258  const wmEvent *event)
259 {
260  PointerRNA ctx_ptr;
261  PointerRNA r_ptr;
262  PropertyRNA *r_prop;
263  uiPieMenu *pie;
264  uiLayout *layout;
265 
266  RNA_pointer_create(nullptr, &RNA_Context, C, &ctx_ptr);
267 
268  if (!RNA_path_resolve(&ctx_ptr, path, &r_ptr, &r_prop)) {
269  return OPERATOR_CANCELLED;
270  }
271 
272  /* invalid property, only accept enums */
273  if (RNA_property_type(r_prop) != PROP_ENUM) {
274  BLI_assert(0);
275  return OPERATOR_CANCELLED;
276  }
277 
278  pie = UI_pie_menu_begin(C, IFACE_(title), ICON_NONE, event);
279 
280  layout = UI_pie_menu_layout(pie);
281 
282  layout = uiLayoutRadial(layout);
283  uiItemFullR(layout, &r_ptr, r_prop, RNA_NO_INDEX, 0, UI_ITEM_R_EXPAND, nullptr, 0);
284 
285  UI_pie_menu_end(C, pie);
286 
287  return OPERATOR_INTERFACE;
288 }
289 
292 /* -------------------------------------------------------------------- */
308  char title[UI_MAX_NAME_STR]; /* parent pie title, copied for level */
309  int icon; /* parent pie icon, copied for level */
310  int totitem; /* total count of *remaining* items */
311 
312  /* needed for calling uiItemsFullEnumO_array again for new level */
314  const char *propname;
317 };
318 
322 static void ui_pie_menu_level_invoke(bContext *C, void *argN, void *arg2)
323 {
324  EnumPropertyItem *item_array = (EnumPropertyItem *)argN;
325  PieMenuLevelData *lvl = (PieMenuLevelData *)arg2;
326  wmWindow *win = CTX_wm_window(C);
327 
328  uiPieMenu *pie = UI_pie_menu_begin(C, IFACE_(lvl->title), lvl->icon, win->eventstate);
329  uiLayout *layout = UI_pie_menu_layout(pie);
330 
331  layout = uiLayoutRadial(layout);
332 
333  PointerRNA ptr;
334 
336  /* So the context is passed to `itemf` functions (some need it). */
339 
340  if (prop) {
341  uiItemsFullEnumO_items(layout,
342  lvl->ot,
343  ptr,
344  prop,
345  lvl->properties,
346  lvl->context,
347  lvl->flag,
348  item_array,
349  lvl->totitem);
350  }
351  else {
352  RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), lvl->propname);
353  }
354 
355  UI_pie_menu_end(C, pie);
356 }
357 
360  const char *propname,
361  IDProperty *properties,
362  const EnumPropertyItem *items,
363  int totitem,
366 {
367  const int totitem_parent = PIE_MAX_ITEMS - 1;
368  const int totitem_remain = totitem - totitem_parent;
369  const size_t array_size = sizeof(EnumPropertyItem) * totitem_remain;
370 
371  /* used as but->func_argN so freeing is handled elsewhere */
372  EnumPropertyItem *remaining = static_cast<EnumPropertyItem *>(
373  MEM_mallocN(array_size + sizeof(EnumPropertyItem), "pie_level_item_array"));
374  memcpy(remaining, items + totitem_parent, array_size);
375  /* A null terminating sentinel element is required. */
376  memset(&remaining[totitem_remain], 0, sizeof(EnumPropertyItem));
377 
378  /* yuk, static... issue is we can't reliably free this without doing dangerous changes */
379  static PieMenuLevelData lvl;
381  lvl.totitem = totitem_remain;
382  lvl.ot = ot;
383  lvl.propname = propname;
384  lvl.properties = properties;
385  lvl.context = context;
386  lvl.flag = flag;
387 
388  /* add a 'more' menu entry */
389  uiBut *but = uiDefIconTextBut(block,
390  UI_BTYPE_BUT,
391  0,
392  ICON_PLUS,
393  "More",
394  0,
395  0,
396  UI_UNIT_X * 3,
397  UI_UNIT_Y,
398  nullptr,
399  0.0f,
400  0.0f,
401  0.0f,
402  0.0f,
403  "Show more items of this menu");
404  UI_but_funcN_set(but, ui_pie_menu_level_invoke, remaining, &lvl);
405 }
406  /* Pie Menu Levels */
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
#define BLI_assert(a)
Definition: BLI_assert.h:46
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define UNUSED(x)
#define ELEM(...)
#define IFACE_(msgid)
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_PASS_THROUGH
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
Read Guarded memory(de)allocation.
Platform independent time functions.
#define RNA_warning(format,...)
Definition: RNA_access.h:756
@ PROP_ENUM
Definition: RNA_types.h:63
struct EnumPropertyItem EnumPropertyItem
#define C
Definition: RandGen.cpp:25
@ UI_BUT_TEXT_LEFT
Definition: UI_interface.h:259
@ UI_LAYOUT_VERTICAL
uiBut * uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:5623
#define UI_UNIT_Y
@ UI_EMBOSS
Definition: UI_interface.h:108
const struct uiStyle * UI_style_get_dpi(void)
void UI_block_theme_style_set(uiBlock *block, char theme_style)
Definition: interface.cc:3634
void UI_menutype_draw(struct bContext *C, struct MenuType *mt, struct uiLayout *layout)
uiBut * uiDefBut(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:4806
@ UI_BLOCK_THEME_STYLE_POPUP
Definition: UI_interface.h:770
void uiItemsFullEnumO_items(uiLayout *layout, struct wmOperatorType *ot, struct PointerRNA ptr, struct PropertyRNA *prop, struct IDProperty *properties, wmOperatorCallContext context, int flag, const struct EnumPropertyItem *item_array, int totitem)
@ UI_LAYOUT_PIEMENU
@ UI_ITEM_R_EXPAND
@ UI_BLOCK_BOUNDS_PIE_CENTER
Definition: UI_interface.h:817
void UI_popup_handlers_add(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, char flag)
uiLayout * UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, const struct uiStyle *style)
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
uiLayout * uiLayoutRadial(uiLayout *layout)
uiBlock * UI_block_begin(const struct bContext *C, struct ARegion *region, const char *name, eUIEmbossType emboss)
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
#define UI_FSTYLE_WIDGET
void uiItemFullR(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, int value, int flag, const char *name, int icon)
void UI_but_funcN_set(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2)
Definition: interface.cc:6007
#define UI_UNIT_X
void UI_block_flag_enable(uiBlock *block, int flag)
Definition: interface.cc:5848
@ UI_BTYPE_BUT
Definition: UI_interface.h:330
@ UI_BTYPE_LABEL
Definition: UI_interface.h:354
#define UI_MAX_NAME_STR
Definition: UI_interface.h:92
void UI_block_region_set(uiBlock *block, struct ARegion *region)
Definition: interface.cc:3551
int UI_fontstyle_string_width(const struct uiFontStyle *fs, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
@ UI_BLOCK_NUMSELECT
Definition: UI_interface.h:138
@ UI_BLOCK_RADIAL
Definition: UI_interface.h:156
@ UI_BLOCK_LOOP
Definition: UI_interface.h:135
@ WM_HANDLER_ACCEPT_DBL_CLICK
Definition: WM_api.h:432
@ KM_RELEASE
Definition: WM_types.h:268
@ KM_CLICK
Definition: WM_types.h:269
wmOperatorCallContext
Definition: WM_types.h:199
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
#define RNA_NO_INDEX
uiPopupBlockHandle * ui_popup_block_create(struct bContext *C, struct ARegion *butregion, uiBut *but, uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func, void *arg, uiFreeArgFunc arg_free)
#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)
uiLayout * UI_pie_menu_layout(uiPieMenu *pie)
void UI_pie_menu_end(bContext *C, uiPieMenu *pie)
int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *event)
int UI_pie_menu_invoke_from_operator_enum(struct bContext *C, const char *title, const char *opname, const char *propname, const wmEvent *event)
uiPieMenu * UI_pie_menu_begin(struct bContext *C, const char *title, int icon, const wmEvent *event)
int UI_pie_menu_invoke_from_rna_enum(struct bContext *C, const char *title, const char *path, const wmEvent *event)
static void ui_pie_menu_level_invoke(bContext *C, void *argN, void *arg2)
void ui_pie_menu_level_create(uiBlock *block, wmOperatorType *ot, const char *propname, IDProperty *properties, const EnumPropertyItem *items, int totitem, wmOperatorCallContext context, wmOperatorCallContext flag)
static uiBlock * ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handle, void *arg_pie)
uint ui_popup_menu_hash(const char *str)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
const char * RNA_struct_identifier(const StructRNA *type)
Definition: rna_access.c:586
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
PropertyType RNA_property_type(PropertyRNA *prop)
Definition: rna_access.c:1010
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
bool RNA_path_resolve(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition: rna_path.cc:503
ListBase uiblocks
char label[BKE_ST_MAXNAME]
Definition: BKE_screen.h:362
float pie_center_spawned[2]
const char * title
wmOperatorCallContext context
char title[UI_MAX_NAME_STR]
wmOperatorCallContext flag
struct StructRNA * type
Definition: RNA_types.h:37
struct PieMenuData pie_data
int bounds_offset[2]
eBlockBoundsCalc bounds_type
char * str
struct ARegion * region
short val
Definition: WM_types.h:680
short type
Definition: WM_types.h:678
struct wmEvent * eventstate
double PIL_check_seconds_timer(void)
Definition: time.c:64
void WM_event_add_mousemove(wmWindow *win)
@ EVENT_NONE
@ LEFTMOUSE
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
MenuType * WM_menutype_find(const char *idname, bool quiet)
Definition: wm_menu_type.c:30
bool WM_menutype_poll(bContext *C, MenuType *mt)
Definition: wm_menu_type.c:87
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:661
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
Definition: wm_operators.c:701