2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2007-12-24 18:27:28 +00:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
2018-06-01 18:19:39 +02:00
|
|
|
* of the License, or (at your option) any later version.
|
2007-12-24 18:27:28 +00:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2007-12-24 18:27:28 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2007 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup wm
|
2014-01-19 23:14:24 +11:00
|
|
|
*
|
|
|
|
* Functions for dealing with wmOperator, adding, removing, calling
|
|
|
|
* as well as some generic operators and shared operator properties.
|
2011-02-25 14:04:21 +00:00
|
|
|
*/
|
|
|
|
|
2010-10-31 14:43:30 +00:00
|
|
|
#include <assert.h>
|
2020-03-19 09:33:03 +01:00
|
|
|
#include <ctype.h>
|
2014-11-23 22:48:48 +01:00
|
|
|
#include <errno.h>
|
2020-03-19 09:33:03 +01:00
|
|
|
#include <float.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2010-11-11 20:32:28 +00:00
|
|
|
|
2014-11-28 22:16:14 +01:00
|
|
|
#ifdef WIN32
|
|
|
|
# include "GHOST_C-api.h"
|
|
|
|
#endif
|
2007-12-24 18:27:28 +00:00
|
|
|
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
2018-03-29 20:38:32 +02:00
|
|
|
#include "CLG_log.h"
|
|
|
|
|
2008-01-14 19:44:20 +00:00
|
|
|
#include "DNA_ID.h"
|
2019-09-26 17:51:21 +02:00
|
|
|
#include "DNA_brush_types.h"
|
2009-09-14 10:56:40 +00:00
|
|
|
#include "DNA_object_types.h"
|
2009-05-19 15:37:50 +00:00
|
|
|
#include "DNA_scene_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_screen_types.h"
|
2008-12-19 18:28:37 +00:00
|
|
|
#include "DNA_userdef_types.h"
|
2007-12-24 18:27:28 +00:00
|
|
|
#include "DNA_windowmanager_types.h"
|
|
|
|
|
2015-08-16 17:32:01 +10:00
|
|
|
#include "BLT_translation.h"
|
2010-01-08 05:51:51 +00:00
|
|
|
|
2009-05-19 12:54:54 +00:00
|
|
|
#include "PIL_time.h"
|
|
|
|
|
2007-12-24 18:27:28 +00:00
|
|
|
#include "BLI_blenlib.h"
|
2018-02-18 21:27:33 +11:00
|
|
|
#include "BLI_dial_2d.h"
|
2008-12-26 03:56:52 +00:00
|
|
|
#include "BLI_dynstr.h" /*for WM_operator_pystring */
|
2010-01-26 11:25:39 +00:00
|
|
|
#include "BLI_math.h"
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2007-12-24 18:27:28 +00:00
|
|
|
|
2011-05-12 01:57:47 +00:00
|
|
|
#include "BKE_brush.h"
|
2019-09-26 17:51:21 +02:00
|
|
|
#include "BKE_colortools.h"
|
2008-12-18 02:56:48 +00:00
|
|
|
#include "BKE_context.h"
|
2018-11-07 18:00:24 +01:00
|
|
|
#include "BKE_global.h"
|
2015-08-10 17:26:37 +02:00
|
|
|
#include "BKE_icons.h"
|
2.5: work on bringing back SpaceTime options
- RMB select, also with SHIFT
- RMB tweak for translate
- SHIFT+D dupli
- BKEY border select/deselect
- AKEY (de)select all
- XKEY delete
- GKEY grab
Added some XXX comments for future todos, especially for when other
spaces come back with time markers.
Also added ED_util for putting in all to-be-cleaned cruft
Context conflict: input methods for Markers can conflict with other
spacetypes. It was solved in pre-2.5 with manually tweaking it all over,
but I would prefer one keymap for all marker stuff. Needs some thinking...
could be solved with a boundbox check for bottom part of 2d window.
Tweak issue: both tweak styles are possible:
- Hold mouse button, move, operator ends on mouse release
- Hold mouse button, move, operator ends on mouse click
Problem is that modally handled operators use fixed keymaps... like ESC,
SPACE, ENTER, or press/release mousebutton for 'assign'. There's a lot
to say for making this all consistant, or become part of 1 general keymap?
Should also be possibe to define 'tweak' defaults for Tablet different
than for mouse...
2008-11-29 15:10:31 +00:00
|
|
|
#include "BKE_idprop.h"
|
2012-04-24 02:01:23 +00:00
|
|
|
#include "BKE_image.h"
|
2020-02-10 12:58:59 +01:00
|
|
|
#include "BKE_lib_id.h"
|
|
|
|
#include "BKE_lib_query.h"
|
2007-12-24 18:27:28 +00:00
|
|
|
#include "BKE_main.h"
|
2013-01-22 04:24:01 +00:00
|
|
|
#include "BKE_material.h"
|
2009-09-12 19:54:39 +00:00
|
|
|
#include "BKE_report.h"
|
2009-05-19 15:37:50 +00:00
|
|
|
#include "BKE_scene.h"
|
2009-10-06 13:04:31 +00:00
|
|
|
#include "BKE_screen.h" /* BKE_ST_MAXNAME */
|
2014-11-17 15:44:19 +01:00
|
|
|
#include "BKE_unit.h"
|
2011-01-07 19:18:31 +00:00
|
|
|
|
2020-03-19 19:37:00 +01:00
|
|
|
#include "BKE_idtype.h"
|
2007-12-24 18:27:28 +00:00
|
|
|
|
2011-06-10 04:36:51 +00:00
|
|
|
#include "BLF_api.h"
|
2009-05-19 12:54:54 +00:00
|
|
|
|
2017-02-28 15:29:51 -05:00
|
|
|
#include "GPU_immediate.h"
|
2017-04-05 18:30:14 +10:00
|
|
|
#include "GPU_immediate_util.h"
|
2017-03-21 02:51:02 -04:00
|
|
|
#include "GPU_matrix.h"
|
2019-03-23 23:54:01 +01:00
|
|
|
#include "GPU_state.h"
|
2017-02-28 15:29:51 -05:00
|
|
|
|
2009-01-24 22:58:22 +00:00
|
|
|
#include "IMB_imbuf_types.h"
|
2009-01-24 16:59:55 +00:00
|
|
|
|
2014-11-17 15:44:19 +01:00
|
|
|
#include "ED_numinput.h"
|
2009-01-06 14:42:54 +00:00
|
|
|
#include "ED_screen.h"
|
2018-04-02 15:02:08 +02:00
|
|
|
#include "ED_undo.h"
|
2012-12-09 10:48:18 +00:00
|
|
|
#include "ED_view3d.h"
|
2009-01-06 14:42:54 +00:00
|
|
|
|
2008-11-21 19:14:38 +00:00
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
2011-02-13 14:16:36 +00:00
|
|
|
#include "RNA_enum_types.h"
|
2008-11-21 19:14:38 +00:00
|
|
|
|
2008-12-15 19:19:39 +00:00
|
|
|
#include "UI_interface.h"
|
2015-01-12 14:44:54 +01:00
|
|
|
#include "UI_interface_icons.h"
|
2008-12-17 15:38:40 +00:00
|
|
|
#include "UI_resources.h"
|
2008-12-15 19:19:39 +00:00
|
|
|
|
2007-12-24 18:27:28 +00:00
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
2.5: gesture code in WM
- Simplified and cleaned previous border code
It was a bit too complex, too many data manipulations
Original idea was to have WM API calls to manage border, circle, lines,
lasso, etc. This now means that WM provides callbacks for custom operators,
so it's very easy to make them. Check bottom of screen_edit.c for an
example.
Currently two borders were coded; with and without cross hair.
Press Bkey in any area-region to test it (note: time window has wrong matrix!)
Some specs to note:
- gestures are in region space, and draw 'over'. That latter still needs some
work when we do real composites.
- only the active region is redrawn.
- on todo is the generic gesture engine for 'tweak' or like how currently grab
gestures in Blender work. These will be configurable per area-region, and WM
then will send the proper "Gesture Event" with properties (N, S, E, W, etc)
to which you then can assign operators. Such events will be generated with low
priority, so other handlers who swallowed mouse events have preference.
2008-11-19 13:16:05 +00:00
|
|
|
|
2008-11-24 10:45:36 +00:00
|
|
|
#include "wm.h"
|
2009-05-19 12:54:54 +00:00
|
|
|
#include "wm_draw.h"
|
2020-04-07 23:41:30 +02:00
|
|
|
#include "wm_event_system.h"
|
2009-11-05 17:32:06 +00:00
|
|
|
#include "wm_event_types.h"
|
Holiday coding log :)
Nice formatted version (pictures soon):
http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability
Short list of main changes:
- Transparent region option (over main region), added code to blend in/out such panels.
- Min size window now 640 x 480
- Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake.
- Macbook retina support, use command line --no-native-pixels to disable it
- Timeline Marker label was drawing wrong
- Trackpad and magic mouse: supports zoom (hold ctrl)
- Fix for splash position: removed ghost function and made window size update after creation immediate
- Fast undo buffer save now adds UI as well. Could be checked for regular file save even...
Quit.blend and temp file saving use this now.
- Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)"
- New Userpref option "Keep Session" - this always saves quit.blend, and loads on start.
This allows keeping UI and data without actual saves, until you actually save.
When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header)
- Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v).
Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards.
- User preferences (themes, keymaps, user settings) now can be saved as a separate file.
Old option is called "Save Startup File" the new one "Save User Settings".
To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still.
- OSX: fixed bug that stopped giving mouse events outside window.
This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
|
|
|
#include "wm_files.h"
|
2009-05-19 12:54:54 +00:00
|
|
|
#include "wm_window.h"
|
2020-04-04 02:17:49 +02:00
|
|
|
#ifdef WITH_XR_OPENXR
|
|
|
|
# include "wm_xr.h"
|
|
|
|
#endif
|
2007-12-24 18:27:28 +00:00
|
|
|
|
2013-02-28 15:31:20 +00:00
|
|
|
#define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)")
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Operator API
|
|
|
|
* \{ */
|
2014-10-28 15:47:51 +01:00
|
|
|
|
2009-07-17 12:26:40 +00:00
|
|
|
/* SOME_OT_op -> some.op */
|
2009-07-18 19:42:13 +00:00
|
|
|
void WM_operator_py_idname(char *to, const char *from)
|
2009-07-17 12:26:40 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
const char *sep = strstr(from, "_OT_");
|
|
|
|
if (sep) {
|
|
|
|
int ofs = (sep - from);
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* note, we use ascii tolower instead of system tolower, because the
|
|
|
|
* latter depends on the locale, and can lead to idname mismatch */
|
|
|
|
memcpy(to, from, sizeof(char) * ofs);
|
|
|
|
BLI_str_tolower_ascii(to, ofs);
|
2009-07-17 12:26:40 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
to[ofs] = '.';
|
|
|
|
BLI_strncpy(to + (ofs + 1), sep + 4, OP_MAX_TYPENAME - (ofs + 1));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* should not happen but support just in case */
|
|
|
|
BLI_strncpy(to, from, OP_MAX_TYPENAME);
|
|
|
|
}
|
2009-07-17 12:26:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* some.op -> SOME_OT_op */
|
2009-07-18 19:42:13 +00:00
|
|
|
void WM_operator_bl_idname(char *to, const char *from)
|
2009-07-17 12:26:40 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (from) {
|
|
|
|
const char *sep = strchr(from, '.');
|
2009-07-17 12:26:40 +00:00
|
|
|
|
2019-09-19 17:15:19 +10:00
|
|
|
int from_len;
|
|
|
|
if (sep && (from_len = strlen(from)) < OP_MAX_TYPENAME - 3) {
|
|
|
|
const int ofs = (sep - from);
|
2019-04-17 06:17:24 +02:00
|
|
|
memcpy(to, from, sizeof(char) * ofs);
|
|
|
|
BLI_str_toupper_ascii(to, ofs);
|
2019-09-19 17:15:19 +10:00
|
|
|
memcpy(to + ofs, "_OT_", 4);
|
|
|
|
memcpy(to + (ofs + 4), sep + 1, (from_len - ofs));
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* should not happen but support just in case */
|
|
|
|
BLI_strncpy(to, from, OP_MAX_TYPENAME);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
to[0] = 0;
|
|
|
|
}
|
2009-07-17 12:26:40 +00:00
|
|
|
}
|
|
|
|
|
2017-08-23 18:17:42 +10:00
|
|
|
/**
|
|
|
|
* Sanity check to ensure #WM_operator_bl_idname won't fail.
|
|
|
|
* \returns true when there are no problems with \a idname, otherwise report an error.
|
|
|
|
*/
|
2019-04-17 06:17:24 +02:00
|
|
|
bool WM_operator_py_idname_ok_or_report(ReportList *reports,
|
|
|
|
const char *classname,
|
|
|
|
const char *idname)
|
|
|
|
{
|
|
|
|
const char *ch = idname;
|
|
|
|
int dot = 0;
|
|
|
|
int i;
|
|
|
|
for (i = 0; *ch; i++, ch++) {
|
|
|
|
if ((*ch >= 'a' && *ch <= 'z') || (*ch >= '0' && *ch <= '9') || *ch == '_') {
|
|
|
|
/* pass */
|
|
|
|
}
|
|
|
|
else if (*ch == '.') {
|
|
|
|
dot++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BKE_reportf(reports,
|
|
|
|
RPT_ERROR,
|
|
|
|
"Registering operator class: '%s', invalid bl_idname '%s', at position %d",
|
|
|
|
classname,
|
|
|
|
idname,
|
|
|
|
i);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i > (MAX_NAME - 3)) {
|
|
|
|
BKE_reportf(reports,
|
|
|
|
RPT_ERROR,
|
|
|
|
"Registering operator class: '%s', invalid bl_idname '%s', "
|
|
|
|
"is too long, maximum length is %d",
|
|
|
|
classname,
|
|
|
|
idname,
|
|
|
|
MAX_NAME - 3);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dot != 1) {
|
|
|
|
BKE_reportf(
|
|
|
|
reports,
|
|
|
|
RPT_ERROR,
|
|
|
|
"Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character",
|
|
|
|
classname,
|
|
|
|
idname);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2017-08-23 18:17:42 +10:00
|
|
|
}
|
|
|
|
|
2015-06-01 14:56:07 +10:00
|
|
|
/**
|
2019-04-20 10:02:28 +02:00
|
|
|
* Print a string representation of the operator,
|
|
|
|
* with the args that it runs so python can run it again.
|
2009-07-29 23:12:30 +00:00
|
|
|
*
|
2013-11-06 20:56:18 +00:00
|
|
|
* When calling from an existing wmOperator, better to use simple version:
|
2015-06-01 14:56:07 +10:00
|
|
|
* `WM_operator_pystring(C, op);`
|
2013-11-06 20:56:18 +00:00
|
|
|
*
|
2015-06-01 14:56:07 +10:00
|
|
|
* \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators).
|
2009-07-29 23:12:30 +00:00
|
|
|
*/
|
2019-04-17 06:17:24 +02:00
|
|
|
char *WM_operator_pystring_ex(bContext *C,
|
|
|
|
wmOperator *op,
|
|
|
|
const bool all_args,
|
|
|
|
const bool macro_args,
|
|
|
|
wmOperatorType *ot,
|
|
|
|
PointerRNA *opptr)
|
|
|
|
{
|
|
|
|
char idname_py[OP_MAX_TYPENAME];
|
|
|
|
|
|
|
|
/* for building the string */
|
|
|
|
DynStr *dynstr = BLI_dynstr_new();
|
|
|
|
char *cstring;
|
|
|
|
char *cstring_args;
|
|
|
|
|
|
|
|
/* arbitrary, but can get huge string with stroke painting otherwise */
|
|
|
|
int max_prop_length = 10;
|
|
|
|
|
|
|
|
WM_operator_py_idname(idname_py, ot->idname);
|
|
|
|
BLI_dynstr_appendf(dynstr, "bpy.ops.%s(", idname_py);
|
|
|
|
|
|
|
|
if (op && op->macro.first) {
|
|
|
|
/* Special handling for macros, else we only get default values in this case... */
|
|
|
|
wmOperator *opm;
|
|
|
|
bool first_op = true;
|
|
|
|
|
|
|
|
opm = macro_args ? op->macro.first : NULL;
|
|
|
|
|
|
|
|
for (; opm; opm = opm->next) {
|
|
|
|
PointerRNA *opmptr = opm->ptr;
|
|
|
|
PointerRNA opmptr_default;
|
|
|
|
if (opmptr == NULL) {
|
|
|
|
WM_operator_properties_create_ptr(&opmptr_default, opm->type);
|
|
|
|
opmptr = &opmptr_default;
|
|
|
|
}
|
|
|
|
|
|
|
|
cstring_args = RNA_pointer_as_string_id(C, opmptr);
|
|
|
|
if (first_op) {
|
|
|
|
BLI_dynstr_appendf(dynstr, "%s=%s", opm->type->idname, cstring_args);
|
|
|
|
first_op = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_dynstr_appendf(dynstr, ", %s=%s", opm->type->idname, cstring_args);
|
|
|
|
}
|
|
|
|
MEM_freeN(cstring_args);
|
|
|
|
|
|
|
|
if (opmptr == &opmptr_default) {
|
|
|
|
WM_operator_properties_free(&opmptr_default);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* only to get the original props for comparisons */
|
|
|
|
PointerRNA opptr_default;
|
|
|
|
const bool macro_args_test = ot->macro.first ? macro_args : true;
|
|
|
|
|
|
|
|
if (opptr == NULL) {
|
|
|
|
WM_operator_properties_create_ptr(&opptr_default, ot);
|
|
|
|
opptr = &opptr_default;
|
|
|
|
}
|
|
|
|
|
|
|
|
cstring_args = RNA_pointer_as_string_keywords(
|
|
|
|
C, opptr, false, all_args, macro_args_test, max_prop_length);
|
|
|
|
BLI_dynstr_append(dynstr, cstring_args);
|
|
|
|
MEM_freeN(cstring_args);
|
|
|
|
|
|
|
|
if (opptr == &opptr_default) {
|
|
|
|
WM_operator_properties_free(&opptr_default);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_dynstr_append(dynstr, ")");
|
|
|
|
|
|
|
|
cstring = BLI_dynstr_get_cstring(dynstr);
|
|
|
|
BLI_dynstr_free(dynstr);
|
|
|
|
return cstring;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *WM_operator_pystring(bContext *C, wmOperator *op, const bool all_args, const bool macro_args)
|
|
|
|
{
|
|
|
|
return WM_operator_pystring_ex(C, op, all_args, macro_args, op->type, op->ptr);
|
2013-11-06 20:56:18 +00:00
|
|
|
}
|
|
|
|
|
2013-12-09 14:20:53 +11:00
|
|
|
/**
|
|
|
|
* \return true if the string was shortened
|
|
|
|
*/
|
|
|
|
bool WM_operator_pystring_abbreviate(char *str, int str_len_max)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
const int str_len = strlen(str);
|
|
|
|
const char *parens_start = strchr(str, '(');
|
2013-12-09 14:20:53 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (parens_start) {
|
|
|
|
const int parens_start_pos = parens_start - str;
|
|
|
|
const char *parens_end = strrchr(parens_start + 1, ')');
|
2013-12-09 14:20:53 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (parens_end) {
|
|
|
|
const int parens_len = parens_end - parens_start;
|
2013-12-09 14:20:53 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (parens_len > str_len_max) {
|
|
|
|
const char *comma_first = strchr(parens_start, ',');
|
2013-12-09 14:20:53 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* truncate after the first comma */
|
|
|
|
if (comma_first) {
|
|
|
|
const char end_str[] = " ... )";
|
|
|
|
const int end_str_len = sizeof(end_str) - 1;
|
2013-12-09 14:20:53 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* leave a place for the first argument*/
|
|
|
|
const int new_str_len = (comma_first - parens_start) + 1;
|
2013-12-09 14:20:53 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (str_len >= new_str_len + parens_start_pos + end_str_len + 1) {
|
|
|
|
/* append " ... )" to the string after the comma */
|
|
|
|
memcpy(str + new_str_len + parens_start_pos, end_str, end_str_len + 1);
|
2013-12-09 14:20:53 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-12-09 14:20:53 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return false;
|
2013-12-09 14:20:53 +11:00
|
|
|
}
|
|
|
|
|
2012-12-18 16:20:30 +00:00
|
|
|
/* return NULL if no match is found */
|
2013-01-22 04:24:01 +00:00
|
|
|
#if 0
|
2018-06-30 20:59:10 +02:00
|
|
|
static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr)
|
2012-12-18 16:20:30 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* loop over all context items and do 2 checks
|
|
|
|
*
|
|
|
|
* - see if the pointer is in the context.
|
|
|
|
* - see if the pointers ID is in the context.
|
|
|
|
*/
|
|
|
|
|
2019-04-20 10:02:28 +02:00
|
|
|
/* Don't get from the context store since this is normally
|
|
|
|
* set only for the UI and not usable elsewhere. */
|
2019-04-17 06:17:24 +02:00
|
|
|
ListBase lb = CTX_data_dir_get_ex(C, false, true, true);
|
|
|
|
LinkData *link;
|
|
|
|
|
|
|
|
const char *member_found = NULL;
|
|
|
|
const char *member_id = NULL;
|
|
|
|
|
|
|
|
for (link = lb.first; link; link = link->next) {
|
|
|
|
const char *identifier = link->data;
|
2019-04-17 08:24:14 +02:00
|
|
|
PointerRNA ctx_item_ptr = {
|
|
|
|
{0}}; // CTX_data_pointer_get(C, identifier); // XXX, this isnt working
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
if (ctx_item_ptr.type == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-08-23 09:52:12 +02:00
|
|
|
if (ptr->owner_id == ctx_item_ptr.owner_id) {
|
2019-04-17 08:24:14 +02:00
|
|
|
if ((ptr->data == ctx_item_ptr.data) && (ptr->type == ctx_item_ptr.type)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
/* found! */
|
|
|
|
member_found = identifier;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (RNA_struct_is_ID(ctx_item_ptr.type)) {
|
|
|
|
/* we found a reference to this ID,
|
|
|
|
* so fallback to it if there is no direct reference */
|
|
|
|
member_id = identifier;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BLI_freelistN(&lb);
|
|
|
|
|
|
|
|
if (member_found) {
|
|
|
|
return member_found;
|
|
|
|
}
|
|
|
|
else if (member_id) {
|
|
|
|
return member_id;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-12-18 16:20:30 +00:00
|
|
|
}
|
2018-06-30 18:05:01 +02:00
|
|
|
|
2013-01-22 04:24:01 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
/* use hard coded checks for now */
|
2018-06-30 18:05:01 +02:00
|
|
|
|
2018-06-30 20:59:10 +02:00
|
|
|
static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr)
|
2013-01-22 04:24:01 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
const char *member_id = NULL;
|
|
|
|
|
2019-08-23 09:52:12 +02:00
|
|
|
if (ptr->owner_id) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
# define CTX_TEST_PTR_ID(C, member, idptr) \
|
|
|
|
{ \
|
|
|
|
const char *ctx_member = member; \
|
|
|
|
PointerRNA ctx_item_ptr = CTX_data_pointer_get(C, ctx_member); \
|
2019-08-23 09:52:12 +02:00
|
|
|
if (ctx_item_ptr.owner_id == idptr) { \
|
2019-04-17 06:17:24 +02:00
|
|
|
member_id = ctx_member; \
|
|
|
|
break; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
(void)0
|
|
|
|
|
|
|
|
# define CTX_TEST_PTR_ID_CAST(C, member, member_full, cast, idptr) \
|
|
|
|
{ \
|
|
|
|
const char *ctx_member = member; \
|
|
|
|
const char *ctx_member_full = member_full; \
|
|
|
|
PointerRNA ctx_item_ptr = CTX_data_pointer_get(C, ctx_member); \
|
2019-08-23 09:52:12 +02:00
|
|
|
if (ctx_item_ptr.owner_id && (ID *)cast(ctx_item_ptr.owner_id) == idptr) { \
|
2019-04-17 06:17:24 +02:00
|
|
|
member_id = ctx_member_full; \
|
|
|
|
break; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
(void)0
|
|
|
|
|
2019-10-18 18:38:24 +11:00
|
|
|
# define TEST_PTR_DATA_TYPE(member, rna_type, rna_ptr, dataptr_cmp) \
|
2019-04-17 06:17:24 +02:00
|
|
|
{ \
|
|
|
|
const char *ctx_member = member; \
|
2019-10-18 18:38:24 +11:00
|
|
|
if (RNA_struct_is_a((rna_ptr)->type, &(rna_type)) && (rna_ptr)->data == (dataptr_cmp)) { \
|
2019-04-17 06:17:24 +02:00
|
|
|
member_id = ctx_member; \
|
|
|
|
break; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
(void)0
|
|
|
|
|
2019-08-23 09:52:12 +02:00
|
|
|
switch (GS(ptr->owner_id->name)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
case ID_SCE: {
|
2019-08-23 09:52:12 +02:00
|
|
|
CTX_TEST_PTR_ID(C, "scene", ptr->owner_id);
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ID_OB: {
|
2019-08-23 09:52:12 +02:00
|
|
|
CTX_TEST_PTR_ID(C, "object", ptr->owner_id);
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* from rna_Main_objects_new */
|
|
|
|
case OB_DATA_SUPPORT_ID_CASE: {
|
|
|
|
# define ID_CAST_OBDATA(id_pt) (((Object *)(id_pt))->data)
|
2019-08-23 09:52:12 +02:00
|
|
|
CTX_TEST_PTR_ID_CAST(C, "object", "object.data", ID_CAST_OBDATA, ptr->owner_id);
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
# undef ID_CAST_OBDATA
|
|
|
|
}
|
|
|
|
case ID_MA: {
|
|
|
|
# define ID_CAST_OBMATACT(id_pt) \
|
2020-02-05 11:23:58 +01:00
|
|
|
(BKE_object_material_get(((Object *)id_pt), ((Object *)id_pt)->actcol))
|
2019-04-17 06:17:24 +02:00
|
|
|
CTX_TEST_PTR_ID_CAST(
|
2019-08-23 09:52:12 +02:00
|
|
|
C, "object", "object.active_material", ID_CAST_OBMATACT, ptr->owner_id);
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
# undef ID_CAST_OBMATACT
|
|
|
|
}
|
|
|
|
case ID_WO: {
|
|
|
|
# define ID_CAST_SCENEWORLD(id_pt) (((Scene *)(id_pt))->world)
|
2019-08-23 09:52:12 +02:00
|
|
|
CTX_TEST_PTR_ID_CAST(C, "scene", "scene.world", ID_CAST_SCENEWORLD, ptr->owner_id);
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
# undef ID_CAST_SCENEWORLD
|
|
|
|
}
|
|
|
|
case ID_SCR: {
|
2019-08-23 09:52:12 +02:00
|
|
|
CTX_TEST_PTR_ID(C, "screen", ptr->owner_id);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
SpaceLink *space_data = CTX_wm_space_data(C);
|
|
|
|
|
2019-10-18 18:38:24 +11:00
|
|
|
TEST_PTR_DATA_TYPE("space_data", RNA_Space, ptr, space_data);
|
|
|
|
TEST_PTR_DATA_TYPE("area", RNA_Area, ptr, CTX_wm_area(C));
|
|
|
|
TEST_PTR_DATA_TYPE("region", RNA_Region, ptr, CTX_wm_region(C));
|
|
|
|
|
|
|
|
switch (space_data->spacetype) {
|
|
|
|
case SPACE_VIEW3D: {
|
|
|
|
const View3D *v3d = (View3D *)space_data;
|
|
|
|
const View3DShading *shading = &v3d->shading;
|
|
|
|
|
|
|
|
TEST_PTR_DATA_TYPE("space_data", RNA_View3DOverlay, ptr, v3d);
|
|
|
|
TEST_PTR_DATA_TYPE("space_data", RNA_View3DShading, ptr, shading);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SPACE_GRAPH: {
|
|
|
|
const SpaceGraph *sipo = (SpaceGraph *)space_data;
|
|
|
|
const bDopeSheet *ads = sipo->ads;
|
|
|
|
TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SPACE_FILE: {
|
|
|
|
const SpaceFile *sfile = (SpaceFile *)space_data;
|
|
|
|
const FileSelectParams *params = sfile->params;
|
|
|
|
TEST_PTR_DATA_TYPE("space_data", RNA_FileSelectParams, ptr, params);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SPACE_IMAGE: {
|
|
|
|
const SpaceImage *sima = (SpaceImage *)space_data;
|
|
|
|
TEST_PTR_DATA_TYPE("space_data", RNA_SpaceUVEditor, ptr, sima);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SPACE_NLA: {
|
|
|
|
const SpaceNla *snla = (SpaceNla *)space_data;
|
|
|
|
const bDopeSheet *ads = snla->ads;
|
|
|
|
TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SPACE_ACTION: {
|
|
|
|
const SpaceAction *sact = (SpaceAction *)space_data;
|
|
|
|
const bDopeSheet *ads = &sact->ads;
|
|
|
|
TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
# undef CTX_TEST_PTR_ID
|
|
|
|
# undef CTX_TEST_PTR_ID_CAST
|
2019-10-18 18:38:24 +11:00
|
|
|
# undef TEST_PTR_DATA_TYPE
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return member_id;
|
2013-01-22 04:24:01 +00:00
|
|
|
}
|
|
|
|
#endif
|
2012-12-18 16:20:30 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static char *wm_prop_pystring_from_context(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *prop,
|
|
|
|
int index)
|
2018-06-30 18:05:01 +02:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
const char *member_id = wm_context_member_from_ptr(C, ptr);
|
|
|
|
char *ret = NULL;
|
|
|
|
if (member_id != NULL) {
|
|
|
|
char *prop_str = RNA_path_struct_property_py(ptr, prop, index);
|
|
|
|
if (prop_str) {
|
|
|
|
ret = BLI_sprintfN("bpy.context.%s.%s", member_id, prop_str);
|
|
|
|
MEM_freeN(prop_str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
2018-06-30 18:05:01 +02:00
|
|
|
}
|
|
|
|
|
2018-06-30 20:59:10 +02:00
|
|
|
const char *WM_context_member_from_ptr(bContext *C, const PointerRNA *ptr)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return wm_context_member_from_ptr(C, ptr);
|
2018-06-30 20:59:10 +02:00
|
|
|
}
|
|
|
|
|
2012-12-18 15:22:06 +00:00
|
|
|
char *WM_prop_pystring_assign(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index)
|
2012-12-18 14:11:19 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
char *lhs, *rhs, *ret;
|
2012-12-18 14:11:19 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
lhs = C ? wm_prop_pystring_from_context(C, ptr, prop, index) : NULL;
|
2012-12-18 16:20:30 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (lhs == NULL) {
|
|
|
|
/* fallback to bpy.data.foo[id] if we dont find in the context */
|
2019-08-22 20:43:19 +03:00
|
|
|
lhs = RNA_path_full_property_py(CTX_data_main(C), ptr, prop, index);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-12-18 16:20:30 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (!lhs) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-12-18 14:11:19 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
rhs = RNA_property_as_string(C, ptr, prop, index, INT_MAX);
|
|
|
|
if (!rhs) {
|
|
|
|
MEM_freeN(lhs);
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-12-18 14:11:19 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ret = BLI_sprintfN("%s = %s", lhs, rhs);
|
|
|
|
MEM_freeN(lhs);
|
|
|
|
MEM_freeN(rhs);
|
|
|
|
return ret;
|
2012-12-18 14:11:19 +00:00
|
|
|
}
|
|
|
|
|
2009-11-24 16:19:15 +00:00
|
|
|
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_pointer_create(NULL, ot->srna, NULL, ptr);
|
2009-11-24 16:19:15 +00:00
|
|
|
}
|
|
|
|
|
2009-01-01 20:44:40 +00:00
|
|
|
void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOperatorType *ot = WM_operatortype_find(opstring, false);
|
2009-01-01 20:44:40 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (ot) {
|
|
|
|
WM_operator_properties_create_ptr(ptr, ot);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
RNA_pointer_create(NULL, &RNA_OperatorProperties, NULL, ptr);
|
|
|
|
}
|
2009-01-01 20:44:40 +00:00
|
|
|
}
|
|
|
|
|
2009-10-12 12:54:08 +00:00
|
|
|
/* similar to the function above except its uses ID properties
|
|
|
|
* used for keymaps and macros */
|
|
|
|
void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (*properties == NULL) {
|
|
|
|
IDPropertyTemplate val = {0};
|
|
|
|
*properties = IDP_New(IDP_GROUP, &val, "wmOpItemProp");
|
|
|
|
}
|
2009-10-12 12:54:08 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (*ptr == NULL) {
|
|
|
|
*ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
|
|
|
|
WM_operator_properties_create(*ptr, opstring);
|
|
|
|
}
|
2009-10-12 12:54:08 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
(*ptr)->data = *properties;
|
2009-10-12 12:54:08 +00:00
|
|
|
}
|
|
|
|
|
2013-04-04 02:05:11 +00:00
|
|
|
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
|
2010-01-27 21:19:39 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_STRUCT_BEGIN (ptr, prop) {
|
|
|
|
switch (RNA_property_type(prop)) {
|
|
|
|
case PROP_ENUM:
|
|
|
|
if (no_context) {
|
|
|
|
RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
RNA_def_property_clear_flag(prop, PROP_ENUM_NO_CONTEXT);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_POINTER: {
|
|
|
|
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
|
|
|
|
|
|
|
|
/* recurse into operator properties */
|
|
|
|
if (RNA_struct_is_a(ptype, &RNA_OperatorProperties)) {
|
|
|
|
PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
|
|
|
|
WM_operator_properties_sanitize(&opptr, no_context);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RNA_STRUCT_END;
|
2010-01-27 21:19:39 +00:00
|
|
|
}
|
2009-10-12 12:54:08 +00:00
|
|
|
|
2019-11-25 01:14:39 +11:00
|
|
|
/**
|
|
|
|
* Set all props to their default.
|
|
|
|
*
|
2018-12-12 12:50:58 +11:00
|
|
|
* \param do_update: Only update un-initialized props.
|
2012-10-31 20:29:32 +00:00
|
|
|
*
|
2019-11-25 01:14:39 +11:00
|
|
|
* \note There's nothing specific to operators here.
|
|
|
|
* This could be made a general function.
|
2012-10-31 20:29:32 +00:00
|
|
|
*/
|
2013-11-26 06:39:14 +11:00
|
|
|
bool WM_operator_properties_default(PointerRNA *ptr, const bool do_update)
|
2012-10-31 20:29:32 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
bool changed = false;
|
|
|
|
RNA_STRUCT_BEGIN (ptr, prop) {
|
|
|
|
switch (RNA_property_type(prop)) {
|
|
|
|
case PROP_POINTER: {
|
|
|
|
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
|
|
|
|
if (ptype != &RNA_Struct) {
|
|
|
|
PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
|
|
|
|
changed |= WM_operator_properties_default(&opptr, do_update);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
if ((do_update == false) || (RNA_property_is_set(ptr, prop) == false)) {
|
|
|
|
if (RNA_property_reset(ptr, prop, -1)) {
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RNA_STRUCT_END;
|
|
|
|
|
|
|
|
return changed;
|
2012-10-31 20:29:32 +00:00
|
|
|
}
|
|
|
|
|
2012-01-11 19:33:14 +00:00
|
|
|
/* remove all props without PROP_SKIP_SAVE */
|
|
|
|
void WM_operator_properties_reset(wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (op->ptr->data) {
|
|
|
|
PropertyRNA *iterprop;
|
|
|
|
iterprop = RNA_struct_iterator_property(op->type->srna);
|
2012-01-11 19:33:14 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_PROP_BEGIN (op->ptr, itemptr, iterprop) {
|
|
|
|
PropertyRNA *prop = itemptr.data;
|
2012-01-11 19:33:14 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
|
|
|
|
const char *identifier = RNA_property_identifier(prop);
|
|
|
|
RNA_struct_idprops_unset(op->ptr, identifier);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RNA_PROP_END;
|
|
|
|
}
|
2012-01-11 19:33:14 +00:00
|
|
|
}
|
|
|
|
|
2013-11-29 16:01:03 +11:00
|
|
|
void WM_operator_properties_clear(PointerRNA *ptr)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
IDProperty *properties = ptr->data;
|
2013-11-29 16:01:03 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (properties) {
|
|
|
|
IDP_ClearProperty(properties);
|
|
|
|
}
|
2013-11-29 16:01:03 +11:00
|
|
|
}
|
|
|
|
|
2009-01-01 20:44:40 +00:00
|
|
|
void WM_operator_properties_free(PointerRNA *ptr)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
IDProperty *properties = ptr->data;
|
2009-01-01 20:44:40 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (properties) {
|
|
|
|
IDP_FreeProperty(properties);
|
|
|
|
ptr->data = NULL; /* just in case */
|
|
|
|
}
|
2009-01-01 20:44:40 +00:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
2020-01-10 17:27:53 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Operator Last Properties API
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
#if 1 /* may want to disable operator remembering previous state for testing */
|
|
|
|
|
|
|
|
static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_properties)
|
|
|
|
{
|
|
|
|
bool changed = false;
|
|
|
|
IDPropertyTemplate val = {0};
|
|
|
|
IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
|
|
|
|
PropertyRNA *iterprop;
|
|
|
|
|
|
|
|
CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname);
|
|
|
|
|
|
|
|
iterprop = RNA_struct_iterator_property(op->type->srna);
|
|
|
|
|
|
|
|
RNA_PROP_BEGIN (op->ptr, itemptr, iterprop) {
|
|
|
|
PropertyRNA *prop = itemptr.data;
|
|
|
|
if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
|
|
|
|
if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */
|
|
|
|
const char *identifier = RNA_property_identifier(prop);
|
|
|
|
IDProperty *idp_src = IDP_GetPropertyFromGroup(last_properties, identifier);
|
|
|
|
if (idp_src) {
|
|
|
|
IDProperty *idp_dst = IDP_CopyProperty(idp_src);
|
|
|
|
|
|
|
|
/* note - in the future this may need to be done recursively,
|
|
|
|
* but for now RNA doesn't access nested operators */
|
|
|
|
idp_dst->flag |= IDP_FLAG_GHOST;
|
|
|
|
|
|
|
|
/* add to temporary group instead of immediate replace,
|
|
|
|
* because we are iterating over this group */
|
|
|
|
IDP_AddToGroup(replaceprops, idp_dst);
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RNA_PROP_END;
|
|
|
|
|
|
|
|
IDP_MergeGroup(op->properties, replaceprops, true);
|
|
|
|
IDP_FreeProperty(replaceprops);
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WM_operator_last_properties_init(wmOperator *op)
|
|
|
|
{
|
|
|
|
bool changed = false;
|
|
|
|
if (op->type->last_properties) {
|
|
|
|
changed |= operator_last_properties_init_impl(op, op->type->last_properties);
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (wmOperator *, opm, &op->macro) {
|
2020-01-10 17:27:53 +11:00
|
|
|
IDProperty *idp_src = IDP_GetPropertyFromGroup(op->type->last_properties, opm->idname);
|
|
|
|
if (idp_src) {
|
|
|
|
changed |= operator_last_properties_init_impl(opm, idp_src);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WM_operator_last_properties_store(wmOperator *op)
|
|
|
|
{
|
|
|
|
if (op->type->last_properties) {
|
|
|
|
IDP_FreeProperty(op->type->last_properties);
|
|
|
|
op->type->last_properties = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (op->properties) {
|
|
|
|
CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname);
|
|
|
|
op->type->last_properties = IDP_CopyProperty(op->properties);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (op->macro.first != NULL) {
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (wmOperator *, opm, &op->macro) {
|
2020-01-10 17:27:53 +11:00
|
|
|
if (opm->properties) {
|
|
|
|
if (op->type->last_properties == NULL) {
|
|
|
|
op->type->last_properties = IDP_New(
|
|
|
|
IDP_GROUP, &(IDPropertyTemplate){0}, "wmOperatorProperties");
|
|
|
|
}
|
|
|
|
IDProperty *idp_macro = IDP_CopyProperty(opm->properties);
|
|
|
|
STRNCPY(idp_macro->name, opm->type->idname);
|
|
|
|
IDP_ReplaceInGroup(op->type->last_properties, idp_macro);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (op->type->last_properties != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
bool WM_operator_last_properties_init(wmOperator *UNUSED(op))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Default Operator Callbacks
|
|
|
|
* \{ */
|
2007-12-24 18:27:28 +00:00
|
|
|
|
2019-11-22 16:46:15 +01:00
|
|
|
/**
|
|
|
|
* Helper to get select and tweak-transform to work conflict free and as desired. See
|
|
|
|
* #WM_operator_properties_generic_select() for details.
|
|
|
|
*
|
|
|
|
* To be used together with #WM_generic_select_invoke() and
|
|
|
|
* #WM_operator_properties_generic_select().
|
|
|
|
*/
|
WM: Utilities for select operators to work with click-dragging items
Based on work by Bastien and Brecht in the Node Editor, this adds more
generalized support for selecting items so that click+drag actions on
items (nodes, makers, dopesheet keys, etc.) works as wanted.
Note that this only adds the barebones to support this in other editors,
it's not used yet (will be done in followup commits).
The behavior is supposed to work as follows:
* Clicking an unselected item immediately selects it, and deselects
other items (doesn't wait for release events).
* Click+drag on an unselected item immediately selects it, deselects
others and drags it in one go (don't require selecting it first!).
* Click+drag on a selected item won't change the selection state (and
won't send an undo push) and start dragging all selected items as soon
as the drag event is recognized.
* Clicking on a selected item will still deselect others, but that will
only happen on mouse release, when we know the intention is not to drag
the item.
Included in: https://developer.blender.org/D5979
Reviewed by: Brecht van Lommel, William Reynish
2019-10-04 15:11:19 +02:00
|
|
|
int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
{
|
|
|
|
PropertyRNA *wait_to_deselect_prop = RNA_struct_find_property(op->ptr,
|
|
|
|
"wait_to_deselect_others");
|
|
|
|
const short init_event_type = (short)POINTER_AS_INT(op->customdata);
|
|
|
|
int ret_value = 0;
|
|
|
|
|
|
|
|
/* get settings from RNA properties for operator */
|
|
|
|
int mval[2];
|
|
|
|
mval[0] = RNA_int_get(op->ptr, "mouse_x");
|
|
|
|
mval[1] = RNA_int_get(op->ptr, "mouse_y");
|
|
|
|
|
|
|
|
if (init_event_type == 0) {
|
|
|
|
if (event->val == KM_PRESS) {
|
|
|
|
RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, true);
|
|
|
|
|
|
|
|
ret_value = op->type->exec(C, op);
|
|
|
|
OPERATOR_RETVAL_CHECK(ret_value);
|
|
|
|
|
|
|
|
op->customdata = POINTER_FROM_INT((int)event->type);
|
|
|
|
if (ret_value & OPERATOR_RUNNING_MODAL) {
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
}
|
|
|
|
return ret_value | OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* If we are in init phase, and cannot validate init of modal operations,
|
|
|
|
* just fall back to basic exec.
|
|
|
|
*/
|
|
|
|
RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, false);
|
|
|
|
|
|
|
|
ret_value = op->type->exec(C, op);
|
|
|
|
OPERATOR_RETVAL_CHECK(ret_value);
|
|
|
|
|
|
|
|
return ret_value | OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event->type == init_event_type && event->val == KM_RELEASE) {
|
|
|
|
RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, false);
|
|
|
|
|
|
|
|
ret_value = op->type->exec(C, op);
|
|
|
|
OPERATOR_RETVAL_CHECK(ret_value);
|
|
|
|
|
|
|
|
return ret_value | OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
|
|
|
|
const int drag_delta[2] = {
|
|
|
|
mval[0] - event->mval[0],
|
|
|
|
mval[1] - event->mval[1],
|
|
|
|
};
|
|
|
|
/* If user moves mouse more than defined threshold, we consider select operator as
|
|
|
|
* finished. Otherwise, it is still running until we get an 'release' event. In any
|
|
|
|
* case, we pass through event, but select op is not finished yet. */
|
|
|
|
if (WM_event_drag_test_with_delta(event, drag_delta)) {
|
|
|
|
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Important not to return anything other than PASS_THROUGH here,
|
|
|
|
* otherwise it prevents underlying tweak detection code to work properly. */
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-06 19:28:53 +01:00
|
|
|
return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
|
WM: Utilities for select operators to work with click-dragging items
Based on work by Bastien and Brecht in the Node Editor, this adds more
generalized support for selecting items so that click+drag actions on
items (nodes, makers, dopesheet keys, etc.) works as wanted.
Note that this only adds the barebones to support this in other editors,
it's not used yet (will be done in followup commits).
The behavior is supposed to work as follows:
* Clicking an unselected item immediately selects it, and deselects
other items (doesn't wait for release events).
* Click+drag on an unselected item immediately selects it, deselects
others and drags it in one go (don't require selecting it first!).
* Click+drag on a selected item won't change the selection state (and
won't send an undo push) and start dragging all selected items as soon
as the drag event is recognized.
* Clicking on a selected item will still deselect others, but that will
only happen on mouse release, when we know the intention is not to drag
the item.
Included in: https://developer.blender.org/D5979
Reviewed by: Brecht van Lommel, William Reynish
2019-10-04 15:11:19 +02:00
|
|
|
}
|
|
|
|
|
2019-11-22 16:46:15 +01:00
|
|
|
/**
|
|
|
|
* Helper to get select and tweak-transform to work conflict free and as desired. See
|
|
|
|
* #WM_operator_properties_generic_select() for details.
|
|
|
|
*
|
|
|
|
* To be used together with #WM_generic_select_modal() and
|
|
|
|
* #WM_operator_properties_generic_select().
|
|
|
|
*/
|
WM: Utilities for select operators to work with click-dragging items
Based on work by Bastien and Brecht in the Node Editor, this adds more
generalized support for selecting items so that click+drag actions on
items (nodes, makers, dopesheet keys, etc.) works as wanted.
Note that this only adds the barebones to support this in other editors,
it's not used yet (will be done in followup commits).
The behavior is supposed to work as follows:
* Clicking an unselected item immediately selects it, and deselects
other items (doesn't wait for release events).
* Click+drag on an unselected item immediately selects it, deselects
others and drags it in one go (don't require selecting it first!).
* Click+drag on a selected item won't change the selection state (and
won't send an undo push) and start dragging all selected items as soon
as the drag event is recognized.
* Clicking on a selected item will still deselect others, but that will
only happen on mouse release, when we know the intention is not to drag
the item.
Included in: https://developer.blender.org/D5979
Reviewed by: Brecht van Lommel, William Reynish
2019-10-04 15:11:19 +02:00
|
|
|
int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
{
|
|
|
|
RNA_int_set(op->ptr, "mouse_x", event->mval[0]);
|
|
|
|
RNA_int_set(op->ptr, "mouse_y", event->mval[1]);
|
|
|
|
|
|
|
|
op->customdata = POINTER_FROM_INT(0);
|
|
|
|
|
|
|
|
return op->type->modal(C, op, event);
|
|
|
|
}
|
|
|
|
|
2013-09-16 04:19:48 +00:00
|
|
|
void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op)
|
2012-12-09 10:48:18 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (op->flag & OP_IS_INVOKE) {
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
|
|
|
|
|
|
|
const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) :
|
|
|
|
ED_scene_grid_scale(scene, NULL);
|
|
|
|
|
|
|
|
/* always run, so the values are initialized,
|
|
|
|
* otherwise we may get differ behavior when (dia != 1.0) */
|
|
|
|
RNA_STRUCT_BEGIN (op->ptr, prop) {
|
|
|
|
if (RNA_property_type(prop) == PROP_FLOAT) {
|
|
|
|
PropertySubType pstype = RNA_property_subtype(prop);
|
|
|
|
if (pstype == PROP_DISTANCE) {
|
|
|
|
/* we don't support arrays yet */
|
|
|
|
BLI_assert(RNA_property_array_check(prop) == false);
|
|
|
|
/* initialize */
|
|
|
|
if (!RNA_property_is_set_ex(op->ptr, prop, false)) {
|
|
|
|
const float value = RNA_property_float_get_default(op->ptr, prop) * dia;
|
|
|
|
RNA_property_float_set(op->ptr, prop, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RNA_STRUCT_END;
|
|
|
|
}
|
2012-12-09 10:48:18 +00:00
|
|
|
}
|
|
|
|
|
2013-09-16 04:04:44 +00:00
|
|
|
int WM_operator_smooth_viewtx_get(const wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return (op->flag & OP_IS_INVOKE) ? U.smooth_viewtx : 0;
|
2013-09-16 04:04:44 +00:00
|
|
|
}
|
|
|
|
|
2008-12-24 18:06:51 +00:00
|
|
|
/* invoke callback, uses enum property named "type" */
|
2016-05-31 16:30:44 +10:00
|
|
|
int WM_menu_invoke_ex(bContext *C, wmOperator *op, int opcontext)
|
2008-12-17 15:38:40 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
PropertyRNA *prop = op->type->prop;
|
|
|
|
uiPopupMenu *pup;
|
|
|
|
uiLayout *layout;
|
|
|
|
|
|
|
|
if (prop == NULL) {
|
|
|
|
CLOG_ERROR(WM_LOG_OPERATORS, "'%s' has no enum property set", op->type->idname);
|
|
|
|
}
|
|
|
|
else if (RNA_property_type(prop) != PROP_ENUM) {
|
|
|
|
CLOG_ERROR(WM_LOG_OPERATORS,
|
|
|
|
"'%s', '%s' is not an enum property",
|
|
|
|
op->type->idname,
|
|
|
|
RNA_property_identifier(prop));
|
|
|
|
}
|
|
|
|
else if (RNA_property_is_set(op->ptr, prop)) {
|
|
|
|
const int retval = op->type->exec(C, op);
|
|
|
|
OPERATOR_RETVAL_CHECK(retval);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
else {
|
2019-06-04 15:50:15 +02:00
|
|
|
pup = UI_popup_menu_begin(C, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
|
2019-04-17 06:17:24 +02:00
|
|
|
layout = UI_popup_menu_layout(pup);
|
|
|
|
/* set this so the default execution context is the same as submenus */
|
|
|
|
uiLayoutSetOperatorContext(layout, opcontext);
|
|
|
|
uiItemsFullEnumO(
|
|
|
|
layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, opcontext, 0);
|
|
|
|
UI_popup_menu_end(C, pup);
|
|
|
|
return OPERATOR_INTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2008-12-17 15:38:40 +00:00
|
|
|
}
|
|
|
|
|
2016-05-31 16:30:44 +10:00
|
|
|
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_REGION_WIN);
|
2016-05-31 16:30:44 +10:00
|
|
|
}
|
|
|
|
|
2017-03-13 10:43:49 +01:00
|
|
|
struct EnumSearchMenu {
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOperator *op; /* the operator that will be executed when selecting an item */
|
2017-03-13 10:43:49 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
bool use_previews;
|
|
|
|
short prv_cols, prv_rows;
|
2017-03-13 10:43:49 +01:00
|
|
|
};
|
2010-01-15 17:23:16 +00:00
|
|
|
|
2019-04-20 10:02:28 +02:00
|
|
|
/** Generic enum search invoke popup. */
|
2020-03-06 16:56:42 +01:00
|
|
|
static uiBlock *wm_enum_search_menu(bContext *C, ARegion *region, void *arg)
|
2010-01-15 17:23:16 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
struct EnumSearchMenu *search_menu = arg;
|
|
|
|
wmWindow *win = CTX_wm_window(C);
|
|
|
|
wmOperator *op = search_menu->op;
|
2019-04-20 10:02:28 +02:00
|
|
|
/* template_ID uses 4 * widget_unit for width,
|
|
|
|
* we use a bit more, some items may have a suffix to show. */
|
2019-04-17 06:17:24 +02:00
|
|
|
const int width = search_menu->use_previews ? 5 * U.widget_unit * search_menu->prv_cols :
|
|
|
|
UI_searchbox_size_x();
|
|
|
|
const int height = search_menu->use_previews ? 5 * U.widget_unit * search_menu->prv_rows :
|
|
|
|
UI_searchbox_size_y();
|
|
|
|
static char search[256] = "";
|
|
|
|
uiBlock *block;
|
|
|
|
uiBut *but;
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
|
2019-04-17 06:17:24 +02:00
|
|
|
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
|
|
|
|
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
|
|
|
|
|
|
|
|
search[0] = '\0';
|
|
|
|
BLI_assert(search_menu->use_previews ||
|
|
|
|
(search_menu->prv_cols == 0 && search_menu->prv_rows == 0));
|
2012-04-13 19:59:29 +00:00
|
|
|
#if 0 /* ok, this isn't so easy... */
|
2019-04-17 08:24:14 +02:00
|
|
|
uiDefBut(block,
|
|
|
|
UI_BTYPE_LABEL,
|
|
|
|
0,
|
2019-06-04 15:50:15 +02:00
|
|
|
WM_operatortype_name(op->type, op->ptr),
|
2019-04-17 08:24:14 +02:00
|
|
|
10,
|
|
|
|
10,
|
|
|
|
UI_searchbox_size_x(),
|
|
|
|
UI_UNIT_Y,
|
|
|
|
NULL,
|
|
|
|
0.0,
|
|
|
|
0.0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
"");
|
2012-04-13 19:59:29 +00:00
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
but = uiDefSearchButO_ptr(block,
|
|
|
|
op->type,
|
|
|
|
op->ptr->data,
|
|
|
|
search,
|
|
|
|
0,
|
|
|
|
ICON_VIEWZOOM,
|
|
|
|
sizeof(search),
|
|
|
|
10,
|
|
|
|
10,
|
|
|
|
width,
|
|
|
|
UI_UNIT_Y,
|
|
|
|
search_menu->prv_rows,
|
|
|
|
search_menu->prv_cols,
|
|
|
|
"");
|
|
|
|
|
|
|
|
/* fake button, it holds space for search items */
|
|
|
|
uiDefBut(block,
|
|
|
|
UI_BTYPE_LABEL,
|
|
|
|
0,
|
|
|
|
"",
|
|
|
|
10,
|
|
|
|
10 - UI_searchbox_size_y(),
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* Move it downwards, mouse over button. */
|
2019-08-27 12:16:16 +02:00
|
|
|
UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, (const int[2]){0, -UI_UNIT_Y});
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
UI_but_focus_on_enter_event(win, but);
|
|
|
|
|
|
|
|
return block;
|
2010-01-15 17:23:16 +00:00
|
|
|
}
|
|
|
|
|
2017-03-13 10:43:49 +01:00
|
|
|
/**
|
|
|
|
* Similar to #WM_enum_search_invoke, but draws previews. Also, this can't
|
|
|
|
* be used as invoke callback directly since it needs additional info.
|
|
|
|
*/
|
2019-04-17 06:17:24 +02:00
|
|
|
int WM_enum_search_invoke_previews(bContext *C, wmOperator *op, short prv_cols, short prv_rows)
|
2017-03-13 10:43:49 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
static struct EnumSearchMenu search_menu;
|
2017-03-13 10:43:49 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
search_menu.op = op;
|
|
|
|
search_menu.use_previews = true;
|
|
|
|
search_menu.prv_cols = prv_cols;
|
|
|
|
search_menu.prv_rows = prv_rows;
|
2017-03-13 10:43:49 +01:00
|
|
|
|
2019-05-14 15:38:51 +02:00
|
|
|
UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu, NULL);
|
2017-03-13 10:43:49 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_INTERFACE;
|
2017-03-13 10:43:49 +01:00
|
|
|
}
|
2010-01-15 17:23:16 +00:00
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
2010-01-15 17:23:16 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
static struct EnumSearchMenu search_menu;
|
|
|
|
search_menu.op = op;
|
2019-05-14 15:38:51 +02:00
|
|
|
UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu, NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_INTERFACE;
|
2010-01-15 17:23:16 +00:00
|
|
|
}
|
|
|
|
|
2009-10-10 12:29:11 +00:00
|
|
|
/* Can't be used as an invoke directly, needs message arg (can be NULL) */
|
2019-05-14 14:13:02 +02:00
|
|
|
int WM_operator_confirm_message_ex(bContext *C,
|
|
|
|
wmOperator *op,
|
|
|
|
const char *title,
|
|
|
|
const int icon,
|
|
|
|
const char *message,
|
|
|
|
const short opcontext)
|
2007-12-24 18:27:28 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
uiPopupMenu *pup;
|
|
|
|
uiLayout *layout;
|
|
|
|
IDProperty *properties = op->ptr->data;
|
2009-12-22 11:59:30 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (properties && properties->len) {
|
|
|
|
properties = IDP_CopyProperty(op->ptr->data);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
properties = NULL;
|
|
|
|
}
|
2009-02-04 11:52:16 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
pup = UI_popup_menu_begin(C, title, icon);
|
|
|
|
layout = UI_popup_menu_layout(pup);
|
2019-05-14 14:13:02 +02:00
|
|
|
uiItemFullO_ptr(layout, op->type, message, ICON_NONE, properties, opcontext, 0, NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
UI_popup_menu_end(C, pup);
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_INTERFACE;
|
2007-12-24 18:27:28 +00:00
|
|
|
}
|
2008-12-17 15:38:40 +00:00
|
|
|
|
2014-02-09 12:28:14 +11:00
|
|
|
int WM_operator_confirm_message(bContext *C, wmOperator *op, const char *message)
|
|
|
|
{
|
2019-05-14 14:13:02 +02:00
|
|
|
return WM_operator_confirm_message_ex(
|
|
|
|
C, op, IFACE_("OK?"), ICON_QUESTION, message, WM_OP_EXEC_REGION_WIN);
|
2014-02-09 12:28:14 +11:00
|
|
|
}
|
2009-10-10 12:29:11 +00:00
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
2009-10-10 12:29:11 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return WM_operator_confirm_message(C, op, NULL);
|
2009-10-10 12:29:11 +00:00
|
|
|
}
|
|
|
|
|
2018-11-20 10:06:02 +11:00
|
|
|
int WM_operator_confirm_or_exec(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
const bool confirm = RNA_boolean_get(op->ptr, "confirm");
|
|
|
|
if (confirm) {
|
|
|
|
return WM_operator_confirm_message(C, op, NULL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return op->type->exec(C, op);
|
|
|
|
}
|
2018-11-20 10:06:02 +11:00
|
|
|
}
|
|
|
|
|
2009-09-12 19:54:39 +00:00
|
|
|
/* op->invoke, opens fileselect if path property not set, otherwise executes */
|
2013-03-13 09:03:46 +00:00
|
|
|
int WM_operator_filesel(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
2009-01-26 09:13:15 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
|
|
|
|
return WM_operator_call_notest(C, op); /* call exec direct */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
WM_event_add_fileselect(C, op);
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
}
|
2009-01-26 09:13:15 +00:00
|
|
|
}
|
|
|
|
|
2013-06-18 15:30:51 +00:00
|
|
|
bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFormatData *im_format)
|
2012-04-24 02:01:23 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
PropertyRNA *prop;
|
|
|
|
char filepath[FILE_MAX];
|
|
|
|
/* dont NULL check prop, this can only run on ops with a 'filepath' */
|
|
|
|
prop = RNA_struct_find_property(op->ptr, "filepath");
|
|
|
|
RNA_property_string_get(op->ptr, prop, filepath);
|
|
|
|
if (BKE_image_path_ensure_ext_from_imformat(filepath, im_format)) {
|
|
|
|
RNA_property_string_set(op->ptr, prop, filepath);
|
|
|
|
/* note, we could check for and update 'filename' here,
|
|
|
|
* but so far nothing needs this. */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2012-04-24 02:01:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-24 14:52:17 +00:00
|
|
|
/* op->poll */
|
2018-07-02 11:47:00 +02:00
|
|
|
bool WM_operator_winactive(bContext *C)
|
2007-12-24 18:27:28 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (CTX_wm_window(C) == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
2007-12-24 18:27:28 +00:00
|
|
|
}
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
/* return false, if the UI should be disabled */
|
2013-04-04 02:05:11 +00:00
|
|
|
bool WM_operator_check_ui_enabled(const bContext *C, const char *idname)
|
2011-12-11 19:23:02 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
2011-12-11 19:23:02 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return !((ED_undo_is_valid(C, idname) == false) || WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY));
|
2011-12-11 19:23:02 +00:00
|
|
|
}
|
|
|
|
|
2011-05-23 10:14:07 +00:00
|
|
|
wmOperator *WM_operator_last_redo(const bContext *C)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
|
|
|
wmOperator *op;
|
2011-05-23 10:14:07 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* only for operators that are registered and did an undo push */
|
|
|
|
for (op = wm->operators.last; op; op = op->prev) {
|
|
|
|
if ((op->type->flag & OPTYPE_REGISTER) && (op->type->flag & OPTYPE_UNDO)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-05-23 10:14:07 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return op;
|
2011-05-23 10:14:07 +00:00
|
|
|
}
|
|
|
|
|
2018-05-02 17:59:43 +02:00
|
|
|
IDProperty *WM_operator_last_properties_ensure_idprops(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (ot->last_properties == NULL) {
|
|
|
|
IDPropertyTemplate val = {0};
|
|
|
|
ot->last_properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
|
|
|
|
}
|
|
|
|
return ot->last_properties;
|
2018-05-02 17:59:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void WM_operator_last_properties_ensure(wmOperatorType *ot, PointerRNA *ptr)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
IDProperty *props = WM_operator_last_properties_ensure_idprops(ot);
|
|
|
|
RNA_pointer_create(NULL, ot->srna, props, ptr);
|
2018-05-02 17:59:43 +02:00
|
|
|
}
|
|
|
|
|
2014-11-23 22:48:48 +01:00
|
|
|
/**
|
2014-11-24 09:33:12 +01:00
|
|
|
* Use for drag & drop a path or name with operators invoke() function.
|
2014-11-23 22:48:48 +01:00
|
|
|
*/
|
|
|
|
ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short idcode)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
ID *id = NULL;
|
|
|
|
/* check input variables */
|
|
|
|
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
|
|
|
|
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
|
|
|
|
char path[FILE_MAX];
|
|
|
|
bool exists = false;
|
|
|
|
|
|
|
|
RNA_string_get(op->ptr, "filepath", path);
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
|
|
|
if (idcode == ID_IM) {
|
|
|
|
id = (ID *)BKE_image_load_exists_ex(bmain, path, &exists);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_assert(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!id) {
|
|
|
|
BKE_reportf(op->reports,
|
|
|
|
RPT_ERROR,
|
|
|
|
"Cannot read %s '%s': %s",
|
2020-03-19 19:37:00 +01:00
|
|
|
BKE_idtype_idcode_to_name(idcode),
|
2019-04-17 06:17:24 +02:00
|
|
|
path,
|
|
|
|
errno ? strerror(errno) : TIP_("unsupported format"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_relative_path) {
|
|
|
|
if (exists == false) {
|
|
|
|
if (idcode == ID_IM) {
|
|
|
|
BLI_path_rel(((Image *)id)->name, BKE_main_blendfile_path(bmain));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (RNA_struct_property_is_set(op->ptr, "name")) {
|
|
|
|
char name[MAX_ID_NAME - 2];
|
|
|
|
RNA_string_get(op->ptr, "name", name);
|
|
|
|
id = BKE_libblock_find_name(bmain, idcode, name);
|
|
|
|
if (!id) {
|
2020-03-20 12:23:04 +11:00
|
|
|
BKE_reportf(
|
|
|
|
op->reports, RPT_ERROR, "%s '%s' not found", BKE_idtype_idcode_to_name(idcode), name);
|
2019-04-17 06:17:24 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
id_us_plus(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
return id;
|
2014-11-23 22:48:48 +01:00
|
|
|
}
|
|
|
|
|
2013-02-19 13:41:58 +00:00
|
|
|
static void wm_block_redo_cb(bContext *C, void *arg_op, int UNUSED(arg_event))
|
2012-11-28 16:42:39 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOperator *op = arg_op;
|
2012-11-28 16:42:39 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (op == WM_operator_last_redo(C)) {
|
|
|
|
/* operator was already executed once? undo & repeat */
|
|
|
|
ED_undo_operator_repeat(C, op);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* operator not executed yet, call it */
|
|
|
|
ED_undo_push_op(C, op);
|
|
|
|
wm_operator_register(C, op);
|
2012-11-28 16:42:39 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_operator_repeat(C, op);
|
|
|
|
}
|
2012-11-28 16:42:39 +00:00
|
|
|
}
|
|
|
|
|
2013-02-19 13:37:48 +00:00
|
|
|
static void wm_block_redo_cancel_cb(bContext *C, void *arg_op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOperator *op = arg_op;
|
2013-02-19 13:37:48 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* if operator never got executed, free it */
|
|
|
|
if (op != WM_operator_last_redo(C)) {
|
|
|
|
WM_operator_free(op);
|
|
|
|
}
|
2013-02-19 13:37:48 +00:00
|
|
|
}
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
static uiBlock *wm_block_create_redo(bContext *C, ARegion *region, void *arg_op)
|
2009-04-01 14:02:06 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOperator *op = arg_op;
|
|
|
|
uiBlock *block;
|
|
|
|
uiLayout *layout;
|
2020-03-15 17:32:25 +11:00
|
|
|
const uiStyle *style = UI_style_get_dpi();
|
2019-04-17 06:17:24 +02:00
|
|
|
int width = 15 * UI_UNIT_X;
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
block = UI_block_begin(C, region, __func__, UI_EMBOSS);
|
2019-04-17 06:17:24 +02:00
|
|
|
UI_block_flag_disable(block, UI_BLOCK_LOOP);
|
|
|
|
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_REGULAR);
|
|
|
|
|
|
|
|
/* UI_BLOCK_NUMSELECT for layer buttons */
|
|
|
|
UI_block_flag_enable(block, UI_BLOCK_NUMSELECT | UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT);
|
|
|
|
|
|
|
|
/* if register is not enabled, the operator gets freed on OPERATOR_FINISHED
|
|
|
|
* ui_apply_but_funcs_after calls ED_undo_operator_repeate_cb and crashes */
|
2019-08-26 14:32:35 +10:00
|
|
|
BLI_assert(op->type->flag & OPTYPE_REGISTER);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
UI_block_func_handle_set(block, wm_block_redo_cb, arg_op);
|
|
|
|
layout = UI_block_layout(
|
|
|
|
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, width, UI_UNIT_Y, 0, style);
|
|
|
|
|
|
|
|
if (op == WM_operator_last_redo(C)) {
|
|
|
|
if (!WM_operator_check_ui_enabled(C, op->type->name)) {
|
|
|
|
uiLayoutSetEnabled(layout, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-16 18:27:23 +11:00
|
|
|
uiLayout *col = uiLayoutColumn(layout, false);
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
uiTemplateOperatorPropertyButs(
|
|
|
|
C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-08-27 12:16:16 +02:00
|
|
|
UI_block_bounds_set_popup(block, 6 * U.dpi_fac, NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
return block;
|
2009-04-01 14:02:06 +00:00
|
|
|
}
|
|
|
|
|
2012-03-27 01:24:16 +00:00
|
|
|
typedef struct wmOpPopUp {
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOperator *op;
|
|
|
|
int width;
|
|
|
|
int height;
|
|
|
|
int free_op;
|
2011-06-24 03:30:50 +00:00
|
|
|
} wmOpPopUp;
|
|
|
|
|
|
|
|
/* Only invoked by OK button in popups created with wm_block_dialog_create() */
|
2010-03-20 18:03:59 +00:00
|
|
|
static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
|
|
|
|
{
|
2019-07-07 22:30:19 +10:00
|
|
|
wmOperator *op;
|
|
|
|
{
|
|
|
|
/* Execute will free the operator.
|
|
|
|
* In this case, wm_operator_ui_popup_cancel wont run. */
|
|
|
|
wmOpPopUp *data = arg1;
|
|
|
|
op = data->op;
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
2010-03-20 18:03:59 +00:00
|
|
|
|
2019-07-07 22:30:19 +10:00
|
|
|
uiBlock *block = arg2;
|
2019-04-17 06:17:24 +02:00
|
|
|
/* Explicitly set UI_RETURN_OK flag, otherwise the menu might be canceled
|
|
|
|
* in case WM_operator_call_ex exits/reloads the current file (T49199). */
|
2011-06-24 03:30:50 +00:00
|
|
|
|
2019-07-07 22:30:19 +10:00
|
|
|
UI_popup_menu_retval_set(block, UI_RETURN_OK, true);
|
2010-03-20 18:03:59 +00:00
|
|
|
|
2019-04-20 10:02:28 +02:00
|
|
|
/* Get context data *after* WM_operator_call_ex
|
|
|
|
* which might have closed the current file and changed context. */
|
2019-04-17 06:17:24 +02:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2019-07-07 22:30:19 +10:00
|
|
|
UI_popup_block_close(C, win, block);
|
2016-09-01 16:55:01 +02:00
|
|
|
|
2019-07-07 22:30:19 +10:00
|
|
|
WM_operator_call_ex(C, op, true);
|
2010-03-20 18:03:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Dialogs are popups that require user verification (click OK) before exec */
|
2020-03-06 16:56:42 +01:00
|
|
|
static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *userData)
|
2010-03-20 18:03:59 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOpPopUp *data = userData;
|
|
|
|
wmOperator *op = data->op;
|
|
|
|
uiBlock *block;
|
|
|
|
uiLayout *layout;
|
2020-03-15 17:32:25 +11:00
|
|
|
const uiStyle *style = UI_style_get_dpi();
|
2010-03-20 18:03:59 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
block = UI_block_begin(C, region, __func__, UI_EMBOSS);
|
2019-04-17 06:17:24 +02:00
|
|
|
UI_block_flag_disable(block, UI_BLOCK_LOOP);
|
|
|
|
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_REGULAR);
|
2012-06-29 20:29:13 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* intentionally don't use 'UI_BLOCK_MOVEMOUSE_QUIT', some dialogues have many items
|
|
|
|
* where quitting by accident is very annoying */
|
|
|
|
UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NUMSELECT);
|
2010-03-20 18:03:59 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
layout = UI_block_layout(
|
|
|
|
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
uiTemplateOperatorPropertyButs(
|
|
|
|
C, layout, op, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* clear so the OK button is left alone */
|
|
|
|
UI_block_func_set(block, NULL, NULL, NULL);
|
2010-03-20 18:03:59 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* new column so as not to interfere with custom layouts [#26436] */
|
|
|
|
{
|
|
|
|
uiBlock *col_block;
|
|
|
|
uiLayout *col;
|
|
|
|
uiBut *btn;
|
2011-03-10 22:22:47 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
col = uiLayoutColumn(layout, false);
|
|
|
|
col_block = uiLayoutGetBlock(col);
|
|
|
|
/* Create OK button, the callback of which will execute op */
|
|
|
|
btn = uiDefBut(
|
|
|
|
col_block, UI_BTYPE_BUT, 0, IFACE_("OK"), 0, -30, 0, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
|
|
|
|
UI_but_flag_enable(btn, UI_BUT_ACTIVE_DEFAULT);
|
|
|
|
UI_but_func_set(btn, dialog_exec_cb, data, col_block);
|
|
|
|
}
|
2010-03-20 18:03:59 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* center around the mouse */
|
2019-08-27 12:16:16 +02:00
|
|
|
UI_block_bounds_set_popup(
|
|
|
|
block, 6 * U.dpi_fac, (const int[2]){data->width / -2, data->height / 2});
|
2010-03-20 18:03:59 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
UI_block_active_only_flagged_buttons(C, region, block);
|
2019-03-20 22:40:38 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return block;
|
2010-03-20 18:03:59 +00:00
|
|
|
}
|
2009-12-06 04:35:00 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
static uiBlock *wm_operator_ui_create(bContext *C, ARegion *region, void *userData)
|
2009-12-06 04:35:00 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOpPopUp *data = userData;
|
|
|
|
wmOperator *op = data->op;
|
|
|
|
uiBlock *block;
|
|
|
|
uiLayout *layout;
|
2020-03-15 17:32:25 +11:00
|
|
|
const uiStyle *style = UI_style_get_dpi();
|
2009-12-06 04:35:00 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
block = UI_block_begin(C, region, __func__, UI_EMBOSS);
|
2019-04-17 06:17:24 +02:00
|
|
|
UI_block_flag_disable(block, UI_BLOCK_LOOP);
|
|
|
|
UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT);
|
|
|
|
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_REGULAR);
|
2009-12-06 04:35:00 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
layout = UI_block_layout(
|
|
|
|
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
|
2009-12-06 04:35:00 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* since ui is defined the auto-layout args are not used */
|
|
|
|
uiTemplateOperatorPropertyButs(C, layout, op, UI_BUT_LABEL_ALIGN_COLUMN, 0);
|
2009-12-06 04:35:00 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
UI_block_func_set(block, NULL, NULL, NULL);
|
2016-06-08 15:51:01 +02:00
|
|
|
|
2019-08-27 12:16:16 +02:00
|
|
|
UI_block_bounds_set_popup(block, 6 * U.dpi_fac, NULL);
|
2009-12-06 04:35:00 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return block;
|
2009-12-06 04:35:00 +00:00
|
|
|
}
|
|
|
|
|
2013-10-30 23:15:27 +00:00
|
|
|
static void wm_operator_ui_popup_cancel(struct bContext *C, void *userData)
|
2011-06-24 03:30:50 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOpPopUp *data = userData;
|
|
|
|
wmOperator *op = data->op;
|
2013-10-30 23:15:27 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (op) {
|
|
|
|
if (op->type->cancel) {
|
|
|
|
op->type->cancel(C, op);
|
|
|
|
}
|
2013-10-30 23:15:27 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (data->free_op) {
|
|
|
|
WM_operator_free(op);
|
|
|
|
}
|
|
|
|
}
|
2011-06-24 03:30:50 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
MEM_freeN(data);
|
2011-06-24 03:30:50 +00:00
|
|
|
}
|
|
|
|
|
2011-11-24 13:51:31 +00:00
|
|
|
static void wm_operator_ui_popup_ok(struct bContext *C, void *arg, int retval)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOpPopUp *data = arg;
|
|
|
|
wmOperator *op = data->op;
|
2011-11-24 13:51:31 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (op && retval > 0) {
|
|
|
|
WM_operator_call_ex(C, op, true);
|
|
|
|
}
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
MEM_freeN(data);
|
2011-11-24 13:51:31 +00:00
|
|
|
}
|
|
|
|
|
2020-01-28 10:49:05 +01:00
|
|
|
int WM_operator_ui_popup(bContext *C, wmOperator *op, int width)
|
2011-06-24 03:30:50 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOpPopUp *data = MEM_callocN(sizeof(wmOpPopUp), "WM_operator_ui_popup");
|
|
|
|
data->op = op;
|
|
|
|
data->width = width * U.dpi_fac;
|
2020-01-28 10:49:05 +01:00
|
|
|
/* Actual used height depends on the content. */
|
|
|
|
data->height = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
data->free_op = true; /* if this runs and gets registered we may want not to free it */
|
|
|
|
UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data, op);
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
2011-06-24 03:30:50 +00:00
|
|
|
}
|
|
|
|
|
2012-11-14 06:13:42 +00:00
|
|
|
/**
|
|
|
|
* For use by #WM_operator_props_popup_call, #WM_operator_props_popup only.
|
|
|
|
*
|
2015-02-07 04:33:48 +11:00
|
|
|
* \note operator menu needs undo flag enabled, for redo callback */
|
2019-04-17 06:17:24 +02:00
|
|
|
static int wm_operator_props_popup_ex(bContext *C,
|
|
|
|
wmOperator *op,
|
|
|
|
const bool do_call,
|
|
|
|
const bool do_redo)
|
|
|
|
{
|
|
|
|
if ((op->type->flag & OPTYPE_REGISTER) == 0) {
|
|
|
|
BKE_reportf(op->reports,
|
|
|
|
RPT_ERROR,
|
|
|
|
"Operator '%s' does not have register enabled, incorrect invoke function",
|
|
|
|
op->type->idname);
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (do_redo) {
|
|
|
|
if ((op->type->flag & OPTYPE_UNDO) == 0) {
|
|
|
|
BKE_reportf(op->reports,
|
|
|
|
RPT_ERROR,
|
|
|
|
"Operator '%s' does not have undo enabled, incorrect invoke function",
|
|
|
|
op->type->idname);
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we don't have global undo, we can't do undo push for automatic redo,
|
|
|
|
* so we require manual OK clicking in this popup */
|
|
|
|
if (!do_redo || !(U.uiflag & USER_GLOBALUNDO)) {
|
2020-01-28 10:49:05 +01:00
|
|
|
return WM_operator_props_dialog_popup(C, op, 300);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op, op);
|
|
|
|
|
|
|
|
if (do_call) {
|
|
|
|
wm_block_redo_cb(C, op, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
2009-04-01 14:02:06 +00:00
|
|
|
}
|
|
|
|
|
2015-06-01 14:56:07 +10:00
|
|
|
/**
|
|
|
|
* Same as #WM_operator_props_popup but don't use operator redo.
|
|
|
|
* just wraps #WM_operator_props_dialog_popup.
|
2013-10-09 14:35:25 +00:00
|
|
|
*/
|
|
|
|
int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return wm_operator_props_popup_ex(C, op, false, false);
|
2013-10-09 14:35:25 +00:00
|
|
|
}
|
|
|
|
|
2015-06-01 14:56:07 +10:00
|
|
|
/**
|
|
|
|
* Same as #WM_operator_props_popup but call the operator first,
|
2012-11-18 01:22:31 +00:00
|
|
|
* This way - the button values correspond to the result of the operator.
|
2015-06-01 14:56:07 +10:00
|
|
|
* Without this, first access to a button will make the result jump, see T32452.
|
|
|
|
*/
|
2013-03-13 09:03:46 +00:00
|
|
|
int WM_operator_props_popup_call(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
2012-11-14 06:13:42 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return wm_operator_props_popup_ex(C, op, true, true);
|
2012-11-14 06:13:42 +00:00
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
int WM_operator_props_popup(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
2012-11-14 06:13:42 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return wm_operator_props_popup_ex(C, op, false, true);
|
2012-11-14 06:13:42 +00:00
|
|
|
}
|
|
|
|
|
2020-01-28 10:49:05 +01:00
|
|
|
int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width)
|
2010-03-20 18:03:59 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmOpPopUp *data = MEM_callocN(sizeof(wmOpPopUp), "WM_operator_props_dialog_popup");
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
data->op = op;
|
|
|
|
data->width = width * U.dpi_fac;
|
2020-01-28 10:49:05 +01:00
|
|
|
/* Actual height depends on the content. */
|
|
|
|
data->height = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
data->free_op = true; /* if this runs and gets registered we may want not to free it */
|
2010-03-20 18:03:59 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* op is not executed until popup OK but is clicked */
|
|
|
|
UI_popup_block_ex(
|
|
|
|
C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data, op);
|
2010-03-20 18:03:59 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_RUNNING_MODAL;
|
2010-03-20 18:03:59 +00:00
|
|
|
}
|
|
|
|
|
2009-04-01 14:02:06 +00:00
|
|
|
int WM_operator_redo_popup(bContext *C, wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* CTX_wm_reports(C) because operator is on stack, not active in event system */
|
|
|
|
if ((op->type->flag & OPTYPE_REGISTER) == 0) {
|
|
|
|
BKE_reportf(CTX_wm_reports(C),
|
|
|
|
RPT_ERROR,
|
|
|
|
"Operator redo '%s' does not have register enabled, incorrect invoke function",
|
|
|
|
op->type->idname);
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
if (op->type->poll && op->type->poll(C) == 0) {
|
|
|
|
BKE_reportf(
|
|
|
|
CTX_wm_reports(C), RPT_ERROR, "Operator redo '%s': wrong context", op->type->idname);
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-05-14 15:38:51 +02:00
|
|
|
UI_popup_block_invoke(C, wm_block_create_redo, op, NULL);
|
2009-04-01 14:02:06 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
2009-04-01 14:02:06 +00:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Debug Menu Operator
|
|
|
|
*
|
|
|
|
* Set internal debug value, mainly for developers.
|
|
|
|
* \{ */
|
2009-05-22 15:02:32 +00:00
|
|
|
|
|
|
|
static int wm_debug_menu_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
G.debug_value = RNA_int_get(op->ptr, "debug_value");
|
|
|
|
ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C));
|
|
|
|
WM_event_add_notifier(C, NC_WINDOW, NULL);
|
2010-12-15 06:12:16 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-05-22 15:02:32 +00:00
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int wm_debug_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
2009-05-22 15:02:32 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_int_set(op->ptr, "debug_value", G.debug_value);
|
2020-01-28 10:49:05 +01:00
|
|
|
return WM_operator_props_dialog_popup(C, op, 180);
|
2009-05-22 15:02:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void WM_OT_debug_menu(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Debug Menu";
|
|
|
|
ot->idname = "WM_OT_debug_menu";
|
|
|
|
ot->description = "Open a popup to set the debug level";
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->invoke = wm_debug_menu_invoke;
|
|
|
|
ot->exec = wm_debug_menu_exec;
|
|
|
|
ot->poll = WM_operator_winactive;
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_def_int(ot->srna, "debug_value", 0, SHRT_MIN, SHRT_MAX, "Debug Value", "", -10000, 10000);
|
2009-05-22 15:02:32 +00:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Reset Defaults Operator
|
|
|
|
* \{ */
|
|
|
|
|
2012-11-12 21:44:48 +00:00
|
|
|
static int wm_operator_defaults_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
PointerRNA ptr = CTX_data_pointer_get_type(C, "active_operator", &RNA_Operator);
|
2012-11-12 21:44:48 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (!ptr.data) {
|
|
|
|
BKE_report(op->reports, RPT_ERROR, "No operator in context");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
2012-11-12 21:44:48 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_operator_properties_reset((wmOperator *)ptr.data);
|
|
|
|
return OPERATOR_FINISHED;
|
2012-11-12 21:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* used by operator preset menu. pre-2.65 this was a 'Reset' button */
|
|
|
|
static void WM_OT_operator_defaults(wmOperatorType *ot)
|
|
|
|
{
|
2020-03-24 14:04:33 +11:00
|
|
|
ot->name = "Restore Operator Defaults";
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->idname = "WM_OT_operator_defaults";
|
|
|
|
ot->description = "Set the active operator to its default values";
|
2012-11-12 21:44:48 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = wm_operator_defaults_exec;
|
2012-11-12 21:44:48 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->flag = OPTYPE_INTERNAL;
|
2012-11-12 21:44:48 +00:00
|
|
|
}
|
2009-11-23 13:58:55 +00:00
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2020-03-24 11:34:18 +11:00
|
|
|
/** \name Operator/Menu Search Operator
|
2019-08-15 03:26:39 +10:00
|
|
|
* \{ */
|
2016-03-02 13:57:16 +11:00
|
|
|
|
|
|
|
struct SearchPopupInit_Data {
|
2020-03-24 11:34:18 +11:00
|
|
|
enum {
|
|
|
|
SEARCH_TYPE_OPERATOR = 0,
|
|
|
|
SEARCH_TYPE_MENU = 1,
|
|
|
|
} search_type;
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
int size[2];
|
2016-03-02 13:57:16 +11:00
|
|
|
};
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
static uiBlock *wm_block_search_menu(bContext *C, ARegion *region, void *userdata)
|
2009-06-03 18:31:37 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
const struct SearchPopupInit_Data *init_data = userdata;
|
|
|
|
static char search[256] = "";
|
|
|
|
uiBlock *block;
|
|
|
|
uiBut *but;
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
|
2019-04-17 06:17:24 +02:00
|
|
|
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
|
|
|
|
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
|
|
|
|
|
|
|
|
but = uiDefSearchBut(block,
|
|
|
|
search,
|
|
|
|
0,
|
|
|
|
ICON_VIEWZOOM,
|
|
|
|
sizeof(search),
|
|
|
|
10,
|
|
|
|
10,
|
|
|
|
init_data->size[0],
|
|
|
|
UI_UNIT_Y,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
"");
|
2020-03-24 11:34:18 +11:00
|
|
|
|
|
|
|
if (init_data->search_type == SEARCH_TYPE_OPERATOR) {
|
|
|
|
UI_but_func_operator_search(but);
|
|
|
|
}
|
|
|
|
else if (init_data->search_type == SEARCH_TYPE_MENU) {
|
|
|
|
UI_but_func_menu_search(but);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_assert(0);
|
|
|
|
}
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
|
|
|
|
|
|
|
|
/* fake button, it holds space for search items */
|
|
|
|
uiDefBut(block,
|
|
|
|
UI_BTYPE_LABEL,
|
|
|
|
0,
|
|
|
|
"",
|
|
|
|
10,
|
|
|
|
10 - init_data->size[1],
|
|
|
|
init_data->size[0],
|
|
|
|
init_data->size[1],
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* Move it downwards, mouse over button. */
|
2019-08-27 12:16:16 +02:00
|
|
|
UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, (const int[2]){0, -UI_UNIT_Y});
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
return block;
|
2009-06-03 18:31:37 +00:00
|
|
|
}
|
|
|
|
|
2010-10-16 02:40:31 +00:00
|
|
|
static int wm_search_menu_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
|
2009-06-03 18:31:37 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-06-03 18:31:37 +00:00
|
|
|
}
|
|
|
|
|
2020-03-24 11:34:18 +11:00
|
|
|
static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2009-06-03 18:31:37 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* Exception for launching via spacebar */
|
2020-03-18 10:38:37 -06:00
|
|
|
if (event->type == EVT_SPACEKEY) {
|
2019-04-17 06:17:24 +02:00
|
|
|
bool ok = true;
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
|
|
|
if (area) {
|
|
|
|
if (area->spacetype == SPACE_CONSOLE) {
|
2019-04-17 06:17:24 +02:00
|
|
|
/* So we can use the shortcut in the console. */
|
|
|
|
ok = false;
|
|
|
|
}
|
2020-04-03 13:25:03 +02:00
|
|
|
else if (area->spacetype == SPACE_TEXT) {
|
2019-04-17 06:17:24 +02:00
|
|
|
/* So we can use the spacebar in the text editor. */
|
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Object *editob = CTX_data_edit_object(C);
|
|
|
|
if (editob && editob->type == OB_FONT) {
|
|
|
|
/* So we can use the spacebar for entering text. */
|
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!ok) {
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-24 11:34:18 +11:00
|
|
|
int search_type;
|
2020-04-16 00:32:30 +10:00
|
|
|
if (STREQ(op->type->idname, "WM_OT_search_menu")) {
|
|
|
|
search_type = SEARCH_TYPE_MENU;
|
2020-03-24 11:34:18 +11:00
|
|
|
}
|
|
|
|
else {
|
2020-04-16 00:32:30 +10:00
|
|
|
search_type = SEARCH_TYPE_OPERATOR;
|
2020-03-24 11:34:18 +11:00
|
|
|
}
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static struct SearchPopupInit_Data data;
|
2020-03-24 11:34:18 +11:00
|
|
|
data = (struct SearchPopupInit_Data){
|
|
|
|
.search_type = search_type,
|
|
|
|
.size = {UI_searchbox_size_x() * 2, UI_searchbox_size_y()},
|
|
|
|
};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-14 15:38:51 +02:00
|
|
|
UI_popup_block_invoke(C, wm_block_search_menu, &data, NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
return OPERATOR_INTERFACE;
|
2009-06-03 18:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void WM_OT_search_menu(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Search Menu";
|
|
|
|
ot->idname = "WM_OT_search_menu";
|
2020-04-16 00:32:30 +10:00
|
|
|
ot->description = "Pop-up a search over all menus in the current context";
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->invoke = wm_search_menu_invoke;
|
|
|
|
ot->exec = wm_search_menu_exec;
|
|
|
|
ot->poll = WM_operator_winactive;
|
2020-04-16 00:32:30 +10:00
|
|
|
}
|
2020-03-24 11:34:18 +11:00
|
|
|
|
2020-04-16 00:32:30 +10:00
|
|
|
static void WM_OT_search_operator(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
ot->name = "Search Operator";
|
|
|
|
ot->idname = "WM_OT_search_operator";
|
|
|
|
ot->description = "Pop-up a search over all available operators in current context";
|
2020-03-24 11:34:18 +11:00
|
|
|
|
2020-04-16 00:32:30 +10:00
|
|
|
ot->invoke = wm_search_menu_invoke;
|
|
|
|
ot->exec = wm_search_menu_exec;
|
|
|
|
ot->poll = WM_operator_winactive;
|
2009-06-03 18:31:37 +00:00
|
|
|
}
|
|
|
|
|
2010-02-11 21:17:05 +00:00
|
|
|
static int wm_call_menu_exec(bContext *C, wmOperator *op)
|
2009-10-06 13:04:31 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
char idname[BKE_ST_MAXNAME];
|
|
|
|
RNA_string_get(op->ptr, "name", idname);
|
2009-10-06 13:04:31 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return UI_popup_menu_invoke(C, idname, op->reports);
|
2009-10-06 13:04:31 +00:00
|
|
|
}
|
|
|
|
|
2019-06-04 15:50:15 +02:00
|
|
|
static const char *wm_call_menu_get_name(wmOperatorType *ot, PointerRNA *ptr)
|
|
|
|
{
|
|
|
|
char idname[BKE_ST_MAXNAME];
|
|
|
|
RNA_string_get(ptr, "name", idname);
|
|
|
|
MenuType *mt = WM_menutype_find(idname, true);
|
2019-08-02 15:01:02 +02:00
|
|
|
return (mt) ? CTX_IFACE_(mt->translation_context, mt->label) :
|
|
|
|
CTX_IFACE_(ot->translation_context, ot->name);
|
2019-06-04 15:50:15 +02:00
|
|
|
}
|
|
|
|
|
2009-10-06 13:04:31 +00:00
|
|
|
static void WM_OT_call_menu(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Call Menu";
|
|
|
|
ot->idname = "WM_OT_call_menu";
|
|
|
|
ot->description = "Call (draw) a pre-defined menu";
|
2009-10-06 13:04:31 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = wm_call_menu_exec;
|
|
|
|
ot->poll = WM_operator_winactive;
|
2019-06-04 15:50:15 +02:00
|
|
|
ot->get_name = wm_call_menu_get_name;
|
2009-10-06 13:04:31 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->flag = OPTYPE_INTERNAL;
|
2011-06-06 11:56:54 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
|
2009-10-06 13:04:31 +00:00
|
|
|
}
|
2009-05-22 15:02:32 +00:00
|
|
|
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
static int wm_call_pie_menu_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
char idname[BKE_ST_MAXNAME];
|
|
|
|
RNA_string_get(op->ptr, "name", idname);
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return UI_pie_menu_invoke(C, idname, event);
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int wm_call_pie_menu_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
char idname[BKE_ST_MAXNAME];
|
|
|
|
RNA_string_get(op->ptr, "name", idname);
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return UI_pie_menu_invoke(C, idname, CTX_wm_window(C)->eventstate);
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void WM_OT_call_menu_pie(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Call Pie Menu";
|
|
|
|
ot->idname = "WM_OT_call_menu_pie";
|
|
|
|
ot->description = "Call (draw) a pre-defined pie menu";
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->invoke = wm_call_pie_menu_invoke;
|
|
|
|
ot->exec = wm_call_pie_menu_exec;
|
|
|
|
ot->poll = WM_operator_winactive;
|
2019-06-04 15:50:15 +02:00
|
|
|
ot->get_name = wm_call_menu_get_name;
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->flag = OPTYPE_INTERNAL;
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the pie menu");
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
}
|
|
|
|
|
2018-05-23 19:46:40 +02:00
|
|
|
static int wm_call_panel_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
char idname[BKE_ST_MAXNAME];
|
|
|
|
RNA_string_get(op->ptr, "name", idname);
|
|
|
|
const bool keep_open = RNA_boolean_get(op->ptr, "keep_open");
|
2018-05-23 19:46:40 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return UI_popover_panel_invoke(C, idname, keep_open, op->reports);
|
2018-05-23 19:46:40 +02:00
|
|
|
}
|
|
|
|
|
2019-06-04 15:50:15 +02:00
|
|
|
static const char *wm_call_panel_get_name(wmOperatorType *ot, PointerRNA *ptr)
|
|
|
|
{
|
|
|
|
char idname[BKE_ST_MAXNAME];
|
|
|
|
RNA_string_get(ptr, "name", idname);
|
|
|
|
PanelType *pt = WM_paneltype_find(idname, true);
|
2019-08-02 15:01:02 +02:00
|
|
|
return (pt) ? CTX_IFACE_(pt->translation_context, pt->label) :
|
|
|
|
CTX_IFACE_(ot->translation_context, ot->name);
|
2019-06-04 15:50:15 +02:00
|
|
|
}
|
|
|
|
|
2018-05-23 19:46:40 +02:00
|
|
|
static void WM_OT_call_panel(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Call Panel";
|
|
|
|
ot->idname = "WM_OT_call_panel";
|
|
|
|
ot->description = "Call (draw) a pre-defined panel";
|
2018-05-23 19:46:40 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = wm_call_panel_exec;
|
|
|
|
ot->poll = WM_operator_winactive;
|
2019-06-04 15:50:15 +02:00
|
|
|
ot->get_name = wm_call_panel_get_name;
|
2018-05-23 19:46:40 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->flag = OPTYPE_INTERNAL;
|
2018-05-23 19:46:40 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
PropertyRNA *prop;
|
2018-06-06 09:24:24 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
prop = RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
prop = RNA_def_boolean(ot->srna, "keep_open", true, "Keep Open", "");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2018-05-23 19:46:40 +02:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Window/Screen Operators
|
|
|
|
* \{ */
|
2007-12-24 18:27:28 +00:00
|
|
|
|
2010-01-27 09:16:28 +00:00
|
|
|
/* this poll functions is needed in place of WM_operator_winactive
|
|
|
|
* while it crashes on full screen */
|
2018-07-02 11:47:00 +02:00
|
|
|
static bool wm_operator_winactive_normal(bContext *C)
|
2010-01-27 09:16:28 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
|
|
|
bScreen *screen;
|
2010-01-27 09:16:28 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (win == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!((screen = WM_window_get_active_screen(win)) && (screen->state == SCREENNORMAL))) {
|
|
|
|
return 0;
|
|
|
|
}
|
2010-01-27 09:16:28 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return 1;
|
2010-01-27 09:16:28 +00:00
|
|
|
}
|
|
|
|
|
2015-10-20 15:41:13 +11:00
|
|
|
/* included for script-access */
|
|
|
|
static void WM_OT_window_close(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Close Window";
|
|
|
|
ot->idname = "WM_OT_window_close";
|
|
|
|
ot->description = "Close the current window";
|
2015-10-20 15:41:13 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = wm_window_close_exec;
|
|
|
|
ot->poll = WM_operator_winactive;
|
2015-10-20 15:41:13 +11:00
|
|
|
}
|
|
|
|
|
2017-03-13 10:43:49 +01:00
|
|
|
static void WM_OT_window_new(wmOperatorType *ot)
|
2007-12-24 18:27:28 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "New Window";
|
|
|
|
ot->idname = "WM_OT_window_new";
|
|
|
|
ot->description = "Create a new window";
|
2017-03-13 10:43:49 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = wm_window_new_exec;
|
|
|
|
ot->poll = wm_operator_winactive_normal;
|
2007-12-24 18:27:28 +00:00
|
|
|
}
|
|
|
|
|
2018-07-03 15:34:26 +02:00
|
|
|
static void WM_OT_window_new_main(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "New Main Window";
|
|
|
|
ot->idname = "WM_OT_window_new_main";
|
|
|
|
ot->description = "Create a new main window with its own workspace and scene selection";
|
2018-07-03 15:34:26 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = wm_window_new_main_exec;
|
|
|
|
ot->poll = wm_operator_winactive_normal;
|
2018-07-03 15:34:26 +02:00
|
|
|
}
|
|
|
|
|
2008-01-01 09:07:02 +00:00
|
|
|
static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Toggle Window Fullscreen";
|
|
|
|
ot->idname = "WM_OT_window_fullscreen_toggle";
|
|
|
|
ot->description = "Toggle the current window fullscreen";
|
2008-01-01 09:07:02 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = wm_window_fullscreen_toggle_exec;
|
|
|
|
ot->poll = WM_operator_winactive;
|
2008-01-01 09:07:02 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 23:09:19 +01:00
|
|
|
static int wm_exit_blender_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-01-31 13:30:56 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wm_exit_schedule_delayed(C);
|
|
|
|
return OPERATOR_FINISHED;
|
2009-01-31 13:30:56 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static int wm_exit_blender_invoke(bContext *C,
|
|
|
|
wmOperator *UNUSED(op),
|
|
|
|
const wmEvent *UNUSED(event))
|
2018-03-23 17:31:33 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (U.uiflag & USER_SAVE_PROMPT) {
|
|
|
|
wm_quit_with_optional_confirmation_prompt(C, CTX_wm_window(C));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
wm_exit_schedule_delayed(C);
|
|
|
|
}
|
|
|
|
return OPERATOR_FINISHED;
|
2018-03-23 17:31:33 +01:00
|
|
|
}
|
|
|
|
|
2010-10-11 22:05:45 +00:00
|
|
|
static void WM_OT_quit_blender(wmOperatorType *ot)
|
2008-01-15 18:54:38 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Quit Blender";
|
|
|
|
ot->idname = "WM_OT_quit_blender";
|
|
|
|
ot->description = "Quit Blender";
|
2008-01-15 18:54:38 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->invoke = wm_exit_blender_invoke;
|
|
|
|
ot->exec = wm_exit_blender_exec;
|
2008-01-15 18:54:38 +00:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Console Toggle Operator (WIN32 only)
|
|
|
|
* \{ */
|
2010-10-18 20:41:52 +00:00
|
|
|
|
2011-05-09 08:01:48 +00:00
|
|
|
#if defined(WIN32)
|
|
|
|
|
2013-07-28 17:06:31 +00:00
|
|
|
static int wm_console_toggle_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
|
2010-10-18 20:41:52 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
GHOST_toggleConsole(2);
|
|
|
|
return OPERATOR_FINISHED;
|
2010-10-18 20:41:52 +00:00
|
|
|
}
|
|
|
|
|
2011-04-06 12:30:07 +00:00
|
|
|
static void WM_OT_console_toggle(wmOperatorType *ot)
|
2010-10-18 20:41:52 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* XXX Have to mark these for xgettext, as under linux they do not exists... */
|
|
|
|
ot->name = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Toggle System Console");
|
|
|
|
ot->idname = "WM_OT_console_toggle";
|
|
|
|
ot->description = N_("Toggle System Console");
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = wm_console_toggle_exec;
|
|
|
|
ot->poll = WM_operator_winactive;
|
2010-10-18 20:41:52 +00:00
|
|
|
}
|
|
|
|
|
2011-05-09 08:01:48 +00:00
|
|
|
#endif
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name default paint cursors, draw always around cursor
|
|
|
|
*
|
|
|
|
* - Returns handler to free.
|
|
|
|
* - `poll(bContext)`: returns 1 if draw should happen.
|
|
|
|
* - `draw(bContext)`: drawing callback for paint cursor.
|
|
|
|
*
|
|
|
|
* \{ */
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
wmPaintCursor *WM_paint_cursor_activate(wmWindowManager *wm,
|
|
|
|
short space_type,
|
|
|
|
short region_type,
|
|
|
|
bool (*poll)(bContext *C),
|
|
|
|
wmPaintCursorDraw draw,
|
|
|
|
void *customdata)
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmPaintCursor *pc = MEM_callocN(sizeof(wmPaintCursor), "paint cursor");
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_addtail(&wm->paintcursors, pc);
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
pc->customdata = customdata;
|
|
|
|
pc->poll = poll;
|
|
|
|
pc->draw = draw;
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
pc->space_type = space_type;
|
|
|
|
pc->region_type = region_type;
|
2018-10-25 16:06:47 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return pc;
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 15:18:24 +11:00
|
|
|
bool WM_paint_cursor_end(wmWindowManager *wm, wmPaintCursor *handle)
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmPaintCursor *pc;
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
for (pc = wm->paintcursors.first; pc; pc = pc->next) {
|
|
|
|
if (pc == (wmPaintCursor *)handle) {
|
|
|
|
BLI_remlink(&wm->paintcursors, pc);
|
|
|
|
MEM_freeN(pc);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2018-10-25 15:18:24 +11:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Radial Control Operator
|
|
|
|
* \{ */
|
2009-01-24 16:59:55 +00:00
|
|
|
|
2016-10-12 20:15:38 +02:00
|
|
|
#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * UI_DPI_FAC)
|
|
|
|
#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * UI_DPI_FAC)
|
2019-04-17 06:17:24 +02:00
|
|
|
#define WM_RADIAL_CONTROL_DISPLAY_WIDTH \
|
|
|
|
(WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE)
|
2015-05-14 14:01:33 +02:00
|
|
|
#define WM_RADIAL_MAX_STR 10
|
2009-01-24 22:58:22 +00:00
|
|
|
|
2011-05-12 01:57:47 +00:00
|
|
|
typedef struct {
|
2019-04-17 06:17:24 +02:00
|
|
|
PropertyType type;
|
|
|
|
PropertySubType subtype;
|
|
|
|
PointerRNA ptr, col_ptr, fill_col_ptr, rot_ptr, zoom_ptr, image_id_ptr;
|
|
|
|
PointerRNA fill_col_override_ptr, fill_col_override_test_ptr;
|
|
|
|
PropertyRNA *prop, *col_prop, *fill_col_prop, *rot_prop, *zoom_prop;
|
|
|
|
PropertyRNA *fill_col_override_prop, *fill_col_override_test_prop;
|
|
|
|
StructRNA *image_id_srna;
|
|
|
|
float initial_value, current_value, min_value, max_value;
|
|
|
|
int initial_mouse[2];
|
2019-09-26 17:51:21 +02:00
|
|
|
int initial_co[2];
|
2019-04-17 06:17:24 +02:00
|
|
|
int slow_mouse[2];
|
|
|
|
bool slow_mode;
|
|
|
|
Dial *dial;
|
|
|
|
unsigned int gltex;
|
|
|
|
ListBase orig_paintcursors;
|
|
|
|
bool use_secondary_tex;
|
|
|
|
void *cursor;
|
|
|
|
NumInput num_input;
|
2011-05-12 01:57:47 +00:00
|
|
|
} RadialControl;
|
2009-01-24 16:59:55 +00:00
|
|
|
|
2014-11-17 15:44:19 +01:00
|
|
|
static void radial_control_update_header(wmOperator *op, bContext *C)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
RadialControl *rc = op->customdata;
|
|
|
|
char msg[UI_MAX_DRAW_STR];
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
|
|
|
if (hasNumInput(&rc->num_input)) {
|
|
|
|
char num_str[NUM_STR_REP_LEN];
|
|
|
|
outputNumInput(&rc->num_input, num_str, &scene->unit);
|
|
|
|
BLI_snprintf(msg, sizeof(msg), "%s: %s", RNA_property_ui_name(rc->prop), num_str);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const char *ui_name = RNA_property_ui_name(rc->prop);
|
|
|
|
switch (rc->subtype) {
|
|
|
|
case PROP_NONE:
|
|
|
|
case PROP_DISTANCE:
|
|
|
|
BLI_snprintf(msg, sizeof(msg), "%s: %0.4f", ui_name, rc->current_value);
|
|
|
|
break;
|
|
|
|
case PROP_PIXEL:
|
|
|
|
BLI_snprintf(msg,
|
|
|
|
sizeof(msg),
|
|
|
|
"%s: %d",
|
|
|
|
ui_name,
|
|
|
|
(int)rc->current_value); /* XXX: round to nearest? */
|
|
|
|
break;
|
|
|
|
case PROP_PERCENTAGE:
|
|
|
|
BLI_snprintf(msg, sizeof(msg), "%s: %3.1f%%", ui_name, rc->current_value);
|
|
|
|
break;
|
|
|
|
case PROP_FACTOR:
|
|
|
|
BLI_snprintf(msg, sizeof(msg), "%s: %1.3f", ui_name, rc->current_value);
|
|
|
|
break;
|
|
|
|
case PROP_ANGLE:
|
|
|
|
BLI_snprintf(msg, sizeof(msg), "%s: %3.2f", ui_name, RAD2DEGF(rc->current_value));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BLI_snprintf(msg, sizeof(msg), "%s", ui_name); /* XXX: No value? */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_status_text(area, msg);
|
2014-11-17 15:44:19 +01:00
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *event)
|
2009-01-24 16:59:55 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
float d[2] = {0, 0};
|
|
|
|
float zoom[2] = {1, 1};
|
|
|
|
|
|
|
|
rc->initial_mouse[0] = event->x;
|
|
|
|
rc->initial_mouse[1] = event->y;
|
|
|
|
|
2019-09-26 17:51:21 +02:00
|
|
|
rc->initial_co[0] = event->x;
|
|
|
|
rc->initial_co[1] = event->y;
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
switch (rc->subtype) {
|
|
|
|
case PROP_NONE:
|
|
|
|
case PROP_DISTANCE:
|
|
|
|
case PROP_PIXEL:
|
|
|
|
d[0] = rc->initial_value;
|
|
|
|
break;
|
|
|
|
case PROP_PERCENTAGE:
|
|
|
|
d[0] = (rc->initial_value) / 100.0f * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
|
|
|
|
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
|
|
|
|
break;
|
|
|
|
case PROP_FACTOR:
|
2019-09-26 17:51:21 +02:00
|
|
|
d[0] = rc->initial_value * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
|
|
|
|
break;
|
|
|
|
case PROP_ANGLE:
|
|
|
|
d[0] = WM_RADIAL_CONTROL_DISPLAY_SIZE * cosf(rc->initial_value);
|
|
|
|
d[1] = WM_RADIAL_CONTROL_DISPLAY_SIZE * sinf(rc->initial_value);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc->zoom_prop) {
|
|
|
|
RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
|
|
|
|
d[0] *= zoom[0];
|
|
|
|
d[1] *= zoom[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
rc->initial_mouse[0] -= d[0];
|
|
|
|
rc->initial_mouse[1] -= d[1];
|
2011-05-12 01:57:47 +00:00
|
|
|
}
|
2010-07-14 14:11:03 +00:00
|
|
|
|
2011-05-12 01:57:47 +00:00
|
|
|
static void radial_control_set_tex(RadialControl *rc)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ImBuf *ibuf;
|
|
|
|
|
|
|
|
switch (RNA_type_to_ID_code(rc->image_id_ptr.type)) {
|
|
|
|
case ID_BR:
|
2019-09-26 17:51:21 +02:00
|
|
|
if ((ibuf = BKE_brush_gen_radial_control_imbuf(
|
|
|
|
rc->image_id_ptr.data,
|
|
|
|
rc->use_secondary_tex,
|
|
|
|
!ELEM(rc->subtype, PROP_NONE, PROP_PIXEL, PROP_DISTANCE)))) {
|
2019-04-17 06:17:24 +02:00
|
|
|
glGenTextures(1, &rc->gltex);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, rc->gltex);
|
|
|
|
glTexImage2D(
|
|
|
|
GL_TEXTURE_2D, 0, GL_R8, ibuf->x, ibuf->y, 0, GL_RED, GL_FLOAT, ibuf->rect_float);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
MEM_freeN(ibuf->rect_float);
|
|
|
|
MEM_freeN(ibuf);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2011-05-12 01:57:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void radial_control_paint_tex(RadialControl *rc, float radius, float alpha)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
float col[3] = {0, 0, 0};
|
|
|
|
float rot;
|
2011-05-12 01:57:47 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* set fill color */
|
|
|
|
if (rc->fill_col_prop) {
|
|
|
|
PointerRNA *fill_ptr;
|
|
|
|
PropertyRNA *fill_prop;
|
2016-02-10 01:48:02 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (rc->fill_col_override_prop && RNA_property_boolean_get(&rc->fill_col_override_test_ptr,
|
|
|
|
rc->fill_col_override_test_prop)) {
|
|
|
|
fill_ptr = &rc->fill_col_override_ptr;
|
|
|
|
fill_prop = rc->fill_col_override_prop;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fill_ptr = &rc->fill_col_ptr;
|
|
|
|
fill_prop = rc->fill_col_prop;
|
|
|
|
}
|
2016-02-10 01:48:02 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_property_float_get_array(fill_ptr, fill_prop, col);
|
|
|
|
}
|
2018-06-07 16:45:10 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
GPUVertFormat *format = immVertexFormat();
|
|
|
|
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
2010-07-14 14:11:03 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (rc->gltex) {
|
2016-11-08 10:51:42 -05:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
uint texCoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
2016-11-08 10:51:42 -05:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, rc->gltex);
|
2009-01-24 22:58:22 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
2016-11-08 10:51:42 -05:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
GLint swizzleMask[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED};
|
|
|
|
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
|
2016-11-08 10:51:42 -05:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* set up rotation if available */
|
|
|
|
if (rc->rot_prop) {
|
|
|
|
rot = RNA_property_float_get(&rc->rot_ptr, rc->rot_prop);
|
|
|
|
GPU_matrix_push();
|
|
|
|
GPU_matrix_rotate_2d(RAD2DEGF(rot));
|
|
|
|
}
|
2011-05-12 01:57:47 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR);
|
2019-03-19 13:07:48 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
immUniformColor3fvAlpha(col, alpha);
|
|
|
|
immUniform1i("image", 0);
|
2019-03-19 13:07:48 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* draw textured quad */
|
|
|
|
immBegin(GPU_PRIM_TRI_FAN, 4);
|
2016-11-08 10:51:42 -05:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
immAttr2f(texCoord, 0, 0);
|
|
|
|
immVertex2f(pos, -radius, -radius);
|
2016-11-08 10:51:42 -05:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
immAttr2f(texCoord, 1, 0);
|
|
|
|
immVertex2f(pos, radius, -radius);
|
2018-06-07 16:45:10 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
immAttr2f(texCoord, 1, 1);
|
|
|
|
immVertex2f(pos, radius, radius);
|
2018-06-07 16:45:10 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
immAttr2f(texCoord, 0, 1);
|
|
|
|
immVertex2f(pos, -radius, radius);
|
2016-11-08 10:51:42 -05:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
immEnd();
|
2011-05-12 01:57:47 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* undo rotation */
|
|
|
|
if (rc->rot_prop) {
|
|
|
|
GPU_matrix_pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* flat color if no texture available */
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
|
|
|
immUniformColor3fvAlpha(col, alpha);
|
|
|
|
imm_draw_circle_fill_2d(pos, 0.0f, 0.0f, radius, 40);
|
|
|
|
}
|
2018-06-07 16:45:10 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
immUnbindProgram();
|
2011-05-12 01:57:47 +00:00
|
|
|
}
|
|
|
|
|
2019-09-26 17:51:21 +02:00
|
|
|
static void radial_control_paint_curve(uint pos, Brush *br, float radius, int line_segments)
|
|
|
|
{
|
|
|
|
GPU_line_width(2.0f);
|
|
|
|
immUniformColor4f(0.8f, 0.8f, 0.8f, 0.85f);
|
|
|
|
float step = (radius * 2.0f) / (float)line_segments;
|
|
|
|
BKE_curvemapping_initialize(br->curve);
|
|
|
|
immBegin(GPU_PRIM_LINES, line_segments * 2);
|
|
|
|
for (int i = 0; i < line_segments; i++) {
|
|
|
|
float h1 = BKE_brush_curve_strength_clamped(br, fabsf((i * step) - radius), radius);
|
|
|
|
immVertex2f(pos, -radius + (i * step), h1 * radius);
|
|
|
|
float h2 = BKE_brush_curve_strength_clamped(br, fabsf(((i + 1) * step) - radius), radius);
|
|
|
|
immVertex2f(pos, -radius + ((i + 1) * step), h2 * radius);
|
|
|
|
}
|
|
|
|
immEnd();
|
|
|
|
}
|
|
|
|
|
2018-04-30 19:47:33 +02:00
|
|
|
static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void *customdata)
|
2011-05-12 01:57:47 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
RadialControl *rc = customdata;
|
2020-03-15 17:32:25 +11:00
|
|
|
const uiStyle *style = UI_style_get();
|
2019-04-17 06:17:24 +02:00
|
|
|
const uiFontStyle *fstyle = &style->widget;
|
|
|
|
const int fontid = fstyle->uifont_id;
|
|
|
|
short fstyle_points = fstyle->points;
|
|
|
|
char str[WM_RADIAL_MAX_STR];
|
|
|
|
short strdrawlen = 0;
|
|
|
|
float strwidth, strheight;
|
|
|
|
float r1 = 0.0f, r2 = 0.0f, rmin = 0.0, tex_radius, alpha;
|
2019-12-30 16:41:20 +01:00
|
|
|
float zoom[2], col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
2020-01-10 12:14:03 +01:00
|
|
|
float text_color[4];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
switch (rc->subtype) {
|
|
|
|
case PROP_NONE:
|
|
|
|
case PROP_DISTANCE:
|
|
|
|
case PROP_PIXEL:
|
|
|
|
r1 = rc->current_value;
|
|
|
|
r2 = rc->initial_value;
|
|
|
|
tex_radius = r1;
|
|
|
|
alpha = 0.75;
|
|
|
|
break;
|
|
|
|
case PROP_PERCENTAGE:
|
|
|
|
r1 = rc->current_value / 100.0f * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
|
|
|
|
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
|
|
|
|
r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
|
|
|
|
rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
|
|
|
|
BLI_snprintf(str, WM_RADIAL_MAX_STR, "%3.1f%%", rc->current_value);
|
|
|
|
strdrawlen = BLI_strlen_utf8(str);
|
|
|
|
tex_radius = r1;
|
|
|
|
alpha = 0.75;
|
|
|
|
break;
|
|
|
|
case PROP_FACTOR:
|
2019-09-26 17:51:21 +02:00
|
|
|
r1 = rc->current_value * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
|
|
|
|
r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
|
|
|
|
rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
|
|
|
|
alpha = rc->current_value / 2.0f + 0.5f;
|
|
|
|
BLI_snprintf(str, WM_RADIAL_MAX_STR, "%1.3f", rc->current_value);
|
|
|
|
strdrawlen = BLI_strlen_utf8(str);
|
|
|
|
break;
|
|
|
|
case PROP_ANGLE:
|
|
|
|
r1 = r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
|
|
|
|
alpha = 0.75;
|
|
|
|
rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
|
|
|
|
BLI_snprintf(str, WM_RADIAL_MAX_STR, "%3.2f", RAD2DEGF(rc->current_value));
|
|
|
|
strdrawlen = BLI_strlen_utf8(str);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE; /* note, this is a dummy value */
|
|
|
|
alpha = 0.75;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-09-26 17:51:21 +02:00
|
|
|
if (rc->subtype == PROP_ANGLE) {
|
|
|
|
/* Use the initial mouse position to draw the rotation preview. This avoids starting the
|
|
|
|
* rotation in a random direction */
|
|
|
|
x = rc->initial_mouse[0];
|
|
|
|
y = rc->initial_mouse[1];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Keep cursor in the original place */
|
|
|
|
x = rc->initial_co[0];
|
|
|
|
y = rc->initial_co[1];
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_matrix_translate_2f((float)x, (float)y);
|
|
|
|
|
|
|
|
GPU_blend(true);
|
|
|
|
GPU_line_smooth(true);
|
|
|
|
|
|
|
|
/* apply zoom if available */
|
|
|
|
if (rc->zoom_prop) {
|
|
|
|
RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
|
|
|
|
GPU_matrix_scale_2fv(zoom);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* draw rotated texture */
|
|
|
|
radial_control_paint_tex(rc, tex_radius, alpha);
|
|
|
|
|
|
|
|
/* set line color */
|
|
|
|
if (rc->col_prop) {
|
|
|
|
RNA_property_float_get_array(&rc->col_ptr, rc->col_prop, col);
|
|
|
|
}
|
|
|
|
|
|
|
|
GPUVertFormat *format = immVertexFormat();
|
|
|
|
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
|
|
|
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
|
|
|
|
|
|
|
if (rc->subtype == PROP_ANGLE) {
|
|
|
|
GPU_matrix_push();
|
|
|
|
|
|
|
|
/* draw original angle line */
|
|
|
|
GPU_matrix_rotate_3f(RAD2DEGF(rc->initial_value), 0.0f, 0.0f, 1.0f);
|
|
|
|
immBegin(GPU_PRIM_LINES, 2);
|
|
|
|
immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f);
|
|
|
|
immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
|
|
|
|
immEnd();
|
|
|
|
|
|
|
|
/* draw new angle line */
|
|
|
|
GPU_matrix_rotate_3f(RAD2DEGF(rc->current_value - rc->initial_value), 0.0f, 0.0f, 1.0f);
|
|
|
|
immBegin(GPU_PRIM_LINES, 2);
|
|
|
|
immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f);
|
|
|
|
immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
|
|
|
|
immEnd();
|
|
|
|
|
|
|
|
GPU_matrix_pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* draw circles on top */
|
2019-09-26 17:51:21 +02:00
|
|
|
GPU_line_width(2.0f);
|
|
|
|
immUniformColor3fvAlpha(col, 0.8f);
|
|
|
|
imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 80);
|
|
|
|
|
|
|
|
GPU_line_width(1.0f);
|
|
|
|
immUniformColor3fvAlpha(col, 0.5f);
|
|
|
|
imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 80);
|
2019-04-17 06:17:24 +02:00
|
|
|
if (rmin > 0.0f) {
|
2019-09-26 17:51:21 +02:00
|
|
|
/* Inner fill circle to increase the contrast of the value */
|
|
|
|
float black[3] = {0.0f};
|
|
|
|
immUniformColor3fvAlpha(black, 0.2f);
|
|
|
|
imm_draw_circle_fill_2d(pos, 0.0, 0.0f, rmin, 80);
|
|
|
|
|
|
|
|
immUniformColor3fvAlpha(col, 0.5f);
|
|
|
|
imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 80);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-09-26 17:51:21 +02:00
|
|
|
|
|
|
|
/* draw curve falloff preview */
|
|
|
|
if (RNA_type_to_ID_code(rc->image_id_ptr.type) == ID_BR && rc->subtype == PROP_FACTOR) {
|
|
|
|
Brush *br = rc->image_id_ptr.data;
|
|
|
|
if (br) {
|
|
|
|
radial_control_paint_curve(pos, br, r2, 120);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
immUnbindProgram();
|
|
|
|
|
2019-09-26 17:51:21 +02:00
|
|
|
BLF_size(fontid, 1.75f * fstyle_points * U.pixelsize, U.dpi);
|
2020-01-10 12:14:03 +01:00
|
|
|
UI_GetThemeColor4fv(TH_TEXT_HI, text_color);
|
|
|
|
BLF_color4fv(fontid, text_color);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* draw value */
|
|
|
|
BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
|
|
|
|
BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f);
|
|
|
|
BLF_draw(fontid, str, strdrawlen);
|
|
|
|
|
|
|
|
GPU_blend(false);
|
|
|
|
GPU_line_smooth(false);
|
2009-01-24 16:59:55 +00:00
|
|
|
}
|
|
|
|
|
2012-01-14 23:54:51 +00:00
|
|
|
typedef enum {
|
2019-04-17 06:17:24 +02:00
|
|
|
RC_PROP_ALLOW_MISSING = 1,
|
|
|
|
RC_PROP_REQUIRE_FLOAT = 2,
|
|
|
|
RC_PROP_REQUIRE_BOOL = 4,
|
2012-01-14 23:54:51 +00:00
|
|
|
} RCPropFlags;
|
|
|
|
|
2015-06-01 14:56:07 +10:00
|
|
|
/**
|
|
|
|
* Attempt to retrieve the rna pointer/property from an rna path.
|
|
|
|
*
|
|
|
|
* \return 0 for failure, 1 for success, and also 1 if property is not set.
|
|
|
|
*/
|
2019-04-17 06:17:24 +02:00
|
|
|
static int radial_control_get_path(PointerRNA *ctx_ptr,
|
|
|
|
wmOperator *op,
|
|
|
|
const char *name,
|
|
|
|
PointerRNA *r_ptr,
|
|
|
|
PropertyRNA **r_prop,
|
|
|
|
int req_length,
|
|
|
|
RCPropFlags flags)
|
|
|
|
{
|
|
|
|
PropertyRNA *unused_prop;
|
|
|
|
int len;
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
/* check flags */
|
|
|
|
if ((flags & RC_PROP_REQUIRE_BOOL) && (flags & RC_PROP_REQUIRE_FLOAT)) {
|
|
|
|
BKE_report(op->reports, RPT_ERROR, "Property cannot be both boolean and float");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get an rna string path from the operator's properties */
|
|
|
|
if (!(str = RNA_string_get_alloc(op->ptr, name, NULL, 0))) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (str[0] == '\0') {
|
|
|
|
if (r_prop) {
|
|
|
|
*r_prop = NULL;
|
|
|
|
}
|
|
|
|
MEM_freeN(str);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!r_prop) {
|
|
|
|
r_prop = &unused_prop;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get rna from path */
|
|
|
|
if (!RNA_path_resolve(ctx_ptr, str, r_ptr, r_prop)) {
|
|
|
|
MEM_freeN(str);
|
|
|
|
if (flags & RC_PROP_ALLOW_MISSING) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BKE_reportf(op->reports, RPT_ERROR, "Could not resolve path '%s'", name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check property type */
|
|
|
|
if (flags & (RC_PROP_REQUIRE_BOOL | RC_PROP_REQUIRE_FLOAT)) {
|
|
|
|
PropertyType prop_type = RNA_property_type(*r_prop);
|
|
|
|
|
|
|
|
if (((flags & RC_PROP_REQUIRE_BOOL) && (prop_type != PROP_BOOLEAN)) ||
|
|
|
|
((flags & RC_PROP_REQUIRE_FLOAT) && (prop_type != PROP_FLOAT))) {
|
|
|
|
MEM_freeN(str);
|
|
|
|
BKE_reportf(op->reports, RPT_ERROR, "Property from path '%s' is not a float", name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check property's array length */
|
|
|
|
if (*r_prop && (len = RNA_property_array_length(r_ptr, *r_prop)) != req_length) {
|
|
|
|
MEM_freeN(str);
|
|
|
|
BKE_reportf(op->reports,
|
|
|
|
RPT_ERROR,
|
|
|
|
"Property from path '%s' has length %d instead of %d",
|
|
|
|
name,
|
|
|
|
len,
|
|
|
|
req_length);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* success */
|
|
|
|
MEM_freeN(str);
|
|
|
|
return 1;
|
2011-05-12 01:57:47 +00:00
|
|
|
}
|
2009-01-24 22:58:22 +00:00
|
|
|
|
2011-05-12 01:57:47 +00:00
|
|
|
/* initialize the rna pointers and properties using rna paths */
|
|
|
|
static int radial_control_get_properties(bContext *C, wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
RadialControl *rc = op->customdata;
|
|
|
|
PointerRNA ctx_ptr, use_secondary_ptr;
|
|
|
|
PropertyRNA *use_secondary_prop = NULL;
|
|
|
|
const char *data_path;
|
|
|
|
|
|
|
|
RNA_pointer_create(NULL, &RNA_Context, C, &ctx_ptr);
|
|
|
|
|
|
|
|
/* check if we use primary or secondary path */
|
|
|
|
if (!radial_control_get_path(&ctx_ptr,
|
|
|
|
op,
|
|
|
|
"use_secondary",
|
|
|
|
&use_secondary_ptr,
|
|
|
|
&use_secondary_prop,
|
|
|
|
0,
|
|
|
|
(RC_PROP_ALLOW_MISSING | RC_PROP_REQUIRE_BOOL))) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (use_secondary_prop && RNA_property_boolean_get(&use_secondary_ptr, use_secondary_prop)) {
|
|
|
|
data_path = "data_path_secondary";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
data_path = "data_path_primary";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!radial_control_get_path(&ctx_ptr, op, data_path, &rc->ptr, &rc->prop, 0, 0)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* data path is required */
|
|
|
|
if (!rc->prop) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!radial_control_get_path(
|
|
|
|
&ctx_ptr, op, "rotation_path", &rc->rot_ptr, &rc->rot_prop, 0, RC_PROP_REQUIRE_FLOAT)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!radial_control_get_path(
|
2019-12-30 16:41:20 +01:00
|
|
|
&ctx_ptr, op, "color_path", &rc->col_ptr, &rc->col_prop, 4, RC_PROP_REQUIRE_FLOAT)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!radial_control_get_path(&ctx_ptr,
|
|
|
|
op,
|
|
|
|
"fill_color_path",
|
|
|
|
&rc->fill_col_ptr,
|
|
|
|
&rc->fill_col_prop,
|
|
|
|
3,
|
|
|
|
RC_PROP_REQUIRE_FLOAT)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!radial_control_get_path(&ctx_ptr,
|
|
|
|
op,
|
|
|
|
"fill_color_override_path",
|
|
|
|
&rc->fill_col_override_ptr,
|
|
|
|
&rc->fill_col_override_prop,
|
|
|
|
3,
|
|
|
|
RC_PROP_REQUIRE_FLOAT)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!radial_control_get_path(&ctx_ptr,
|
|
|
|
op,
|
|
|
|
"fill_color_override_test_path",
|
|
|
|
&rc->fill_col_override_test_ptr,
|
|
|
|
&rc->fill_col_override_test_prop,
|
|
|
|
0,
|
|
|
|
RC_PROP_REQUIRE_BOOL)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* slightly ugly; allow this property to not resolve
|
|
|
|
* correctly. needed because 3d texture paint shares the same
|
|
|
|
* keymap as 2d image paint */
|
|
|
|
if (!radial_control_get_path(&ctx_ptr,
|
|
|
|
op,
|
|
|
|
"zoom_path",
|
|
|
|
&rc->zoom_ptr,
|
|
|
|
&rc->zoom_prop,
|
|
|
|
2,
|
|
|
|
RC_PROP_REQUIRE_FLOAT | RC_PROP_ALLOW_MISSING)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!radial_control_get_path(&ctx_ptr, op, "image_id", &rc->image_id_ptr, NULL, 0, 0)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if (rc->image_id_ptr.data) {
|
|
|
|
/* extra check, pointer must be to an ID */
|
|
|
|
if (!RNA_struct_is_ID(rc->image_id_ptr.type)) {
|
|
|
|
BKE_report(op->reports, RPT_ERROR, "Pointer from path image_id is not an ID");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rc->use_secondary_tex = RNA_boolean_get(op->ptr, "secondary_tex");
|
|
|
|
|
|
|
|
return 1;
|
2009-01-24 16:59:55 +00:00
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2009-01-24 16:59:55 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmWindowManager *wm;
|
|
|
|
RadialControl *rc;
|
|
|
|
|
|
|
|
if (!(op->customdata = rc = MEM_callocN(sizeof(RadialControl), "RadialControl"))) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!radial_control_get_properties(C, op)) {
|
|
|
|
MEM_freeN(rc);
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get type, initial, min, and max values of the property */
|
|
|
|
switch ((rc->type = RNA_property_type(rc->prop))) {
|
|
|
|
case PROP_INT: {
|
|
|
|
int value, min, max, step;
|
|
|
|
|
|
|
|
value = RNA_property_int_get(&rc->ptr, rc->prop);
|
|
|
|
RNA_property_int_ui_range(&rc->ptr, rc->prop, &min, &max, &step);
|
|
|
|
|
|
|
|
rc->initial_value = value;
|
|
|
|
rc->min_value = min_ii(value, min);
|
|
|
|
rc->max_value = max_ii(value, max);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PROP_FLOAT: {
|
|
|
|
float value, min, max, step, precision;
|
|
|
|
|
|
|
|
value = RNA_property_float_get(&rc->ptr, rc->prop);
|
|
|
|
RNA_property_float_ui_range(&rc->ptr, rc->prop, &min, &max, &step, &precision);
|
|
|
|
|
|
|
|
rc->initial_value = value;
|
|
|
|
rc->min_value = min_ff(value, min);
|
|
|
|
rc->max_value = max_ff(value, max);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
BKE_report(op->reports, RPT_ERROR, "Property must be an integer or a float");
|
|
|
|
MEM_freeN(rc);
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initialize numerical input */
|
|
|
|
initNumInput(&rc->num_input);
|
|
|
|
rc->num_input.idx_max = 0;
|
|
|
|
rc->num_input.val_flag[0] |= NUM_NO_NEGATIVE;
|
|
|
|
rc->num_input.unit_sys = USER_UNIT_NONE;
|
|
|
|
rc->num_input.unit_type[0] = B_UNIT_LENGTH;
|
|
|
|
|
|
|
|
/* get subtype of property */
|
|
|
|
rc->subtype = RNA_property_subtype(rc->prop);
|
|
|
|
if (!ELEM(rc->subtype,
|
|
|
|
PROP_NONE,
|
|
|
|
PROP_DISTANCE,
|
|
|
|
PROP_FACTOR,
|
|
|
|
PROP_PERCENTAGE,
|
|
|
|
PROP_ANGLE,
|
|
|
|
PROP_PIXEL)) {
|
|
|
|
BKE_report(op->reports,
|
|
|
|
RPT_ERROR,
|
|
|
|
"Property must be a none, distance, factor, percentage, angle, or pixel");
|
|
|
|
MEM_freeN(rc);
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc->current_value = rc->initial_value;
|
|
|
|
radial_control_set_initial_mouse(rc, event);
|
|
|
|
radial_control_set_tex(rc);
|
|
|
|
|
|
|
|
/* temporarily disable other paint cursors */
|
|
|
|
wm = CTX_wm_manager(C);
|
|
|
|
rc->orig_paintcursors = wm->paintcursors;
|
|
|
|
BLI_listbase_clear(&wm->paintcursors);
|
|
|
|
|
|
|
|
/* add radial control paint cursor */
|
|
|
|
rc->cursor = WM_paint_cursor_activate(
|
|
|
|
wm, SPACE_TYPE_ANY, RGN_TYPE_ANY, op->type->poll, radial_control_paint_cursor, rc);
|
|
|
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
2009-01-24 16:59:55 +00:00
|
|
|
}
|
|
|
|
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
static void radial_control_set_value(RadialControl *rc, float val)
|
2009-01-25 21:02:52 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
switch (rc->type) {
|
|
|
|
case PROP_INT:
|
|
|
|
RNA_property_int_set(&rc->ptr, rc->prop, val);
|
|
|
|
break;
|
|
|
|
case PROP_FLOAT:
|
|
|
|
RNA_property_float_set(&rc->ptr, rc->prop, val);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2009-01-25 21:02:52 +00:00
|
|
|
}
|
|
|
|
|
2013-10-30 23:08:53 +00:00
|
|
|
static void radial_control_cancel(bContext *C, wmOperator *op)
|
2011-06-06 11:04:54 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
RadialControl *rc = op->customdata;
|
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2011-06-06 11:04:54 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (rc->dial) {
|
|
|
|
MEM_freeN(rc->dial);
|
|
|
|
rc->dial = NULL;
|
|
|
|
}
|
2014-11-17 15:44:19 +01:00
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_status_text(area, NULL);
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_paint_cursor_end(wm, rc->cursor);
|
2011-06-06 11:04:54 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* restore original paint cursors */
|
|
|
|
wm->paintcursors = rc->orig_paintcursors;
|
2011-06-06 11:04:54 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* not sure if this is a good notifier to use;
|
|
|
|
* intended purpose is to update the UI so that the
|
|
|
|
* new value is displayed in sliders/numfields */
|
|
|
|
WM_event_add_notifier(C, NC_WINDOW, NULL);
|
2011-06-06 11:04:54 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
glDeleteTextures(1, &rc->gltex);
|
2011-06-06 11:04:54 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
MEM_freeN(rc);
|
2011-06-06 11:04:54 +00:00
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
2009-01-24 16:59:55 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
RadialControl *rc = op->customdata;
|
|
|
|
float new_value, dist = 0.0f, zoom[2];
|
2019-11-14 00:06:48 +11:00
|
|
|
float delta[2];
|
|
|
|
int ret = OPERATOR_RUNNING_MODAL;
|
2019-04-17 06:17:24 +02:00
|
|
|
bool snap;
|
|
|
|
float angle_precision = 0.0f;
|
|
|
|
const bool has_numInput = hasNumInput(&rc->num_input);
|
|
|
|
bool handled = false;
|
|
|
|
float numValue;
|
|
|
|
/* TODO: fix hardcoded events */
|
|
|
|
|
|
|
|
snap = event->ctrl != 0;
|
|
|
|
|
|
|
|
/* Modal numinput active, try to handle numeric inputs first... */
|
|
|
|
if (event->val == KM_PRESS && has_numInput && handleNumInput(C, &rc->num_input, event)) {
|
|
|
|
handled = true;
|
|
|
|
applyNumInput(&rc->num_input, &numValue);
|
|
|
|
|
|
|
|
if (rc->subtype == PROP_ANGLE) {
|
|
|
|
numValue = DEG2RADF(numValue);
|
|
|
|
numValue = fmod(numValue, 2.0f * (float)M_PI);
|
|
|
|
if (numValue < 0.0f) {
|
|
|
|
numValue += 2.0f * (float)M_PI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CLAMP(numValue, rc->min_value, rc->max_value);
|
|
|
|
new_value = numValue;
|
|
|
|
|
|
|
|
radial_control_set_value(rc, new_value);
|
|
|
|
rc->current_value = new_value;
|
|
|
|
radial_control_update_header(op, C);
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
handled = false;
|
|
|
|
switch (event->type) {
|
2020-03-18 10:38:37 -06:00
|
|
|
case EVT_ESCKEY:
|
2019-04-17 06:17:24 +02:00
|
|
|
case RIGHTMOUSE:
|
|
|
|
/* canceled; restore original value */
|
|
|
|
radial_control_set_value(rc, rc->initial_value);
|
|
|
|
ret = OPERATOR_CANCELLED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LEFTMOUSE:
|
2020-03-18 10:38:37 -06:00
|
|
|
case EVT_PADENTER:
|
|
|
|
case EVT_RETKEY:
|
2019-04-17 06:17:24 +02:00
|
|
|
/* done; value already set */
|
|
|
|
RNA_property_update(C, &rc->ptr, rc->prop);
|
|
|
|
ret = OPERATOR_FINISHED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MOUSEMOVE:
|
|
|
|
if (!has_numInput) {
|
|
|
|
if (rc->slow_mode) {
|
|
|
|
if (rc->subtype == PROP_ANGLE) {
|
|
|
|
float position[2] = {event->x, event->y};
|
|
|
|
|
|
|
|
/* calculate the initial angle here first */
|
|
|
|
delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0];
|
|
|
|
delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1];
|
|
|
|
|
|
|
|
/* precision angle gets calculated from dial and gets added later */
|
|
|
|
angle_precision = -0.1f * BLI_dial_angle(rc->dial, position);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0];
|
2019-10-01 20:00:48 +02:00
|
|
|
delta[1] = 0.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
if (rc->zoom_prop) {
|
|
|
|
RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
|
|
|
|
delta[0] /= zoom[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
dist = len_v2(delta);
|
|
|
|
|
|
|
|
delta[0] = event->x - rc->slow_mouse[0];
|
|
|
|
|
|
|
|
if (rc->zoom_prop) {
|
|
|
|
delta[0] /= zoom[0];
|
|
|
|
}
|
|
|
|
|
2019-10-01 20:00:48 +02:00
|
|
|
dist = dist + 0.1f * (delta[0]);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
delta[0] = rc->initial_mouse[0] - event->x;
|
2019-10-03 23:26:05 +02:00
|
|
|
delta[1] = rc->initial_mouse[1] - event->y;
|
2019-04-17 06:17:24 +02:00
|
|
|
if (rc->zoom_prop) {
|
|
|
|
RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
|
|
|
|
delta[0] /= zoom[0];
|
2019-10-03 23:26:05 +02:00
|
|
|
delta[1] /= zoom[1];
|
|
|
|
}
|
|
|
|
if (rc->subtype == PROP_ANGLE) {
|
|
|
|
dist = len_v2(delta);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dist = clamp_f(-delta[0], 0.0f, FLT_MAX);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate new value and apply snapping */
|
|
|
|
switch (rc->subtype) {
|
|
|
|
case PROP_NONE:
|
|
|
|
case PROP_DISTANCE:
|
|
|
|
case PROP_PIXEL:
|
|
|
|
new_value = dist;
|
|
|
|
if (snap) {
|
|
|
|
new_value = ((int)new_value + 5) / 10 * 10;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_PERCENTAGE:
|
|
|
|
new_value = ((dist - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) /
|
|
|
|
WM_RADIAL_CONTROL_DISPLAY_WIDTH) *
|
|
|
|
100.0f;
|
|
|
|
if (snap) {
|
|
|
|
new_value = ((int)(new_value + 2.5f)) / 5 * 5;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_FACTOR:
|
|
|
|
new_value = (WM_RADIAL_CONTROL_DISPLAY_SIZE - dist) /
|
|
|
|
WM_RADIAL_CONTROL_DISPLAY_WIDTH;
|
|
|
|
if (snap) {
|
|
|
|
new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f;
|
|
|
|
}
|
2019-09-26 17:51:21 +02:00
|
|
|
/* Invert new value to increase the factor moving the mouse to the right */
|
|
|
|
new_value = 1 - new_value;
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
case PROP_ANGLE:
|
|
|
|
new_value = atan2f(delta[1], delta[0]) + (float)M_PI + angle_precision;
|
|
|
|
new_value = fmod(new_value, 2.0f * (float)M_PI);
|
|
|
|
if (new_value < 0.0f) {
|
|
|
|
new_value += 2.0f * (float)M_PI;
|
|
|
|
}
|
|
|
|
if (snap) {
|
|
|
|
new_value = DEG2RADF(((int)RAD2DEGF(new_value) + 5) / 10 * 10);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
new_value = dist; /* dummy value, should this ever happen? - campbell */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clamp and update */
|
|
|
|
CLAMP(new_value, rc->min_value, rc->max_value);
|
|
|
|
radial_control_set_value(rc, new_value);
|
|
|
|
rc->current_value = new_value;
|
|
|
|
handled = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-03-18 10:38:37 -06:00
|
|
|
case EVT_LEFTSHIFTKEY:
|
|
|
|
case EVT_RIGHTSHIFTKEY: {
|
2019-04-17 06:17:24 +02:00
|
|
|
if (event->val == KM_PRESS) {
|
|
|
|
rc->slow_mouse[0] = event->x;
|
|
|
|
rc->slow_mouse[1] = event->y;
|
|
|
|
rc->slow_mode = true;
|
|
|
|
if (rc->subtype == PROP_ANGLE) {
|
|
|
|
float initial_position[2] = {UNPACK2(rc->initial_mouse)};
|
|
|
|
float current_position[2] = {UNPACK2(rc->slow_mouse)};
|
|
|
|
rc->dial = BLI_dial_initialize(initial_position, 0.0f);
|
|
|
|
/* immediately set the position to get a an initial direction */
|
|
|
|
BLI_dial_angle(rc->dial, current_position);
|
|
|
|
}
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
if (event->val == KM_RELEASE) {
|
|
|
|
rc->slow_mode = false;
|
|
|
|
handled = true;
|
|
|
|
if (rc->dial) {
|
|
|
|
MEM_freeN(rc->dial);
|
|
|
|
rc->dial = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Modal numinput inactive, try to handle numeric inputs last... */
|
|
|
|
if (!handled && event->val == KM_PRESS && handleNumInput(C, &rc->num_input, event)) {
|
|
|
|
applyNumInput(&rc->num_input, &numValue);
|
|
|
|
|
|
|
|
if (rc->subtype == PROP_ANGLE) {
|
|
|
|
numValue = DEG2RADF(numValue);
|
|
|
|
numValue = fmod(numValue, 2.0f * (float)M_PI);
|
|
|
|
if (numValue < 0.0f) {
|
|
|
|
numValue += 2.0f * (float)M_PI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CLAMP(numValue, rc->min_value, rc->max_value);
|
|
|
|
new_value = numValue;
|
|
|
|
|
|
|
|
radial_control_set_value(rc, new_value);
|
|
|
|
|
|
|
|
rc->current_value = new_value;
|
|
|
|
radial_control_update_header(op, C);
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ED_region_tag_redraw(CTX_wm_region(C));
|
|
|
|
radial_control_update_header(op, C);
|
|
|
|
|
2019-11-14 00:37:51 +11:00
|
|
|
if (ret & OPERATOR_FINISHED) {
|
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
|
|
|
if (wm->op_undo_depth == 0) {
|
|
|
|
ID *id = rc->ptr.owner_id;
|
|
|
|
if (ED_undo_is_legacy_compatible_for_property(C, id)) {
|
|
|
|
ED_undo_push(C, op->type->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (ret != OPERATOR_RUNNING_MODAL) {
|
|
|
|
radial_control_cancel(C, op);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2011-05-12 01:57:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void WM_OT_radial_control(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Radial Control";
|
|
|
|
ot->idname = "WM_OT_radial_control";
|
|
|
|
ot->description = "Set some size property (like e.g. brush size) with mouse wheel";
|
|
|
|
|
|
|
|
ot->invoke = radial_control_invoke;
|
|
|
|
ot->modal = radial_control_modal;
|
|
|
|
ot->cancel = radial_control_cancel;
|
|
|
|
|
2019-11-14 00:37:51 +11:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_BLOCKING;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* all paths relative to the context */
|
|
|
|
PropertyRNA *prop;
|
|
|
|
prop = RNA_def_string(ot->srna,
|
|
|
|
"data_path_primary",
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
"Primary Data Path",
|
|
|
|
"Primary path of property to be set by the radial control");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
prop = RNA_def_string(ot->srna,
|
|
|
|
"data_path_secondary",
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
"Secondary Data Path",
|
|
|
|
"Secondary path of property to be set by the radial control");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
prop = RNA_def_string(ot->srna,
|
|
|
|
"use_secondary",
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
"Use Secondary",
|
|
|
|
"Path of property to select between the primary and secondary data paths");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
prop = RNA_def_string(ot->srna,
|
|
|
|
"rotation_path",
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
"Rotation Path",
|
|
|
|
"Path of property used to rotate the texture display");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
prop = RNA_def_string(ot->srna,
|
|
|
|
"color_path",
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
"Color Path",
|
|
|
|
"Path of property used to set the color of the control");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
prop = RNA_def_string(ot->srna,
|
|
|
|
"fill_color_path",
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
"Fill Color Path",
|
|
|
|
"Path of property used to set the fill color of the control");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
prop = RNA_def_string(
|
|
|
|
ot->srna, "fill_color_override_path", NULL, 0, "Fill Color Override Path", "");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
prop = RNA_def_string(
|
|
|
|
ot->srna, "fill_color_override_test_path", NULL, 0, "Fill Color Override Test", "");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
prop = RNA_def_string(ot->srna,
|
|
|
|
"zoom_path",
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
"Zoom Path",
|
|
|
|
"Path of property used to set the zoom level for the control");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
prop = RNA_def_string(ot->srna,
|
|
|
|
"image_id",
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
"Image ID",
|
|
|
|
"Path of ID that is used to generate an image for the control");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
prop = RNA_def_boolean(
|
|
|
|
ot->srna, "secondary_tex", false, "Secondary Texture", "Tweak brush secondary/mask texture");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2009-01-24 16:59:55 +00:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Redraw Timer Operator
|
|
|
|
*
|
|
|
|
* Use for simple benchmarks.
|
|
|
|
* \{ */
|
2009-05-19 12:54:54 +00:00
|
|
|
|
|
|
|
/* uses no type defines, fully local testing function anyway... ;) */
|
|
|
|
|
2010-06-14 10:33:26 +00:00
|
|
|
static void redraw_timer_window_swap(bContext *C)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area;
|
2019-04-17 06:17:24 +02:00
|
|
|
CTX_wm_menu_set(C, NULL);
|
2010-06-14 10:33:26 +00:00
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
for (area = CTX_wm_screen(C)->areabase.first; area; area = area->next) {
|
|
|
|
ED_area_tag_redraw(area);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
wm_draw_update(C);
|
2010-06-14 10:33:26 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
CTX_wm_window_set(C, win); /* XXX context manipulation warning! */
|
2010-06-14 10:33:26 +00:00
|
|
|
}
|
|
|
|
|
2015-07-12 22:57:35 +10:00
|
|
|
enum {
|
2019-04-17 06:17:24 +02:00
|
|
|
eRTDrawRegion = 0,
|
|
|
|
eRTDrawRegionSwap = 1,
|
|
|
|
eRTDrawWindow = 2,
|
|
|
|
eRTDrawWindowSwap = 3,
|
|
|
|
eRTAnimationStep = 4,
|
|
|
|
eRTAnimationPlay = 5,
|
|
|
|
eRTUndo = 6,
|
2015-06-23 12:53:33 +02:00
|
|
|
};
|
|
|
|
|
2017-10-18 15:07:26 +11:00
|
|
|
static const EnumPropertyItem redraw_timer_type_items[] = {
|
2019-04-17 06:17:24 +02:00
|
|
|
{eRTDrawRegion, "DRAW", 0, "Draw Region", "Draw Region"},
|
|
|
|
{eRTDrawRegionSwap, "DRAW_SWAP", 0, "Draw Region + Swap", "Draw Region and Swap"},
|
|
|
|
{eRTDrawWindow, "DRAW_WIN", 0, "Draw Window", "Draw Window"},
|
|
|
|
{eRTDrawWindowSwap, "DRAW_WIN_SWAP", 0, "Draw Window + Swap", "Draw Window and Swap"},
|
|
|
|
{eRTAnimationStep, "ANIM_STEP", 0, "Anim Step", "Animation Steps"},
|
|
|
|
{eRTAnimationPlay, "ANIM_PLAY", 0, "Anim Play", "Animation Playback"},
|
|
|
|
{eRTUndo, "UNDO", 0, "Undo/Redo", "Undo/Redo"},
|
|
|
|
{0, NULL, 0, NULL, NULL},
|
2012-03-27 01:24:16 +00:00
|
|
|
};
|
2010-06-14 10:33:26 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static void redraw_timer_step(bContext *C,
|
|
|
|
Main *bmain,
|
|
|
|
Scene *scene,
|
|
|
|
struct Depsgraph *depsgraph,
|
|
|
|
wmWindow *win,
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area,
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region,
|
2019-04-17 06:17:24 +02:00
|
|
|
const int type,
|
|
|
|
const int cfra)
|
|
|
|
{
|
|
|
|
if (type == eRTDrawRegion) {
|
2020-03-06 16:56:42 +01:00
|
|
|
if (region) {
|
2020-04-03 13:25:03 +02:00
|
|
|
wm_draw_region_test(C, area, region);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type == eRTDrawRegionSwap) {
|
|
|
|
CTX_wm_menu_set(C, NULL);
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(region);
|
2019-04-17 06:17:24 +02:00
|
|
|
wm_draw_update(C);
|
|
|
|
|
|
|
|
CTX_wm_window_set(C, win); /* XXX context manipulation warning! */
|
|
|
|
}
|
|
|
|
else if (type == eRTDrawWindow) {
|
|
|
|
bScreen *screen = WM_window_get_active_screen(win);
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area_iter;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
CTX_wm_menu_set(C, NULL);
|
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
for (area_iter = screen->areabase.first; area_iter; area_iter = area_iter->next) {
|
2020-04-03 12:51:03 +02:00
|
|
|
ARegion *region_iter;
|
2020-04-03 13:25:03 +02:00
|
|
|
CTX_wm_area_set(C, area_iter);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
for (region_iter = area_iter->regionbase.first; region_iter;
|
|
|
|
region_iter = region_iter->next) {
|
2020-04-03 12:51:03 +02:00
|
|
|
if (region_iter->visible) {
|
|
|
|
CTX_wm_region_set(C, region_iter);
|
2020-04-03 13:25:03 +02:00
|
|
|
wm_draw_region_test(C, area_iter, region_iter);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CTX_wm_window_set(C, win); /* XXX context manipulation warning! */
|
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
CTX_wm_area_set(C, area);
|
2020-03-06 16:56:42 +01:00
|
|
|
CTX_wm_region_set(C, region);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else if (type == eRTDrawWindowSwap) {
|
|
|
|
redraw_timer_window_swap(C);
|
|
|
|
}
|
|
|
|
else if (type == eRTAnimationStep) {
|
|
|
|
scene->r.cfra += (cfra == scene->r.cfra) ? 1 : -1;
|
|
|
|
BKE_scene_graph_update_for_newframe(depsgraph, bmain);
|
|
|
|
}
|
|
|
|
else if (type == eRTAnimationPlay) {
|
|
|
|
/* play anim, return on same frame as started with */
|
|
|
|
int tot = (scene->r.efra - scene->r.sfra) + 1;
|
|
|
|
|
|
|
|
while (tot--) {
|
|
|
|
/* todo, ability to escape! */
|
|
|
|
scene->r.cfra++;
|
|
|
|
if (scene->r.cfra > scene->r.efra) {
|
|
|
|
scene->r.cfra = scene->r.sfra;
|
|
|
|
}
|
|
|
|
|
|
|
|
BKE_scene_graph_update_for_newframe(depsgraph, bmain);
|
|
|
|
redraw_timer_window_swap(C);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { /* eRTUndo */
|
2020-04-07 23:41:30 +02:00
|
|
|
/* Undo and redo, including depsgraph update since that can be a
|
|
|
|
* significant part of the cost. */
|
2019-04-17 06:17:24 +02:00
|
|
|
ED_undo_pop(C);
|
2020-04-07 23:41:30 +02:00
|
|
|
wm_event_do_refresh_wm_and_depsgraph(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
ED_undo_redo(C);
|
2020-04-07 23:41:30 +02:00
|
|
|
wm_event_do_refresh_wm_and_depsgraph(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2015-07-12 22:57:35 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
static int redraw_timer_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2019-05-21 12:34:54 +02:00
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
double time_start, time_delta;
|
|
|
|
const int type = RNA_enum_get(op->ptr, "type");
|
|
|
|
const int iter = RNA_int_get(op->ptr, "iterations");
|
|
|
|
const double time_limit = (double)RNA_float_get(op->ptr, "time_limit");
|
|
|
|
const int cfra = scene->r.cfra;
|
|
|
|
int a, iter_steps = 0;
|
|
|
|
const char *infostr = "";
|
2019-07-25 16:36:22 +02:00
|
|
|
|
|
|
|
/* NOTE: Depsgraph is used to update scene for a new state, so no need to ensure evaluation here.
|
|
|
|
*/
|
|
|
|
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
2015-07-12 22:57:35 +10:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_cursor_wait(1);
|
2010-06-14 10:33:26 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
time_start = PIL_check_seconds_timer();
|
2010-06-14 10:33:26 +00:00
|
|
|
|
2019-05-21 12:34:54 +02:00
|
|
|
wm_window_make_drawable(wm, win);
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
for (a = 0; a < iter; a++) {
|
2020-04-03 13:25:03 +02:00
|
|
|
redraw_timer_step(C, bmain, scene, depsgraph, win, area, region, type, cfra);
|
2019-04-17 06:17:24 +02:00
|
|
|
iter_steps += 1;
|
2010-06-14 10:33:26 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (time_limit != 0.0) {
|
|
|
|
if ((PIL_check_seconds_timer() - time_start) > time_limit) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
a = 0;
|
|
|
|
}
|
|
|
|
}
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
time_delta = (PIL_check_seconds_timer() - time_start) * 1000;
|
2010-06-14 10:33:26 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_enum_description(redraw_timer_type_items, type, &infostr);
|
2010-06-14 10:33:26 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_cursor_wait(0);
|
2010-06-14 10:33:26 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
BKE_reportf(op->reports,
|
|
|
|
RPT_WARNING,
|
|
|
|
"%d x %s: %.4f ms, average: %.8f ms",
|
|
|
|
iter_steps,
|
|
|
|
infostr,
|
|
|
|
time_delta,
|
|
|
|
time_delta / iter_steps);
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-05-19 12:54:54 +00:00
|
|
|
}
|
|
|
|
|
2009-09-22 09:12:39 +00:00
|
|
|
static void WM_OT_redraw_timer(wmOperatorType *ot)
|
2009-05-19 12:54:54 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Redraw Timer";
|
|
|
|
ot->idname = "WM_OT_redraw_timer";
|
|
|
|
ot->description = "Simple redraw timer to test the speed of updating the interface";
|
2010-06-14 10:33:26 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
ot->exec = redraw_timer_exec;
|
|
|
|
ot->poll = WM_operator_winactive;
|
2009-05-19 12:54:54 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", redraw_timer_type_items, eRTDrawRegion, "Type", "");
|
|
|
|
RNA_def_int(
|
|
|
|
ot->srna, "iterations", 10, 1, INT_MAX, "Iterations", "Number of times to redraw", 1, 1000);
|
|
|
|
RNA_def_float(ot->srna,
|
|
|
|
"time_limit",
|
|
|
|
0.0,
|
|
|
|
0.0,
|
|
|
|
FLT_MAX,
|
|
|
|
"Time Limit",
|
|
|
|
"Seconds to run the test for (override iterations)",
|
|
|
|
0.0,
|
|
|
|
60.0);
|
2009-05-19 12:54:54 +00:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2019-08-18 04:11:50 +10:00
|
|
|
/** \name Report Memory Statistics
|
2019-08-15 03:26:39 +10:00
|
|
|
*
|
|
|
|
* Use for testing/debugging.
|
|
|
|
* \{ */
|
2009-05-19 12:54:54 +00:00
|
|
|
|
2010-10-16 02:40:31 +00:00
|
|
|
static int memory_statistics_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
|
2009-10-27 10:29:51 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
MEM_printmemlist_stats();
|
|
|
|
return OPERATOR_FINISHED;
|
2009-10-27 10:29:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void WM_OT_memory_statistics(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Memory Statistics";
|
|
|
|
ot->idname = "WM_OT_memory_statistics";
|
|
|
|
ot->description = "Print memory statistics to the console";
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = memory_statistics_exec;
|
2009-10-27 10:29:51 +00:00
|
|
|
}
|
2009-05-19 12:54:54 +00:00
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Data-Block Preview Generation Operator
|
|
|
|
*
|
|
|
|
* Use for material/texture/light ... etc.
|
|
|
|
* \{ */
|
2015-01-12 14:44:54 +01:00
|
|
|
|
2016-03-24 16:10:05 +01:00
|
|
|
typedef struct PreviewsIDEnsureData {
|
2019-04-17 06:17:24 +02:00
|
|
|
bContext *C;
|
|
|
|
Scene *scene;
|
2016-03-24 16:10:05 +01:00
|
|
|
} PreviewsIDEnsureData;
|
2015-01-12 14:44:54 +01:00
|
|
|
|
|
|
|
static void previews_id_ensure(bContext *C, Scene *scene, ID *id)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_assert(ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA));
|
2015-01-12 14:44:54 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* Only preview non-library datablocks, lib ones do not pertain to this .blend file!
|
|
|
|
* Same goes for ID with no user. */
|
|
|
|
if (!ID_IS_LINKED(id) && (id->us != 0)) {
|
|
|
|
UI_id_icon_render(C, scene, id, false, false);
|
|
|
|
UI_id_icon_render(C, scene, id, true, false);
|
|
|
|
}
|
2015-01-12 14:44:54 +01:00
|
|
|
}
|
|
|
|
|
2020-02-13 12:56:10 +01:00
|
|
|
static int previews_id_ensure_callback(LibraryIDLinkCallbackData *cb_data)
|
2015-01-12 14:44:54 +01:00
|
|
|
{
|
2020-02-13 12:56:10 +01:00
|
|
|
const int cb_flag = cb_data->cb_flag;
|
|
|
|
|
2020-03-11 12:47:25 +01:00
|
|
|
if (cb_flag & IDWALK_CB_EMBEDDED) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
}
|
2017-01-30 21:34:23 +01:00
|
|
|
|
2020-02-13 12:56:10 +01:00
|
|
|
PreviewsIDEnsureData *data = cb_data->user_data;
|
|
|
|
ID *id = *cb_data->id_pointer;
|
2015-01-12 14:44:54 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (id && (id->tag & LIB_TAG_DOIT)) {
|
|
|
|
BLI_assert(ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA));
|
|
|
|
previews_id_ensure(data->C, data->scene, id);
|
|
|
|
id->tag &= ~LIB_TAG_DOIT;
|
|
|
|
}
|
2015-01-12 14:44:54 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return IDWALK_RET_NOP;
|
2015-01-12 14:44:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
ListBase *lb[] = {
|
|
|
|
&bmain->materials, &bmain->textures, &bmain->images, &bmain->worlds, &bmain->lights, NULL};
|
|
|
|
PreviewsIDEnsureData preview_id_data;
|
|
|
|
Scene *scene;
|
|
|
|
ID *id;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* We use LIB_TAG_DOIT to check whether we have already handled a given ID or not. */
|
|
|
|
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
|
|
|
|
for (i = 0; lb[i]; i++) {
|
|
|
|
BKE_main_id_tag_listbase(lb[i], LIB_TAG_DOIT, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
preview_id_data.C = C;
|
|
|
|
for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
|
|
|
|
preview_id_data.scene = scene;
|
|
|
|
id = (ID *)scene;
|
|
|
|
|
|
|
|
BKE_library_foreach_ID_link(
|
|
|
|
NULL, id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check a last time for ID not used (fake users only, in theory), and
|
|
|
|
* do our best for those, using current scene... */
|
|
|
|
for (i = 0; lb[i]; i++) {
|
|
|
|
for (id = lb[i]->first; id; id = id->next) {
|
|
|
|
if (id->tag & LIB_TAG_DOIT) {
|
|
|
|
previews_id_ensure(C, NULL, id);
|
|
|
|
id->tag &= ~LIB_TAG_DOIT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2015-01-12 14:44:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void WM_OT_previews_ensure(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Refresh Data-Block Previews";
|
|
|
|
ot->idname = "WM_OT_previews_ensure";
|
|
|
|
ot->description =
|
|
|
|
"Ensure data-block previews are available and up-to-date "
|
|
|
|
"(to be saved in .blend file, only for some types like materials, textures, etc.)";
|
2015-01-12 14:44:54 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = previews_ensure_exec;
|
2015-01-12 14:44:54 +01:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Data-Block Preview Clear Operator
|
|
|
|
* \{ */
|
2015-08-10 17:26:37 +02:00
|
|
|
|
2020-03-03 17:21:22 +01:00
|
|
|
typedef enum PreviewFilterID {
|
|
|
|
PREVIEW_FILTER_ALL,
|
|
|
|
PREVIEW_FILTER_GEOMETRY,
|
|
|
|
PREVIEW_FILTER_SHADING,
|
|
|
|
PREVIEW_FILTER_SCENE,
|
|
|
|
PREVIEW_FILTER_COLLECTION,
|
|
|
|
PREVIEW_FILTER_OBJECT,
|
|
|
|
PREVIEW_FILTER_MATERIAL,
|
|
|
|
PREVIEW_FILTER_LIGHT,
|
|
|
|
PREVIEW_FILTER_WORLD,
|
|
|
|
PREVIEW_FILTER_TEXTURE,
|
|
|
|
PREVIEW_FILTER_IMAGE,
|
|
|
|
} PreviewFilterID;
|
|
|
|
|
2015-08-10 17:26:37 +02:00
|
|
|
/* Only types supporting previews currently. */
|
2017-10-18 15:07:26 +11:00
|
|
|
static const EnumPropertyItem preview_id_type_items[] = {
|
2020-03-03 17:21:22 +01:00
|
|
|
{PREVIEW_FILTER_ALL, "ALL", 0, "All Types", ""},
|
|
|
|
{PREVIEW_FILTER_GEOMETRY,
|
2019-06-13 11:10:17 +02:00
|
|
|
"GEOMETRY",
|
|
|
|
0,
|
|
|
|
"All Geometry Types",
|
|
|
|
"Clear previews for scenes, collections and objects"},
|
2020-03-03 17:21:22 +01:00
|
|
|
{PREVIEW_FILTER_SHADING,
|
2019-06-13 11:10:17 +02:00
|
|
|
"SHADING",
|
|
|
|
0,
|
|
|
|
"All Shading Types",
|
2020-02-17 13:00:01 +01:00
|
|
|
"Clear previews for materials, lights, worlds, textures and images"},
|
2020-03-03 17:21:22 +01:00
|
|
|
{PREVIEW_FILTER_SCENE, "SCENE", 0, "Scenes", ""},
|
|
|
|
{PREVIEW_FILTER_COLLECTION, "COLLECTION", 0, "Collections", ""},
|
|
|
|
{PREVIEW_FILTER_OBJECT, "OBJECT", 0, "Objects", ""},
|
|
|
|
{PREVIEW_FILTER_MATERIAL, "MATERIAL", 0, "Materials", ""},
|
|
|
|
{PREVIEW_FILTER_LIGHT, "LIGHT", 0, "Lights", ""},
|
|
|
|
{PREVIEW_FILTER_WORLD, "WORLD", 0, "Worlds", ""},
|
|
|
|
{PREVIEW_FILTER_TEXTURE, "TEXTURE", 0, "Textures", ""},
|
|
|
|
{PREVIEW_FILTER_IMAGE, "IMAGE", 0, "Images", ""},
|
2019-04-17 06:17:24 +02:00
|
|
|
#if 0 /* XXX TODO */
|
2020-03-03 17:21:22 +01:00
|
|
|
{PREVIEW_FILTER_BRUSH, "BRUSH", 0, "Brushes", ""},
|
2015-08-10 17:26:37 +02:00
|
|
|
#endif
|
2019-01-19 13:21:18 +11:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
2015-08-10 17:26:37 +02:00
|
|
|
};
|
|
|
|
|
2020-03-03 17:21:22 +01:00
|
|
|
static uint preview_filter_to_idfilter(enum PreviewFilterID filter)
|
|
|
|
{
|
|
|
|
switch (filter) {
|
|
|
|
case PREVIEW_FILTER_ALL:
|
|
|
|
return FILTER_ID_SCE | FILTER_ID_GR | FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_LA |
|
|
|
|
FILTER_ID_WO | FILTER_ID_TE | FILTER_ID_IM;
|
|
|
|
case PREVIEW_FILTER_GEOMETRY:
|
|
|
|
return FILTER_ID_SCE | FILTER_ID_GR | FILTER_ID_OB;
|
|
|
|
case PREVIEW_FILTER_SHADING:
|
|
|
|
return FILTER_ID_MA | FILTER_ID_LA | FILTER_ID_WO | FILTER_ID_TE | FILTER_ID_IM;
|
|
|
|
case PREVIEW_FILTER_SCENE:
|
|
|
|
return FILTER_ID_SCE;
|
|
|
|
case PREVIEW_FILTER_COLLECTION:
|
|
|
|
return FILTER_ID_GR;
|
|
|
|
case PREVIEW_FILTER_OBJECT:
|
|
|
|
return FILTER_ID_OB;
|
|
|
|
case PREVIEW_FILTER_MATERIAL:
|
|
|
|
return FILTER_ID_MA;
|
|
|
|
case PREVIEW_FILTER_LIGHT:
|
|
|
|
return FILTER_ID_LA;
|
|
|
|
case PREVIEW_FILTER_WORLD:
|
|
|
|
return FILTER_ID_WO;
|
|
|
|
case PREVIEW_FILTER_TEXTURE:
|
|
|
|
return FILTER_ID_TE;
|
|
|
|
case PREVIEW_FILTER_IMAGE:
|
|
|
|
return FILTER_ID_IM;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-10 17:26:37 +02:00
|
|
|
static int previews_clear_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2019-04-18 17:17:32 +02:00
|
|
|
ListBase *lb[] = {
|
|
|
|
&bmain->objects,
|
|
|
|
&bmain->collections,
|
|
|
|
&bmain->materials,
|
|
|
|
&bmain->worlds,
|
|
|
|
&bmain->lights,
|
|
|
|
&bmain->textures,
|
|
|
|
&bmain->images,
|
|
|
|
NULL,
|
|
|
|
};
|
2019-04-17 06:17:24 +02:00
|
|
|
int i;
|
2015-08-10 17:26:37 +02:00
|
|
|
|
2020-03-03 17:21:22 +01:00
|
|
|
const int id_filters = preview_filter_to_idfilter(RNA_enum_get(op->ptr, "id_type"));
|
2015-08-10 17:26:37 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
for (i = 0; lb[i]; i++) {
|
|
|
|
ID *id = lb[i]->first;
|
|
|
|
if (!id) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-08-10 17:26:37 +02:00
|
|
|
|
2019-04-20 10:02:28 +02:00
|
|
|
#if 0
|
|
|
|
printf("%s: %d, %d, %d -> %d\n",
|
|
|
|
id->name,
|
|
|
|
GS(id->name),
|
2020-03-19 19:37:00 +01:00
|
|
|
BKE_idtype_idcode_to_idfilter(GS(id->name)),
|
2019-04-20 10:02:28 +02:00
|
|
|
id_filters,
|
2020-03-19 19:37:00 +01:00
|
|
|
BKE_idtype_idcode_to_idfilter(GS(id->name)) & id_filters);
|
2019-04-20 10:02:28 +02:00
|
|
|
#endif
|
2015-08-10 17:26:37 +02:00
|
|
|
|
2020-03-19 19:37:00 +01:00
|
|
|
if (!(BKE_idtype_idcode_to_idfilter(GS(id->name)) & id_filters)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
continue;
|
|
|
|
}
|
2015-08-10 17:26:37 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
for (; id; id = id->next) {
|
|
|
|
PreviewImage *prv_img = BKE_previewimg_id_ensure(id);
|
2015-08-10 17:26:37 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
BKE_previewimg_clear(prv_img);
|
|
|
|
}
|
|
|
|
}
|
2015-08-10 17:26:37 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2015-08-10 17:26:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void WM_OT_previews_clear(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "Clear Data-Block Previews";
|
|
|
|
ot->idname = "WM_OT_previews_clear";
|
|
|
|
ot->description =
|
|
|
|
"Clear data-block previews (only for some types like objects, materials, textures, etc.)";
|
2015-08-10 17:26:37 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = previews_clear_exec;
|
|
|
|
ot->invoke = WM_menu_invoke;
|
2015-08-10 17:26:37 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->prop = RNA_def_enum_flag(ot->srna,
|
|
|
|
"id_type",
|
|
|
|
preview_id_type_items,
|
2020-03-03 17:21:22 +01:00
|
|
|
PREVIEW_FILTER_ALL,
|
2019-04-17 06:17:24 +02:00
|
|
|
"Data-Block Type",
|
|
|
|
"Which data-block previews to clear");
|
2015-08-10 17:26:37 +02:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Doc from UI Operator
|
|
|
|
* \{ */
|
2015-08-10 17:26:37 +02:00
|
|
|
|
2015-04-27 01:17:51 +10:00
|
|
|
static int doc_view_manual_ui_context_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
PointerRNA ptr_props;
|
|
|
|
char buf[512];
|
|
|
|
short retval = OPERATOR_CANCELLED;
|
2015-04-27 01:17:51 +10:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (UI_but_online_manual_id_from_active(C, buf, sizeof(buf))) {
|
|
|
|
WM_operator_properties_create(&ptr_props, "WM_OT_doc_view_manual");
|
|
|
|
RNA_string_set(&ptr_props, "doc_id", buf);
|
2015-04-27 01:17:51 +10:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
retval = WM_operator_name_call_ptr(
|
|
|
|
C, WM_operatortype_find("WM_OT_doc_view_manual", false), WM_OP_EXEC_DEFAULT, &ptr_props);
|
2015-04-27 01:17:51 +10:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_operator_properties_free(&ptr_props);
|
|
|
|
}
|
2015-04-27 01:17:51 +10:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return retval;
|
2015-04-27 01:17:51 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
static void WM_OT_doc_view_manual_ui_context(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "View Online Manual";
|
|
|
|
ot->idname = "WM_OT_doc_view_manual_ui_context";
|
|
|
|
ot->description = "View a context based online manual in a web browser";
|
2015-04-27 01:17:51 +10:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* callbacks */
|
|
|
|
ot->poll = ED_operator_regionactive;
|
|
|
|
ot->exec = doc_view_manual_ui_context_exec;
|
2015-04-27 01:17:51 +10:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Toggle Stereo 3D Operator
|
|
|
|
*
|
|
|
|
* Turning it fullscreen if needed.
|
|
|
|
* \{ */
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
static void WM_OT_stereo3d_set(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
|
|
ot->name = "Set Stereo 3D";
|
|
|
|
ot->idname = "WM_OT_set_stereo_3d";
|
|
|
|
ot->description = "Toggle 3D stereo support for current window (or change the display mode)";
|
|
|
|
|
|
|
|
ot->exec = wm_stereo3d_set_exec;
|
|
|
|
ot->invoke = wm_stereo3d_set_invoke;
|
|
|
|
ot->poll = WM_operator_winactive;
|
|
|
|
ot->ui = wm_stereo3d_set_draw;
|
|
|
|
ot->check = wm_stereo3d_set_check;
|
|
|
|
ot->cancel = wm_stereo3d_set_cancel;
|
|
|
|
|
|
|
|
prop = RNA_def_enum(ot->srna,
|
|
|
|
"display_mode",
|
|
|
|
rna_enum_stereo3d_display_items,
|
|
|
|
S3D_DISPLAY_ANAGLYPH,
|
|
|
|
"Display Mode",
|
|
|
|
"");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
prop = RNA_def_enum(ot->srna,
|
|
|
|
"anaglyph_type",
|
|
|
|
rna_enum_stereo3d_anaglyph_type_items,
|
|
|
|
S3D_ANAGLYPH_REDCYAN,
|
|
|
|
"Anaglyph Type",
|
|
|
|
"");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
prop = RNA_def_enum(ot->srna,
|
|
|
|
"interlace_type",
|
|
|
|
rna_enum_stereo3d_interlace_type_items,
|
|
|
|
S3D_INTERLACE_ROW,
|
|
|
|
"Interlace Type",
|
|
|
|
"");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
prop = RNA_def_boolean(ot->srna,
|
|
|
|
"use_interlace_swap",
|
|
|
|
false,
|
|
|
|
"Swap Left/Right",
|
|
|
|
"Swap left and right stereo channels");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
prop = RNA_def_boolean(ot->srna,
|
|
|
|
"use_sidebyside_crosseyed",
|
|
|
|
false,
|
|
|
|
"Cross-Eyed",
|
|
|
|
"Right eye should see left image and vice-versa");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
#ifdef WITH_XR_OPENXR
|
|
|
|
|
|
|
|
static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data)
|
|
|
|
{
|
|
|
|
const bool session_exists = WM_xr_session_exists(xr_data);
|
|
|
|
|
|
|
|
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
|
|
|
LISTBASE_FOREACH (SpaceLink *, slink, &area->spacedata) {
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (slink->spacetype == SPACE_VIEW3D) {
|
|
|
|
View3D *v3d = (View3D *)slink;
|
|
|
|
|
|
|
|
if (v3d->flag & V3D_XR_SESSION_MIRROR) {
|
|
|
|
ED_view3d_xr_mirror_update(area, v3d, session_exists);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session_exists) {
|
|
|
|
wmWindowManager *wm = bmain->wm.first;
|
|
|
|
const Scene *scene = WM_windows_scene_get_from_screen(wm, screen);
|
|
|
|
|
|
|
|
ED_view3d_xr_shading_update(wm, v3d, scene);
|
|
|
|
}
|
|
|
|
/* Ensure no 3D View is tagged as session root. */
|
|
|
|
else {
|
|
|
|
v3d->runtime.flag &= ~V3D_RUNTIME_XR_SESSION_ROOT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-31 16:39:59 +02:00
|
|
|
|
|
|
|
WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void wm_xr_session_update_screen_on_exit_cb(const wmXrData *xr_data)
|
|
|
|
{
|
|
|
|
/* Just use G_MAIN here, storing main isn't reliable enough on file read or exit. */
|
|
|
|
wm_xr_session_update_screen(G_MAIN, xr_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wm_xr_session_toggle_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
|
|
|
|
|
|
|
/* Lazy-create xr context - tries to dynlink to the runtime, reading active_runtime.json. */
|
|
|
|
if (wm_xr_init(wm) == false) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
v3d->runtime.flag |= V3D_RUNTIME_XR_SESSION_ROOT;
|
|
|
|
wm_xr_session_toggle(wm, wm_xr_session_update_screen_on_exit_cb);
|
|
|
|
wm_xr_session_update_screen(bmain, &wm->xr);
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void WM_OT_xr_session_toggle(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Toggle VR Session";
|
|
|
|
ot->idname = "WM_OT_xr_session_toggle";
|
|
|
|
ot->description =
|
|
|
|
"Open a view for use with virtual reality headsets, or close it if already "
|
|
|
|
"opened";
|
|
|
|
|
|
|
|
/* callbacks */
|
|
|
|
ot->exec = wm_xr_session_toggle_exec;
|
|
|
|
ot->poll = ED_operator_view3d_active;
|
|
|
|
|
|
|
|
/* XXX INTERNAL just to hide it from the search menu by default, an Add-on will expose it in the
|
|
|
|
* UI instead. Not meant as a permanent solution. */
|
|
|
|
ot->flag = OPTYPE_INTERNAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* WITH_XR_OPENXR */
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Operator Registration & Keymaps
|
|
|
|
* \{ */
|
|
|
|
|
2018-07-13 12:15:18 +02:00
|
|
|
void wm_operatortypes_register(void)
|
2007-12-24 18:27:28 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_operatortype_append(WM_OT_window_close);
|
|
|
|
WM_operatortype_append(WM_OT_window_new);
|
|
|
|
WM_operatortype_append(WM_OT_window_new_main);
|
|
|
|
WM_operatortype_append(WM_OT_read_history);
|
|
|
|
WM_operatortype_append(WM_OT_read_homefile);
|
|
|
|
WM_operatortype_append(WM_OT_read_factory_settings);
|
|
|
|
WM_operatortype_append(WM_OT_save_homefile);
|
|
|
|
WM_operatortype_append(WM_OT_save_userpref);
|
2019-05-13 12:44:08 +10:00
|
|
|
WM_operatortype_append(WM_OT_read_userpref);
|
2019-05-13 13:25:51 +10:00
|
|
|
WM_operatortype_append(WM_OT_read_factory_userpref);
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_operatortype_append(WM_OT_userpref_autoexec_path_add);
|
|
|
|
WM_operatortype_append(WM_OT_userpref_autoexec_path_remove);
|
|
|
|
WM_operatortype_append(WM_OT_window_fullscreen_toggle);
|
|
|
|
WM_operatortype_append(WM_OT_quit_blender);
|
|
|
|
WM_operatortype_append(WM_OT_open_mainfile);
|
|
|
|
WM_operatortype_append(WM_OT_revert_mainfile);
|
|
|
|
WM_operatortype_append(WM_OT_link);
|
|
|
|
WM_operatortype_append(WM_OT_append);
|
|
|
|
WM_operatortype_append(WM_OT_lib_relocate);
|
|
|
|
WM_operatortype_append(WM_OT_lib_reload);
|
|
|
|
WM_operatortype_append(WM_OT_recover_last_session);
|
|
|
|
WM_operatortype_append(WM_OT_recover_auto_save);
|
|
|
|
WM_operatortype_append(WM_OT_save_as_mainfile);
|
|
|
|
WM_operatortype_append(WM_OT_save_mainfile);
|
|
|
|
WM_operatortype_append(WM_OT_redraw_timer);
|
|
|
|
WM_operatortype_append(WM_OT_memory_statistics);
|
|
|
|
WM_operatortype_append(WM_OT_debug_menu);
|
|
|
|
WM_operatortype_append(WM_OT_operator_defaults);
|
|
|
|
WM_operatortype_append(WM_OT_splash);
|
|
|
|
WM_operatortype_append(WM_OT_search_menu);
|
2020-04-16 00:32:30 +10:00
|
|
|
WM_operatortype_append(WM_OT_search_operator);
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_operatortype_append(WM_OT_call_menu);
|
|
|
|
WM_operatortype_append(WM_OT_call_menu_pie);
|
|
|
|
WM_operatortype_append(WM_OT_call_panel);
|
|
|
|
WM_operatortype_append(WM_OT_radial_control);
|
|
|
|
WM_operatortype_append(WM_OT_stereo3d_set);
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
#ifdef WITH_XR_OPENXR
|
|
|
|
WM_operatortype_append(WM_OT_xr_session_toggle);
|
|
|
|
#endif
|
2010-11-11 20:32:28 +00:00
|
|
|
#if defined(WIN32)
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_operatortype_append(WM_OT_console_toggle);
|
2010-10-18 20:41:52 +00:00
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_operatortype_append(WM_OT_previews_ensure);
|
|
|
|
WM_operatortype_append(WM_OT_previews_clear);
|
|
|
|
WM_operatortype_append(WM_OT_doc_view_manual_ui_context);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* gizmos */
|
|
|
|
WM_operatortype_append(GIZMOGROUP_OT_gizmo_select);
|
|
|
|
WM_operatortype_append(GIZMOGROUP_OT_gizmo_tweak);
|
2007-12-24 18:27:28 +00:00
|
|
|
}
|
|
|
|
|
2010-04-02 03:52:44 +00:00
|
|
|
/* circleselect-like modal operators */
|
2009-11-05 17:32:06 +00:00
|
|
|
static void gesture_circle_modal_keymap(wmKeyConfig *keyconf)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
static const EnumPropertyItem modal_items[] = {
|
|
|
|
{GESTURE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
|
|
|
|
{GESTURE_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
|
|
|
|
{GESTURE_MODAL_CIRCLE_ADD, "ADD", 0, "Add", ""},
|
|
|
|
{GESTURE_MODAL_CIRCLE_SUB, "SUBTRACT", 0, "Subtract", ""},
|
|
|
|
{GESTURE_MODAL_CIRCLE_SIZE, "SIZE", 0, "Size", ""},
|
2009-11-05 17:32:06 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
{GESTURE_MODAL_SELECT, "SELECT", 0, "Select", ""},
|
|
|
|
{GESTURE_MODAL_DESELECT, "DESELECT", 0, "DeSelect", ""},
|
|
|
|
{GESTURE_MODAL_NOP, "NOP", 0, "No Operation", ""},
|
2009-11-05 17:32:06 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
{0, NULL, 0, NULL, NULL},
|
|
|
|
};
|
2009-11-05 17:32:06 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* WARNING - name is incorrect, use for non-3d views */
|
2020-03-27 10:58:00 +11:00
|
|
|
wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Gesture Circle");
|
2009-11-05 17:32:06 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* this function is called for each spacetype, only needs to add map once */
|
|
|
|
if (keymap && keymap->modal_items) {
|
|
|
|
return;
|
|
|
|
}
|
2009-11-05 17:32:06 +00:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
keymap = WM_modalkeymap_ensure(keyconf, "View3D Gesture Circle", modal_items);
|
2009-11-05 17:32:06 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* assign map to operators */
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_circle");
|
|
|
|
WM_modalkeymap_assign(keymap, "UV_OT_select_circle");
|
|
|
|
WM_modalkeymap_assign(keymap, "CLIP_OT_select_circle");
|
|
|
|
WM_modalkeymap_assign(keymap, "MASK_OT_select_circle");
|
|
|
|
WM_modalkeymap_assign(keymap, "NODE_OT_select_circle");
|
|
|
|
WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle");
|
|
|
|
WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle");
|
|
|
|
WM_modalkeymap_assign(keymap, "ACTION_OT_select_circle");
|
2009-11-05 17:32:06 +00:00
|
|
|
}
|
|
|
|
|
2010-04-04 00:21:37 +00:00
|
|
|
/* straight line modal operators */
|
|
|
|
static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
static const EnumPropertyItem modal_items[] = {
|
|
|
|
{GESTURE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
|
|
|
|
{GESTURE_MODAL_SELECT, "SELECT", 0, "Select", ""},
|
|
|
|
{GESTURE_MODAL_BEGIN, "BEGIN", 0, "Begin", ""},
|
|
|
|
{0, NULL, 0, NULL, NULL},
|
|
|
|
};
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Gesture Straight Line");
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* this function is called for each spacetype, only needs to add map once */
|
|
|
|
if (keymap && keymap->modal_items) {
|
|
|
|
return;
|
|
|
|
}
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
keymap = WM_modalkeymap_ensure(keyconf, "Gesture Straight Line", modal_items);
|
2018-06-07 16:43:52 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* assign map to operators */
|
|
|
|
WM_modalkeymap_assign(keymap, "IMAGE_OT_sample_line");
|
|
|
|
WM_modalkeymap_assign(keymap, "PAINT_OT_weight_gradient");
|
|
|
|
WM_modalkeymap_assign(keymap, "MESH_OT_bisect");
|
2010-04-04 00:21:37 +00:00
|
|
|
}
|
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
/* box_select-like modal operators */
|
|
|
|
static void gesture_box_modal_keymap(wmKeyConfig *keyconf)
|
2009-11-06 22:51:08 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
static const EnumPropertyItem modal_items[] = {
|
|
|
|
{GESTURE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
|
|
|
|
{GESTURE_MODAL_SELECT, "SELECT", 0, "Select", ""},
|
|
|
|
{GESTURE_MODAL_DESELECT, "DESELECT", 0, "DeSelect", ""},
|
|
|
|
{GESTURE_MODAL_BEGIN, "BEGIN", 0, "Begin", ""},
|
|
|
|
{0, NULL, 0, NULL, NULL},
|
|
|
|
};
|
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Gesture Box");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* this function is called for each spacetype, only needs to add map once */
|
|
|
|
if (keymap && keymap->modal_items) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
keymap = WM_modalkeymap_ensure(keyconf, "Gesture Box", modal_items);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* assign map to operators */
|
|
|
|
WM_modalkeymap_assign(keymap, "ACTION_OT_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "ANIM_OT_channels_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "ANIM_OT_previewrange_set");
|
|
|
|
WM_modalkeymap_assign(keymap, "INFO_OT_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "FILE_OT_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "GRAPH_OT_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "MARKER_OT_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "NLA_OT_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "NODE_OT_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "NODE_OT_viewer_border");
|
|
|
|
WM_modalkeymap_assign(keymap, "PAINT_OT_hide_show");
|
|
|
|
WM_modalkeymap_assign(keymap, "OUTLINER_OT_select_box");
|
|
|
|
// WM_modalkeymap_assign(keymap, "SCREEN_OT_box_select"); // template
|
|
|
|
WM_modalkeymap_assign(keymap, "SEQUENCER_OT_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "SEQUENCER_OT_view_ghost_border");
|
|
|
|
WM_modalkeymap_assign(keymap, "UV_OT_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "CLIP_OT_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "CLIP_OT_graph_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "MASK_OT_select_box");
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border");
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border");
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border");
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_box");
|
2019-04-20 10:02:28 +02:00
|
|
|
/* XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel */
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border");
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border");
|
|
|
|
WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
|
|
|
|
WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_box");
|
2009-11-06 22:51:08 +00:00
|
|
|
}
|
|
|
|
|
2010-04-02 03:52:44 +00:00
|
|
|
/* zoom to border modal operators */
|
|
|
|
static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
static const EnumPropertyItem modal_items[] = {
|
|
|
|
{GESTURE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
|
|
|
|
{GESTURE_MODAL_IN, "IN", 0, "In", ""},
|
|
|
|
{GESTURE_MODAL_OUT, "OUT", 0, "Out", ""},
|
|
|
|
{GESTURE_MODAL_BEGIN, "BEGIN", 0, "Begin", ""},
|
|
|
|
{0, NULL, 0, NULL, NULL},
|
|
|
|
};
|
2010-04-02 03:52:44 +00:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Gesture Zoom Border");
|
2010-04-02 03:52:44 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* this function is called for each spacetype, only needs to add map once */
|
|
|
|
if (keymap && keymap->modal_items) {
|
|
|
|
return;
|
|
|
|
}
|
2010-04-02 03:52:44 +00:00
|
|
|
|
2020-03-27 10:58:00 +11:00
|
|
|
keymap = WM_modalkeymap_ensure(keyconf, "Gesture Zoom Border", modal_items);
|
2010-04-02 03:52:44 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* assign map to operators */
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border");
|
|
|
|
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border");
|
|
|
|
WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
|
2010-04-02 03:52:44 +00:00
|
|
|
}
|
|
|
|
|
2008-11-19 16:28:11 +00:00
|
|
|
/* default keymap for windows and screens, only call once per WM */
|
Key Configuration
Keymaps are now saveable and configurable from the user preferences, note
that editing one item in a keymap means the whole keymap is now defined by
the user and will not be updated by Blender, an option for syncing might be
added later. The outliner interface is still there, but I will probably
remove it.
There's actually 3 levels now:
* Default builtin key configuration.
* Key configuration loaded from .py file, for configs like Blender 2.4x
or other 3D applications.
* Keymaps edited by the user and saved in .B.blend. These can be saved
to .py files as well to make creating distributable configurations
easier.
Also, user preferences sections were reorganized a bit, now there is:
Interface, Editing, Input, Files and System.
Implementation notes:
* wmKeyConfig was added which represents a key configuration containing
keymaps.
* wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap.
* Modal maps are not wrapped yet.
* User preferences DNA file reading did not support newdataadr() yet,
added this now for reading keymaps.
* Key configuration related settings are now RNA wrapped.
* is_property_set and is_property_hidden python methods were added.
2009-10-08 18:40:03 +00:00
|
|
|
void wm_window_keymap(wmKeyConfig *keyconf)
|
2008-11-19 16:28:11 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_keymap_ensure(keyconf, "Window", 0, 0);
|
2009-11-05 17:32:06 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
wm_gizmos_keymap(keyconf);
|
|
|
|
gesture_circle_modal_keymap(keyconf);
|
|
|
|
gesture_box_modal_keymap(keyconf);
|
|
|
|
gesture_zoom_border_modal_keymap(keyconf);
|
|
|
|
gesture_straightline_modal_keymap(keyconf);
|
2018-11-08 15:59:51 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_keymap_fix_linking();
|
2.5 Branch
==========
* Changed wmOperatorType, removing init/exit callbacks and adding cancel
callback, removed default storage in favor of properties. Defined return
values for exec/invoke/modal/cancel.
* Don't allocate operator on the stack, and removed operator copy for
handlers. Now it frees based on return values from callbacks, and just
keeps a wmOperator on the heap. Also it now registers after the operator
is fully finished, to get the correct final properties.
* Changed OP_get_* functions to return 1 if the property is found and 0
otherwise, gives more readable code in my opinion. Added OP_verify_*
functions to quickly check if the property is available and set if it's
not, that's common for exec/invoke.
* Removed WM_operatortypelist_append in favor of WM_operatortype_append
which takes a function pointer instead of a list, avoids macro's and
duplicating code.
* Fix a crash where the handler would still be used while it was freed by
the operator.
* Spacetypes now have operatortypes() and keymap() callbacks to abstract
them a bit more.
* Renamed C->curarea to C->area for consistency. Removed View3D/View2D/
SpaceIpo from bContext, seems bad to keep these.
* Set context variables like window/screen/area/region to NULL again when
leaving that context, instead of leaving the pointers there.
* Added if(G.f & G_DEBUG) for many of the prints, makes output a bit
cleaner and easier to debug.
* Fixed priority of the editors/interface module in scons, would otherwise
give link errors.
* Added start of generic view2d api.
* Added space_time with some basic drawing and a single operator to change
the frame.
2008-06-11 10:10:31 +00:00
|
|
|
}
|
|
|
|
|
2019-08-15 03:26:39 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Enum Filter Functions
|
|
|
|
*
|
2017-11-21 16:33:36 +11:00
|
|
|
* Filter functions that can be used with rna_id_itemf() below.
|
|
|
|
* Should return false if 'id' should be excluded.
|
2019-08-15 03:26:39 +10:00
|
|
|
*
|
|
|
|
* \{ */
|
|
|
|
|
2017-11-21 16:33:36 +11:00
|
|
|
static bool rna_id_enum_filter_single(ID *id, void *user_data)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return (id != user_data);
|
2017-11-21 16:33:36 +11:00
|
|
|
}
|
|
|
|
|
2009-11-04 10:25:57 +00:00
|
|
|
/* Generic itemf's for operators that take library args */
|
2019-04-17 06:17:24 +02:00
|
|
|
static const EnumPropertyItem *rna_id_itemf(bContext *UNUSED(C),
|
|
|
|
PointerRNA *UNUSED(ptr),
|
|
|
|
bool *r_free,
|
|
|
|
ID *id,
|
|
|
|
bool local,
|
|
|
|
bool (*filter_ids)(ID *id, void *user_data),
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
EnumPropertyItem item_tmp = {0}, *item = NULL;
|
|
|
|
int totitem = 0;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for (; id; id = id->next) {
|
|
|
|
if ((filter_ids != NULL) && filter_ids(user_data, id) == false) {
|
|
|
|
i++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (local == false || !ID_IS_LINKED(id)) {
|
|
|
|
item_tmp.identifier = item_tmp.name = id->name + 2;
|
|
|
|
item_tmp.value = i++;
|
|
|
|
RNA_enum_item_add(&item, &totitem, &item_tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RNA_enum_item_end(&item, &totitem);
|
|
|
|
*r_free = true;
|
|
|
|
|
|
|
|
return item;
|
2009-11-04 10:25:57 +00:00
|
|
|
}
|
|
|
|
|
2010-02-23 19:32:32 +00:00
|
|
|
/* can add more as needed */
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_action_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2010-02-23 19:32:32 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(
|
|
|
|
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->actions.first : NULL, false, NULL, NULL);
|
2010-05-05 15:41:38 +00:00
|
|
|
}
|
2012-04-23 07:32:13 +00:00
|
|
|
#if 0 /* UNUSED */
|
2019-04-17 08:24:14 +02:00
|
|
|
const EnumPropertyItem *RNA_action_local_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2010-05-05 15:41:38 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->action.first : NULL, true);
|
2010-02-23 19:32:32 +00:00
|
|
|
}
|
2012-04-23 07:32:13 +00:00
|
|
|
#endif
|
2010-05-05 15:41:38 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_collection_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2009-11-04 10:25:57 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(
|
|
|
|
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->collections.first : NULL, false, NULL, NULL);
|
2010-05-05 15:41:38 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_collection_local_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2010-05-05 15:41:38 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(
|
|
|
|
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->collections.first : NULL, true, NULL, NULL);
|
2009-11-04 10:25:57 +00:00
|
|
|
}
|
2010-05-05 15:41:38 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_image_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2010-03-05 18:19:32 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(
|
|
|
|
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->images.first : NULL, false, NULL, NULL);
|
2010-05-05 15:41:38 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_image_local_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2010-05-05 15:41:38 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(
|
|
|
|
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->images.first : NULL, true, NULL, NULL);
|
2010-03-05 18:19:32 +00:00
|
|
|
}
|
2010-05-05 15:41:38 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_scene_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2009-11-04 10:25:57 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(
|
|
|
|
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->scenes.first : NULL, false, NULL, NULL);
|
2010-05-05 15:41:38 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_scene_local_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2010-05-05 15:41:38 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(
|
|
|
|
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->scenes.first : NULL, true, NULL, NULL);
|
2017-11-21 16:33:36 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_scene_without_active_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2017-11-21 16:33:36 +11:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Scene *scene_active = C ? CTX_data_scene(C) : NULL;
|
|
|
|
return rna_id_itemf(C,
|
|
|
|
ptr,
|
|
|
|
r_free,
|
|
|
|
C ? (ID *)CTX_data_main(C)->scenes.first : NULL,
|
2019-04-25 14:27:56 +02:00
|
|
|
false,
|
2019-04-17 06:17:24 +02:00
|
|
|
rna_id_enum_filter_single,
|
|
|
|
scene_active);
|
2009-11-04 10:25:57 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_movieclip_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2012-03-21 18:02:29 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(
|
|
|
|
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->movieclips.first : NULL, false, NULL, NULL);
|
2012-03-21 18:02:29 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_movieclip_local_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2012-03-21 18:02:29 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(
|
|
|
|
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->movieclips.first : NULL, true, NULL, NULL);
|
2012-03-21 18:02:29 +00:00
|
|
|
}
|
2012-06-07 18:24:36 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_mask_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2012-06-07 18:24:36 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(
|
|
|
|
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->masks.first : NULL, false, NULL, NULL);
|
2012-06-07 18:24:36 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
const EnumPropertyItem *RNA_mask_local_itemf(bContext *C,
|
|
|
|
PointerRNA *ptr,
|
|
|
|
PropertyRNA *UNUSED(prop),
|
|
|
|
bool *r_free)
|
2012-06-07 18:24:36 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return rna_id_itemf(
|
|
|
|
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->masks.first : NULL, true, NULL, NULL);
|
2012-06-07 18:24:36 +00:00
|
|
|
}
|
2019-08-15 03:26:39 +10:00
|
|
|
|
|
|
|
/** \} */
|