apply patches

This commit is contained in:
Jaume Bellet 2024-01-20 00:46:45 +01:00
parent 887c739ed6
commit c88ad44057
97 changed files with 2790 additions and 59 deletions

View File

@ -22,6 +22,7 @@ Blender Convenience Targets
* developer: Enable faster builds, error checking and tests, recommended for developers.
* ninja: Use ninja build tool for faster builds.
* ccache: Use ccache for faster rebuilds.
* tornavis-lite: Build lite adding mechanical blender deps.
Note: when passing in multiple targets their order is not important.
So for a fast build you can for e.g. run 'make lite ccache ninja'.
@ -126,6 +127,9 @@ Utilities
* update_code:
Updates git and all submodules but not svn.
* tornavis-apply:
Applies mechanical Blender patches.
* format:
Format source code using clang-format & autopep8 (uses PATHS if passed in). For example::
@ -276,6 +280,11 @@ ifneq "$(findstring lite, $(MAKECMDGOALS))" ""
BUILD_DIR:=$(BUILD_DIR)_lite
CMAKE_CONFIG_ARGS:=-C"$(BLENDER_DIR)/build_files/cmake/config/blender_lite.cmake" $(CMAKE_CONFIG_ARGS)
endif
ifneq "$(findstring mbleder-lite, $(MAKECMDGOALS))" ""
BUILD_DIR:=$(BUILD_DIR)_lite
CMAKE_CONFIG_ARGS:=-C"$(BLENDER_DIR)/build_files/cmake/config/blender_lite.cmake" $(CMAKE_CONFIG_ARGS)
CMAKE_CONFIG_ARGS:=-DWITH_BOOST=YES $(CMAKE_CONFIG_ARGS)
endif
ifneq "$(findstring release, $(MAKECMDGOALS))" ""
BUILD_DIR:=$(BUILD_DIR)_release
CMAKE_CONFIG_ARGS:=-C"$(BLENDER_DIR)/build_files/cmake/config/blender_release.cmake" $(CMAKE_CONFIG_ARGS)
@ -407,6 +416,7 @@ bpy: all
developer: all
ninja: all
ccache: all
tornavis-lite: all
# -----------------------------------------------------------------------------
# Build dependencies
@ -590,6 +600,9 @@ format: .FORCE
@$(PYTHON) tools/utils_maintenance/autopep8_format_paths.py --autopep8-command="$(AUTOPEP8)" $(PATHS)
tornavis-apply: .FORCE
@$(PYTHON) ./build_files/utils/apply_tornavis_patches.py
# -----------------------------------------------------------------------------
# Documentation
#

View File

