Blender  V2.93
interface_region_menu_pie.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19 
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "MEM_guardedalloc.h"
31 
32 #include "DNA_userdef_types.h"
33 
34 #include "BLI_blenlib.h"
35 #include "BLI_utildefines.h"
36 
37 #include "PIL_time.h"
38 
39 #include "BKE_context.h"
40 #include "BKE_screen.h"
41 
42 #include "WM_api.h"
43 #include "WM_types.h"
44 
45 #include "RNA_access.h"
46 
47 #include "UI_interface.h"
48 
49 #include "BLT_translation.h"
50 
51 #include "ED_screen.h"
52 
53 #include "interface_intern.h"
55 
56 /* -------------------------------------------------------------------- */
60 struct uiPieMenu {
61  uiBlock *block_radial; /* radial block of the pie menu (more could be added later) */
63  int mx, my;
64 };
65 
66 static uiBlock *ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handle, void *arg_pie)
67 {
68  uiBlock *block;
69  uiPieMenu *pie = arg_pie;
70  int minwidth, width, height;
71 
72  minwidth = UI_MENU_WIDTH_MIN;
73  block = pie->block_radial;
74 
75  /* in some cases we create the block before the region,
76  * so we set it delayed here if necessary */
77  if (BLI_findindex(&handle->region->uiblocks, block) == -1) {
78  UI_block_region_set(block, handle->region);
79  }
80 
82 
85 
86  block->minbounds = minwidth;
87  block->bounds = 1;
88  block->bounds_offset[0] = 0;
89  block->bounds_offset[1] = 0;
91 
92  block->pie_data.pie_center_spawned[0] = pie->mx;
93  block->pie_data.pie_center_spawned[1] = pie->my;
94 
95  return pie->block_radial;
96 }
97 
98 static float ui_pie_menu_title_width(const char *name, int icon)
99 {
100  const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
101  return (UI_fontstyle_string_width(fstyle, name) + (UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f))));
102 }
103 
104 uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, const wmEvent *event)
105 {
106  const uiStyle *style = UI_style_get_dpi();
107  uiPieMenu *pie;
108  short event_type;
109 
110  wmWindow *win = CTX_wm_window(C);
111 
112  pie = MEM_callocN(sizeof(*pie), "pie menu");
113 
114  pie->block_radial = UI_block_begin(C, NULL, __func__, UI_EMBOSS);
115  /* may be useful later to allow spawning pies
116  * from old positions */
117  /* pie->block_radial->flag |= UI_BLOCK_POPUP_MEMORY; */
118  pie->block_radial->puphash = ui_popup_menu_hash(title);
120 
121  /* if pie is spawned by a left click, release or click event,
122  * it is always assumed to be click style */
123  if (event->type == LEFTMOUSE || ELEM(event->val, KM_RELEASE, KM_CLICK)) {
127  }
128  else {
129  if (win->pie_event_type_last != EVENT_NONE) {
130  /* original pie key has been released, so don't propagate the event */
131  if (win->pie_event_type_lock == EVENT_NONE) {
132  event_type = EVENT_NONE;
134  }
135  else {
136  event_type = win->pie_event_type_last;
137  }
138  }
139  else {
140  event_type = event->type;
141  }
142 
143  pie->block_radial->pie_data.event_type = event_type;
144  win->pie_event_type_lock = event_type;
145  }
146 
147  pie->layout = UI_block_layout(
148  pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
149 
150  /* Note event->x/y is where we started dragging in case of KM_CLICK_DRAG. */
151  pie->mx = event->x;
152  pie->my = event->y;
153 
154  /* create title button */
155  if (title[0]) {
156  uiBut *but;
157  char titlestr[256];
158  int w;
159  if (icon) {
160  BLI_snprintf(titlestr, sizeof(titlestr), " %s", title);
161  w = ui_pie_menu_title_width(titlestr, icon);
162  but = uiDefIconTextBut(pie->block_radial,
164  0,
165  icon,
166  titlestr,
167  0,
168  0,
169  w,
170  UI_UNIT_Y,
171  NULL,
172  0.0,
173  0.0,
174  0,
175  0,
176  "");
177  }
178  else {
179  w = ui_pie_menu_title_width(title, 0);
180  but = uiDefBut(pie->block_radial,
182  0,
183  title,
184  0,
185  0,
186  w,
187  UI_UNIT_Y,
188  NULL,
189  0.0,
190  0.0,
191  0,
192  0,
193  "");
194  }
195  /* do not align left */
196  but->drawflag &= ~UI_BUT_TEXT_LEFT;
197  pie->block_radial->pie_data.title = but->str;
198  pie->block_radial->pie_data.icon = icon;
199  }
200 
201  return pie;
202 }
203 
205 {
206  wmWindow *window = CTX_wm_window(C);
207  uiPopupBlockHandle *menu;
208 
210  menu->popup = true;
212 
214  WM_event_add_mousemove(window);
215 
216  MEM_freeN(pie);
217 }
218 
220 {
221  return pie->layout;
222 }
223 
224 int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *event)
225 {
226  uiPieMenu *pie;
227  uiLayout *layout;
228  MenuType *mt = WM_menutype_find(idname, true);
229 
230  if (mt == NULL) {
231  printf("%s: named menu \"%s\" not found\n", __func__, idname);
232  return OPERATOR_CANCELLED;
233  }
234 
235  if (WM_menutype_poll(C, mt) == false) {
236  /* cancel but allow event to pass through, just like operators do */
238  }
239 
240  pie = UI_pie_menu_begin(C, IFACE_(mt->label), ICON_NONE, event);
241  layout = UI_pie_menu_layout(pie);
242 
243  UI_menutype_draw(C, mt, layout);
244 
245  UI_pie_menu_end(C, pie);
246 
247  return OPERATOR_INTERFACE;
248 }
249 
251  const char *title,
252  const char *opname,
253  const char *propname,
254  const wmEvent *event)
255 {
256  uiPieMenu *pie;
257  uiLayout *layout;
258 
259  pie = UI_pie_menu_begin(C, IFACE_(title), ICON_NONE, event);
260  layout = UI_pie_menu_layout(pie);
261 
262  layout = uiLayoutRadial(layout);
263  uiItemsEnumO(layout, opname, propname);
264 
265  UI_pie_menu_end(C, pie);
266 
267  return OPERATOR_INTERFACE;
268 }
269 
271  const char *title,
272  const char *path,
273  const wmEvent *event)
274 {
275  PointerRNA ctx_ptr;
276  PointerRNA r_ptr;
277  PropertyRNA *r_prop;
278  uiPieMenu *pie;
279  uiLayout *layout;
280 
281  RNA_pointer_create(NULL, &RNA_Context, C, &ctx_ptr);
282 
283  if (!RNA_path_resolve(&ctx_ptr, path, &r_ptr, &r_prop)) {
284  return OPERATOR_CANCELLED;
285  }
286 
287  /* invalid property, only accept enums */
288  if (RNA_property_type(r_prop) != PROP_ENUM) {
289  BLI_assert(0);
290  return OPERATOR_CANCELLED;
291  }
292 
293  pie = UI_pie_menu_begin(C, IFACE_(title), ICON_NONE, event);
294 
295  layout = UI_pie_menu_layout(pie);
296 
297  layout = uiLayoutRadial(layout);
298  uiItemFullR(layout, &r_ptr, r_prop, RNA_NO_INDEX, 0, UI_ITEM_R_EXPAND, NULL, 0);
299 
300  UI_pie_menu_end(C, pie);
301 
302  return OPERATOR_INTERFACE;
303 }
304 
307 /* -------------------------------------------------------------------- */
324 typedef struct PieMenuLevelData {
325  char title[UI_MAX_NAME_STR]; /* parent pie title, copied for level */
326  int icon; /* parent pie icon, copied for level */
327  int totitem; /* total count of *remaining* items */
328 
329  /* needed for calling uiItemsFullEnumO_array again for new level */
331  const char *propname;
333  int context, flag;
335 
339 static void ui_pie_menu_level_invoke(bContext *C, void *argN, void *arg2)
340 {
341  EnumPropertyItem *item_array = (EnumPropertyItem *)argN;
342  PieMenuLevelData *lvl = (PieMenuLevelData *)arg2;
343  wmWindow *win = CTX_wm_window(C);
344 
345  uiPieMenu *pie = UI_pie_menu_begin(C, IFACE_(lvl->title), lvl->icon, win->eventstate);
346  uiLayout *layout = UI_pie_menu_layout(pie);
347 
348  layout = uiLayoutRadial(layout);
349 
350  PointerRNA ptr;
351 
353  /* so the context is passed to itemf functions (some need it) */
356 
357  if (prop) {
358  uiItemsFullEnumO_items(layout,
359  lvl->ot,
360  ptr,
361  prop,
362  lvl->properties,
363  lvl->context,
364  lvl->flag,
365  item_array,
366  lvl->totitem);
367  }
368  else {
369  RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), lvl->propname);
370  }
371 
372  UI_pie_menu_end(C, pie);
373 }
374 
380  const char *propname,
381  IDProperty *properties,
382  const EnumPropertyItem *items,
383  int totitem,
384  int context,
385  int flag)
386 {
387  const int totitem_parent = PIE_MAX_ITEMS - 1;
388  const int totitem_remain = totitem - totitem_parent;
389  const size_t array_size = sizeof(EnumPropertyItem) * totitem_remain;
390 
391  /* used as but->func_argN so freeing is handled elsewhere */
392  EnumPropertyItem *remaining = MEM_mallocN(array_size + sizeof(EnumPropertyItem),
393  "pie_level_item_array");
394  memcpy(remaining, items + totitem_parent, array_size);
395  /* A NULL terminating sentinel element is required. */
396  memset(&remaining[totitem_remain], 0, sizeof(EnumPropertyItem));
397 
398  /* yuk, static... issue is we can't reliably free this without doing dangerous changes */
399  static PieMenuLevelData lvl;
401  lvl.totitem = totitem_remain;
402  lvl.ot = ot;
403  lvl.propname = propname;
404  lvl.properties = properties;
405  lvl.context = context;
406  lvl.flag = flag;
407 
408  /* add a 'more' menu entry */
409  uiBut *but = uiDefIconTextBut(block,
410  UI_BTYPE_BUT,
411  0,
412  ICON_PLUS,
413  "More",
414  0,
415  0,
416  UI_UNIT_X * 3,
417  UI_UNIT_Y,
418  NULL,
419  0.0f,
420  0.0f,
421  0.0f,
422  0.0f,
423  "Show more items of this menu");
424  UI_but_funcN_set(but, ui_pie_menu_level_invoke, remaining, &lvl);
425 }
426  /* Pie Menu Levels */
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
#define BLI_assert(a)
Definition: BLI_assert.h:58
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#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 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
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
Read Guarded memory(de)allocation.
Platform independent time functions.
StructRNA RNA_Context
#define RNA_warning(format,...)
Definition: RNA_access.h:1437
@ PROP_ENUM
Definition: RNA_types.h:77
struct EnumPropertyItem EnumPropertyItem
#define C
Definition: RandGen.cpp:39
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.c:5603
#define UI_UNIT_Y
@ UI_ITEM_R_EXPAND
@ UI_BUT_TEXT_LEFT
Definition: UI_interface.h:259
@ UI_EMBOSS
Definition: UI_interface.h:107
const struct uiStyle * UI_style_get_dpi(void)
void UI_block_theme_style_set(uiBlock *block, char theme_style)
Definition: interface.c:3547
@ UI_LAYOUT_PIEMENU
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.c:4687
void uiItemsFullEnumO_items(uiLayout *layout, struct wmOperatorType *ot, struct PointerRNA ptr, struct PropertyRNA *prop, struct IDProperty *properties, int context, int flag, const struct EnumPropertyItem *item_array, int totitem)
@ UI_BLOCK_BOUNDS_PIE_CENTER
Definition: UI_interface.h:701
void UI_popup_handlers_add(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const char flag)
@ UI_BLOCK_NUMSELECT
Definition: UI_interface.h:143
@ UI_BLOCK_RADIAL
Definition: UI_interface.h:161
@ UI_BLOCK_LOOP
Definition: UI_interface.h:140
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)
int UI_fontstyle_string_width(const struct uiFontStyle *fs, const char *str)
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.c:6301
#define UI_UNIT_X
@ UI_LAYOUT_VERTICAL
void UI_block_flag_enable(uiBlock *block, int flag)
Definition: interface.c:6067
@ UI_BTYPE_BUT
Definition: UI_interface.h:334
@ UI_BTYPE_LABEL
Definition: UI_interface.h:358
#define UI_MAX_NAME_STR
Definition: UI_interface.h:91
@ UI_BLOCK_THEME_STYLE_POPUP
Definition: UI_interface.h:671
void UI_block_region_set(uiBlock *block, struct ARegion *region)
Definition: interface.c:3468
@ WM_HANDLER_ACCEPT_DBL_CLICK
Definition: WM_api.h:315
#define KM_CLICK
Definition: WM_types.h:244
#define KM_RELEASE
Definition: WM_types.h:243
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
#define RNA_NO_INDEX
@ UI_PIE_CLICK_STYLE
#define PIE_MAX_ITEMS
uiPopupBlockHandle * ui_popup_block_create(struct bContext *C, struct ARegion *butregion, uiBut *but, uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func, void *arg, void(*arg_free)(void *arg))
#define UI_MENU_WIDTH_MIN
void ui_pie_menu_level_create(uiBlock *block, wmOperatorType *ot, const char *propname, IDProperty *properties, const EnumPropertyItem *items, int totitem, int context, int flag)
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)
struct PieMenuLevelData PieMenuLevelData
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:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
const char * RNA_struct_identifier(const StructRNA *type)
Definition: rna_access.c:723
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
PropertyType RNA_property_type(PropertyRNA *prop)
Definition: rna_access.c:1155
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition: rna_access.c:5400
struct SELECTID_Context context
Definition: select_engine.c:47
ListBase uiblocks
char label[BKE_ST_MAXNAME]
Definition: BKE_screen.h:376
float pie_center_spawned[2]
const char * title
char title[UI_MAX_NAME_STR]
struct StructRNA * type
Definition: RNA_types.h:51
struct PieMenuData pie_data
int bounds_offset[2]
eBlockBoundsCalc bounds_type
char * str
struct ARegion * region
short val
Definition: WM_types.h:579
short type
Definition: WM_types.h:577
struct wmEvent * eventstate
double PIL_check_seconds_timer(void)
Definition: time.c:80
void WM_event_add_mousemove(wmWindow *win)
@ EVENT_NONE
@ LEFTMOUSE
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156
MenuType * WM_menutype_find(const char *idname, bool quiet)
Definition: wm_menu_type.c:44
bool WM_menutype_poll(bContext *C, MenuType *mt)
Definition: wm_menu_type.c:102
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:584
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
Definition: wm_operators.c:620