@ -4,35 +4,24 @@ linking to external resources instead of including content in-line.
See 'release/text/readme.html' for the end user read-me.
-->
Blender
![Tornavis logo](https://www.tornavis.org/tornavis.png)
=======
Blender is the free and open source 3D creation suite.
It supports the entirety of the 3D pipeline-modeling, rigging, animation, simulation, rendering, compositing,
motion tracking and video editing.
![Blender screenshot](https://code.blender.org/wp-content/uploads/2018/12/springrg.jpg "Blender screenshot")
Tornavis Project (aka mblender) aims to give mechanical engineering and design tools to a really awesome piece of software.
Project Pages
-------------
- [Main Website](http://www.blender.org)
- [Reference Manual](https://docs.blender.org/manual/en/latest/index.html)
- [User Community](https://www.blender.org/community/)
- [Website](https://www.tornavis.org)
Development
-----------
- [Build Instructions](https://developer.blender.org/docs/handbook/building_blender/)
- [Code Review & Bug Tracker](https://projects.blender.org)
- [Developer Forum](https://devtalk.blender.org)
- [Developer Documentation](https://developer.blender.org/docs/)
Project is currently on development, on **early** early stages.
License
-------
Blender as a whole is licensed under the GNU General Public License, Version 3.
Individual files may have a different, but compatible license.
Tornavis inherits Blender License.
See [blender.org/about/license](https://www.blender.org/about/license) for details.

View File

@ -0,0 +1,108 @@
#!/usr/bin/env python3
#
# Mechanical Blender
"""
"make mblender" for applying mblender patches on current source.
"""
import argparse
import sys
import os
import make_utils
from make_utils import call
MB_0001 = "https://www.tornavis.org/mblender_patches/patches/mb-0001-operator-repeat.patch"
MB_0002 = "https://www.tornavis.org/mblender_patches/patches/mb-0002-readme-file.patch"
MB_0003 = "https://www.tornavis.org/mblender_patches/patches/mb-0003-mblender-make-target-windows.patch"
MB_0004 = "https://www.tornavis.org/mblender_patches/patches/mb-0004-mblender-make-target-linux.patch"
MB_0005 = "https://www.tornavis.org/mblender_patches/patches/mb-0005-splash-changes.patch"
MB_0006 = "https://www.tornavis.org/mblender_patches/patches/mb-0006-allow-no-modal-transform.patch"
MB_0007 = "https://www.tornavis.org/mblender_patches/patches/mb-0007-transform-flags.patch"
MB_0008 = "https://www.tornavis.org/mblender_patches/patches/mb-0008-mblender-core.patch"
MB_0009 = "https://www.tornavis.org/mblender_patches/patches/mb-0009-addon-menu-references.patch"
MB_0010 = "https://www.tornavis.org/mblender_patches/patches/mb-0010-url-presets.patch"
MB_0011 = "https://www.tornavis.org/mblender_patches/patches/mb-0011-operator-handlers.patch"
MB_0012 = "https://www.tornavis.org/mblender_patches/patches/mb-0012-custom-splash.patch"
MB_0013 = "https://www.tornavis.org/mblender_patches/patches/mb-0013-blender-top-bar.patch"
MB_0013_BIN = "https://www.tornavis.org/mblender_patches/patches/mb-0013-blender-top-bar.tar"
MB_0014 = "https://www.tornavis.org/mblender_patches/patches/mb-0014-bpy-images.patch"
MB_0015 = "https://www.tornavis.org/mblender_patches/patches/mb-0015-image-ui.patch"
MB_0016 = "https://www.tornavis.org/mblender_patches/patches/mb-0016-create-object-with-custom-orientation.patch"
def parse_arguments() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("--git-command", default="git")
parser.add_argument("--wget-command", default="wget")
return parser.parse_args()
args = parse_arguments()
git_command = args.git_command
wget_command = args.wget_command
tmp_file = "/tmp/mblender.patch"
tmp_file2 = "/tmp/mblender.tar"
if make_utils.command_missing(git_command):
sys.stderr.write("git not found, can't checkout test files\n")
sys.exit(1)
if make_utils.command_missing(wget_command):
sys.stderr.write("wget not found, used for downloading patches\n")
sys.exit(1)
if __name__ == "__main__":
call([wget_command, MB_0001, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0002, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0003, "-O", tmp_file])
call([git_command, "apply", tmp_file])
# MB-0004 Already applied
call([wget_command, MB_0005, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0006, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0007, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0008, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0009, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0010, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0011, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0012, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0013, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0013_BIN, "-O", tmp_file2])
call(["cmake","-E","tar", "xf", tmp_file2])
call([wget_command, MB_0014, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0015, "-O", tmp_file])
call([git_command, "apply", tmp_file])
call([wget_command, MB_0016, "-O", tmp_file])
call([git_command, "apply", tmp_file])

View File

@ -0,0 +1,116 @@
if "%GIT%" == "" (
echo Git not found, cannot apply patches.
goto ERR
)
if "%CURL%" == "" (
echo Curl not found, cannot download patches
goto ERR
)
set MB_0001=https://www.tornavis.org/mblender_patches/patches/mb-0001-operator-repeat.patch
set MB_0002=https://www.tornavis.org/mblender_patches/patches/mb-0002-readme-file.patch
set MB_0003=https://www.tornavis.org/mblender_patches/patches/mb-0003-mblender-make-target-windows.patch
set MB_0004=https://www.tornavis.org/mblender_patches/patches/mb-0004-mblender-make-target-linux.patch
set MB_0005=https://www.tornavis.org/mblender_patches/patches/mb-0005-splash-changes.patch
set MB_0006=https://www.tornavis.org/mblender_patches/patches/mb-0006-allow-no-modal-transform.patch
set MB_0007=https://www.tornavis.org/mblender_patches/patches/mb-0007-transform-flags.patch
set MB_0008=https://www.tornavis.org/mblender_patches/patches/mb-0008-mblender-core.patch
set MB_0009=https://www.tornavis.org/mblender_patches/patches/mb-0009-addon-menu-references.patch
set MB_0010=https://www.tornavis.org/mblender_patches/patches/mb-0010-url-presets.patch
set MB_0011=https://www.tornavis.org/mblender_patches/patches/mb-0011-operator-handlers.patch
set MB_0012=https://www.tornavis.org/mblender_patches/patches/mb-0012-custom-splash.patch
set MB_0013=https://www.tornavis.org/mblender_patches/patches/mb-0013-blender-top-bar.patch
set MB_0013_BIN=https://www.tornavis.org/mblender_patches/patches/mb-0013-blender-top-bar.tar
set MB_0014=https://www.tornavis.org/mblender_patches/patches/mb-0014-bpy-images.patch
set MB_0015=https://www.tornavis.org/mblender_patches/patches/mb-0015-image-ui.patch
set MB_0016=https://www.tornavis.org/mblender_patches/patches/mb-0016-create-object-with-custom-orientation.patch
set MB_0017=https://www.tornavis.org/mblender_patches/patches/mb-0017-transform-orientation-origin.patch
set MB_0018=https://www.tornavis.org/mblender_patches/patches/mb-0018-ucs.patch
echo [APPLY] %MB_0001%
"%CURL%" "%MB_0001%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] %MB_0002%
"%CURL%" "%MB_0002%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
REM MB-0003 already applied
echo [APPLY] "%MB_0004%
"%CURL%" "%MB_0004%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY]"%MB_0005%
"%CURL%" "%MB_0005%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0006%
"%CURL%" "%MB_0006%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0007%
"%CURL%" "%MB_0007%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0008%
"%CURL%" "%MB_0008%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0009%
"%CURL%" "%MB_0009%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0010%
"%CURL%" "%MB_0010%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0011%
"%CURL%" "%MB_0011%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0012%
"%CURL%" "%MB_0012%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0013%
"%CURL%" "%MB_0013%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [BINARY] %MB_0013_BIN%
"%CURL%" "%MB_0013_BIN%" --ssl-no-revoke -o data.tar
if errorlevel 1 goto ERR
"%CMAKE%" -E tar xf data.tar
if errorlevel 1 goto ERR
del data.tar
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0014%
"%CURL%" "%MB_0014%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0015%
"%CURL%" "%MB_0015%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0016%
"%CURL%" "%MB_0016%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0017%
"%CURL%" "%MB_0017%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [APPLY] "%MB_0018%
"%CURL%" "%MB_0018%" --ssl-no-revoke | "%GIT%" apply
if errorlevel 1 goto ERR
echo [OK] Now build blender as usually.
:EOF
exit /b 0
:ERR
echo [ERROR] Something went wrong!
exit /b 1

View File

@ -3,6 +3,7 @@ for %%X in (svn.exe) do (set SVN=%%~$PATH:X)
for %%X in (cmake.exe) do (set CMAKE=%%~$PATH:X)
for %%X in (ctest.exe) do (set CTEST=%%~$PATH:X)
for %%X in (git.exe) do (set GIT=%%~$PATH:X)
for %%X in (curl.exe) do (set CURL=%%~$PATH:X)
REM For python, default on 310 but if that does not exist also check
REM the 311, 312 and finally 39 folders to see if those are there, it checks
REM this far ahead to ensure good lib folder compatibility in the future

View File

@ -113,6 +113,13 @@ if NOT "%1" == "" (
) else if "%1" == "svnfix" (
set SVN_FIX=1
goto EOF
) else if "%1" == "tornavis-apply" (
set MB_PATCHES=1
goto EOF
) else if "%1" == "tornavis-lite" (
set TARGET=Lite
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -C"%BLENDER_DIR%\build_files\cmake\config\blender_lite.cmake"
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_BOOST=On
) else (
echo Command "%1" unknown, aborting!
goto ERR

View File

@ -6,6 +6,7 @@ echo - lite
echo - headless
echo - cycles
echo - bpy
echo - tornavis-lite ^(lite adding tornavis deps^)
echo.
echo Utilities ^(not associated with building^)
echo - clean ^(Target must be set^)
@ -15,6 +16,7 @@ echo - nobuild ^(only generate project files^)
echo - showhash ^(Show git hashes of source tree^)
echo - test ^(Run automated tests with ctest^)
echo - format [path] ^(Format the source using clang-format, path is optional, requires python 3.x to be available^)
echo - tornavis-apply ^(Apply all tornavis' patches^)
echo.
echo Configuration options
echo - verbose ^(enable diagnostic output during configuration^)

View File

@ -16,6 +16,11 @@ if errorlevel 1 goto EOF
call "%BLENDER_DIR%\build_files\windows\find_dependencies.cmd"
if errorlevel 1 goto EOF
if "%MB_PATCHES%" == "1" (
call "%BLENDER_DIR%\build_files\windows\apply_tornavis_patches.cmd"
goto EOF
)
REM if it is one of the convenience targets and BLENDER_BIN is set
REM skip compiler detection
if "%ICONS%%ICONS_GEOM%%DOC_PY%" == "1" (

View File

@ -0,0 +1 @@
Binary data like icons or images related to mechanical blender

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -13,8 +13,27 @@ _op_as_string = _ops_module.as_string
_op_get_rna_type = _ops_module.get_rna_type
_op_get_bl_options = _ops_module.get_bl_options
_op_handlers = _ops_module.handlers
_ModuleType = type(_ops_module)
class handler_action:
def __init__(self, mod, append_func, remove_func):
self._mod = mod
self._append_func = append_func
self._remove_func = remove_func
def append(self,cb, owner = None, args = None, poll = None):
#is there a way to remove self from console show?
self._append_func(owner=owner, op = self._mod.idname(), cb=cb, args=args, poll = poll)
def remove(self, cb = None, owner = None):
self._remove_func(owner=owner, op = self._mod.idname(), cb=cb, args=None, poll = None)
def remove_handlers(owner = None, cb = None):
_op_handlers.remove(owner = owner, cb = cb, op = None, args = None, poll = None)
# -----------------------------------------------------------------------------
# Callable Operator Wrapper
@ -26,7 +45,14 @@ class _BPyOpsSubModOp:
eg. bpy.ops.object.somefunc
"""
__slots__ = ("_module", "_func")
__slots__ = ("_module", "_func", "handlers")
class _handlers:
def __init__(self, mod):
self.invoke_pre = handler_action(mod, _op_handlers.pre_invoke, _op_handlers.pre_invoke_remove)
self.invoke_post = handler_action(mod, _op_handlers.post_invoke, _op_handlers.post_invoke_remove)
self.modal = handler_action(mod, _op_handlers.modal, _op_handlers.modal_remove)
self.modal_end = handler_action(mod, _op_handlers.modal_end, _op_handlers.modal_end_remove)
def _get_doc(self):
idname = self.idname()
@ -77,6 +103,7 @@ class _BPyOpsSubModOp:
def __init__(self, module, func):
self._module = module
self._func = func
self.handlers = self._handlers(self)
def poll(self, *args):
C_exec, _C_undo = _BPyOpsSubModOp._parse_args(args)
@ -178,4 +205,6 @@ def __dir__():
else:
submodules.add(id_split[0])
submodules.add("remove_handlers")
return list(submodules)

View File

@ -66,7 +66,7 @@ _preferences = _bpy.context.preferences
_is_factory_startup = _bpy.app.factory_startup
# Directories added to the start of `sys.path` for all of Blender's "scripts" directories.
_script_module_dirs = "startup", "modules"
_script_module_dirs = "startup", "modules","tornavis"
# Base scripts, this points to the directory containing: "modules" & "startup" (see `_script_module_dirs`).
# In Blender's code-base this is `./scripts`.
@ -308,6 +308,10 @@ def load_scripts(*, reload_scripts=False, refresh_scripts=False, extensions=True
for mod in modules_from_path(path, loaded_modules):
test_register(mod)
if path_subdir == "tornavis":
for mod in modules_from_path(path, loaded_modules):
test_register(mod)
if reload_scripts:
# Update key-maps for key-map items referencing operators defined in "startup".
# Without this, key-map items wont be set properly, see: #113309.

View File

@ -0,0 +1,49 @@
# SPDX-FileCopyrightText: 2015-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
"""
This module contains utility functions to handle custom images.
"""
__all__ = (
"load",
"release"
"list",
)
from _bpy import _utils_images
list = []
def load(name, path):
r = _utils_images.load(name, path)
if r != None:
data = {'id' : r , 'name' : name, 'path' : path}
list.append(data)
return data;
else:
return None;
load.__doc__ = _utils_images.load.__doc__;
def release(image_id):
r = _utils_images.release(image_id)
if r == True:
for data in list:
if data.get('id') == image_id:
list.remove(data)
return r;
release.__doc__ = _utils_images.release.__doc__
import atexit
def exit_clear():
while len(list):
release(list[0].get('id'))
atexit.register(exit_clear)
del atexit, exit_clear

View File

@ -987,6 +987,11 @@ class AddonPreferences(StructRNA, metaclass=RNAMeta):
__slots__ = ()
class ReferencedDrawFunc:
def __init__(self, func):
self.func = func
self.used = False
class _GenericUI:
__slots__ = ()
@ -1007,6 +1012,13 @@ class _GenericUI:
else:
owner_names = None
if (hasattr(cls, "reference_debug") and cls.reference_debug):
print ("---")
# Reset drawn flag, to be able shown error if not used
for label in cls.referenced_post:
for ref in cls.referenced_post[label]:
ref.used = False
for func in draw_ls._draw_funcs:
# Begin 'owner_id' filter.
@ -1030,11 +1042,38 @@ class _GenericUI:
self.layout.operator_context = operator_context_default
for label in cls.referenced_post:
for ref in cls.referenced_post[label]:
if ref.used == False:
print("ERR: ", label, " referenced not drawn in", self.__class__.__name__)
draw_funcs = draw_ls._draw_funcs = [cls.draw]
cls.draw = draw_ls
cls.referenced_pre = {}
cls.referenced_post = {}
return draw_funcs
def draw_referenced_pre(cls, label):
if (hasattr(cls, "reference_debug") and cls.reference_debug):
print (label)
cls._dyn_ui_initialize()
if label in cls.referenced_pre:
for ref in cls.referenced_pre[label]:
#need to get the context
ref.used = True
ref.func(cls, None)
def draw_referenced_post(cls, label):
cls._dyn_ui_initialize()
if label in cls.referenced_post:
for ref in cls.referenced_post[label]:
#need to get the context
ref.used = True
ref.func(cls, None)
@staticmethod
def _dyn_owner_apply(draw_func):
from _bpy import _bl_owner_id_get
@ -1047,24 +1086,36 @@ class _GenericUI:
return bool(getattr(cls.draw, "_draw_funcs", None))
@classmethod
def append(cls, draw_func):
def append(cls, draw_func, label_referenced = None):
"""
Append a draw function to this menu,
takes the same arguments as the menus draw function
"""
draw_funcs = cls._dyn_ui_initialize()
cls._dyn_owner_apply(draw_func)
draw_funcs.append(draw_func)
if label_referenced != None:
if not (label_referenced in cls.referenced_post):
cls.referenced_post[label_referenced] = []
cls.referenced_post[label_referenced].append(ReferencedDrawFunc(draw_func))
else:
draw_funcs.append(draw_func)
@classmethod
def prepend(cls, draw_func):
def prepend(cls, draw_func, label_referenced = None):
"""
Prepend a draw function to this menu, takes the same arguments as
the menus draw function
"""
draw_funcs = cls._dyn_ui_initialize()
cls._dyn_owner_apply(draw_func)
draw_funcs.insert(0, draw_func)
if label_referenced != None:
if not (label_referenced in cls.referenced_pre):
cls.referenced_pre[label_referenced] = []
cls.referenced_pre[label_referenced].append(ReferencedDrawFunc(draw_func))
else:
draw_funcs.insert(0, draw_func)
@classmethod
def remove(cls, draw_func):

View File

@ -3334,6 +3334,7 @@ class WM_MT_splash(Menu):
col2.operator("wm.url_open_preset", text="Donate", icon='FUND').type = 'FUND'
col2.operator("wm.url_open_preset", text="What's New", icon='URL').type = 'RELEASE_NOTES'
col2.operator("wm.url_open_preset", text="Tornavis project's Website", icon='URL').type = 'TORNAVIS'
layout.separator()
layout.separator()

View File

@ -659,8 +659,12 @@ class VIEW3D_HT_header(Header):
# Orientation
if object_mode in {'OBJECT', 'EDIT', 'EDIT_GPENCIL'} or has_pose_mode:
orient_slot = scene.transform_orientation_slots[0]
row = layout.row(align=True)
view = context.space_data
row = layout.row(align=True)
row.prop(view, "ucs", text="UCS")
row = layout.row(align=True)
sub = row.row()
sub.ui_units_x = 4
sub.prop_with_popover(
@ -7624,7 +7628,10 @@ class VIEW3D_PT_transform_orientations(Panel):
row = layout.row(align=False)
row.prop(orientation, "name", text="", icon='OBJECT_ORIGIN')
row.operator("transform.delete_orientation", text="", icon='X', emboss=False)
row = layout.row()
row.label(text="Origin:")
row = layout.row()
row.prop(orientation, "origin", text="", icon='OBJECT_ORIGIN')
class VIEW3D_PT_gpencil_origin(Panel):
bl_space_type = 'VIEW_3D'

View File

@ -0,0 +1,47 @@
import bpy
import bpy.utils.images
import os
img = None
class WM_MT_splash_about_mblender(bpy.types.Menu):
bl_label = "About Tornavis"
def draw(self, context):
layout = self.layout
layout.operator_context = 'EXEC_DEFAULT'
split = layout.split(factor=0.6)
split.template_image_ui(image_value = img['id'], scale= 1)
layout.row().label(text="Tornavis - A project for giving CAD development to Blender")
row = layout.row()
row.emboss = 'PULLDOWN_MENU'
col = row.column()
col.operator("wm.url_open", text="Patreon", icon='FUND').url = "https://www.patreon.com/tornavis"
col.operator("wm.url_open", text="Credits", icon='URL').url = "https://tornavis.org/#credits"
col.operator("wm.url_open", text="License", icon='URL').url = "https://tornavis.org/#license"
col.operator("wm.url_open_preset", text="Tornavis Website", icon='URL').type = 'TORNAVIS'
def draw_mblender_about_menu(self, context):
self.layout.operator("wm.splash_custom", text=WM_MT_splash_about_mblender.bl_label).menutype='WM_MT_splash_about_mblender'
def draw_blender_doc_menu(self, context):
self.layout.operator("wm.url_open_preset", text="Tornavis Project's documentation", icon='URL').type = 'TORNAVIS_DOC'
def register():
global img
bpy.types.TOPBAR_MT_blender.append(draw_mblender_about_menu, label_referenced = "About Blender")
bpy.types.TOPBAR_MT_help.append(draw_blender_doc_menu, label_referenced = "Manual")
bpy.utils.register_class(WM_MT_splash_about_mblender)
path = os.path.join(bpy.utils.system_resource('DATAFILES', path="tornavis"), 'tornavis_logo.png')
img = bpy.utils.images.load('tornavis-logo', path)
def unregister():
global img
bpy.utils.unregister_class(AboutMBlenderOperator)
bpy.utils.unregister_class(WM_MT_splash_about_mblender)
bpy.utils.images.release(img['id'])

View File

@ -0,0 +1,17 @@
import bpy
def register ():
# bpy.ops.wm.url_open_preset(type="TORNAVIS")
bpy.types.WM_OT_url_open_preset.preset_items.append(
(('TORNAVIS', "Tornavis.org", "Tornavis project official web-site"),
"https://www.tornavis.org")
)
bpy.types.WM_OT_url_open_preset.preset_items.append(
(('TORNAVIS_DOC', "Tornavis Doc", "Tornavis project documentation"),
"https://www.tornavis.org/#documentation")
)
def unregister():
pass

View File

@ -159,6 +159,7 @@ add_subdirectory(functions)
add_subdirectory(makesdna)
add_subdirectory(makesrna)
add_subdirectory(compositor)
add_subdirectory(tornavis)
if(WITH_BLENDER_THUMBNAILER)
add_subdirectory(blendthumb)

View File

@ -69,6 +69,7 @@ struct View3D;
struct ViewLayer;
struct wmGizmoGroup;
struct wmMsgBus;
struct wmOpHandlers;
struct wmWindow;
struct wmWindowManager;
struct WorkSpace;
@ -191,6 +192,7 @@ void *CTX_wm_region_data(const bContext *C);
ARegion *CTX_wm_menu(const bContext *C);
wmGizmoGroup *CTX_wm_gizmo_group(const bContext *C);
wmMsgBus *CTX_wm_message_bus(const bContext *C);
wmOpHandlers *CTX_wm_op_handlers(const bContext *C);
ReportList *CTX_wm_reports(const bContext *C);
View3D *CTX_wm_view3d(const bContext *C);

View File

@ -763,6 +763,11 @@ wmMsgBus *CTX_wm_message_bus(const bContext *C)
return C->wm.manager ? C->wm.manager->message_bus : nullptr;
}
struct wmOpHandlers *CTX_wm_op_handlers(const bContext *C)
{
return C->wm.manager ? C->wm.manager->op_handlers : nullptr;
}
ReportList *CTX_wm_reports(const bContext *C)
{
if (C->wm.manager) {

View File

@ -104,10 +104,13 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata)
float viewinv[4][4], wininv[4][4];
float viewmat[4][4], winmat[4][4];
float ucsmat[4][4], ucsinv[4][4];
DRW_view_winmat_get(nullptr, winmat, false);
DRW_view_winmat_get(nullptr, wininv, true);
DRW_view_viewmat_get(nullptr, viewmat, false);
DRW_view_viewmat_get(nullptr, viewinv, true);
DRW_view_ucsmat_get(nullptr, ucsmat, false);
DRW_view_ucsmat_get(nullptr, ucsinv, true);
/* If perspective view or non-axis aligned view. */
if (winmat[3][3] == 0.0f || rv3d->view == RV3D_VIEW_USER) {
@ -142,8 +145,8 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata)
zpos_flag = SHOW_AXIS_Z;
float zvec[3], campos[3];
negate_v3_v3(zvec, viewinv[2]);
copy_v3_v3(campos, viewinv[3]);
negate_v3_v3(zvec, ucsinv[2]);
copy_v3_v3(campos, ucsinv[3]);
/* z axis : chose the most facing plane */
if (fabsf(zvec[0]) < fabsf(zvec[1])) {
@ -205,7 +208,7 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata)
* component, which may not be correct if the user is "shrunk" or "enlarged" by zooming in or
* out. Therefore, we need to compensate the values here. */
/* Assumption is uniform scaling (all column vectors are of same length). */
float viewinvscale = len_v3(viewinv[0]);
float viewinvscale = len_v3(ucsinv[0]);
grid->distance *= viewinvscale;
}
}

View File

@ -44,5 +44,5 @@ void main()
local_pos.z = clamp(local_pos.z, -1.0, 0.0);
}
gl_Position = drw_view.winmat * (drw_view.viewmat * vec4(real_pos, 1.0));
gl_Position = drw_view.winmat * (drw_view.ucsmat * vec4(real_pos, 1.0));
}

View File

@ -694,6 +694,16 @@ bool DRW_pass_is_empty(DRWPass *pass);
/* Views. */
/**
* Create a view with culling.
*/
DRWView *DRW_view_create(const float viewmat[4][4],
const float winmat[4][4],
const float (*culling_viewmat)[4],
const float (*culling_winmat)[4],
DRWCallVisibilityFn *visibility_fn);
/**
* Create a view with culling.
*/
@ -717,6 +727,10 @@ void DRW_view_update(DRWView *view,
const float winmat[4][4],
const float (*culling_viewmat)[4],
const float (*culling_winmat)[4]);
/**
* Update ucs matrix
*/
void DRW_view_ucs_update(DRWView *view, const float ucsmat[4][4]);
/**
* Update matrices of a view created with #DRW_view_create_sub.
*/
@ -751,6 +765,7 @@ void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len);
void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse);
void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse);
void DRW_view_ucsmat_get(const DRWView *view, float mat[4][4], bool inverse);
void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse);
/**

View File

@ -581,6 +581,7 @@ static void drw_manager_init(DRWManager *dst, GPUViewport *viewport, const int s
if (rv3d != nullptr) {
dst->pixsize = rv3d->pixsize;
dst->view_default = DRW_view_create(rv3d->viewmat, rv3d->winmat, nullptr, nullptr, nullptr);
DRW_view_ucs_update(dst->view_default, rv3d->ucsmat);
if (dst->draw_ctx.sh_cfg == GPU_SHADER_CFG_CLIPPED) {
int plane_len = (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) ? 4 : 6;

View File

@ -2294,6 +2294,11 @@ void DRW_view_update(DRWView *view,
#endif
}
void DRW_view_ucs_update(DRWView *view, const float ucsmat[4][4]) {
copy_m4_m4(view->storage.ucsmat.ptr(), ucsmat);
}
const DRWView *DRW_view_default_get()
{
return DST.view_default;
@ -2368,6 +2373,20 @@ void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse)
copy_m4_m4(mat, (inverse) ? storage->viewinv.ptr() : storage->viewmat.ptr());
}
void DRW_view_ucsmat_get(const DRWView *view, float mat[4][4], bool inverse)
{
view = (view) ? view : DST.view_default;
const ViewMatrices *storage = &view->storage;
copy_m4_m4(mat, storage->ucsmat.ptr());
if (inverse) {
float tmp[4][4];
invert_m4_m4(tmp, mat);
copy_m4_m4(mat, tmp);
}
}
void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse)
{
view = (view) ? view : DST.view_default;

View File

@ -125,6 +125,7 @@ struct ViewMatrices {
float4x4 viewinv;
float4x4 winmat;
float4x4 wininv;
float4x4 ucsmat;
};
BLI_STATIC_ASSERT_ALIGN(ViewMatrices, 16)

View File

@ -82,7 +82,7 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
void BIF_clearTransformOrientation(bContext *C);
void BIF_removeTransformOrientation(bContext *C, TransformOrientation *target);
void BIF_removeTransformOrientationIndex(bContext *C, int index);
bool BIF_createTransformOrientation(bContext *C,
TransformOrientation* BIF_createTransformOrientation(bContext *C,
ReportList *reports,
const char *name,
bool use_view,

View File

@ -57,6 +57,8 @@ struct wmOperator;
struct wmWindow;
struct wmWindowManager;
struct TransformOrientation;
/* for derivedmesh drawing callbacks, for view3d_select, .... */
struct ViewContext {
bContext *C;
@ -1048,6 +1050,15 @@ void ED_view3d_update_viewmat(Depsgraph *depsgraph,
const rcti *rect,
bool offscreen);
bool ED_view3d_quat_from_axis_view(char view, char view_axis_roll, float r_quat[4]);
bool ED_view3d_quat_from_axis_view_transform(
Scene *scene, View3D *v3d, const char view, const char view_axis_roll, float r_quat[4]);
bool ED_view3d_quat_from_axis_view_ucs(TransformOrientation *ts,
char viewnum,
char view_axis_roll,
float quat[4]);
bool ED_view3d_quat_to_axis_view(const float viewquat[4],
float epsilon,
char *r_view,
@ -1067,6 +1078,9 @@ char ED_view3d_lock_view_from_index(int index);
char ED_view3d_axis_view_opposite(char view);
bool ED_view3d_lock(RegionView3D *rv3d);
bool ED_view3d_lock_ucs(TransformOrientation *ts, struct RegionView3D *rv3d);
void ED_view3d_datamask(const Scene *scene,
ViewLayer *view_layer,
const View3D *v3d,

View File

@ -2236,6 +2236,9 @@ void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout);
*/
void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout);
void *uiLayoutGetParentObject(uiLayout *layout);
struct ExtensionRNA *uiLayoutGetParentRnaExt(uiLayout *layout);
/* Only for convenience. */
void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but);
@ -2457,6 +2460,9 @@ void uiTemplatePreview(uiLayout *layout,
MTex *slot,
const char *preview_id);
void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, bool expand);
void uiTemplateImageUI(uiLayout *layout, int image_id, float image_scale);
/**
* \param icon_scale: Scale of the icon, 1x == button height.
*/

View File

@ -168,6 +168,10 @@ struct uiLayout {
eUIEmbossType emboss;
/** for fixed width or height to avoid UI size changes */
float units[2];
ExtensionRNA *parent_rna_ext;
void *parent_object;
};
struct uiLayoutItemFlow {
@ -6042,6 +6046,20 @@ bContextStore *uiLayoutGetContextStore(uiLayout *layout)
return layout->context;
}
void *uiLayoutGetParentObject(uiLayout * layout)
{
return layout->parent_object;
}
ExtensionRNA *uiLayoutGetParentRnaExt(uiLayout *layout)
{
// rna ext is set on menu draw, layout maybe a sublayout
while (layout && layout->parent_rna_ext == NULL) {
layout = layout->parent;
}
return layout ? layout->parent_rna_ext : NULL;
}
void uiLayoutContextCopy(uiLayout *layout, const bContextStore *context)
{
uiBlock *block = layout->root->block;
@ -6136,6 +6154,9 @@ void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
menu.layout = layout;
menu.type = mt;
layout->parent_rna_ext = &mt->rna_ext;
layout->parent_object = (void*) &menu;
if (G.debug & G_DEBUG_WM) {
printf("%s: opening menu \"%s\"\n", __func__, mt->idname);
}
@ -6158,6 +6179,10 @@ void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
if (layout->context) {
CTX_store_set(C, nullptr);
}
layout->parent_rna_ext = NULL;
layout->parent_object = NULL;
}
static bool ui_layout_has_panel_label(const uiLayout *layout, const PanelType *pt)

View File

@ -84,6 +84,9 @@
#include "ED_render.hh"
#include "ED_screen.hh"
#include "ED_undo.hh"
#include "ED_datafiles.h"
#include "IMB_imbuf.hh"
#include "IMB_imbuf.hh"
#include "IMB_imbuf_types.hh"
@ -104,6 +107,8 @@
#include "UI_view2d.hh"
#include "interface_intern.hh"
#include "BPY_extern.h"
/* we may want to make this optional, disable for now. */
// #define USE_OP_RESET_BUT
@ -3380,6 +3385,28 @@ void uiTemplatePreview(uiLayout *layout,
/** \} */
void uiTemplateImageUI(uiLayout* layout, int image_id,float image_scale) {
ImBuf *ibuf = IMB_dupImBuf((ImBuf *) BPY_utils_images_get(image_id));
if (ibuf) {
int width = ibuf->x * image_scale;
int height = (width * ibuf->y) / ibuf->x;
IMB_premultiply_alpha(ibuf);
IMB_scaleImBuf(ibuf, width, height);
bTheme *btheme = UI_GetTheme();
uchar *color = btheme->tui.wcol_menu_back.text_sel;
//color = btheme->tui.wcol_box.inner;
uiBlock *block = uiLayoutAbsoluteBlock(layout);
uiBut *but = uiDefButImage(block, ibuf, 0, U.widget_unit, width, height, color);
}
}
/* -------------------------------------------------------------------- */
/** \name ColorRamp Template
* \{ */

View File

@ -20,6 +20,7 @@ set(INC
../../shader_fx
../../windowmanager
../../../../extern/fmtlib/include
../transform
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna

View File

@ -90,6 +90,7 @@
#include "BKE_speaker.h"
#include "BKE_vfont.hh"
#include "BKE_volume.hh"
#include "BKE_scene.h"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_build.hh"
@ -127,6 +128,8 @@
#include "object_intern.h"
#include "transform_orientations.hh"
using blender::float3;
using blender::float4x4;
using blender::Vector;
@ -348,15 +351,35 @@ float ED_object_new_primitive_matrix(bContext *C,
View3D *v3d = CTX_wm_view3d(C);
float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3];
float ts_mat[3][3];
char ts_name[MAX_NAME];
//int orientation_index = v3d->twmode - V3D_MANIP_CUSTOM;
TransformOrientation *custom_orientation = nullptr;
if (scene->orientation_slots->type >= V3D_ORIENT_CUSTOM &&
scene->orientation_slots->index_custom != -1)
{
custom_orientation = BKE_scene_transform_orientation_find(
scene, scene->orientation_slots->index_custom);
}
unit_m4(r_primmat);
eul_to_mat3(rmat, rot);
invert_m3(rmat);
if (custom_orientation) {
applyTransformOrientation(custom_orientation, ts_mat, ts_name);
invert_m3(ts_mat);
mul_m3_m3m3(mat, rmat, ts_mat);
copy_m3_m3(rmat, mat);
}
/* inverse transform for initial rotation and object */
copy_m3_m4(mat, obedit->object_to_world);
mul_m3_m3m3(cmat, rmat, mat);
invert_m3_m3(imat, cmat);
copy_m4_m3(r_primmat, imat);
/* center */

View File

@ -4025,9 +4025,10 @@ static void view3d_localview_update_rv3d(RegionView3D *rv3d)
}
static void region_quadview_init_rv3d(
ScrArea *area, ARegion *region, const char viewlock, const char view, const char persp)
ScrArea *area, Scene *scene, ARegion *region, const char viewlock, const char view, const char persp)
{
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
View3D *v3d = static_cast<View3D *>(area->spacedata.first);
if (persp == RV3D_CAMOB) {
ED_view3d_lastview_store(rv3d);
@ -4039,7 +4040,27 @@ static void region_quadview_init_rv3d(
rv3d->view_axis_roll = RV3D_VIEW_AXIS_ROLL_0;
rv3d->persp = persp;
ED_view3d_lock(rv3d);
if (v3d->ucs) {
TransformOrientation *custom_orientation = nullptr;
if (scene->orientation_slots->type >= V3D_ORIENT_CUSTOM &&
scene->orientation_slots->index_custom != -1)
{
custom_orientation = BKE_scene_transform_orientation_find(
scene, scene->orientation_slots->index_custom);
}
if (custom_orientation) {
ED_view3d_lock_ucs(custom_orientation, rv3d);
}
else {
// Invalid ucs
ED_view3d_lock(rv3d);
}
}
else {
// Global
ED_view3d_lock(rv3d);
}
view3d_localview_update_rv3d(rv3d);
if ((viewlock & RV3D_BOXCLIP) && (persp == RV3D_ORTHO)) {
ED_view3d_quadview_update(area, region, true);
@ -4108,6 +4129,7 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
else {
/* Enter quad-view */
ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
region->alignment = RGN_ALIGN_QSPLIT;
@ -4132,14 +4154,20 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
(rv3d->viewlock_quad & ~RV3D_VIEWLOCK_INIT) :
RV3D_LOCK_ROTATION;
region_quadview_init_rv3d(
area, region, viewlock, ED_view3d_lock_view_from_index(index_qsplit++), RV3D_ORTHO);
region_quadview_init_rv3d(area,
scene,
(region = region->next),
viewlock,
ED_view3d_lock_view_from_index(index_qsplit++),
RV3D_ORTHO);
region_quadview_init_rv3d(area,
scene,
(region = region->next),
viewlock,
ED_view3d_lock_view_from_index(index_qsplit++),
RV3D_ORTHO);
region_quadview_init_rv3d(area,
scene,
(region = region->next),
viewlock,
ED_view3d_lock_view_from_index(index_qsplit++),

View File

@ -134,6 +134,40 @@ void ED_view3d_update_viewmat(Depsgraph *depsgraph,
/* NOTE: calls BKE_object_where_is_calc for camera... */
view3d_viewmatrix_set(depsgraph, scene, v3d, rv3d, rect ? rect_scale : nullptr);
}
if (v3d->ucs > 0) {
TransformOrientation *custom_orientation = nullptr;
if (scene->orientation_slots->type >= V3D_ORIENT_CUSTOM &&
+scene->orientation_slots->index_custom != -1)
{
custom_orientation = BKE_scene_transform_orientation_find(
+scene, scene->orientation_slots->index_custom);
}
if (custom_orientation) {
float m[4][4] = {{0}}, mt[4][4];
unit_m4(m);
unit_m4(mt); // Translation matrix
copy_m4_m3(m, custom_orientation->mat);
translate_m4(mt,
custom_orientation->origin[0],
custom_orientation->origin[1],
custom_orientation->origin[2]);
mul_m4_series(rv3d->ucsmat, rv3d->viewmat, mt, m);
}
else {
// Invalid
v3d->ucs = 0;
copy_m4_m4(rv3d->ucsmat, rv3d->viewmat);
}
}
else {
copy_m4_m4(rv3d->ucsmat, rv3d->viewmat);
}
/* update utility matrices */
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
invert_m4_m4(rv3d->persinv, rv3d->persmat);

View File

@ -164,7 +164,8 @@ static int view_axis_exec(bContext *C, wmOperator *op)
/* Use this to test if we started out with a camera */
const int nextperspo = (rv3d->persp == RV3D_CAMOB) ? rv3d->lpersp : perspo;
float quat[4];
ED_view3d_quat_from_axis_view(viewnum, view_axis_roll, quat);
Scene *scene = CTX_data_scene(C);
ED_view3d_quat_from_axis_view_transform(scene, v3d, viewnum, view_axis_roll, quat);
axis_set_view(
C, v3d, region, quat, viewnum, view_axis_roll, nextperspo, align_quat, smooth_viewtx);

View File

@ -1425,6 +1425,33 @@ static float view3d_quat_axis[6][4][4] = {
};
bool ED_view3d_quat_from_axis_view_transform(Scene *scene, View3D *v3d, const char view,
const char view_axis_roll,
float r_quat[4])
{
if (v3d->ucs) {
TransformOrientation *custom_orientation = nullptr;
if (scene->orientation_slots->type >= V3D_ORIENT_CUSTOM &&
scene->orientation_slots->index_custom != -1)
{
custom_orientation = BKE_scene_transform_orientation_find(
scene, scene->orientation_slots->index_custom);
}
if (custom_orientation) {
return ED_view3d_quat_from_axis_view_ucs(custom_orientation,view, view_axis_roll, r_quat);
}
else {
// Invalid ucs
return ED_view3d_quat_from_axis_view(view,view_axis_roll, r_quat);
}
}
else {
return ED_view3d_quat_from_axis_view(view, view_axis_roll, r_quat);
}
}
bool ED_view3d_quat_from_axis_view(const char view, const char view_axis_roll, float r_quat[4])
{
BLI_assert(view_axis_roll <= RV3D_VIEW_AXIS_ROLL_270);
@ -1435,6 +1462,43 @@ bool ED_view3d_quat_from_axis_view(const char view, const char view_axis_roll, f
return false;
}
bool ED_view3d_quat_from_axis_view_ucs(TransformOrientation *ts,
char view,
char view_axis_roll, float quat[4])
{
float m[3][3];
float eul[3];
copy_m3_m3(m, ts->mat);
mat3_to_eul(eul, m);
switch (view) {
case RV3D_VIEW_TOP:
// XY
invert_m3(m);
mat3_to_quat(quat, m);
break;
case RV3D_VIEW_FRONT:
// ZX
rotate_eul(eul, 'X', M_PI / 2.0f);
eul_to_mat3(m, eul);
invert_m3(m);
mat3_to_quat(quat, m);
break;
case RV3D_VIEW_RIGHT:
// ZY
rotate_eul(eul, 'Z', M_PI / 2.0f);
rotate_eul(eul, 'X', M_PI / 2.0f);
eul_to_mat3(m, eul);
invert_m3(m);
mat3_to_quat(quat, m);
break;
default:
ED_view3d_quat_from_axis_view(view, view_axis_roll, quat);
}
return true;
}
bool ED_view3d_quat_to_axis_view(const float quat[4],
const float epsilon,
char *r_view,
@ -1538,6 +1602,12 @@ bool ED_view3d_lock(RegionView3D *rv3d)
return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->view_axis_roll, rv3d->viewquat);
}
bool ED_view3d_lock_ucs(TransformOrientation *ts, RegionView3D *rv3d)
{
ED_view3d_quat_from_axis_view_ucs(ts, rv3d->view, rv3d->view_axis_roll, rv3d->viewquat);
return true;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -713,6 +713,8 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
}
case TFM_MODAL_PASSTHROUGH_NAVIGATE:
return t->vod != nullptr;
case TFM_MODAL_NO_MODAL_TRANSFORM:
break;
}
return true;
}
@ -768,6 +770,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{TFM_MODAL_AUTOCONSTRAINTPLANE, "AUTOCONSTRAINPLANE", 0, "Automatic Constraint Plane", ""},
{TFM_MODAL_PRECISION, "PRECISION", 0, "Precision Mode", ""},
{TFM_MODAL_PASSTHROUGH_NAVIGATE, "PASSTHROUGH_NAVIGATE", 0, "Navigate", ""},
{TFM_MODAL_NO_MODAL_TRANSFORM, "NO_MODAL_TRANSFORM", 0, "Allow movements around the scene",""},
{0, nullptr, 0, nullptr, nullptr},
};
@ -967,12 +970,74 @@ static bool transform_event_modal_constraint(TransInfo *t, short modal_type)
return true;
}
static void switchTransformNoModal(TransInfo *t, const wmEvent *event) {
t->flag ^= T_TRANSFORM_NO_MODAL;
{
// Enable/Disable modal events allowing to be processed as non-modal events
wmKeyMapItem *kmi;
for (kmi =(wmKeyMapItem*) t->keymap->items.first; kmi; kmi = kmi->next)
{
if (ELEM(kmi->type, LEFTMOUSE, RIGHTMOUSE, MIDDLEMOUSE, WHEELDOWNMOUSE, WHEELUPMOUSE)) {
if ((t->flag & T_TRANSFORM_NO_MODAL) == 0) {
kmi->flag &= ~KMI_INACTIVE;
}
else {
kmi->flag |= KMI_INACTIVE;
}
}
}
}
if ((t->flag & T_TRANSFORM_NO_MODAL) == 0) {
// Transform Restart
}
}
int transformEvent(TransInfo *t, const wmEvent *event)
{
bool handled = false;
bool is_navigating = t->vod ? ((RegionView3D *)t->region->regiondata)->rflag & RV3D_NAVIGATING :
false;
if (t->flag & T_TRANSFORM_NO_MODAL) {
if (ELEM(event->val, KM_PRESS, KM_RELEASE) &&
ELEM(event->type, LEFTMOUSE, RIGHTMOUSE, MIDDLEMOUSE))
{
return OPERATOR_PASS_THROUGH;
}
else if (ELEM(event->type,
BUTTON4MOUSE,
BUTTON5MOUSE,
BUTTON6MOUSE,
BUTTON7MOUSE,
MOUSEPAN,
MOUSEZOOM,
MOUSEROTATE,
WHEELINMOUSE,
WHEELOUTMOUSE,
WHEELUPMOUSE,
WHEELDOWNMOUSE))
{
return OPERATOR_PASS_THROUGH;
}
else if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case TFM_MODAL_CANCEL:
t->state = TRANS_CANCEL;
break;
case TFM_MODAL_CONFIRM:
t->state = TRANS_CONFIRM;
break;
case TFM_MODAL_NO_MODAL_TRANSFORM:
t->redraw |= TREDRAW_HARD; // Redraw the Header
switchTransformNoModal(t, event);
break;
}
}
return 0;
}
/* Handle modal numinput events first, if already activated. */
if (!is_navigating && ((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) &&
hasNumInput(&t->num) && handleNumInput(t->context, &(t->num), event))
@ -1013,6 +1078,11 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
break;
case TFM_MODAL_NO_MODAL_TRANSFORM:
switchTransformNoModal(t, event);
handled = true;
t->redraw |= TREDRAW_HARD;
break;
case TFM_MODAL_TRANSLATE:
case TFM_MODAL_ROTATE:
case TFM_MODAL_RESIZE:
@ -1311,6 +1381,10 @@ int transformEvent(TransInfo *t, const wmEvent *event)
/* Else do non-mapped events. */
else if (event->val == KM_PRESS) {
switch (event->type) {
case EVT_MKEY :
t->flag |= T_TRANSFORM_MULTIPLE;
handled = true;
break;
case EVT_CKEY:
if (event->flag & WM_EVENT_IS_REPEAT) {
break;
@ -1838,6 +1912,12 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_property_boolean_set(
op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE) != 0);
}
if ((prop = RNA_struct_find_property(op->ptr, "transform_multiple"))) {
RNA_boolean_set(op->ptr, "transform_multiple", (t->flag & T_TRANSFORM_MULTIPLE) != 0);
}
}
static void initSnapSpatial(TransInfo *t, float r_snap[3], float *r_snap_precision)
@ -1934,6 +2014,12 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initTransInfo(C, t, op, event);
if (prop = RNA_struct_find_property(op->ptr, "transform_multiple")) {
if (RNA_boolean_get(op->ptr, "transform_multiple")) {
t->flag |= T_TRANSFORM_MULTIPLE;
}
}
if (t->spacetype == SPACE_VIEW3D) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
@ -2055,6 +2141,12 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
calculatePropRatio(t);
calculateCenter(t);
if (t->spacetype == SPACE_VIEW3D) {
float p[3] = {0, 0, 0};
ED_view3d_win_to_3d_int((View3D*) t->view, t->region, p, event->mval, t->iloc);
}
if (event) {
/* Initialize accurate transform to settings requested by keymap. */
bool use_accurate = false;
@ -2165,7 +2257,7 @@ void transformApply(bContext *C, TransInfo *t)
int transformEnd(bContext *C, TransInfo *t)
{
int exit_code = OPERATOR_RUNNING_MODAL;
int exit_code = (t->flag & T_TRANSFORM_NO_MODAL) ? OPERATOR_HANDLED : OPERATOR_RUNNING_MODAL;
t->context = C;
@ -2185,6 +2277,10 @@ int transformEnd(bContext *C, TransInfo *t)
exit_code = OPERATOR_FINISHED;
}
if (t->state == TRANS_CONFIRM && (t->flag & T_TRANSFORM_MULTIPLE)) {
exit_code |= OPERATOR_REPEAT;
}
/* aftertrans does insert keyframes, and clears base flags; doesn't read transdata */
special_aftertrans_update(C, t);

View File

@ -150,6 +150,12 @@ enum eTFlag {
/** Special flag for when the transform code is called after keys have been duplicated. */
T_DUPLICATED_KEYFRAMES = 1 << 26,
/* Used on MB-0001-operator-repeat */
T_TRANSFORM_MULTIPLE = 1 << 27,
/* Used on MB-0006-allow-no-modal-transform*/
T_TRANSFORM_NO_MODAL = 1 << 28,
};
ENUM_OPERATORS(eTFlag, T_DUPLICATED_KEYFRAMES);
@ -285,6 +291,7 @@ enum {
TFM_MODAL_EDIT_SNAP_SOURCE_OFF = 35,
TFM_MODAL_PASSTHROUGH_NAVIGATE = 36,
TFM_MODAL_NO_MODAL_TRANSFORM = 37,
};
/** \} */
@ -561,6 +568,8 @@ struct TransInfo {
/** Mouse side of the current frame, 'L', 'R' or 'B' */
char frame_side;
float iloc[3]; /* Initial location */
/** copy from #RegionView3D, prevents feedback. */
float viewmat[4][4];
/** and to make sure we don't have to. */

View File

@ -258,6 +258,8 @@ static int create_orientation_exec(bContext *C, wmOperator *op)
const bool use_view = RNA_boolean_get(op->ptr, "use_view");
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
const bool set_ucs = RNA_boolean_get(op->ptr, "set_ucs");
TransformOrientation *ts;
RNA_string_get(op->ptr, "name", name);
@ -268,7 +270,9 @@ static int create_orientation_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
if (!BIF_createTransformOrientation(C, op->reports, name, use_view, use, overwrite)) {
ts = BIF_createTransformOrientation(C, op->reports, name, use_view, use, overwrite);
if (ts == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unable to create orientation");
return OPERATOR_CANCELLED;
}
@ -279,6 +283,16 @@ static int create_orientation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
}
if (set_ucs) {
if (scene) {
// 0 = Global
v3d->ucs = BLI_findindex(&scene->transform_spaces, ts) + 1;
}
else {
BKE_report(op->reports, RPT_ERROR, "Cannot set ucs!");
}
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
return OPERATOR_FINISHED;
@ -305,6 +319,8 @@ static void TRANSFORM_OT_create_orientation(wmOperatorType *ot)
"Use View",
"Use the current view instead of the active object to create the new orientation");
RNA_def_boolean(ot->srna, "set_ucs", false, "Set as UCS", "Select as ucs after its creation");
WM_operatortype_props_advanced_begin(ot);
RNA_def_boolean(
@ -464,7 +480,7 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
exit_code |= transformEnd(C, t);
if ((exit_code & OPERATOR_RUNNING_MODAL) == 0) {
if ((exit_code & (OPERATOR_CANCELLED | OPERATOR_FINISHED))) {
transformops_exit(C, op);
exit_code &= ~OPERATOR_PASS_THROUGH; /* Preventively remove pass-through. */
}
@ -817,6 +833,8 @@ void Transform_Properties(wmOperatorType *ot, int flags)
"Forces the use of Auto Merge and Split");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
RNA_def_boolean(ot->srna, "transform_multiple", 0, "Multiple", "Apply Multiple times");
}
static void TRANSFORM_OT_translate(wmOperatorType *ot)

View File

@ -97,6 +97,7 @@ static TransformOrientation *createViewSpace(bContext *C,
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
float mat[3][3];
float origin[3] = {0};
if (!rv3d) {
return nullptr;
@ -116,7 +117,7 @@ static TransformOrientation *createViewSpace(bContext *C,
}
}
return addMatrixSpace(C, mat, name, overwrite);
return addMatrixSpace(C, mat, origin, name, overwrite);
}
static TransformOrientation *createObjectSpace(bContext *C,
@ -127,6 +128,7 @@ static TransformOrientation *createObjectSpace(bContext *C,
Base *base = CTX_data_active_base(C);
Object *ob;
float mat[3][3];
float origin[3];
if (base == nullptr) {
return nullptr;
@ -135,6 +137,7 @@ static TransformOrientation *createObjectSpace(bContext *C,
ob = base->object;
copy_m3_m4(mat, ob->object_to_world);
copy_v3_v3(origin, ob->loc);
normalize_m3(mat);
/* use object name if no name is given */
@ -142,7 +145,7 @@ static TransformOrientation *createObjectSpace(bContext *C,
name = ob->id.name + 2;
}
return addMatrixSpace(C, mat, name, overwrite);
return addMatrixSpace(C, mat, origin, name, overwrite);
}
static TransformOrientation *createBoneSpace(bContext *C,
@ -152,8 +155,9 @@ static TransformOrientation *createBoneSpace(bContext *C,
{
float mat[3][3];
float normal[3], plane[3];
float origin[3];
getTransformOrientation(C, normal, plane);
getTransformOrientation(C, normal, plane, origin);
if (createSpaceNormalTangent(mat, normal, plane) == 0) {
BKE_reports_prepend(reports, "Cannot use zero-length bone");
@ -164,7 +168,7 @@ static TransformOrientation *createBoneSpace(bContext *C,
name = "Bone";
}
return addMatrixSpace(C, mat, name, overwrite);
return addMatrixSpace(C, mat, origin, name, overwrite);
}
static TransformOrientation *createCurveSpace(bContext *C,
@ -174,8 +178,9 @@ static TransformOrientation *createCurveSpace(bContext *C,
{
float mat[3][3];
float normal[3], plane[3];
float origin[3];
getTransformOrientation(C, normal, plane);
getTransformOrientation(C, normal, plane, origin);
if (createSpaceNormalTangent(mat, normal, plane) == 0) {
BKE_reports_prepend(reports, "Cannot use zero-length curve");
@ -186,7 +191,7 @@ static TransformOrientation *createCurveSpace(bContext *C,
name = "Curve";
}
return addMatrixSpace(C, mat, name, overwrite);
return addMatrixSpace(C, mat, origin, name, overwrite);
}
static TransformOrientation *createMeshSpace(bContext *C,
@ -197,8 +202,9 @@ static TransformOrientation *createMeshSpace(bContext *C,
float mat[3][3];
float normal[3], plane[3];
int type;
float origin[3];
type = getTransformOrientation(C, normal, plane);
type = getTransformOrientation(C, normal, plane, origin);
switch (type) {
case ORIENTATION_VERT:
@ -235,7 +241,7 @@ static TransformOrientation *createMeshSpace(bContext *C,
return nullptr;
}
return addMatrixSpace(C, mat, name, overwrite);
return addMatrixSpace(C, mat, origin, name, overwrite);
}
static bool test_rotmode_euler(short rotmode)
@ -431,7 +437,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa
return true;
}
bool BIF_createTransformOrientation(bContext *C,
TransformOrientation* BIF_createTransformOrientation(bContext *C,
ReportList *reports,
const char *name,
const bool use_view,
@ -468,11 +474,12 @@ bool BIF_createTransformOrientation(bContext *C,
if (activate && ts != nullptr) {
BIF_selectTransformOrientation(C, ts);
}
return (ts != nullptr);
return (ts);
}
TransformOrientation *addMatrixSpace(bContext *C,
float mat[3][3],
float origin[3],
const char *name,
const bool overwrite)
{
@ -500,6 +507,7 @@ TransformOrientation *addMatrixSpace(bContext *C,
/* copy matrix into transform space */
copy_m3_m3(ts->mat, mat);
copy_v3_v3(ts->origin, origin);
return ts;
}
@ -898,6 +906,7 @@ int getTransformOrientation_ex(const Scene *scene,
Object *obedit,
float normal[3],
float plane[3],
float origin[3],
const short around)
{
int result = ORIENTATION_NONE;
@ -905,6 +914,7 @@ int getTransformOrientation_ex(const Scene *scene,
zero_v3(normal);
zero_v3(plane);
zero_v3(origin);
if (obedit) {
float imat[3][3], mat[3][3];
@ -1129,6 +1139,24 @@ int getTransformOrientation_ex(const Scene *scene,
}
}
if (em->bm->totvertsel > 1) {
BMIter iter;
BMVert *v;
int i = 0;
zero_v3(origin);
BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
add_v3_v3(origin, v->co);
i++;
}
}
mul_v3_fl(origin, 1.0f / i);
mul_m4_v3(ob->object_to_world, origin);
}
/* not needed but this matches 2.68 and older behavior */
negate_v3(plane);
@ -1425,7 +1453,7 @@ int getTransformOrientation_ex(const Scene *scene,
return result;
}
int getTransformOrientation(const bContext *C, float normal[3], float plane[3])
int getTransformOrientation(const bContext *C, float normal[3], float plane[3], float origin[3])
{
Object *obact = CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
@ -1437,7 +1465,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3])
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
return getTransformOrientation_ex(scene, view_layer, v3d, obact, obedit, normal, plane, around);
return getTransformOrientation_ex(scene, view_layer, v3d, obact, obedit, normal, plane, origin, around);
}
void ED_getTransformOrientationMatrix(const Scene *scene,
@ -1450,10 +1478,11 @@ void ED_getTransformOrientationMatrix(const Scene *scene,
{
float normal[3] = {0.0, 0.0, 0.0};
float plane[3] = {0.0, 0.0, 0.0};
float origin[3] = {0.0, 0.0, 0.0};
int type;
type = getTransformOrientation_ex(scene, view_layer, v3d, ob, obedit, normal, plane, around);
type = getTransformOrientation_ex(scene, view_layer, v3d, ob, obedit, normal, plane, origin, around);
/* Fallback, when the plane can't be calculated. */
if (ORIENTATION_USE_PLANE(type) && is_zero_v3(plane)) {

View File

@ -47,6 +47,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa
TransformOrientation *addMatrixSpace(bContext *C,
float mat[3][3],
float origin[3],
const char *name,
bool overwrite);
void applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char r_name[64]);
@ -67,5 +68,6 @@ int getTransformOrientation_ex(const Scene *scene,
Object *obedit,
float normal[3],
float plane[3],
float origin[3],
short around);
int getTransformOrientation(const bContext *C, float normal[3], float plane[3]);
int getTransformOrientation(const bContext *C, float normal[3], float plane[3], float origin [3]);

View File

@ -321,7 +321,7 @@ typedef struct TransformOrientation {
/** MAX_NAME. */
char name[64];
float mat[3][3];
char _pad[4];
float origin[3];
} TransformOrientation;
/** Some preview UI data need to be saved in file. */

View File

@ -39,6 +39,8 @@ typedef struct RegionView3D {
/** Offset/scale for camera GLSL texture-coordinates. */
float viewcamtexcofac[4];
float ucsmat[4][4];
/** viewmat/persmat multiplied with object matrix, while drawing and selection. */
float viewmatob[4][4];
float persmatob[4][4];
@ -358,6 +360,10 @@ typedef struct View3D {
/** Runtime evaluation data (keep last). */
View3D_Runtime runtime;
int ucs;
char _pad5[4];
} View3D;
/** #View3D::stereo3d_flag */

View File

@ -213,6 +213,8 @@ typedef struct wmWindowManager {
struct wmMsgBus *message_bus;
struct wmOpHandlers *op_handlers;
// #ifdef WITH_XR_OPENXR
wmXrData xr;
// #endif
@ -646,10 +648,12 @@ enum {
* \note this isn't great design (using operators to trigger UI) avoid where possible.
*/
OPERATOR_INTERFACE = (1 << 5),
/* Create a new operator based on current */
OPERATOR_REPEAT = (1 << 6),
};
#define OPERATOR_FLAGS_ALL \
(OPERATOR_RUNNING_MODAL | OPERATOR_CANCELLED | OPERATOR_FINISHED | OPERATOR_PASS_THROUGH | \
OPERATOR_HANDLED | OPERATOR_INTERFACE | 0)
OPERATOR_HANDLED | OPERATOR_INTERFACE | OPERATOR_REPEAT | 0)
/* sanity checks for debug mode only */
#define OPERATOR_RETVAL_CHECK(ret) \

View File

@ -2937,6 +2937,12 @@ static void rna_def_transform_orientation(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
RNA_def_property_ui_text(prop, "Name", "Name of the custom transform orientation");
RNA_def_property_update(prop, NC_SCENE | ND_TRANSFORM, nullptr);
prop = RNA_def_property(srna, "origin", PROP_FLOAT, PROP_XYZ);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Origin", "Origin of the custom transform orientation");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
static void rna_def_transform_orientation_slot(BlenderRNA *brna)

View File

@ -536,6 +536,10 @@ static const EnumPropertyItem rna_enum_curve_display_handle_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
const EnumPropertyItem ucs_items[] = {
{0, "global", 0, "Global", "Use global as system coordinates"}, {0, NULL, 0, NULL, NULL}};
#ifdef RNA_RUNTIME
# include "AS_asset_representation.hh"
@ -1549,6 +1553,44 @@ static void rna_SpaceView3D_use_local_collections_update(bContext *C, PointerRNA
}
}
const EnumPropertyItem *rna_ucs_itemf(bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
bool *r_free)
{
Scene *scene = NULL;
ListBase *transform_spaces;
TransformOrientation *ts = NULL;
EnumPropertyItem tmp = {0, "", 0, "", ""};
EnumPropertyItem *item = NULL;
int i = 1, totitem = 0;
RNA_enum_items_add(&item, &totitem, ucs_items);
scene = CTX_data_scene(C);
if (scene) {
transform_spaces = &scene->transform_spaces;
ts = (TransformOrientation*) transform_spaces->first;
}
if (ts) {
RNA_enum_item_add_separator(&item, &totitem);
for (; ts; ts = ts->next) {
tmp.identifier = ts->name;
tmp.name = ts->name;
tmp.value = i++;
RNA_enum_item_add(&item, &totitem, &tmp);
}
}
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
static const EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *C,
PointerRNA * /*ptr*/,
PropertyRNA * /*prop*/,
@ -5285,6 +5327,14 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Overlay Settings", "Settings for display of overlays in the 3D viewport");
prop = RNA_def_property(srna, "ucs", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "ucs");
RNA_def_property_enum_items(prop, ucs_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ucs_itemf");
RNA_def_property_ui_text(prop, "UCS", "User Coordinate System");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
rna_def_space_view3d_shading(brna);
rna_def_space_view3d_overlay(brna);

View File

@ -990,7 +990,7 @@ static StructRNA *rna_Menu_register(Main *bmain,
const char *error_prefix = "Registering menu class:";
MenuType *mt, dummy_mt = {nullptr};
Menu dummy_menu = {nullptr};
bool have_function[2];
bool have_function[4];
size_t over_alloc = 0; /* Warning, if this becomes a mess, we better do another allocation. */
size_t description_size = 0;
char _menu_descr[RNA_DYN_DESCR_MAX];
@ -2194,6 +2194,19 @@ static void rna_def_menu(BlenderRNA *brna)
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
/* draw referenced */
func = RNA_def_function(srna, "draw_referenced_pre", nullptr);
RNA_def_function_ui_description(func, "Draw UI elements into the menu UI layout before reference");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_string(func, "label", nullptr, 0, "", "draw reference menu label");
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
func = RNA_def_function(srna, "draw_referenced_post", nullptr);
RNA_def_function_ui_description(func, "Draw UI elements into the menu UI layout after reference");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_string(func, "label", nullptr, 0, "", "draw reference menu label");
RNA_def_parameter_flags(parm,PropertyFlag(0), PARM_REQUIRED);
RNA_define_verify_sdna(false); /* not in sdna */
prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE);

View File

@ -11,6 +11,7 @@
#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "BLT_translation.h"
#include "RNA_define.hh"
@ -326,6 +327,63 @@ static void rna_uiItemPointerR(uiLayout *layout,
layout, ptr, prop, searchptr, searchprop, name, icon, results_are_suggestions);
}
static void rna_call_draw_referenced(uiLayout *layout, const char *name, FunctionRNA *func)
{
if (*name == '\0') {
return;
}
char *label = (char*) MEM_callocN(255, __func__); // Error defined as not dinamic []
BLI_strncpy(label, name, 255);
// Remove ... added in some menus, like Open...
size_t label_len = BLI_strnlen(name, 255);
if (label_len > 4) {
char *end = label + label_len;
if (*(end - 1) == '.' && *(end - 2) == '.' && *(end - 3) == '.') {
*(end - 3) = '\0';
}
}
ExtensionRNA *ext_rna = uiLayoutGetParentRnaExt(layout);
if (ext_rna) {
PointerRNA ptr = RNA_pointer_create(NULL, ext_rna->srna, uiLayoutGetParentObject(layout));
ParameterList list;
RNA_parameter_list_create(&list, &ptr, func);
// Do not know how the get the context, is lost on python RNA call.
// RNA_parameter_set_lookup(&list, "context", &C);
// rna_ext->call((bContext *)C, &ptr, func, &list);
RNA_parameter_set_lookup(&list, "label", &label);
ext_rna->call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
MEM_freeN(label);
}
static void rna_call_draw_referenced_pre(uiLayout *layout, const char *name)
{
extern FunctionRNA rna_Menu_draw_referenced_pre_func;
FunctionRNA *func;
func = &rna_Menu_draw_referenced_pre_func; /* RNA_struct_find_function(&ptr,
"draw_referenced_pre") */
rna_call_draw_referenced(layout, name, func);
}
static void rna_call_draw_referenced_post(uiLayout *layout, const char *name)
{
extern FunctionRNA rna_Menu_draw_referenced_post_func;
FunctionRNA *func;
func = &rna_Menu_draw_referenced_post_func; /* RNA_struct_find_function(&ptr, "draw_referenced_post") */
rna_call_draw_referenced(layout, name, func);
}
static PointerRNA rna_uiItemO(uiLayout *layout,
const char *opname,
const char *name,
@ -337,6 +395,11 @@ static PointerRNA rna_uiItemO(uiLayout *layout,
int icon_value)
{
wmOperatorType *ot;
char original_name[255] = {0};
if (name) {
BLI_strncpy(original_name, name, 255);
}
ot = WM_operatortype_find(opname, false); /* print error next */
if (!ot || !ot->srna) {
@ -344,6 +407,13 @@ static PointerRNA rna_uiItemO(uiLayout *layout,
return PointerRNA_NULL;
}
if (name && *name != '\0') {
BLI_strncpy(original_name, name, 255);
}
else {
BLI_strncpy(original_name, ot->name, 255);
}
/* Get translated name (label). */
name = rna_translate_ui_text(name, text_ctxt, ot->srna, nullptr, translate);
@ -358,10 +428,15 @@ static PointerRNA rna_uiItemO(uiLayout *layout,
flag |= UI_ITEM_O_DEPRESS;
}
rna_call_draw_referenced_pre(layout, original_name);
PointerRNA opptr;
uiItemFullO_ptr(
layout, ot, name, icon, nullptr, uiLayoutGetOperatorContext(layout), flag, &opptr);
return opptr;
rna_call_draw_referenced_post(layout, original_name);
return opptr;
}
static PointerRNA rna_uiItemOMenuHold(uiLayout *layout,
@ -405,8 +480,17 @@ static void rna_uiItemsEnumO(uiLayout *layout,
const char *propname,
const bool icon_only)
{
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
/** Calling only once per operator **/
rna_call_draw_referenced_pre(layout, ot->name);
eUI_Item_Flag flag = icon_only ? UI_ITEM_R_ICON_ONLY : UI_ITEM_NONE;
uiItemsFullEnumO(layout, opname, propname, nullptr, uiLayoutGetOperatorContext(layout), flag);
rna_call_draw_referenced_post(layout, ot->name);
}
static PointerRNA rna_uiItemMenuEnumO(uiLayout *layout,
@ -420,6 +504,12 @@ static PointerRNA rna_uiItemMenuEnumO(uiLayout *layout,
{
wmOperatorType *ot = WM_operatortype_find(opname, false); /* print error next */
char original_name[255] = {0};
if (name) {
BLI_strncpy(original_name, name, 255);
}
if (!ot || !ot->srna) {
RNA_warning("%s '%s'", ot ? "unknown operator" : "operator missing srna", opname);
return PointerRNA_NULL;
@ -428,8 +518,13 @@ static PointerRNA rna_uiItemMenuEnumO(uiLayout *layout,
/* Get translated name (label). */
name = rna_translate_ui_text(name, text_ctxt, ot->srna, nullptr, translate);
rna_call_draw_referenced_pre(layout, original_name);
PointerRNA opptr;
uiItemMenuEnumFullO_ptr(layout, C, ot, propname, name, icon, &opptr);
rna_call_draw_referenced_post(layout, original_name);
return opptr;
}
@ -465,12 +560,33 @@ static void rna_uiItemM(uiLayout *layout,
icon = icon_value;
}
MenuType *mt = WM_menutype_find(menuname, false);
if (mt == NULL) {
RNA_warning("not found %s", menuname);
return;
}
rna_call_draw_referenced_pre(layout, mt->label);
uiItemM(layout, menuname, name, icon);
rna_call_draw_referenced_post(layout, mt->label);
}
static void rna_uiItemM_contents(uiLayout *layout, const char *menuname)
{
MenuType *mt = WM_menutype_find(menuname, false);
if (mt == NULL) {
RNA_warning("not found %s", menuname);
return;
}
rna_call_draw_referenced_pre(layout, mt->label);
uiItemMContents(layout, menuname);
rna_call_draw_referenced_post(layout, mt->label);
}
static void rna_uiItemPopoverPanel(uiLayout *layout,
@ -1751,6 +1867,21 @@ void RNA_api_ui_layout(StructRNA *srna)
1.0f,
100.0f);
func = RNA_def_function(srna, "template_image_ui", "uiTemplateImageUI");
RNA_def_function_ui_description(func, "A image on UI");
parm = RNA_def_int(func, "image_value", 0, 0, INT_MAX, "image to display", "", 0, INT_MAX);
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
RNA_def_float(func,
"scale",
1.0f,
1.0f,
100.0f,
"Scale",
"Scale the icon size (by the button size)",
1.0f,
100.0f);
func = RNA_def_function(srna, "template_icon_view", "uiTemplateIconView");
RNA_def_function_ui_description(func, "Enum. Large widget showing Icon previews");
api_ui_item_rna_common(func);

View File

@ -0,0 +1 @@
/* Empty file */

View File

@ -133,6 +133,8 @@ bool BPY_string_is_keyword(const char *str);
void BPY_callback_screen_free(struct ARegionType *art);
void BPY_callback_wm_free(struct wmWindowManager *wm);
void* BPY_utils_images_get(int image_id);
/* I18n for addons */
#ifdef WITH_INTERNATIONAL
const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid);

View File

@ -15,6 +15,7 @@ set(INC
../../windowmanager
../../../../intern/mantaflow/extern
../../../../intern/opencolorio
../../tornavis
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
)
@ -39,6 +40,7 @@ set(SRC
bpy_app_timers.cc
bpy_app_translations.cc
bpy_app_usd.cc
bpy_app_tornavis.cc
bpy_capi_utils.cc
bpy_driver.cc
bpy_gizmo_wrap.cc
@ -68,6 +70,7 @@ set(SRC
bpy_rna_ui.cc
bpy_traceback.cc
bpy_utils_previews.cc
bpy_utils_images.cc
bpy_utils_units.cc
stubs.cc
@ -86,6 +89,7 @@ set(SRC
bpy_app_timers.h
bpy_app_translations.h
bpy_app_usd.h
bpy_app_tornavis.h
bpy_capi_utils.h
bpy_driver.h
bpy_gizmo_wrap.h
@ -110,6 +114,7 @@ set(SRC
bpy_rna_ui.h
bpy_traceback.h
bpy_utils_previews.h
bpy_utils_images.h
bpy_utils_units.h
../BPY_extern.h
../BPY_extern_clog.h
@ -128,6 +133,7 @@ set(LIB
PRIVATE bf::intern::guardedalloc
PRIVATE bf::animrig
bf_python_gpu
tornavis
${PYTHON_LINKFLAGS}
${PYTHON_LIBRARIES}

View File

@ -46,6 +46,7 @@
#include "bpy_rna_id_collection.h"
#include "bpy_rna_types_capi.h"
#include "bpy_utils_previews.h"
#include "bpy_utils_images.h"
#include "bpy_utils_units.h"
#include "../generic/py_capi_utils.h"
@ -686,6 +687,7 @@ void BPy_init_modules(bContext *C)
PyModule_AddObject(mod, "app", BPY_app_struct());
PyModule_AddObject(mod, "_utils_units", BPY_utils_units());
PyModule_AddObject(mod, "_utils_previews", BPY_utils_previews_module());
PyModule_AddObject(mod, "_utils_images", BPY_utils_images_module());
PyModule_AddObject(mod, "msgbus", BPY_msgbus_module());
PointerRNA ctx_ptr = RNA_pointer_create(nullptr, &RNA_Context, C);

View File

@ -23,6 +23,7 @@
#include "bpy_app_openvdb.h"
#include "bpy_app_sdl.h"
#include "bpy_app_usd.h"
#include "bpy_app_tornavis.h"
#include "bpy_app_translations.h"
@ -116,6 +117,7 @@ static PyStructSequence_Field app_info_fields[] = {
{"build_options", "A set containing most important enabled optional build features"},
{"handlers", "Application handler callbacks"},
{"translations", "Application and addons internationalization API"},
{"tornavis", "Tornavis options"},
/* Modules (not struct sequence). */
{"icons", "Manage custom icons"},
@ -200,6 +202,7 @@ static PyObject *make_app_info()
SetObjItem(BPY_app_build_options_struct());
SetObjItem(BPY_app_handlers_struct());
SetObjItem(BPY_app_translations_struct());
SetObjItem(BPY_app_tornavis_struct());
/* modules */
SetObjItem(BPY_app_icons_module());

View File

@ -0,0 +1,71 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup pythonintern
*/
#include <Python.h>
#include "BLI_utildefines.h"
#include "bpy_app_tornavis.h"
#include "MB_tornavis.h"
static PyTypeObject BlenderAppTornavisType;
static PyStructSequence_Field app_tornavis_info_fields[] = {
{"patches", nullptr},
{nullptr},
};
static PyStructSequence_Desc app_tornavis_info_desc = {
"bpy.app.tornavis", /* name */
"This module contains options about tornavis project", /* doc */
app_tornavis_info_fields, /* fields */
ARRAY_SIZE(app_tornavis_info_fields) - 1,
};
static PyObject *make_tornavis_info()
{
PyObject *tornavis_info;
PyObject *list;
int pos=0;
char *patch = nullptr;
tornavis_info = PyStructSequence_New(&BlenderAppTornavisType);
if (tornavis_info == nullptr) {
return nullptr;
}
list = PyList_New(0);
PyStructSequence_SET_ITEM(tornavis_info, pos++, list);
for (int i =0 ; (patch = MB_patch_get(i)); i++) {
PyList_Append(list, PyUnicode_FromString(patch));
}
return tornavis_info;
}
PyObject *BPY_app_tornavis_struct()
{
PyObject *ret;
PyStructSequence_InitType(&BlenderAppTornavisType, &app_tornavis_info_desc);
ret = make_tornavis_info();
/* prevent user from creating new instances */
BlenderAppTornavisType.tp_init = nullptr;
BlenderAppTornavisType.tp_new = nullptr;
/* Without this we can't do `set(sys.modules)` #29635. */
BlenderAppTornavisType.tp_hash = (hashfunc)_Py_HashPointer;
return ret;
}

View File

@ -0,0 +1,19 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup pythonintern
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
PyObject *BPY_app_tornavis_struct(void);
#ifdef __cplusplus
}
#endif

View File

@ -36,6 +36,7 @@
#include "RNA_prototypes.h"
#include "WM_api.hh"
#include "WM_op_handlers.h"
#include "WM_types.hh"
#include "MEM_guardedalloc.h"
@ -461,11 +462,493 @@ static PyModuleDef bpy_ops_module = {
/*m_free*/ nullptr,
};
static int bpy_op_handler_check(void *py_data, void* owner, void *callback)
{
PyObject *py_owner = PyTuple_GET_ITEM(py_data, 0);
PyObject *py_callback = PyTuple_GET_ITEM(py_data, 2);
if (owner != NULL && callback != NULL) {
return (py_owner == owner && py_callback == callback);
}
else if (owner != NULL)
{
return (py_owner == owner);
}
else { //callback != NULL
return (py_callback == callback);
}
}
/*
* @Properties Rna Properties that has been used to set the operator
*/
static PyObject *bpy_op_get_operator_params(PointerRNA *properties)
{
const char *arg_name = NULL;
PyObject *py_dict = PyDict_New();
PyObject *data;
RNA_STRUCT_BEGIN (properties, prop) {
arg_name = RNA_property_identifier(prop);
data = NULL;
if (STREQ(arg_name, "rna_type")) {
continue;
}
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN: {
bool val = RNA_property_boolean_get(properties, prop);
// from Py Docs, Py_False and Py_truee needs to be treated just like any other object with
// respect to reference counts.
data = val ? Py_False : Py_True;
break;
}
case PROP_INT: {
const int prop_array_length = RNA_property_array_length(properties, prop);
if (prop_array_length == 0) {
int val = RNA_property_int_get(properties, prop);
data = PyLong_FromLong(val);
}
else {
int *values = (int*) MEM_callocN(sizeof(int) * prop_array_length, __func__);
RNA_property_int_get_array(properties, prop, values);
data = PyTuple_New(prop_array_length);
for (int i = 0; i < prop_array_length; i++) {
PyObject *py_val = PyLong_FromLong(*(values + i));
PyTuple_SET_ITEM(data, i, py_val);
}
MEM_freeN(values);
}
break;
}
case PROP_FLOAT: {
const int prop_array_length = RNA_property_array_length(properties, prop);
if (prop_array_length == 0) {
float val;
val = RNA_property_float_get(properties, prop);
data = PyFloat_FromDouble(val);
}
else {
float *values = (float*) MEM_callocN(sizeof(float) * prop_array_length, __func__);
RNA_property_float_get_array(properties, prop, values);
data = PyTuple_New(prop_array_length);
for (int i = 0; i < prop_array_length; i++) {
PyObject *py_val = PyFloat_FromDouble(*(values + i));
PyTuple_SET_ITEM(data, i, py_val);
}
MEM_freeN(values);
}
break;
}
case PROP_STRING: {
char buff[256];
char *value = RNA_property_string_get_alloc(properties, prop, buff, sizeof(buff), NULL);
data = PyUnicode_FromString(value);
if (value != buff) {
MEM_freeN(value);
}
break;
}
case PROP_ENUM: {
int val = RNA_property_enum_get(properties, prop);
data = PyLong_FromLong(val);
break;
}
case PROP_POINTER: {
data = PyUnicode_FromString("POINTER");
break;
}
case PROP_COLLECTION: {
data = PyUnicode_FromString("COLLECTION");
break;
}
default:
BLI_assert(false);
}
if (data != NULL) {
PyDict_SetItemString(py_dict, arg_name, data);
}
}
RNA_STRUCT_END;
return py_dict;
}
static bool bpy_op_callback_get_return_value(PyObject *callback, PyObject *py_ret)
{
bool ret = true; // Do not interrump on error
if (py_ret == NULL) {
PyC_Err_PrintWithFunc(callback);
}
else {
if (py_ret == Py_None) {
// pass
}
else if (py_ret == Py_True) {
// pass
}
else if (py_ret == Py_False){
ret = false;
} else {
PyErr_SetString(PyExc_ValueError, "the return value must be None or boolean");
PyC_Err_PrintWithFunc(callback);
}
Py_DECREF(py_ret);
}
return ret;
}
static PyObject *bpy_op_get_callback_call(PyObject *callback,
bContext *C, const wmEvent *event, int *operator_ret, PyObject *params, PyObject *callback_args)
{
PointerRNA ctx_ptr;
PointerRNA event_ptr;
PyObject *bpy_ctx;
PyObject *bpy_event;
PyObject *py_ret;
ctx_ptr = RNA_pointer_create(nullptr, &RNA_Context, C);
bpy_ctx = pyrna_struct_CreatePyObject(&ctx_ptr);
if (event != NULL) {
event_ptr = RNA_pointer_create(NULL, &RNA_Event, (void*) event);
bpy_event = pyrna_struct_CreatePyObject(&event_ptr);
}
else {
bpy_event = Py_None;
}
int s = (operator_ret == NULL) ? 3 : 4;
int c = (callback_args == Py_None) ? s : PyTuple_GET_SIZE(callback_args) + s;
PyObject *func_args = PyTuple_New(c);
PyTuple_SET_ITEM(func_args, 0, bpy_ctx);
PyTuple_SET_ITEM(func_args, 1, bpy_event);
PyTuple_SET_ITEM(func_args, 2, params);
if (operator_ret != NULL) {
PyObject *op_ret = pyrna_enum_bitfield_to_py(rna_enum_operator_return_items, *operator_ret);
PyTuple_SET_ITEM(func_args, 3, op_ret);
}
for (int i = s; i < c; i++) {
PyTuple_SET_ITEM(func_args, i, PyTuple_GET_ITEM(callback_args, i - s));
}
py_ret = PyObject_CallObject(callback, func_args);
Py_DECREF(func_args);
return py_ret;
}
static bool bpy_op_handler_poll(struct bContext *C,
const wmEvent *event, void *py_data,
PointerRNA *properties)
{
bool ret = true;
PyGILState_STATE gilstate; // this is because is not thread safe
bpy_context_set(C, &gilstate);
{
PyObject *callback_args = PyTuple_GET_ITEM(py_data, 3);
PyObject *py_poll = PyTuple_GET_ITEM(py_data, 4);
// Properties get null on modall poll, params are not bypassed to Py poll function
PyObject *params = (properties == NULL) ? Py_None : bpy_op_get_operator_params(properties);
if (py_poll != Py_None) {
PyObject *py_ret = bpy_op_get_callback_call(py_poll, C, event, NULL, params, callback_args);
if (py_ret == NULL) {
// Error
PyErr_Print();
return false;
}
else if (py_ret == Py_True) {
ret = true;
Py_DECREF(py_ret);
}
else if (py_ret == Py_False) {
ret = false;
Py_DECREF(py_ret);
}
else {
ret = false;
Py_DECREF(py_ret);
PyErr_SetString(PyExc_ValueError, "the return value must be boolean");
PyC_Err_PrintWithFunc(py_poll);
}
}
// Py_DECREF(params);
}
bpy_context_clear(C, &gilstate);
return ret;
}
static bool bpy_op_handler_modal (bContext *C, const wmEvent *event, void *py_data, PointerRNA *properties, int operator_ret)
{
// this is because is not thread safe
bool ret = true;
PyGILState_STATE gilstate;
bpy_context_set(C, &gilstate);
{
PyObject *callback = PyTuple_GET_ITEM(py_data, 2);
PyObject *callback_args = PyTuple_GET_ITEM(py_data, 3);
PyObject *py_ret = bpy_op_get_callback_call(callback, C, event, &operator_ret, Py_None, callback_args);
ret = bpy_op_callback_get_return_value(callback, py_ret);
}
bpy_context_clear(C, &gilstate);
return ret;
}
static bool bpy_op_handler_invoke(bContext *C,
const wmEvent *event,
void *py_data,
PointerRNA *properties,
int operator_ret)
{
bool ret = true;
// this is because is not thread safe
PyGILState_STATE gilstate;
bpy_context_set(C, &gilstate);
{
PyObject *callback = PyTuple_GET_ITEM(py_data, 2);
PyObject *callback_args = PyTuple_GET_ITEM(py_data, 3);
PyObject *params = bpy_op_get_operator_params(properties);
PyObject *py_ret = bpy_op_get_callback_call(callback, C, event, operator_ret ? &operator_ret : NULL , params, callback_args);
ret = bpy_op_callback_get_return_value(callback, py_ret);
}
bpy_context_clear(C, &gilstate);
return ret;
}
static PyObject *bpy_op_handler_proc(
PyObject *args,
PyObject *kw)
{
const char *error_prefix = "op_handler_proc";
PyObject *py_op = NULL;
PyObject *py_owner = NULL; // Object who creates the handler
PyObject *callback = NULL, *py_poll = NULL;
PyObject *callback_args = NULL;
if (PyTuple_GET_SIZE(args) != 0) {
PyErr_Format(PyExc_TypeError, "%s: only keyword arguments are supported", error_prefix);
}
// see https://docs.python.org/3/c-api/arg.html
static const char *_keywords[] = {"owner", "op", "cb", "args", "poll", NULL};
static _PyArg_Parser _parser = {"OOOOO|:handler_proc", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &py_owner, &py_op, &callback, &callback_args, &py_poll)) {
PyErr_SetString(
PyExc_TypeError, "Cannot set arguments, or types does not match");
}
if (callback != Py_None && !PyFunction_Check(callback)) {
// Callback may be none on remove
PyErr_Format(
PyExc_TypeError, "callback expects a function, found %.200s", Py_TYPE(callback)->tp_name);
}
if (py_poll != Py_None && !PyFunction_Check(py_poll)) {
// Callback may be none on remove
PyErr_Format(
PyExc_TypeError, "poll expects a function, found %.200s", Py_TYPE(callback)->tp_name);
}
if (py_op != Py_None && !PyUnicode_Check(py_op)) {
PyErr_Format(
PyExc_TypeError, "op expects an astring, found %.200s", Py_TYPE(py_op)->tp_name);
}
if (PyErr_Occurred() != NULL) {
PyErr_Print();
return NULL;
}
PyObject *py_data = PyTuple_New(5);
PyTuple_SET_ITEMS(py_data,
Py_INCREF_RET(py_owner), // 0
Py_INCREF_RET(py_op), // 1
Py_INCREF_RET(callback), // 2
Py_INCREF_RET(callback_args), // 3
Py_INCREF_RET(py_poll)); // 4
return Py_INCREF_RET(py_data);
}
static PyObject *op_handler_append(int handler_id , PyObject *args, PyObject *kw)
{
bContext *C = BPY_context_get();
struct wmOpHandlers *op_handlers = CTX_wm_op_handlers(C);
PyObject *py_data = bpy_op_handler_proc(args, kw);
bool (*func)(bContext * C,const wmEvent * event, void *, PointerRNA *, int) = nullptr;
switch (handler_id) {
case HANDLER_TYPE_PRE_INVOKE:
case HANDLER_TYPE_POST_INVOKE:
func = bpy_op_handler_invoke;
break;
case HANDLER_TYPE_MODAL:
case HANDLER_TYPE_MODAL_END:
func = bpy_op_handler_modal;
break;
}
if (py_data != NULL) {
PyObject *py_owner = PyTuple_GET_ITEM(py_data, 0);
PyObject *py_op = PyTuple_GET_ITEM(py_data, 1);
PyObject *py_callback = PyTuple_GET_ITEM(py_data, 2);
PyObject *py_poll = PyTuple_GET_ITEM(py_data, 4);
if (py_op == Py_None) {
PyErr_Format(PyExc_TypeError, "missing operator");
}
else if (py_callback == Py_None) {
PyErr_Format(PyExc_TypeError, "callback expects a function");
} else {
WM_op_handlers_append(op_handlers,
handler_id,
py_owner,
PyUnicode_AsUTF8(py_op),
func,
bpy_op_handler_check,
py_poll == Py_None ? NULL : bpy_op_handler_poll,
py_data);
}
}
if (PyErr_Occurred() != NULL) {
PyErr_Print();
}
Py_RETURN_NONE;
}
static PyObject *op_handler_remove(int handler_id, PyObject *args, PyObject *kw)
{
bContext *C = BPY_context_get();
struct wmOpHandlers *op_handlers = CTX_wm_op_handlers(C);
PyObject *py_data = bpy_op_handler_proc(args, kw);
if (py_data != NULL) {
PyObject *py_owner = PyTuple_GET_ITEM(py_data, 0);
PyObject *py_op = PyTuple_GET_ITEM(py_data, 1);
PyObject *py_cb = PyTuple_GET_ITEM(py_data, 2);
if (py_owner == Py_None && py_cb == Py_None) {
PyErr_Format(PyExc_TypeError, "missing owner or callback");
} else {
if (WM_op_handlers_remove(op_handlers,
handler_id,
(py_op == Py_None ? NULL : PyUnicode_AsUTF8(py_op)),
(py_cb == Py_None ? NULL : py_cb),
(py_owner == Py_None ? NULL : py_owner)) == 0) {
PyErr_Format(PyExc_NameError, "data not found on %s", PyUnicode_AsUTF8(py_op));
}
}
}
if (PyErr_Occurred() != NULL) {
PyErr_Print();
}
Py_RETURN_NONE;
}
static PyObject *op_handler_append_pre_invoke(PyObject *self, PyObject *args, PyObject *kw)
{
return op_handler_append(HANDLER_TYPE_PRE_INVOKE, args, kw);
}
static PyObject *op_handler_append_post_invoke(PyObject *self, PyObject *args, PyObject *kw)
{
return op_handler_append(HANDLER_TYPE_POST_INVOKE, args, kw);
}
static PyObject *op_handler_append_modal(PyObject *self, PyObject *args, PyObject *kw)
{
return op_handler_append(HANDLER_TYPE_MODAL, args, kw);
}
static PyObject *op_handler_append_modal_end(PyObject *self, PyObject *args, PyObject *kw)
{
return op_handler_append(HANDLER_TYPE_MODAL_END, args, kw);
}
static PyObject *op_handler_remove_pre_invoke(PyObject *self, PyObject *args, PyObject *kw)
{
return op_handler_remove(HANDLER_TYPE_PRE_INVOKE, args, kw);
}
static PyObject *op_handler_remove_post_invoke(PyObject *self, PyObject *args, PyObject *kw)
{
return op_handler_remove(HANDLER_TYPE_POST_INVOKE, args, kw);
}
static PyObject *op_handler_remove_modal(PyObject *self, PyObject *args, PyObject *kw)
{
return op_handler_remove(HANDLER_TYPE_MODAL, args, kw);
}
static PyObject *op_handler_remove_modal_end(PyObject *self, PyObject *args, PyObject *kw)
{
return op_handler_remove(HANDLER_TYPE_MODAL_END, args, kw);
}
static PyObject *op_handlers_remove(PyObject *self, PyObject *args, PyObject *kw)
{
return op_handler_remove(HANDLER_TYPE_ALL, args, kw);
}
static struct PyMethodDef bpy_ops_handlers_methods[] = {
{"pre_invoke", (PyCFunction)op_handler_append_pre_invoke, METH_VARARGS | METH_KEYWORDS, NULL},
{"post_invoke", (PyCFunction)op_handler_append_post_invoke, METH_VARARGS | METH_KEYWORDS, NULL},
{"modal", (PyCFunction)op_handler_append_modal, METH_VARARGS | METH_KEYWORDS, NULL},
{"modal_end", (PyCFunction)op_handler_append_modal_end, METH_VARARGS | METH_KEYWORDS, NULL},
{"pre_invoke_remove", (PyCFunction)op_handler_remove_pre_invoke, METH_VARARGS | METH_KEYWORDS, NULL},
{"post_invoke_remove", (PyCFunction)op_handler_remove_post_invoke, METH_VARARGS | METH_KEYWORDS, NULL},
{"modal_remove",(PyCFunction)op_handler_remove_post_invoke, METH_VARARGS | METH_KEYWORDS, NULL},
{"modal_end_remove", (PyCFunction)op_handler_remove_modal_end, METH_VARARGS | METH_KEYWORDS, NULL},
{"remove", (PyCFunction)op_handlers_remove, METH_VARARGS | METH_KEYWORDS, NULL},
{NULL, NULL, 0, NULL},
};
static struct PyModuleDef bpy_ops_handlers = {
PyModuleDef_HEAD_INIT,
"_bpy.ops.handlers",
NULL,
-1, /* multiple "initialization" just copies the module dict. */
bpy_ops_handlers_methods,
NULL,
NULL,
NULL,
NULL,
};
PyObject *BPY_operator_module()
{
PyObject *submodule;
submodule = PyModule_Create(&bpy_ops_module);
PyObject *handlers = PyModule_Create(&bpy_ops_handlers);
Py_INCREF(handlers);
if (PyModule_AddObject(submodule, "handlers", handlers) < 0) {
Py_DECREF(submodule);
Py_DECREF(handlers);
return NULL;
}
return submodule;
}

View File

@ -1303,6 +1303,25 @@ static int pyrna_prop_to_enum_bitfield(
return ret;
}
PyObject *pyrna_enum_bitfield_to_py(const EnumPropertyItem *items, int value)
{
PyObject *ret = PySet_New(NULL);
const char *identifier[RNA_ENUM_BITFLAG_SIZE + 1];
if (RNA_enum_bitflag_identifiers(items, value, identifier)) {
PyObject *item;
int index;
for (index = 0; identifier[index]; index++) {
item = PyUnicode_FromString(identifier[index]);
PySet_Add(ret, item);
Py_DECREF(item);
}
}
return ret;
}
static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
{
PyObject *item, *ret = nullptr;

View File

@ -189,6 +189,8 @@ PyObject *pyrna_id_CreatePyObject(struct ID *id);
bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id);
bool pyrna_id_CheckPyObject(PyObject *obj);
PyObject *pyrna_enum_bitfield_to_py(const struct EnumPropertyItem *items, int value);
/* operators also need this to set args */
int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, bool all_args, const char *error_prefix);
PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop);

View File

@ -0,0 +1,173 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup pythonintern
*
* This file defines a singleton py object accessed via 'bpy.utils.images',
*/
#include <Python.h>
#include <structmember.h>
#include <string.h>
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "RNA_access.hh"
#include "RNA_prototypes.h"
#include "RNA_types.hh"
#include "BPY_extern.h"
#include "bpy_rna.h"
#include "bpy_utils_images.h"
#include "../generic/py_capi_utils.h"
#include "MEM_guardedalloc.h"
#include "IMB_imbuf.hh"
#include "../generic/python_utildefines.h"
struct bpy_image_data{
bpy_image_data *prev;
bpy_image_data *next;
int id;
ImBuf *ibuf;
std::string name;
std::string path;
};
int bpy_images_last_id = 0;
ListBase bpy_images_list;
bpy_image_data* BPY_utils_images_get_data(int image_id) {
return (bpy_image_data *)BLI_listbase_bytes_find(
&bpy_images_list, &image_id, sizeof(int), sizeof(bpy_image_data *) * 2);
}
void* BPY_utils_images_get(int image_id)
{
bpy_image_data *el = BPY_utils_images_get_data(image_id);
return (el != nullptr) ? el->ibuf : nullptr;
}
PyDoc_STRVAR(bpy_utils_images_load_doc,
".. method:: load(name, filepath)\n"
"\n"
" Generate a new preview from given file path.\n"
"\n"
" :arg name: The name identifying the image.\n"
" :type name: string\n"
" :arg filepath: The file path to the image.\n"
" :type filepath: string or bytes\n"
" :return: image id.\n"
" :rtype: long`\n");
static PyObject *bpy_utils_images_load(PyObject * /*self*/, PyObject *args)
{
char *name = NULL;
PyC_UnicodeAsBytesAndSize_Data filepath_data = {nullptr};
if (!PyArg_ParseTuple(args,
"s" /* `name` */
"O&" /* `filepath` */
":load",
&name,
PyC_ParseUnicodeAsBytesAndSize,
&filepath_data,
0))
{
return nullptr;
}
if (!filepath_data.value || !name) {
Py_RETURN_NONE;
}
ImBuf *ibuf = IMB_loadiffname(filepath_data.value, 0, nullptr);
if (ibuf) {
bpy_image_data *data = MEM_new<bpy_image_data>(__func__);
data->id = ++bpy_images_last_id;
data->ibuf = ibuf;
data->name = name;
data->path = filepath_data.value;
BLI_addtail(&bpy_images_list, data);
return PyLong_FromLong(data->id);
}
else {
Py_RETURN_NONE;
}
}
PyDoc_STRVAR(bpy_utils_images_release_doc,
".. method:: release(image_id)\n"
"\n"
" Release (free) a previously added image.\n"
"\n"
"\n"
" :arg image_id: The id identifying the image.\n"
" :type name: long\n"
" :return: true if release.\n"
" :rtype: bool`\n");
static PyObject *bpy_utils_images_release(PyObject * /*self*/, PyObject *args)
{
int image_id = -1;
if (!PyArg_ParseTuple(args, "i:release", &image_id)) {
return nullptr;
}
bpy_image_data *el = BPY_utils_images_get_data(image_id);
if (el != nullptr) {
BLI_remlink(&bpy_images_list, el);
IMB_freeImBuf(el->ibuf);
MEM_freeN(el);
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
static PyMethodDef bpy_utils_images_methods[] = {
/* Can't use METH_KEYWORDS alone, see http://bugs.python.org/issue11587 */
{"load", (PyCFunction)bpy_utils_images_load, METH_VARARGS, bpy_utils_images_load_doc},
{"release",(PyCFunction)bpy_utils_images_release,METH_VARARGS, bpy_utils_images_release_doc},
{nullptr, nullptr, 0, nullptr},
};
PyDoc_STRVAR(
bpy_utils_images_doc,
"This object contains basic static methods to handle cached (non-ID) previews in Blender\n"
"(low-level API, not exposed to final users).");
static PyModuleDef bpy_utils_images_module = {
/*m_base*/ PyModuleDef_HEAD_INIT,
/*m_name*/ "bpy._utils_images",
/*m_doc*/ bpy_utils_images_doc,
/*m_size*/ 0,
/*m_methods*/ bpy_utils_images_methods,
/*m_slots*/ nullptr,
/*m_traverse*/ nullptr,
/*m_clear*/ nullptr,
/*m_free*/ nullptr,
};
PyObject *BPY_utils_images_module()
{
PyObject *submodule;
submodule = PyModule_Create(&bpy_utils_images_module);
return submodule;
}

View File

@ -0,0 +1,19 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup pythonintern
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
PyObject *BPY_utils_images_module(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,45 @@
#
#
#
set(INC
.
../blenlib
)
set(LIB
PRIVATE bf::blenlib
)
if(WITH_BOOST)
list(APPEND INC_SYS
${BOOST_INCLUDE_DIR}
)
else()
message (FATAL_ERROR "tornavis requires WITH_BOOST")
endif()
# Auto fill source files, so patches will not touch that file
file(GLOB sources "MB_*")
foreach(source ${sources})
get_filename_component(name ${source} NAME)
list(APPEND SRC "${name}")
endforeach()
# Generate a Definition for each found patch
file(GLOB patches "patches/*")
foreach(patch ${patches})
get_filename_component(def ${patch} NAME_WE)
get_filename_component(name ${patch} NAME)
if (${name} MATCHES "^MB_[0-9][0-9][0-9][0-9]\.h$" )
add_definitions(-D${def})
list(APPEND SRC "patches/${name}")
else()
message (FATAL_ERROR "invalid patch file ${name}")
endif ()
endforeach()
blender_add_lib(tornavis "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@ -0,0 +1,149 @@
#ifndef MB_BLENDER_PATCHES_H
#define MB_BLENDER_PATCHES_H
#ifdef MB_0001
#include "patches/MB_0001.h"
#define MB_0001_APPLIED 1
#else
#define MB_0001_APPLIED 0
#endif
#ifdef MB_0002
#include "patches/MB_0002.h"
#define MB_0002_APPLIED 1
#else
#define MB_0002_APPLIED 0
#endif
#ifdef MB_0003
#include "patches/MB_0003.h"
#define MB_0003_APPLIED 1
#else
# define MB_0003_APPLIED 0
#endif
#ifdef MB_0004
#include "patches/MB_0004.h"
#define MB_0004_APPLIED 1
#else
# define MB_0004_APPLIED 0
#endif
#ifdef MB_0005
#include "patches/MB_0005.h"
#define MB_0005_APPLIED 1
#else
# define MB_0005_APPLIED 0
#endif
#ifdef MB_0006
#include "patches/MB_0006.h"
#define MB_0006_APPLIED 1
#else
#define MB_0006_APPLIED 0
#endif
#ifdef MB_0007
#include "patches/MB_0007.h"
#define MB_0007_APPLIED 1
#else
#define MB_0007_APPLIED 0
#endif
#ifdef MB_0008
#include "patches/MB_0008.h"
#define MB_0008_APPLIED 1
#else
#define MB_0008_APPLIED 0
#endif
#ifdef MB_0009
#include "patches/MB_0009.h"
#define MB_0009_APPLIED 1
#else
#define MB_0009_APPLIED 0
#endif
#ifdef MB_0010
#include "patches/MB_0010.h"
#define MB_0010_APPLIED 1
#else
#define MB_0010_APPLIED 0
#endif
#ifdef MB_0011
#include "patches/MB_0011.h"
#define MB_0011_APPLIED 1
#else
#define MB_0011_APPLIED 0
#endif
#ifdef MB_0012
#include "patches/MB_0012.h"
#define MB_0012_APPLIED 1
#else
#define MB_0012_APPLIED 0
#endif
#ifdef MB_0013
#include "patches/MB_0013.h"
#define MB_0013_APPLIED 1
#else
#define MB_0013_APPLIED 0
#endif
#ifdef MB_0014
#include "patches/MB_0014.h"
#define MB_0014_APPLIED 1
#else
#define MB_0014_APPLIED 0
#endif
#ifdef MB_0015
#include "patches/MB_0015.h"
#define MB_0015_APPLIED 1
#else
#define MB_0015_APPLIED 0
#endif
#ifdef MB_0016
#include "patches/MB_0016.h"
#define MB_0016_APPLIED 1
#else
#define MB_0016_APPLIED 0
#endif
#ifdef MB_0017
#include "patches/MB_0017.h"
#define MB_0017_APPLIED 1
#else
#define MB_0017_APPLIED 0
#endif
#ifdef MB_0018
#include "patches/MB_0018.h"
#define MB_0018_APPLIED 1
#else
#define MB_0018_APPLIED 0
#endif
#ifdef MB_0019
#include "patches/MB_0019.h"
#define MB_0019_APPLIED 1
#else
#define MB_0019_APPLIED 0
#endif
#ifdef MB_0020
#include "patches/MB_0020.h"
#define MB_0020_APPLIED 1
#else
#define MB_0020_APPLIED 0
#endif
#ifndef MB_0021
#define MAX_MB_PATCHES 21
#endif
#endif // !MB_BLENDER_PATCHES_H

View File

@ -0,0 +1,68 @@
/**
*
*/
#include "MB_patches.h"
#include <boost/preprocessor/if.hpp>
#include <BLI_assert.h>
#include <stdio.h>
#include <string.h>
char patches[MAX_MB_PATCHES][8] = {0};
void MB_patches_discover()
{
int i = 0;
BOOST_PP_IF(MB_0001_APPLIED, strcpy(patches[i++], "MB_0001"), );
BOOST_PP_IF(MB_0002_APPLIED, strcpy(patches[i++], "MB_0002"), );
BOOST_PP_IF(MB_0003_APPLIED, strcpy(patches[i++], "MB_0003"), );
BOOST_PP_IF(MB_0004_APPLIED, strcpy(patches[i++], "MB_0004"), );
BOOST_PP_IF(MB_0005_APPLIED, strcpy(patches[i++], "MB_0005"), );
BOOST_PP_IF(MB_0006_APPLIED, strcpy(patches[i++], "MB_0006"), );
BOOST_PP_IF(MB_0007_APPLIED, strcpy(patches[i++], "MB_0007"), );
BOOST_PP_IF(MB_0008_APPLIED, strcpy(patches[i++], "MB_0008"), );
BOOST_PP_IF(MB_0009_APPLIED, strcpy(patches[i++], "MB_0009"), );
BOOST_PP_IF(MB_0010_APPLIED, strcpy(patches[i++], "MB_0010"), );
BOOST_PP_IF(MB_0011_APPLIED, strcpy(patches[i++], "MB_0011"), );
BOOST_PP_IF(MB_0012_APPLIED, strcpy(patches[i++], "MB_0012"), );
BOOST_PP_IF(MB_0013_APPLIED, strcpy(patches[i++], "MB_0013"), );
BOOST_PP_IF(MB_0014_APPLIED, strcpy(patches[i++], "MB_0014"), );
BOOST_PP_IF(MB_0015_APPLIED, strcpy(patches[i++], "MB_0015"), );
BOOST_PP_IF(MB_0016_APPLIED, strcpy(patches[i++], "MB_0016"), );
BOOST_PP_IF(MB_0017_APPLIED, strcpy(patches[i++], "MB_0017"), );
BOOST_PP_IF(MB_0018_APPLIED, strcpy(patches[i++], "MB_0018"), );
BOOST_PP_IF(MB_0019_APPLIED, strcpy(patches[i++], "MB_0019"), );
BOOST_PP_IF(MB_0020_APPLIED, strcpy(patches[i++], "MB_0020"), );
// Not necessary becuase initialitzed to {0}
strcpy(patches[i++], "\0");
return;
}
void MB_init(void) {
MB_patches_discover();
}
char* MB_patch_get(int pos) {
BLI_assert(pos < MAX_MB_PATCHES);
return *patches[pos] == '\0' ? nullptr : patches[pos];
}
void MB_print_info()
{
printf("%s", "Tornavis Info\n");
printf("%s", "---------------------\n");
for (int i = 0; i < MAX_MB_PATCHES; i++) {
if (*patches[i] == '\0') {
break;
}
printf("Applied Patch %s\n", patches[i]);
}
printf("%s", "---------------------\n");
}

View File

@ -0,0 +1,13 @@
/**
*
*/
#ifndef MB_BLENDER_H
#define MB_BLENDER_H
void MB_init(void);
void MB_patches_discover(void);
char* MB_patch_get(int pos);
void MB_print_info(void);
#endif

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty file */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty file */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty File */

View File

@ -0,0 +1 @@
/* Empty file */

View File

@ -70,10 +70,12 @@ set(SRC
message_bus/intern/wm_message_bus.cc
message_bus/intern/wm_message_bus_rna.cc
message_bus/intern/wm_message_bus_static.cc
op_handlers/intern/wm_op_handlers.cc
WM_api.hh
WM_keymap.hh
WM_message.hh
WM_op_handlers.h
WM_toolsystem.hh
WM_types.hh
wm.hh
@ -93,6 +95,8 @@ set(SRC
gizmo/intern/wm_gizmo_intern.hh
message_bus/intern/wm_message_bus_intern.hh
message_bus/wm_message_bus.hh
op_handlers/wm_op_handlers.h
op_handlers/intern/wm_op_handlers_intern.h
)
set(LIB

View File

@ -0,0 +1,25 @@
/*
* 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
* of the License, or (at your option) any later version.
*
* 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup wm
*/
#pragma once
struct wmOpHandlers;
#include "op_handlers/wm_op_handlers.h"

View File

@ -41,6 +41,7 @@
#include "WM_api.hh"
#include "WM_message.hh"
#include "WM_op_handlers.h"
#include "WM_types.hh"
#include "wm.hh"
#include "wm_draw.hh"
@ -217,6 +218,7 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
wm->undo_stack = nullptr;
wm->message_bus = nullptr;
wm->op_handlers = nullptr;
wm->xr.runtime = nullptr;
@ -474,6 +476,10 @@ void WM_check(bContext *C)
wm->message_bus = WM_msgbus_create();
}
if (wm->op_handlers == NULL) {
wm->op_handlers = WM_op_handlers_create();
}
if (!G.background) {
/* Case: file-read. */
if ((wm->init_flag & WM_INIT_FLAG_WINDOW) == 0) {
@ -574,6 +580,11 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
WM_msgbus_destroy(wm->message_bus);
}
if (wm->op_handlers != nullptr) {
WM_op_handlers_destroy(wm->op_handlers);
}
#ifdef WITH_PYTHON
BPY_callback_wm_free(wm);
#endif

View File

@ -66,6 +66,7 @@
#include "WM_api.hh"
#include "WM_message.hh"
#include "WM_op_handlers.h"
#include "WM_toolsystem.hh"
#include "WM_types.hh"
@ -1512,6 +1513,12 @@ static int wm_operator_invoke(bContext *C,
return WM_operator_poll(C, ot);
}
// Ensure any change is processed by poll
if (WM_op_handlers_operator_pre_invoke(C, event, CTX_wm_op_handlers(C), ot, properties) ==
false) {
return OPERATOR_FINISHED;
}
if (WM_operator_poll(C, ot)) {
wmWindowManager *wm = CTX_wm_manager(C);
const intptr_t undo_id_prev = wm_operator_undo_active_id(wm);
@ -1552,6 +1559,8 @@ static int wm_operator_invoke(bContext *C,
retval = op->type->invoke(C, op, &event_temp);
OPERATOR_RETVAL_CHECK(retval);
WM_op_handlers_operator_post_invoke(C, event, CTX_wm_op_handlers(C), ot, op->ptr, retval);
if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
wm->op_undo_depth--;
}
@ -1564,6 +1573,8 @@ static int wm_operator_invoke(bContext *C,
retval = op->type->exec(C, op);
OPERATOR_RETVAL_CHECK(retval);
WM_op_handlers_operator_post_invoke(C, event, CTX_wm_op_handlers(C), ot, op->ptr, retval);
if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
wm->op_undo_depth--;
}
@ -2478,9 +2489,20 @@ static eHandlerActionFlag wm_handler_operator_call(bContext *C,
wm->op_undo_depth++;
}
/* Warning, after this call all context data and 'event' may be freed. see check below. */
retval = ot->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
if ( (WM_get_op_handlers(CTX_wm_op_handlers(C), ot->idname) != NULL) && !ot->poll(C)) {
// Py Handler, changing poll conditions
retval = OPERATOR_CANCELLED;
}
else {
/* Warning, after this call all context data and 'event' may be freed. see check below. */
retval = ot->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
if (WM_op_handlers_operator_modal(C, event, CTX_wm_op_handlers(C), ot, retval) == false) {
retval = OPERATOR_CANCELLED;
}
}
if (ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
wm->op_undo_depth--;
@ -2494,7 +2516,10 @@ static eHandlerActionFlag wm_handler_operator_call(bContext *C,
wm_event_modalkeymap_end(event, &event_backup);
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
wm_operator_reports(C, op, retval, false);
WM_op_handlers_operator_modal_end(C, nullptr, CTX_wm_op_handlers(C), ot, retval);
wm_operator_reports(C, op, retval, false);
wmOperator *op_test = handler->op->opm ? handler->op->opm : handler->op;
if (op_test->type->modalkeymap) {
@ -2526,6 +2551,9 @@ static eHandlerActionFlag wm_handler_operator_call(bContext *C,
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
}
else if (retval & OPERATOR_REPEAT) {
wm_operator_invoke(C, ot, event, properties, NULL, false, true);
}
else {
/* This special cases is for areas and regions that get removed. */
CTX_wm_area_set(C, nullptr);

View File

@ -4113,6 +4113,7 @@ void wm_operatortypes_register()
WM_operatortype_append(WM_OT_operator_defaults);
WM_operatortype_append(WM_OT_splash);
WM_operatortype_append(WM_OT_splash_about);
WM_operatortype_append(WM_OT_splash_custom);
WM_operatortype_append(WM_OT_search_menu);
WM_operatortype_append(WM_OT_search_operator);
WM_operatortype_append(WM_OT_search_single_menu);

View File

@ -49,6 +49,9 @@
#include "WM_api.hh"
#include "WM_types.hh"
#include "RNA_define.hh"
#include "RNA_access.hh"
#include "wm.hh"
static void wm_block_close(bContext *C, void *arg_block, void * /*arg*/)
@ -200,6 +203,10 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void * /*ar
BKE_blender_version_string(),
splash_width - 8.0 * UI_SCALE_FAC,
splash_height - 13.0 * UI_SCALE_FAC);
wm_block_splash_add_label(block,
"Tornavis Project",
splash_width - 8.0 * UI_SCALE_FAC,
splash_height - ((13.0 + 10) * UI_SCALE_FAC));
}
const int layout_margin_x = UI_SCALE_FAC * 26;
@ -336,3 +343,66 @@ void WM_OT_splash_about(wmOperatorType *ot)
ot->invoke = wm_about_invoke;
ot->poll = WM_operator_winactive;
}
static uiBlock *wm_block_create_custom_splash(bContext *C, ARegion *region, void *arg) {
char *menutype_str = (char*) arg;
const uiStyle *style = UI_style_get_dpi();
const int text_points_max = MAX2(style->widget.points, style->widgetlabel.points);
const int dialog_width = text_points_max * 42 * UI_SCALE_FAC;
uiBlock *block = UI_block_begin(C, region, "about", UI_EMBOSS);
UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
uiLayout *layout = UI_block_layout(
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style);
uiLayout *col = uiLayoutColumn(layout, true);
MenuType *mt = WM_menutype_find(menutype_str, true);
if (mt) {
UI_menutype_draw(C, mt, col);
} else {
CLOG_ERROR(WM_LOG_OPERATORS, "cannot find WM menutype '%s'", menutype_str);
}
UI_block_bounds_set_centered(block, 22 * UI_SCALE_FAC);
return block;
}
static int wm_about_custom_exec(bContext *C, wmOperator *op)
{
char *menutype_str = MEM_cnew_array<char>(100, __func__);
*menutype_str = '\0';
if (RNA_struct_property_is_set(op->ptr, "menutype")) {
RNA_string_get(op->ptr, "menutype", menutype_str);
}
UI_popup_block_invoke(C, wm_block_create_custom_splash, menutype_str, MEM_freeN);
return OPERATOR_FINISHED;
}
static int wm_about_custom_invoke(bContext *C, wmOperator *op , const wmEvent * /*event*/) {
return op->type->exec(C, op);
}
void WM_OT_splash_custom(wmOperatorType *ot)
{
PropertyRNA *prop;
prop = RNA_def_string(ot->srna, "menutype", "MT_", 100, "", "MenuType class name");
ot->name = "Custom Splash";
ot->idname = "WM_OT_splash_custom";
ot->description = "Open a splash window with some custom information";
ot->exec = wm_about_custom_exec;
ot->invoke = wm_about_custom_invoke;
ot->poll = WM_operator_winactive;
}

View File

@ -525,6 +525,7 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
str += " - Blender ";
str += BKE_blender_version_string_compact();
str += " - Tornavis";
GHOST_SetTitle(handle, str.c_str());

View File

@ -0,0 +1,246 @@
/*
* 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
* of the License, or (at your option) any later version.
*
* 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup wm
*/
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_windowmanager_types.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "WM_types.hh"
#include "op_handlers/intern/wm_op_handlers_intern.h"
#include "op_handlers/wm_op_handlers.h"
/* -------------------------------------------------------------------------- */
/** \name Public API
* \{ */
struct wmOpHandlers *WM_op_handlers_create(void)
{
struct wmOpHandlers *op_handlers = (wmOpHandlers*) MEM_callocN(sizeof(*op_handlers), __func__);
return op_handlers;
}
void WM_op_handlers_destroy(struct wmOpHandlers *op_handlers)
{
LISTBASE_FOREACH (wmOpHandlerData *, opHandlers, &op_handlers->handlers ) {
BLI_freelistN(&opHandlers->pre_invoke);
BLI_freelistN(&opHandlers->post_invoke);
BLI_freelistN(&opHandlers->modal);
BLI_freelistN(&opHandlers->modal_end);
}
BLI_freelistN(&op_handlers->handlers);
MEM_freeN(op_handlers);
op_handlers = NULL;
}
ListBase *WM_op_handlers_get_handler_list(wmOpHandlerData *opHandlers, int id)
{
ListBase *list = NULL;
switch (id) {
case HANDLER_TYPE_PRE_INVOKE:
list = &opHandlers->pre_invoke;
break;
case HANDLER_TYPE_POST_INVOKE:
list = &opHandlers->post_invoke;
break;
case HANDLER_TYPE_MODAL:
list = &opHandlers->modal;
break;
case HANDLER_TYPE_MODAL_END:
list = &opHandlers->modal_end;
break;
default:
BLI_assert(false);
}
return list;
}
wmOpHandlerData *WM_get_op_handlers(struct wmOpHandlers *op_handlers, const char *op_name)
{
return (wmOpHandlerData*) BLI_findstring(&op_handlers->handlers, op_name, offsetof(wmOpHandlerData, id_name));
}
void WM_op_handlers_append(struct wmOpHandlers *op_handlers,
int id,
void *py_handle,
const char *op_name,
bool (*cb)(struct bContext *, const struct wmEvent *event, void *, PointerRNA *properties, int),
int (*check)(void *, void*, void*),
bool (*poll)(struct bContext *, const struct wmEvent *event, void *, PointerRNA *properties),
void *py_data)
{
wmOpHandlerData *opHandlers = WM_get_op_handlers(op_handlers, op_name);
wmHandlerData *data = (wmHandlerData *)MEM_mallocN(sizeof(wmHandlerData), "wmHandlerData");
if (opHandlers == NULL) {
// Create
opHandlers = (wmOpHandlerData *) MEM_callocN(sizeof(wmOpHandlerData), "wmOpHandlerData");
BLI_strncpy(opHandlers->id_name, op_name, OP_MAX_TYPENAME);
BLI_addtail(&op_handlers->handlers, opHandlers);
}
data->py_handle = py_handle;
data->id_name = opHandlers->id_name;
data->cb = cb;
data->check = check;
data->poll = poll;
data->py_data = py_data;
ListBase *list = WM_op_handlers_get_handler_list(opHandlers, id);
BLI_addtail(list, data);
}
int WM_op_handlers_remove_all(struct wmOpHandlers *op_handlers, void *cb, void *owner)
{
int ret = 0;
LISTBASE_FOREACH (wmOpHandlerData *, opHandlers, &op_handlers->handlers) {
ret += WM_op_handlers_remove(op_handlers, HANDLER_TYPE_PRE_INVOKE, opHandlers->id_name, cb, owner);
ret += WM_op_handlers_remove(op_handlers, HANDLER_TYPE_POST_INVOKE, opHandlers->id_name, cb, owner);
ret += WM_op_handlers_remove(op_handlers, HANDLER_TYPE_MODAL, opHandlers->id_name, cb, owner);
ret += WM_op_handlers_remove(op_handlers, HANDLER_TYPE_MODAL_END, opHandlers->id_name, cb, owner);
}
return ret;
}
int WM_op_handlers_remove(
struct wmOpHandlers *op_handlers, int id, const char *op_name, void *cb, void *owner)
{
int ret = 0;
if (id == HANDLER_TYPE_ALL) {
ret = WM_op_handlers_remove_all(op_handlers, cb, owner);
}
else {
wmOpHandlerData *opHandlers = WM_get_op_handlers(op_handlers, op_name);
if (opHandlers != NULL) {
ListBase *list = WM_op_handlers_get_handler_list(opHandlers, id);
wmHandlerData *next;
for (wmHandlerData *data = (wmHandlerData*) list->first; data; data = next) {
next = data->next;
if (data->check(data->py_data, owner, cb)) {
BLI_freelinkN(list, data);
ret++;
}
}
}
}
return ret;
}
bool WM_op_handlers_operator_exec(struct bContext *C,
const wmEvent *event,
ListBase *list,
struct wmOperatorType *ot,
struct PointerRNA *properties,
int retval)
{
bool ret = true;
LISTBASE_FOREACH (wmHandlerData *, data, list) {
if (data->poll == nullptr || data->poll(C, event, data->py_data, properties)) {
ret = ret && data->cb(C, event, data->py_data, properties, retval);
}
}
return ret;
}
// Previous to invoke
bool WM_op_handlers_operator_pre_invoke(struct bContext *C,
const wmEvent *event,
struct wmOpHandlers *op_handlers,
struct wmOperatorType *ot,
PointerRNA *properties)
{
bool ret = true;
if (op_handlers != NULL) {
wmOpHandlerData *opHandlers = WM_get_op_handlers(op_handlers, ot->idname);
if (opHandlers != NULL) {
ListBase *list = WM_op_handlers_get_handler_list(opHandlers, HANDLER_TYPE_PRE_INVOKE);
ret = ret && WM_op_handlers_operator_exec(C, event, list, ot, properties, 0);
}
}
return ret;
}
// Post To invoke
void WM_op_handlers_operator_post_invoke(struct bContext *C,
const wmEvent *event,
struct wmOpHandlers *op_handlers,
struct wmOperatorType *ot,
struct PointerRNA *properties,
int retval)
{
if (op_handlers != NULL) {
wmOpHandlerData *opHandlers = WM_get_op_handlers(op_handlers, ot->idname);
if (opHandlers != NULL) {
ListBase *list = WM_op_handlers_get_handler_list(opHandlers, HANDLER_TYPE_POST_INVOKE);
WM_op_handlers_operator_exec(C, event, list, ot, properties, retval);
}
}
}
bool WM_op_handlers_operator_modal(struct bContext *C,
const wmEvent *event,
struct wmOpHandlers *op_handlers,
struct wmOperatorType *ot,
int retval
)
{
bool ret = true;
if (op_handlers != NULL) {
wmOpHandlerData *opHandlers = WM_get_op_handlers(op_handlers, ot->idname);
if (opHandlers != NULL) {
ListBase *list = WM_op_handlers_get_handler_list(opHandlers, HANDLER_TYPE_MODAL);
ret = ret && WM_op_handlers_operator_exec(C, event, list, ot, NULL, retval);
}
}
return ret;
}
void WM_op_handlers_operator_modal_end(struct bContext *C,
const wmEvent *event,
struct wmOpHandlers *op_handlers,
struct wmOperatorType *ot,
int retval)
{
if (op_handlers != NULL) {
wmOpHandlerData *opHandlers = WM_get_op_handlers(op_handlers, ot->idname);
if (opHandlers != NULL) {
ListBase *list = WM_op_handlers_get_handler_list(opHandlers, HANDLER_TYPE_MODAL_END);
WM_op_handlers_operator_exec(C, event, list, ot, NULL, retval);
}
}
}
/** \} */

View File

@ -0,0 +1,36 @@
/*
* 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
* of the License, or (at your option) any later version.
*
* 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup wm
*/
#pragma once
#include "../wm_op_handlers.h"
typedef struct wmHandlerData {
struct wmHandlerData *next, *prev;
char *id_name; // Pointer to wmOpHandlerData.id_name
void *py_handle;
void *py_data;
bool (*cb)(struct bContext *, const wmEvent *event, void *, PointerRNA *properties, int); // callback
int (*check)(void *, void*, void*);
bool (*poll)(struct bContext *, const wmEvent *event, void *, PointerRNA *properties);
} wmHandlerData;

View File

@ -0,0 +1,101 @@
/*
* 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
* of the License, or (at your option) any later version.
*
* 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup wm
*/
#pragma once
#include <stdio.h>
#include "RNA_types.hh"
#define HANDLER_TYPE_ALL 0
#define HANDLER_TYPE_PRE_INVOKE 1
#define HANDLER_TYPE_POST_INVOKE 2
#define HANDLER_TYPE_MODAL 3
#define HANDLER_TYPE_MODAL_END 4
#ifdef __cplusplus
extern "C" {
#endif
struct wmOpHandlers {
/** Handlers in order of being added. */
ListBase handlers;
};
typedef struct wmOpHandlerData {
struct wmOpHandlerData *next, *prev;
char id_name[OP_MAX_TYPENAME];
/** Handlers in order of being added. */
ListBase pre_invoke;
ListBase post_invoke;
ListBase modal;
ListBase modal_end;
} wmOpHandlerData;
struct wmOpHandlers *WM_op_handlers_create(void);
void WM_op_handlers_destroy(struct wmOpHandlers *opHandlers);
wmOpHandlerData *WM_get_op_handlers(struct wmOpHandlers *op_handlers, const char *op_name);
void WM_op_handlers_append(struct wmOpHandlers *op_handlers, int id,
void *handle,
const char *op_name,
bool (*cb)(struct bContext *, const struct wmEvent *event, void *, PointerRNA *properties, int),
int (*check)(void *, void*, void *),
bool (*poll)(struct bContext *, const struct wmEvent *event, void *, PointerRNA *properties),
void *py_data);
int WM_op_handlers_remove(struct wmOpHandlers *op_handlers,
int id,
const char *op_name,
void *cb,
void *owner);
bool WM_op_handlers_operator_pre_invoke(struct bContext *C,
const struct wmEvent *event,
struct wmOpHandlers *op_handlers,
struct wmOperatorType *ot,
PointerRNA *properties);
void WM_op_handlers_operator_post_invoke(struct bContext *C,
const struct wmEvent *event,
struct wmOpHandlers *op_handlers,
struct wmOperatorType *ot,
PointerRNA *properties, int retval);
bool WM_op_handlers_operator_modal(struct bContext *C,
const struct wmEvent *event,
struct wmOpHandlers *op_handlers,
struct wmOperatorType *ot, int retval);
void WM_op_handlers_operator_modal_end(struct bContext *C,
const struct wmEvent *event,
struct wmOpHandlers *op_handlers,
struct wmOperatorType *ot,
int retval);
#ifdef __cplusplus
}
#endif

View File

@ -98,6 +98,7 @@ void wm_autosave_delete();
void WM_OT_splash(wmOperatorType *ot);
void WM_OT_splash_about(wmOperatorType *ot);
void WM_OT_splash_custom(wmOperatorType *ot);
/* `wm_stereo.cc` */

View File

@ -12,6 +12,7 @@ set(INC
../blender/makesrna
../blender/render
../blender/windowmanager
../blender/tornavis
)
set(LIB
@ -21,6 +22,7 @@ set(LIB
PRIVATE bf::intern::clog
PRIVATE bf::intern::guardedalloc
bf_windowmanager
tornavis
)
if(HAVE_FEENABLEEXCEPT)
@ -477,6 +479,13 @@ install(
DESTINATION ${TARGETDIR_VER}/datafiles
)
#tornavis
install(
DIRECTORY ${CMAKE_SOURCE_DIR}/release/datafiles/tornavis
DESTINATION ${TARGETDIR_VER}/datafiles
)
# localization
if(WITH_INTERNATIONAL)
set(_locale_dir "${CMAKE_SOURCE_DIR}/locale")

View File

@ -51,6 +51,8 @@
#include "BKE_vfont.hh"
#include "BKE_volume.hh"
#include "MB_tornavis.h"
#ifndef WITH_PYTHON_MODULE
# include "BLI_args.h"
#endif
@ -467,6 +469,8 @@ int main(int argc,
/* After parsing number of threads argument. */
BLI_task_scheduler_init();
MB_init();
#ifndef WITH_PYTHON_MODULE
/* The settings pass includes:
* - Background-mode assignment (#Global.background), checked by other subsystems

View File

@ -47,6 +47,8 @@
# include "GPU_context.h"
# include "MB_tornavis.h"
# ifdef WITH_FFMPEG
# include "IMB_imbuf.hh"
# endif
@ -1479,6 +1481,16 @@ static int arg_handle_start_with_console(int /*argc*/, const char ** /*argv*/, v
return 0;
}
static const char arg_handle_tornavis_info_doc[] =
"\n\t"
"Shows Tornavis project info on loading.";
static int arg_handle_tornavis_info(int /*argc*/, const char ** /*argv*/, void * /*data*/)
{
MB_print_info();
return 0;
}
static const char arg_handle_register_extension_doc[] =
"\n\t"
"Register blend-file extension for current user, then exit (Windows only).";
@ -2523,6 +2535,8 @@ void main_args_setup(bContext *C, bArgs *ba, bool all)
BLI_args_add(ba, nullptr, "--open-last", CB(arg_handle_load_last_file), C);
BLI_args_add(ba, nullptr, "--tornavis-info", CB(arg_handle_tornavis_info), nullptr);
# undef CB
# undef CB_EX
# undef CB_ALL

2
tornavis/patches.py Normal file
View File

@ -0,0 +1,2 @@
names = []