forked from bartvdbraak/blender
Tool System: experimental fallback tool support
Implement T66304 as an experimental option, available under the preferences "Experimental" section. - When enabled most tools in the 3D view have a gizmo. - Dragging outside the gizmo uses the 'fallback' tool. - The fallback tool can be changed or disabled in the tool options or from a pie menu (Alt-W).
This commit is contained in:
parent
7465078e63
commit
6ffcddc10a
@ -412,6 +412,8 @@ def km_window(params):
|
||||
("wm.batch_rename", {"type": 'F2', "value": 'PRESS', "ctrl": True}, None),
|
||||
("wm.search_menu", {"type": 'F3', "value": 'PRESS'}, None),
|
||||
op_menu("TOPBAR_MT_file_context_menu", {"type": 'F4', "value": 'PRESS'}),
|
||||
# Pass through when when no tool-system exists or the fallback isn't available.
|
||||
("wm.toolbar_fallback_pie", {"type": 'W', "value": 'PRESS', "alt": True}, None),
|
||||
# Alt as "Leader-Key".
|
||||
("wm.toolbar_prompt", {"type": 'LEFT_ALT', "value": 'CLICK'}, None),
|
||||
("wm.toolbar_prompt", {"type": 'RIGHT_ALT', "value": 'CLICK'}, None),
|
||||
|
@ -1645,6 +1645,12 @@ class WM_OT_tool_set_by_id(Operator):
|
||||
default=False,
|
||||
options={'SKIP_SAVE'},
|
||||
)
|
||||
as_fallback: BoolProperty(
|
||||
name="Set Fallback",
|
||||
description="Set the fallback tool instead of the primary tool",
|
||||
default=False,
|
||||
options={'SKIP_SAVE', 'HIDDEN'},
|
||||
)
|
||||
|
||||
space_type: rna_space_type_prop
|
||||
|
||||
@ -1672,7 +1678,10 @@ class WM_OT_tool_set_by_id(Operator):
|
||||
space_type = context.space_data.type
|
||||
|
||||
fn = activate_by_id_or_cycle if self.cycle else activate_by_id
|
||||
if fn(context, space_type, self.name):
|
||||
if fn(context, space_type, self.name, as_fallback=self.as_fallback):
|
||||
if self.as_fallback:
|
||||
tool_settings = context.tool_settings
|
||||
tool_settings.workspace_tool_type = 'FALLBACK'
|
||||
return {'FINISHED'}
|
||||
else:
|
||||
self.report({'WARNING'}, f"Tool {self.name!r:s} not found for space {space_type!r:s}.")
|
||||
@ -1699,13 +1708,20 @@ class WM_OT_tool_set_by_index(Operator):
|
||||
default=True,
|
||||
)
|
||||
|
||||
as_fallback: BoolProperty(
|
||||
name="Set Fallback",
|
||||
description="Set the fallback tool instead of the primary",
|
||||
default=False,
|
||||
options={'SKIP_SAVE', 'HIDDEN'},
|
||||
)
|
||||
|
||||
space_type: rna_space_type_prop
|
||||
|
||||
def execute(self, context):
|
||||
from bl_ui.space_toolsystem_common import (
|
||||
activate_by_id,
|
||||
activate_by_id_or_cycle,
|
||||
item_from_index,
|
||||
item_from_index_active,
|
||||
item_from_flat_index,
|
||||
)
|
||||
|
||||
@ -1714,7 +1730,7 @@ class WM_OT_tool_set_by_index(Operator):
|
||||
else:
|
||||
space_type = context.space_data.type
|
||||
|
||||
fn = item_from_flat_index if self.expand else item_from_index
|
||||
fn = item_from_flat_index if self.expand else item_from_index_active
|
||||
item = fn(context, space_type, self.index)
|
||||
if item is None:
|
||||
# Don't report, since the number of tools may change.
|
||||
@ -1722,7 +1738,10 @@ class WM_OT_tool_set_by_index(Operator):
|
||||
|
||||
# Same as: WM_OT_tool_set_by_id
|
||||
fn = activate_by_id_or_cycle if self.cycle else activate_by_id
|
||||
if fn(context, space_type, item.idname):
|
||||
if fn(context, space_type, item.idname, as_fallback=self.as_fallback):
|
||||
if self.as_fallback:
|
||||
tool_settings = context.tool_settings
|
||||
tool_settings.workspace_tool_type = 'FALLBACK'
|
||||
return {'FINISHED'}
|
||||
else:
|
||||
# Since we already have the tool, this can't happen.
|
||||
@ -1776,6 +1795,41 @@ class WM_OT_toolbar(Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class WM_OT_toolbar_fallback_pie(Operator):
|
||||
bl_idname = "wm.toolbar_fallback_pie"
|
||||
bl_label = "Fallback Tool Pie Menu"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.space_data is not None
|
||||
|
||||
def invoke(self, context, event):
|
||||
if not context.preferences.experimental.use_tool_fallback:
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
|
||||
space_type = context.space_data.type
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is None:
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
# It's possible we don't have the fallback tool available.
|
||||
# This can happen in the image editor for example when there is no selection
|
||||
# in painting modes.
|
||||
item, _ = cls._tool_get_by_id(context, space_type, cls.tool_fallback_id)
|
||||
if item is None:
|
||||
print("Tool", cls.tool_fallback_id, "not active in", cls)
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
def draw_cb(self, context):
|
||||
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
|
||||
ToolSelectPanelHelper.draw_fallback_tool_items_for_pie_menu(self.layout, context)
|
||||
|
||||
wm = context.window_manager
|
||||
wm.popup_menu_pie(draw_func=draw_cb, title="Fallback Tool", event=event)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class WM_OT_toolbar_prompt(Operator):
|
||||
"""Leader key like functionality for accessing tools"""
|
||||
bl_idname = "wm.toolbar_prompt"
|
||||
@ -2563,6 +2617,7 @@ classes = (
|
||||
WM_OT_tool_set_by_id,
|
||||
WM_OT_tool_set_by_index,
|
||||
WM_OT_toolbar,
|
||||
WM_OT_toolbar_fallback_pie,
|
||||
WM_OT_toolbar_prompt,
|
||||
BatchRenameAction,
|
||||
WM_OT_batch_rename,
|
||||
|
@ -162,7 +162,7 @@ class ToolActivePanelHelper:
|
||||
layout.use_property_decorate = False
|
||||
ToolSelectPanelHelper.draw_active_tool_header(
|
||||
context,
|
||||
layout,
|
||||
layout.column(),
|
||||
show_tool_name=True,
|
||||
tool_key=ToolSelectPanelHelper._tool_key_from_context(context, space_type=self.bl_space_type),
|
||||
)
|
||||
@ -262,76 +262,100 @@ class ToolSelectPanelHelper:
|
||||
else:
|
||||
yield item, -1
|
||||
|
||||
@staticmethod
|
||||
def _tool_get_active(context, space_type, mode, with_icon=False):
|
||||
@classmethod
|
||||
def _tool_get_active(cls, context, space_type, mode, with_icon=False):
|
||||
"""
|
||||
Return the active Python tool definition and icon name.
|
||||
"""
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is not None:
|
||||
tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type, mode)
|
||||
tool_active_id = getattr(tool_active, "idname", None)
|
||||
for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context, mode)):
|
||||
if item is not None:
|
||||
if item.idname == tool_active_id:
|
||||
if with_icon:
|
||||
icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon)
|
||||
else:
|
||||
icon_value = 0
|
||||
return (item, tool_active, icon_value)
|
||||
tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type, mode)
|
||||
tool_active_id = getattr(tool_active, "idname", None)
|
||||
for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context, mode)):
|
||||
if item is not None:
|
||||
if item.idname == tool_active_id:
|
||||
if with_icon:
|
||||
icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon)
|
||||
else:
|
||||
icon_value = 0
|
||||
return (item, tool_active, icon_value)
|
||||
return None, None, 0
|
||||
|
||||
@staticmethod
|
||||
def _tool_get_by_id(context, space_type, idname):
|
||||
@classmethod
|
||||
def _tool_get_by_id(cls, context, space_type, idname):
|
||||
"""
|
||||
Return the active Python tool definition and index (if in sub-group, else -1).
|
||||
"""
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is not None:
|
||||
for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)):
|
||||
if item is not None:
|
||||
if item.idname == idname:
|
||||
return (cls, item, index)
|
||||
return None, None, -1
|
||||
for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)):
|
||||
if item is not None:
|
||||
if item.idname == idname:
|
||||
return (item, index)
|
||||
return None, -1
|
||||
|
||||
@staticmethod
|
||||
def _tool_get_by_flat_index(context, space_type, tool_index):
|
||||
@classmethod
|
||||
def _tool_get_by_id_active(cls, context, space_type, idname):
|
||||
"""
|
||||
Return the active Python tool definition and index (if in sub-group, else -1).
|
||||
"""
|
||||
for item in cls.tools_from_context(context):
|
||||
if item is not None:
|
||||
if type(item) is tuple:
|
||||
if item[0].idname == idname:
|
||||
index = cls._tool_group_active.get(item[0].idname, 0)
|
||||
return (item[index], index)
|
||||
else:
|
||||
if item.idname == idname:
|
||||
return (item, -1)
|
||||
return None, -1
|
||||
|
||||
@classmethod
|
||||
def _tool_get_by_id_active_with_group(cls, context, space_type, idname):
|
||||
"""
|
||||
Return the active Python tool definition and index (if in sub-group, else -1).
|
||||
"""
|
||||
for item in cls.tools_from_context(context):
|
||||
if item is not None:
|
||||
if type(item) is tuple:
|
||||
if item[0].idname == idname:
|
||||
index = cls._tool_group_active.get(item[0].idname, 0)
|
||||
return (item[index], index, item)
|
||||
else:
|
||||
if item.idname == idname:
|
||||
return (item, -1, None)
|
||||
return None, -1, None
|
||||
|
||||
@classmethod
|
||||
def _tool_get_by_flat_index(cls, context, space_type, tool_index):
|
||||
"""
|
||||
Return the active Python tool definition and index (if in sub-group, else -1).
|
||||
|
||||
Return the index of the expanded list.
|
||||
"""
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is not None:
|
||||
i = 0
|
||||
for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)):
|
||||
if item is not None:
|
||||
if i == tool_index:
|
||||
return (cls, item, index)
|
||||
i += 1
|
||||
return None, None, -1
|
||||
i = 0
|
||||
for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)):
|
||||
if item is not None:
|
||||
if i == tool_index:
|
||||
return (item, index)
|
||||
i += 1
|
||||
return None, -1
|
||||
|
||||
@staticmethod
|
||||
def _tool_get_by_index(context, space_type, tool_index):
|
||||
@classmethod
|
||||
def _tool_get_active_by_index(cls, context, space_type, tool_index):
|
||||
"""
|
||||
Return the active Python tool definition and index (if in sub-group, else -1).
|
||||
|
||||
Return the index of the list without expanding.
|
||||
"""
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is not None:
|
||||
i = 0
|
||||
for item in cls.tools_from_context(context):
|
||||
if item is not None:
|
||||
if i == tool_index:
|
||||
if type(item) is tuple:
|
||||
index = cls._tool_group_active.get(item[0].idname, 0)
|
||||
item = item[index]
|
||||
else:
|
||||
index = -1
|
||||
return (cls, item, index)
|
||||
i += 1
|
||||
return None, None, -1
|
||||
i = 0
|
||||
for item in cls.tools_from_context(context):
|
||||
if item is not None:
|
||||
if i == tool_index:
|
||||
if type(item) is tuple:
|
||||
index = cls._tool_group_active.get(item[0].idname, 0)
|
||||
item = item[index]
|
||||
else:
|
||||
index = -1
|
||||
return (item, index)
|
||||
i += 1
|
||||
return None, -1
|
||||
|
||||
@staticmethod
|
||||
def _tool_active_from_context(context, space_type, mode=None, create=False):
|
||||
@ -633,6 +657,24 @@ class ToolSelectPanelHelper:
|
||||
space_type = context.space_data.type
|
||||
return ToolSelectPanelHelper._tool_active_from_context(context, space_type)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def draw_active_tool_fallback(
|
||||
context, layout, tool,
|
||||
*,
|
||||
is_horizontal_layout=False,
|
||||
):
|
||||
tool_fallback = tool.tool_fallback
|
||||
space_type = tool.space_type
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
item_fallback, _index = cls._tool_get_by_id(context, space_type, tool_fallback)
|
||||
if item_fallback is not None:
|
||||
draw_settings = item_fallback.draw_settings
|
||||
if draw_settings is not None:
|
||||
if not is_horizontal_layout:
|
||||
layout.separator()
|
||||
draw_settings(context, layout, tool)
|
||||
|
||||
@staticmethod
|
||||
def draw_active_tool_header(
|
||||
context, layout,
|
||||
@ -640,6 +682,7 @@ class ToolSelectPanelHelper:
|
||||
show_tool_name=False,
|
||||
tool_key=None,
|
||||
):
|
||||
is_horizontal_layout = layout.direction != 'VERTICAL'
|
||||
if tool_key is None:
|
||||
space_type, mode = ToolSelectPanelHelper._tool_key_from_context(context)
|
||||
else:
|
||||
@ -647,7 +690,9 @@ class ToolSelectPanelHelper:
|
||||
|
||||
if space_type is None:
|
||||
return None
|
||||
item, tool, icon_value = ToolSelectPanelHelper._tool_get_active(context, space_type, mode, with_icon=True)
|
||||
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
item, tool, icon_value = cls._tool_get_active(context, space_type, mode, with_icon=True)
|
||||
if item is None:
|
||||
return None
|
||||
# Note: we could show 'item.text' here but it makes the layout jitter when switching tools.
|
||||
@ -658,8 +703,128 @@ class ToolSelectPanelHelper:
|
||||
draw_settings = item.draw_settings
|
||||
if draw_settings is not None:
|
||||
draw_settings(context, layout, tool)
|
||||
|
||||
if context.preferences.experimental.use_tool_fallback:
|
||||
tool_fallback = tool.tool_fallback
|
||||
else:
|
||||
tool_fallback = None
|
||||
|
||||
if tool_fallback and tool_fallback != item.idname:
|
||||
tool_settings = context.tool_settings
|
||||
|
||||
# Show popover which looks like an enum but isn't one.
|
||||
if tool_settings.workspace_tool_type == 'FALLBACK':
|
||||
tool_fallback_id = cls.tool_fallback_id
|
||||
item, _select_index = cls._tool_get_by_id_active(context, space_type, tool_fallback_id)
|
||||
label = item.label
|
||||
else:
|
||||
label = "Active Tool"
|
||||
|
||||
split = layout.split(factor=0.5)
|
||||
row = split.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Drag")
|
||||
row = split.row()
|
||||
row.context_pointer_set("tool", tool)
|
||||
row.popover(panel="TOPBAR_PT_tool_fallback", text=label)
|
||||
|
||||
return tool
|
||||
|
||||
# Show a list of tools in the popover.
|
||||
@staticmethod
|
||||
def draw_fallback_tool_items(layout, context):
|
||||
|
||||
space_type = context.space_data.type
|
||||
if space_type == 'PROPERTIES':
|
||||
space_type = 'VIEW_3D'
|
||||
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
tool_fallback_id = cls.tool_fallback_id
|
||||
|
||||
_item, _select_index, item_group = cls._tool_get_by_id_active_with_group(context, space_type, tool_fallback_id)
|
||||
|
||||
if item_group is None:
|
||||
# Could print comprehensive message - listing available items.
|
||||
raise Exception("Fallback tool doesn't exist")
|
||||
|
||||
col = layout.column(align=True)
|
||||
tool_settings = context.tool_settings
|
||||
col.prop_enum(
|
||||
tool_settings,
|
||||
"workspace_tool_type",
|
||||
value='DEFAULT',
|
||||
text="Active Tool",
|
||||
)
|
||||
is_active_tool = (tool_settings.workspace_tool_type == 'DEFAULT')
|
||||
|
||||
col = layout.column(align=True)
|
||||
if is_active_tool:
|
||||
index_current = -1
|
||||
else:
|
||||
index_current = cls._tool_group_active.get(item_group[0].idname, 0)
|
||||
for i, sub_item in enumerate(item_group):
|
||||
is_active = (i == index_current)
|
||||
|
||||
props = col.operator(
|
||||
"wm.tool_set_by_id",
|
||||
text=sub_item.label,
|
||||
depress=is_active,
|
||||
)
|
||||
props.name = sub_item.idname
|
||||
props.as_fallback = True
|
||||
props.space_type = space_type
|
||||
|
||||
@staticmethod
|
||||
def draw_fallback_tool_items_for_pie_menu(layout, context):
|
||||
space_type = context.space_data.type
|
||||
if space_type == 'PROPERTIES':
|
||||
space_type = 'VIEW_3D'
|
||||
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
tool_fallback_id = cls.tool_fallback_id
|
||||
|
||||
_item, _select_index, item_group = cls._tool_get_by_id_active_with_group(context, space_type, tool_fallback_id)
|
||||
|
||||
if item_group is None:
|
||||
# Could print comprehensive message - listing available items.
|
||||
raise Exception("Fallback tool doesn't exist")
|
||||
|
||||
# Allow changing the active tool,
|
||||
# even though this isn't the purpose of the pie menu
|
||||
# it's confusing from a user perspective if we don't allow it.
|
||||
is_fallback_group_active = getattr(
|
||||
ToolSelectPanelHelper._tool_active_from_context(context, space_type),
|
||||
"idname", None,
|
||||
) in (item.idname for item in item_group)
|
||||
|
||||
pie = layout.menu_pie()
|
||||
tool_settings = context.tool_settings
|
||||
pie.prop_enum(
|
||||
tool_settings,
|
||||
"workspace_tool_type",
|
||||
value='DEFAULT',
|
||||
text="Active Tool",
|
||||
icon='TOOL_SETTINGS', # Could use a less generic icon.
|
||||
)
|
||||
is_active_tool = (tool_settings.workspace_tool_type == 'DEFAULT')
|
||||
|
||||
if is_active_tool:
|
||||
index_current = -1
|
||||
else:
|
||||
index_current = cls._tool_group_active.get(item_group[0].idname, 0)
|
||||
for i, sub_item in enumerate(item_group):
|
||||
is_active = (i == index_current)
|
||||
props = pie.operator(
|
||||
"wm.tool_set_by_id",
|
||||
text=sub_item.label,
|
||||
depress=is_active,
|
||||
icon_value=ToolSelectPanelHelper._icon_value_from_icon_handle(sub_item.icon),
|
||||
)
|
||||
props.name = sub_item.idname
|
||||
props.space_type = space_type
|
||||
if not is_fallback_group_active:
|
||||
props.as_fallback = True
|
||||
|
||||
|
||||
# The purpose of this menu is to be a generic popup to select between tools
|
||||
# in cases when a single tool allows to select alternative tools.
|
||||
@ -701,7 +866,43 @@ class WM_MT_toolsystem_submenu(Menu):
|
||||
).name = item.idname
|
||||
|
||||
|
||||
def _activate_by_item(context, space_type, item, index):
|
||||
def _activate_by_item(context, space_type, item, index, *, as_fallback=False):
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
tool_fallback_id = cls.tool_fallback_id
|
||||
|
||||
if as_fallback:
|
||||
# To avoid complicating logic too much, isolate all fallback logic to this block.
|
||||
# This will set the tool again, using the item for the fallback instead of the primary tool.
|
||||
#
|
||||
# If this ends up needing to be more complicated,
|
||||
# it would be better to split it into a separate function.
|
||||
|
||||
_item, _select_index, item_group = cls._tool_get_by_id_active_with_group(context, space_type, tool_fallback_id)
|
||||
|
||||
if item_group is None:
|
||||
# Could print comprehensive message - listing available items.
|
||||
raise Exception("Fallback tool doesn't exist")
|
||||
index_new = -1
|
||||
for i, sub_item in enumerate(item_group):
|
||||
if sub_item.idname == item.idname:
|
||||
index_new = i
|
||||
break
|
||||
if index_new == -1:
|
||||
raise Exception("Fallback tool not found in group")
|
||||
|
||||
cls._tool_group_active[tool_fallback_id] = index_new
|
||||
|
||||
# Done, now get the current tool to replace the item & index.
|
||||
tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type)
|
||||
item, index = cls._tool_get_by_id(context, space_type, getattr(tool_active, "idname", None))
|
||||
|
||||
# Find fallback keymap.
|
||||
item_fallback = None
|
||||
_item, select_index = cls._tool_get_by_id(context, space_type, tool_fallback_id)
|
||||
if select_index != -1:
|
||||
item_fallback, _index = cls._tool_get_active_by_index(context, space_type, select_index)
|
||||
# End calculating fallback.
|
||||
|
||||
tool = ToolSelectPanelHelper._tool_active_from_context(context, space_type, create=True)
|
||||
tool.setup(
|
||||
idname=item.idname,
|
||||
@ -711,6 +912,9 @@ def _activate_by_item(context, space_type, item, index):
|
||||
data_block=item.data_block or "",
|
||||
operator=item.operator or "",
|
||||
index=index,
|
||||
|
||||
idname_fallback=item_fallback.idname if item_fallback else "",
|
||||
keymap_fallback=(item_fallback.keymap[0] or "") if item_fallback else "",
|
||||
)
|
||||
|
||||
WindowManager = bpy.types.WindowManager
|
||||
@ -729,18 +933,22 @@ def _activate_by_item(context, space_type, item, index):
|
||||
_activate_by_item._cursor_draw_handle = {}
|
||||
|
||||
|
||||
def activate_by_id(context, space_type, text):
|
||||
_cls, item, index = ToolSelectPanelHelper._tool_get_by_id(context, space_type, text)
|
||||
def activate_by_id(context, space_type, idname, *, as_fallback=False):
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is None:
|
||||
return False
|
||||
item, index = cls._tool_get_by_id(context, space_type, idname)
|
||||
if item is None:
|
||||
return False
|
||||
_activate_by_item(context, space_type, item, index)
|
||||
_activate_by_item(context, space_type, item, index, as_fallback=as_fallback)
|
||||
return True
|
||||
|
||||
|
||||
def activate_by_id_or_cycle(context, space_type, idname, offset=1):
|
||||
def activate_by_id_or_cycle(context, space_type, idname, *, offset=1, as_fallback=False):
|
||||
|
||||
# Only cycle when the active tool is activated again.
|
||||
cls, item, _index = ToolSelectPanelHelper._tool_get_by_id(context, space_type, idname)
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
item, _index = cls._tool_get_by_id(context, space_type, idname)
|
||||
if item is None:
|
||||
return False
|
||||
|
||||
@ -774,7 +982,8 @@ def activate_by_id_or_cycle(context, space_type, idname, offset=1):
|
||||
|
||||
def description_from_id(context, space_type, idname, *, use_operator=True):
|
||||
# Used directly for tooltips.
|
||||
_cls, item, _index = ToolSelectPanelHelper._tool_get_by_id(context, space_type, idname)
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
item, _index = cls._tool_get_by_id(context, space_type, idname)
|
||||
if item is None:
|
||||
return False
|
||||
|
||||
@ -806,23 +1015,52 @@ def description_from_id(context, space_type, idname, *, use_operator=True):
|
||||
|
||||
def item_from_id(context, space_type, idname):
|
||||
# Used directly for tooltips.
|
||||
_cls, item, _index = ToolSelectPanelHelper._tool_get_by_id(context, space_type, idname)
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is None:
|
||||
return None
|
||||
item, _index = cls._tool_get_by_id(context, space_type, idname)
|
||||
return item
|
||||
|
||||
|
||||
def item_from_id_active(context, space_type, idname):
|
||||
# Used directly for tooltips.
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is None:
|
||||
return None
|
||||
item, _index = cls._tool_get_by_id_active(context, space_type, idname)
|
||||
return item
|
||||
|
||||
|
||||
def item_from_id_active_with_group(context, space_type, idname):
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is None:
|
||||
return None
|
||||
cls, item, _index = cls._tool_get_by_id_active_with_group(context, space_type, idname)
|
||||
return item
|
||||
|
||||
|
||||
def item_from_flat_index(context, space_type, index):
|
||||
_cls, item, _index = ToolSelectPanelHelper._tool_get_by_flat_index(context, space_type, index)
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is None:
|
||||
return None
|
||||
item, _index = cls._tool_get_by_flat_index(context, space_type, index)
|
||||
return item
|
||||
|
||||
|
||||
def item_from_index(context, space_type, index):
|
||||
_cls, item, _index = ToolSelectPanelHelper._tool_get_by_index(context, space_type, index)
|
||||
def item_from_index_active(context, space_type, index):
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is None:
|
||||
return None
|
||||
item, _index = cls._tool_get_active_by_index(context, space_type, index)
|
||||
return item
|
||||
|
||||
|
||||
def keymap_from_id(context, space_type, idname):
|
||||
# Used directly for tooltips.
|
||||
_cls, item, _index = ToolSelectPanelHelper._tool_get_by_id(context, space_type, idname)
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
if cls is None:
|
||||
return None
|
||||
item, _index = cls._tool_get_by_id(context, space_type, idname)
|
||||
if item is None:
|
||||
return False
|
||||
|
||||
|
@ -297,8 +297,15 @@ class _defs_transform:
|
||||
if layout.use_property_split:
|
||||
layout.label(text="Gizmos:")
|
||||
|
||||
props = tool.gizmo_group_properties("VIEW3D_GGT_xform_gizmo")
|
||||
layout.prop(props, "drag_action")
|
||||
show_drag = True
|
||||
if context.preferences.experimental.use_tool_fallback:
|
||||
tool_settings = context.tool_settings
|
||||
if tool_settings.workspace_tool_type == 'FALLBACK':
|
||||
show_drag = False
|
||||
|
||||
if show_drag:
|
||||
props = tool.gizmo_group_properties("VIEW3D_GGT_xform_gizmo")
|
||||
layout.prop(props, "drag_action")
|
||||
|
||||
_template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 1)
|
||||
|
||||
@ -472,7 +479,7 @@ class _defs_edit_mesh:
|
||||
idname="builtin.rip_region",
|
||||
label="Rip Region",
|
||||
icon="ops.mesh.rip",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_free",
|
||||
keymap=(),
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
@ -512,7 +519,7 @@ class _defs_edit_mesh:
|
||||
idname="builtin.edge_slide",
|
||||
label="Edge Slide",
|
||||
icon="ops.transform.edge_slide",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_normal",
|
||||
keymap=(),
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
@ -527,7 +534,7 @@ class _defs_edit_mesh:
|
||||
idname="builtin.vertex_slide",
|
||||
label="Vertex Slide",
|
||||
icon="ops.transform.vert_slide",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_free",
|
||||
keymap=(),
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
@ -579,7 +586,7 @@ class _defs_edit_mesh:
|
||||
idname="builtin.inset_faces",
|
||||
label="Inset Faces",
|
||||
icon="ops.mesh.inset",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_normal",
|
||||
keymap=(),
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
@ -597,7 +604,7 @@ class _defs_edit_mesh:
|
||||
idname="builtin.bevel",
|
||||
label="Bevel",
|
||||
icon="ops.mesh.bevel",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_normal",
|
||||
keymap=(),
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
@ -629,7 +636,7 @@ class _defs_edit_mesh:
|
||||
idname="builtin.extrude_along_normals",
|
||||
label="Extrude Along Normals",
|
||||
icon="ops.mesh.extrude_region_shrink_fatten",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_normal",
|
||||
operator="mesh.extrude_region_shrink_fatten",
|
||||
keymap=(),
|
||||
draw_settings=draw_settings,
|
||||
@ -641,7 +648,7 @@ class _defs_edit_mesh:
|
||||
idname="builtin.extrude_individual",
|
||||
label="Extrude Individual",
|
||||
icon="ops.mesh.extrude_faces_move",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_normal",
|
||||
keymap=(),
|
||||
)
|
||||
|
||||
@ -698,7 +705,7 @@ class _defs_edit_mesh:
|
||||
idname="builtin.smooth",
|
||||
label="Smooth",
|
||||
icon="ops.mesh.vertices_smooth",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_normal",
|
||||
keymap=(),
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
@ -714,7 +721,7 @@ class _defs_edit_mesh:
|
||||
idname="builtin.randomize",
|
||||
label="Randomize",
|
||||
icon="ops.transform.vertex_random",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_normal",
|
||||
keymap=(),
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
@ -753,7 +760,7 @@ class _defs_edit_mesh:
|
||||
idname="builtin.shrink_fatten",
|
||||
label="Shrink/Fatten",
|
||||
icon="ops.transform.shrink_fatten",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_normal",
|
||||
keymap=(),
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
@ -764,7 +771,7 @@ class _defs_edit_mesh:
|
||||
idname="builtin.push_pull",
|
||||
label="Push/Pull",
|
||||
icon="ops.transform.push_pull",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_normal",
|
||||
keymap=(),
|
||||
)
|
||||
|
||||
@ -890,7 +897,7 @@ class _defs_edit_curve:
|
||||
idname="builtin.randomize",
|
||||
label="Randomize",
|
||||
icon="ops.curve.vertex_random",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_tool_generic_handle_normal",
|
||||
keymap=(),
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
@ -1682,6 +1689,9 @@ class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
|
||||
# Satisfy the 'ToolSelectPanelHelper' API.
|
||||
keymap_prefix = "Image Editor Tool:"
|
||||
|
||||
# Default group to use as a fallback.
|
||||
tool_fallback_id = "builtin.select"
|
||||
|
||||
@classmethod
|
||||
def tools_from_context(cls, context, mode=None):
|
||||
if mode is None:
|
||||
@ -1766,6 +1776,9 @@ class NODE_PT_tools_active(ToolSelectPanelHelper, Panel):
|
||||
# Satisfy the 'ToolSelectPanelHelper' API.
|
||||
keymap_prefix = "Node Editor Tool:"
|
||||
|
||||
# Default group to use as a fallback.
|
||||
tool_fallback_id = "builtin.select"
|
||||
|
||||
@classmethod
|
||||
def tools_from_context(cls, context, mode=None):
|
||||
if mode is None:
|
||||
@ -1822,6 +1835,9 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
|
||||
# Satisfy the 'ToolSelectPanelHelper' API.
|
||||
keymap_prefix = "3D View Tool:"
|
||||
|
||||
# Default group to use as a fallback.
|
||||
tool_fallback_id = "builtin.select"
|
||||
|
||||
@classmethod
|
||||
def tools_from_context(cls, context, mode=None):
|
||||
if mode is None:
|
||||
|
@ -78,6 +78,23 @@ class TOPBAR_HT_upper_bar(Header):
|
||||
unlink="scene.view_layer_remove")
|
||||
|
||||
|
||||
class TOPBAR_PT_tool_fallback(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "Layers"
|
||||
bl_ui_units_x = 8
|
||||
|
||||
def draw(self, context):
|
||||
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
|
||||
layout = self.layout
|
||||
|
||||
tool_settings = context.tool_settings
|
||||
ToolSelectPanelHelper.draw_fallback_tool_items(layout, context)
|
||||
if tool_settings.workspace_tool_type == 'FALLBACK':
|
||||
tool = context.tool
|
||||
ToolSelectPanelHelper.draw_active_tool_fallback(context, layout, tool)
|
||||
|
||||
|
||||
class TOPBAR_PT_gpencil_layers(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'HEADER'
|
||||
@ -772,6 +789,7 @@ classes = (
|
||||
TOPBAR_MT_render,
|
||||
TOPBAR_MT_window,
|
||||
TOPBAR_MT_help,
|
||||
TOPBAR_PT_tool_fallback,
|
||||
TOPBAR_PT_gpencil_layers,
|
||||
TOPBAR_PT_gpencil_primitive,
|
||||
TOPBAR_PT_gpencil_fill,
|
||||
|
@ -2188,6 +2188,12 @@ class USERPREF_PT_experimental_all(ExperimentalPanel, Panel):
|
||||
# For the other settings create new panels
|
||||
# and make sure they are disabled if use_experimental_all is True
|
||||
|
||||
url_prefix = "https://developer.blender.org/"
|
||||
|
||||
row = col.row()
|
||||
row.prop(experimental, "use_tool_fallback")
|
||||
|
||||
row.operator("wm.url_open", text="", icon='URL').url = url_prefix + "T66304"
|
||||
|
||||
"""
|
||||
# Example panel, leave it here so we always have a template to follow even
|
||||
|
@ -61,6 +61,7 @@ set(SRC
|
||||
view3d_gizmo_preselect.c
|
||||
view3d_gizmo_preselect_type.c
|
||||
view3d_gizmo_ruler.c
|
||||
view3d_gizmo_tool_generic.c
|
||||
view3d_header.c
|
||||
view3d_iterators.c
|
||||
view3d_ops.c
|
||||
|
@ -626,6 +626,8 @@ static void view3d_widgets(void)
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_xform_extrude);
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_elem);
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_edgering);
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_tool_generic_handle_normal);
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_tool_generic_handle_free);
|
||||
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_ruler);
|
||||
WM_gizmotype_append(VIEW3D_GT_ruler_item);
|
||||
|
236
source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
Normal file
236
source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* 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 spview3d
|
||||
*/
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "ED_screen.h"
|
||||
#include "ED_transform.h"
|
||||
#include "ED_gizmo_library.h"
|
||||
#include "ED_gizmo_utils.h"
|
||||
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "WM_toolsystem.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
#include "WM_toolsystem.h"
|
||||
#include "WM_message.h"
|
||||
|
||||
#include "view3d_intern.h" /* own include */
|
||||
|
||||
static const char *handle_normal_id;
|
||||
static const char *handle_free_id;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Generic Tool
|
||||
* \{ */
|
||||
|
||||
static bool WIDGETGROUP_tool_generic_poll(const bContext *C, wmGizmoGroupType *gzgt)
|
||||
{
|
||||
if (!U.experimental.use_tool_fallback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static wmGizmo *tool_generic_create_gizmo(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
{
|
||||
wmGizmo *gz;
|
||||
|
||||
if (gzgroup->type->idname == handle_normal_id) {
|
||||
gz = WM_gizmo_new("GIZMO_GT_button_2d", gzgroup, NULL);
|
||||
|
||||
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
|
||||
UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
|
||||
|
||||
unit_m4(gz->matrix_offset);
|
||||
|
||||
PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
|
||||
RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
|
||||
|
||||
gz->scale_basis = 0.12f;
|
||||
gz->matrix_offset[3][2] -= 12.0;
|
||||
RNA_enum_set(gz->ptr,
|
||||
"draw_options",
|
||||
(ED_GIZMO_BUTTON_SHOW_BACKDROP | ED_GIZMO_BUTTON_SHOW_HELPLINE |
|
||||
ED_GIZMO_BUTTON_SHOW_OUTLINE));
|
||||
}
|
||||
else {
|
||||
gz = WM_gizmo_new("GIZMO_GT_button_2d", gzgroup, NULL);
|
||||
|
||||
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
|
||||
UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
|
||||
|
||||
unit_m4(gz->matrix_offset);
|
||||
gz->scale_basis = 0.16f * 3;
|
||||
|
||||
PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
|
||||
RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
|
||||
|
||||
RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
|
||||
|
||||
/* Make the center low alpha. */
|
||||
WM_gizmo_set_line_width(gz, 2.0f);
|
||||
RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.125f);
|
||||
}
|
||||
|
||||
bToolRef *tref = WM_toolsystem_ref_from_context((bContext *)C);
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
struct wmKeyConfig *kc = wm->defaultconf;
|
||||
|
||||
gz->keymap = WM_keymap_ensure(kc, tref->runtime->keymap, tref->space_type, RGN_TYPE_WINDOW);
|
||||
return gz;
|
||||
}
|
||||
|
||||
static void WIDGETGROUP_tool_generic_setup(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
{
|
||||
wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__);
|
||||
wwrapper->gizmo = tool_generic_create_gizmo(C, gzgroup);
|
||||
gzgroup->customdata = wwrapper;
|
||||
}
|
||||
|
||||
static void WIDGETGROUP_tool_generic_refresh(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
{
|
||||
wmGizmoWrapper *wwrapper = gzgroup->customdata;
|
||||
wmGizmo *gz = wwrapper->gizmo;
|
||||
|
||||
ToolSettings *ts = CTX_data_tool_settings(C);
|
||||
if (ts->workspace_tool_type != SCE_WORKSPACE_TOOL_FALLBACK) {
|
||||
gzgroup->use_fallback_keymap = false;
|
||||
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
gzgroup->use_fallback_keymap = true;
|
||||
}
|
||||
|
||||
/* skip, we don't draw anything anyway */
|
||||
{
|
||||
int orientation;
|
||||
if (gzgroup->type->idname == handle_normal_id) {
|
||||
orientation = V3D_ORIENT_NORMAL;
|
||||
}
|
||||
else {
|
||||
orientation = V3D_ORIENT_GLOBAL; /* dummy, use view. */
|
||||
}
|
||||
|
||||
struct TransformBounds tbounds;
|
||||
const bool hide = ED_transform_calc_gizmo_stats(C,
|
||||
&(struct TransformCalcParams){
|
||||
.use_only_center = true,
|
||||
.orientation_type = orientation + 1,
|
||||
},
|
||||
&tbounds) == 0;
|
||||
|
||||
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, hide);
|
||||
if (hide) {
|
||||
return;
|
||||
}
|
||||
copy_m4_m3(gz->matrix_basis, tbounds.axis);
|
||||
copy_v3_v3(gz->matrix_basis[3], tbounds.center);
|
||||
negate_v3(gz->matrix_basis[2]);
|
||||
}
|
||||
|
||||
WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_OFFSET_SCALE, true);
|
||||
}
|
||||
|
||||
static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
|
||||
wmGizmoGroup *gzgroup,
|
||||
struct wmMsgBus *mbus)
|
||||
{
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
|
||||
wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
|
||||
.owner = ar,
|
||||
.user_data = gzgroup->parent_gzmap,
|
||||
.notify = WM_gizmo_do_msg_notify_tag_refresh,
|
||||
};
|
||||
|
||||
{
|
||||
extern PropertyRNA rna_ToolSettings_workspace_tool_type;
|
||||
const PropertyRNA *props[] = {
|
||||
&rna_ToolSettings_workspace_tool_type,
|
||||
};
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
PointerRNA toolsettings_ptr;
|
||||
RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(props); i++) {
|
||||
WM_msg_subscribe_rna(
|
||||
mbus, &toolsettings_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *handle_normal_id = "VIEW3D_GGT_tool_generic_handle_normal";
|
||||
static const char *handle_free_id = "VIEW3D_GGT_tool_generic_handle_free";
|
||||
|
||||
void VIEW3D_GGT_tool_generic_handle_normal(wmGizmoGroupType *gzgt)
|
||||
{
|
||||
gzgt->name = "Generic Tool Widget Normal";
|
||||
gzgt->idname = handle_normal_id;
|
||||
|
||||
gzgt->flag |= (WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP);
|
||||
|
||||
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
|
||||
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
|
||||
|
||||
gzgt->poll = WIDGETGROUP_tool_generic_poll;
|
||||
gzgt->setup = WIDGETGROUP_tool_generic_setup;
|
||||
gzgt->refresh = WIDGETGROUP_tool_generic_refresh;
|
||||
gzgt->message_subscribe = WIDGETGROUP_gizmo_message_subscribe;
|
||||
}
|
||||
|
||||
void VIEW3D_GGT_tool_generic_handle_free(wmGizmoGroupType *gzgt)
|
||||
{
|
||||
gzgt->name = "Generic Tool Widget Free";
|
||||
gzgt->idname = handle_free_id;
|
||||
|
||||
gzgt->flag |= (WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP);
|
||||
|
||||
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
|
||||
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
|
||||
|
||||
gzgt->poll = WIDGETGROUP_tool_generic_poll;
|
||||
gzgt->setup = WIDGETGROUP_tool_generic_setup;
|
||||
gzgt->refresh = WIDGETGROUP_tool_generic_refresh;
|
||||
gzgt->message_subscribe = WIDGETGROUP_gizmo_message_subscribe;
|
||||
}
|
||||
|
||||
/** \} */
|
@ -261,6 +261,8 @@ void VIEW3D_GGT_armature_spline(struct wmGizmoGroupType *gzgt);
|
||||
void VIEW3D_GGT_navigate(struct wmGizmoGroupType *gzgt);
|
||||
void VIEW3D_GGT_mesh_preselect_elem(struct wmGizmoGroupType *gzgt);
|
||||
void VIEW3D_GGT_mesh_preselect_edgering(struct wmGizmoGroupType *gzgt);
|
||||
void VIEW3D_GGT_tool_generic_handle_normal(struct wmGizmoGroupType *gzgt);
|
||||
void VIEW3D_GGT_tool_generic_handle_free(struct wmGizmoGroupType *gzgt);
|
||||
|
||||
void VIEW3D_GGT_ruler(struct wmGizmoGroupType *gzgt);
|
||||
void VIEW3D_GT_ruler_item(struct wmGizmoType *gzt);
|
||||
|
@ -1322,6 +1322,17 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
extern PropertyRNA rna_ToolSettings_workspace_tool_type;
|
||||
const PropertyRNA *props[] = {
|
||||
&rna_ToolSettings_workspace_tool_type,
|
||||
};
|
||||
for (int i = 0; i < ARRAY_SIZE(props); i++) {
|
||||
WM_msg_subscribe_rna(
|
||||
mbus, &toolsettings_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
PointerRNA view3d_ptr;
|
||||
RNA_pointer_create(&screen->id, &RNA_SpaceView3D, sa->spacedata.first, &view3d_ptr);
|
||||
|
||||
@ -1818,6 +1829,13 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
for (int i = MAN_AXIS_RANGE_ROT_START; i < MAN_AXIS_RANGE_ROT_END; i++) {
|
||||
ggd->gizmos[i]->select_bias = rotate_select_bias;
|
||||
}
|
||||
|
||||
if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
|
||||
gzgroup->use_fallback_keymap = true;
|
||||
}
|
||||
else {
|
||||
gzgroup->use_fallback_keymap = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
|
||||
@ -2028,7 +2046,7 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
|
||||
gzgt->name = "3D View: Transform Gizmo";
|
||||
gzgt->idname = "VIEW3D_GGT_xform_gizmo";
|
||||
|
||||
gzgt->flag = WM_GIZMOGROUPTYPE_3D;
|
||||
gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP;
|
||||
|
||||
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
|
||||
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
|
||||
@ -2062,7 +2080,8 @@ void VIEW3D_GGT_xform_gizmo_context(wmGizmoGroupType *gzgt)
|
||||
gzgt->name = "3D View: Transform Gizmo Context";
|
||||
gzgt->idname = "VIEW3D_GGT_xform_gizmo_context";
|
||||
|
||||
gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_PERSISTENT;
|
||||
gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_PERSISTENT |
|
||||
WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP;
|
||||
|
||||
gzgt->poll = WIDGETGROUP_gizmo_poll_context;
|
||||
gzgt->setup = WIDGETGROUP_gizmo_setup;
|
||||
@ -2212,6 +2231,13 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr
|
||||
|
||||
/* Needed to test view orientation changes. */
|
||||
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
|
||||
|
||||
if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
|
||||
gzgroup->use_fallback_keymap = true;
|
||||
}
|
||||
else {
|
||||
gzgroup->use_fallback_keymap = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C,
|
||||
@ -2263,7 +2289,7 @@ void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
|
||||
gzgt->name = "Transform Cage";
|
||||
gzgt->idname = "VIEW3D_GGT_xform_cage";
|
||||
|
||||
gzgt->flag |= WM_GIZMOGROUPTYPE_3D;
|
||||
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP;
|
||||
|
||||
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
|
||||
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
|
||||
@ -2385,6 +2411,13 @@ static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzg
|
||||
|
||||
/* Needed to test view orientation changes. */
|
||||
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
|
||||
|
||||
if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
|
||||
gzgroup->use_fallback_keymap = true;
|
||||
}
|
||||
else {
|
||||
gzgroup->use_fallback_keymap = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C,
|
||||
@ -2446,7 +2479,7 @@ void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
|
||||
gzgt->name = "Transform Shear";
|
||||
gzgt->idname = "VIEW3D_GGT_xform_shear";
|
||||
|
||||
gzgt->flag |= WM_GIZMOGROUPTYPE_3D;
|
||||
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP;
|
||||
|
||||
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
|
||||
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
|
||||
|
@ -55,9 +55,10 @@ enum {
|
||||
|
||||
static const float extrude_button_scale = 0.15f;
|
||||
static const float extrude_button_offset_scale = 1.5f;
|
||||
static const float extrude_arrow_scale = 1.0f;
|
||||
static const float extrude_arrow_xyz_axis_scale = 1.0f;
|
||||
static const float extrude_arrow_normal_axis_scale = 1.0f;
|
||||
static const float extrude_outer_scale = 1.2f;
|
||||
static const float extrude_arrow_scale = 0.7f;
|
||||
static const float extrude_arrow_xyz_axis_scale = 0.6666f;
|
||||
static const float extrude_arrow_normal_axis_scale = 0.6666f;
|
||||
static const float extrude_dial_scale = 0.2;
|
||||
|
||||
static const uchar shape_plus[] = {
|
||||
@ -69,6 +70,8 @@ typedef struct GizmoExtrudeGroup {
|
||||
|
||||
/* XYZ & normal. */
|
||||
wmGizmo *invoke_xyz_no[4];
|
||||
/* Only visible when 'drag' tool option is disabled. */
|
||||
wmGizmo *invoke_view;
|
||||
/* Constrained & unconstrained (arrow & circle). */
|
||||
wmGizmo *adjust[2];
|
||||
int adjust_axis;
|
||||
@ -126,11 +129,19 @@ static void gizmo_mesh_extrude_setup(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
|
||||
ggd->adjust[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
|
||||
ggd->adjust[1] = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
|
||||
RNA_enum_set(ggd->adjust[1]->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ggd->invoke_xyz_no[i] = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL);
|
||||
ggd->invoke_xyz_no[i]->flag |= WM_GIZMO_DRAW_OFFSET_SCALE;
|
||||
}
|
||||
|
||||
{
|
||||
ggd->invoke_view = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
|
||||
ggd->invoke_view->select_bias = -2.0f;
|
||||
RNA_enum_set(ggd->invoke_view->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT);
|
||||
}
|
||||
|
||||
{
|
||||
PropertyRNA *prop = RNA_struct_find_property(ggd->invoke_xyz_no[3]->ptr, "shape");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@ -170,6 +181,8 @@ static void gizmo_mesh_extrude_setup(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
UI_GetThemeColor3fv(TH_AXIS_X + i, ggd->invoke_xyz_no[i]->color);
|
||||
}
|
||||
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->invoke_xyz_no[3]->color);
|
||||
ggd->invoke_view->color[3] = 0.5f;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->adjust[i]->color);
|
||||
}
|
||||
@ -177,6 +190,9 @@ static void gizmo_mesh_extrude_setup(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
for (int i = 0; i < 4; i++) {
|
||||
WM_gizmo_set_scale(ggd->invoke_xyz_no[i], extrude_button_scale);
|
||||
}
|
||||
WM_gizmo_set_scale(ggd->invoke_view, extrude_outer_scale);
|
||||
ggd->invoke_view->line_width = 2.0f;
|
||||
|
||||
WM_gizmo_set_scale(ggd->adjust[0], extrude_arrow_scale);
|
||||
WM_gizmo_set_scale(ggd->adjust[1], extrude_dial_scale);
|
||||
ggd->adjust[1]->line_width = 2.0f;
|
||||
@ -193,6 +209,15 @@ static void gizmo_mesh_extrude_setup(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
PointerRNA *ptr = WM_gizmo_operator_set(ggd->invoke_view, 0, ggd->ot_extrude, NULL);
|
||||
PointerRNA macroptr = RNA_pointer_get(ptr, "TRANSFORM_OT_translate");
|
||||
RNA_boolean_set(¯optr, "release_confirm", true);
|
||||
|
||||
bool constraint[3] = {0, 0, 0};
|
||||
RNA_boolean_set_array(¯optr, "constraint_axis", constraint);
|
||||
}
|
||||
|
||||
/* Adjust extrude. */
|
||||
for (int i = 0; i < 2; i++) {
|
||||
wmGizmo *gz = ggd->adjust[i];
|
||||
@ -211,6 +236,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
for (int i = 0; i < 4; i++) {
|
||||
WM_gizmo_set_flag(ggd->invoke_xyz_no[i], WM_GIZMO_HIDDEN, true);
|
||||
}
|
||||
WM_gizmo_set_flag(ggd->invoke_view, WM_GIZMO_HIDDEN, true);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
WM_gizmo_set_flag(ggd->adjust[i], WM_GIZMO_HIDDEN, true);
|
||||
}
|
||||
@ -303,6 +329,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
for (int i = 0; i < axis_len_used; i++) {
|
||||
WM_gizmo_set_matrix_location(ggd->invoke_xyz_no[i], tbounds.center);
|
||||
}
|
||||
WM_gizmo_set_matrix_location(ggd->invoke_view, tbounds.center);
|
||||
/* Un-hide. */
|
||||
for (int i = 0; i < axis_len_used; i++) {
|
||||
WM_gizmo_set_flag(ggd->invoke_xyz_no[i], WM_GIZMO_HIDDEN, false);
|
||||
@ -351,6 +378,15 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
WM_gizmo_set_flag(ggd->invoke_xyz_no[3], WM_GIZMO_HIDDEN, true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
|
||||
WM_gizmo_set_flag(ggd->invoke_view, WM_GIZMO_HIDDEN, false);
|
||||
gzgroup->use_fallback_keymap = true;
|
||||
}
|
||||
else {
|
||||
WM_gizmo_set_flag(ggd->invoke_view, WM_GIZMO_HIDDEN, true);
|
||||
gzgroup->use_fallback_keymap = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void gizmo_mesh_extrude_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
@ -380,6 +416,11 @@ static void gizmo_mesh_extrude_draw_prepare(const bContext *C, wmGizmoGroup *gzg
|
||||
copy_v3_v3(ggd->adjust[1]->matrix_basis[1], rv3d->viewinv[1]);
|
||||
copy_v3_v3(ggd->adjust[1]->matrix_basis[2], rv3d->viewinv[2]);
|
||||
}
|
||||
if ((ggd->invoke_view->flag & WM_GIZMO_HIDDEN) == 0) {
|
||||
copy_v3_v3(ggd->invoke_view->matrix_basis[0], rv3d->viewinv[0]);
|
||||
copy_v3_v3(ggd->invoke_view->matrix_basis[1], rv3d->viewinv[1]);
|
||||
copy_v3_v3(ggd->invoke_view->matrix_basis[2], rv3d->viewinv[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,6 +441,9 @@ static void gizmo_mesh_extrude_invoke_prepare(const bContext *UNUSED(C),
|
||||
}
|
||||
RNA_float_set_array(¯optr, "value", ggd->redo_xform.value);
|
||||
}
|
||||
else if (gz == ggd->invoke_view) {
|
||||
/* pass */
|
||||
}
|
||||
else {
|
||||
/* Workaround for extrude action modifying normals. */
|
||||
const int i = BLI_array_findindex(ggd->invoke_xyz_no, ARRAY_SIZE(ggd->invoke_xyz_no), &gz);
|
||||
@ -449,6 +493,20 @@ static void gizmo_mesh_extrude_message_subscribe(const bContext *C,
|
||||
},
|
||||
&msg_sub_value_gz_tag_refresh,
|
||||
__func__);
|
||||
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
PointerRNA toolsettings_ptr;
|
||||
RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
|
||||
extern PropertyRNA rna_ToolSettings_workspace_tool_type;
|
||||
const PropertyRNA *props[] = {
|
||||
&rna_ToolSettings_workspace_tool_type,
|
||||
};
|
||||
for (int i = 0; i < ARRAY_SIZE(props); i++) {
|
||||
WM_msg_subscribe_rna(
|
||||
mbus, &toolsettings_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VIEW3D_GGT_xform_extrude(struct wmGizmoGroupType *gzgt)
|
||||
@ -456,7 +514,7 @@ void VIEW3D_GGT_xform_extrude(struct wmGizmoGroupType *gzgt)
|
||||
gzgt->name = "3D View Extrude";
|
||||
gzgt->idname = "VIEW3D_GGT_xform_extrude";
|
||||
|
||||
gzgt->flag = WM_GIZMOGROUPTYPE_3D;
|
||||
gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP;
|
||||
|
||||
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
|
||||
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
|
||||
|
@ -1509,7 +1509,10 @@ typedef struct ToolSettings {
|
||||
/* XXX: these sculpt_paint_* fields are deprecated, use the
|
||||
* unified_paint_settings field instead! */
|
||||
short sculpt_paint_settings DNA_DEPRECATED;
|
||||
char _pad5[2];
|
||||
|
||||
char workspace_tool_type;
|
||||
|
||||
char _pad5[1];
|
||||
int sculpt_paint_unified_size DNA_DEPRECATED;
|
||||
float sculpt_paint_unified_unprojected_radius DNA_DEPRECATED;
|
||||
float sculpt_paint_unified_alpha DNA_DEPRECATED;
|
||||
@ -2042,6 +2045,12 @@ enum {
|
||||
SCE_OBJECT_MODE_LOCK = (1 << 0),
|
||||
};
|
||||
|
||||
/* ToolSettings.workspace_tool_flag */
|
||||
enum {
|
||||
SCE_WORKSPACE_TOOL_FALLBACK = 0,
|
||||
SCE_WORKSPACE_TOOL_DEFAULT = 1,
|
||||
};
|
||||
|
||||
/* ToolSettings.snap_flag */
|
||||
#define SCE_SNAP (1 << 0)
|
||||
#define SCE_SNAP_ROTATE (1 << 1)
|
||||
|
@ -607,7 +607,10 @@ typedef struct UserDef_FileSpaceData {
|
||||
typedef struct UserDef_Experimental {
|
||||
/** #eUserPref_Experimental_Flag options. */
|
||||
int flag;
|
||||
char _pad0[4];
|
||||
|
||||
char use_tool_fallback;
|
||||
|
||||
char _pad0[3];
|
||||
} UserDef_Experimental;
|
||||
|
||||
typedef struct UserDef {
|
||||
|
@ -35,6 +35,10 @@ typedef struct bToolRef_Runtime {
|
||||
char gizmo_group[64];
|
||||
char data_block[64];
|
||||
|
||||
/** Optionally use these when not interacting directly with the primary tools gizmo. */
|
||||
char idname_fallback[64];
|
||||
char keymap_fallback[64];
|
||||
|
||||
/** Use to infer primary operator to use when setting accelerator keys. */
|
||||
char op[64];
|
||||
|
||||
|
@ -2867,6 +2867,17 @@ static void rna_def_tool_settings(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Lock Object Modes", "Restrict select to the current mode");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
|
||||
|
||||
static const EnumPropertyItem workspace_tool_items[] = {
|
||||
{SCE_WORKSPACE_TOOL_DEFAULT, "DEFAULT", 0, "Active Tool", ""},
|
||||
{SCE_WORKSPACE_TOOL_FALLBACK, "FALLBACK", 0, "Select", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
prop = RNA_def_property(srna, "workspace_tool_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "workspace_tool_type");
|
||||
RNA_def_property_enum_items(prop, workspace_tool_items);
|
||||
RNA_def_property_ui_text(prop, "Drag", "Action when dragging in the viewport");
|
||||
|
||||
/* Transform */
|
||||
prop = RNA_def_property(srna, "use_proportional_edit", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "proportional_edit", PROP_EDIT_USE);
|
||||
|
@ -5845,6 +5845,11 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
|
||||
"All Experimental Features",
|
||||
"Expose all the experimental features in the user interface");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_tool_fallback", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "use_tool_fallback", 1);
|
||||
RNA_def_property_ui_text(prop, "Fallback Tool Support", "Allow selection with an active tool");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
}
|
||||
|
||||
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
|
@ -192,6 +192,18 @@ static int rna_WorkSpaceTool_widget_length(PointerRNA *ptr)
|
||||
return tref->runtime ? strlen(tref->runtime->gizmo_group) : 0;
|
||||
}
|
||||
|
||||
static void rna_WorkSpaceTool_tool_fallback_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
bToolRef *tref = ptr->data;
|
||||
strcpy(value, tref->runtime ? tref->runtime->idname_fallback : "");
|
||||
}
|
||||
|
||||
static int rna_WorkSpaceTool_tool_fallback_length(PointerRNA *ptr)
|
||||
{
|
||||
bToolRef *tref = ptr->data;
|
||||
return tref->runtime ? strlen(tref->runtime->idname_fallback) : 0;
|
||||
}
|
||||
|
||||
#else /* RNA_RUNTIME */
|
||||
|
||||
static void rna_def_workspace_owner(BlenderRNA *brna)
|
||||
@ -290,6 +302,13 @@ static void rna_def_workspace_tool(BlenderRNA *brna)
|
||||
prop, "rna_WorkSpaceTool_widget_get", "rna_WorkSpaceTool_widget_length", NULL);
|
||||
RNA_define_verify_sdna(1);
|
||||
|
||||
prop = RNA_def_property(srna, "tool_fallback", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Fallback", "");
|
||||
RNA_def_property_string_funcs(
|
||||
prop, "rna_WorkSpaceTool_tool_fallback_get", "rna_WorkSpaceTool_tool_fallback_length", NULL);
|
||||
RNA_define_verify_sdna(1);
|
||||
|
||||
RNA_api_workspace_tool(srna);
|
||||
}
|
||||
|
||||
|
@ -43,14 +43,16 @@
|
||||
static void rna_WorkSpaceTool_setup(ID *id,
|
||||
bToolRef *tref,
|
||||
bContext *C,
|
||||
const char *tool_idname,
|
||||
const char *idname,
|
||||
/* Args for: 'bToolRef_Runtime'. */
|
||||
int cursor,
|
||||
const char *keymap,
|
||||
const char *gizmo_group,
|
||||
const char *data_block,
|
||||
const char *op_idname,
|
||||
int index)
|
||||
int index,
|
||||
const char *idname_fallback,
|
||||
const char *keymap_fallback)
|
||||
{
|
||||
bToolRef_Runtime tref_rt = {0};
|
||||
|
||||
@ -61,7 +63,10 @@ static void rna_WorkSpaceTool_setup(ID *id,
|
||||
STRNCPY(tref_rt.op, op_idname);
|
||||
tref_rt.index = index;
|
||||
|
||||
WM_toolsystem_ref_set_from_runtime(C, (WorkSpace *)id, tref, &tref_rt, tool_idname);
|
||||
STRNCPY(tref_rt.idname_fallback, idname_fallback ? idname_fallback : NULL);
|
||||
STRNCPY(tref_rt.keymap_fallback, keymap_fallback ? keymap_fallback : NULL);
|
||||
|
||||
WM_toolsystem_ref_set_from_runtime(C, (WorkSpace *)id, tref, &tref_rt, idname);
|
||||
}
|
||||
|
||||
static void rna_WorkSpaceTool_refresh_from_context(ID *id, bToolRef *tref, Main *bmain)
|
||||
@ -140,6 +145,9 @@ void RNA_api_workspace_tool(StructRNA *srna)
|
||||
RNA_def_string(func, "operator", NULL, MAX_NAME, "Operator", "");
|
||||
RNA_def_int(func, "index", 0, INT_MIN, INT_MAX, "Index", "", INT_MIN, INT_MAX);
|
||||
|
||||
RNA_def_string(func, "idname_fallback", NULL, MAX_NAME, "Fallback Identifier", "");
|
||||
RNA_def_string(func, "keymap_fallback", NULL, KMAP_MAX_NAME, "Fallback Key Map", "");
|
||||
|
||||
/* Access tool operator options (optionally create). */
|
||||
func = RNA_def_function(srna, "operator_properties", "rna_WorkSpaceTool_operator_properties");
|
||||
RNA_def_function_flag(func, FUNC_USE_REPORTS);
|
||||
|
@ -120,6 +120,12 @@ typedef enum eWM_GizmoFlagGroupTypeFlag {
|
||||
* We could even move the options into the key-map item.
|
||||
* ~ campbell. */
|
||||
WM_GIZMOGROUPTYPE_TOOL_INIT = (1 << 6),
|
||||
|
||||
/**
|
||||
* This gizmo type supports using the fallback tools keymap.
|
||||
* #wmGizmoGroup.use_tool_fallback will need to be set too.
|
||||
*/
|
||||
WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP = (1 << 7),
|
||||
} eWM_GizmoFlagGroupTypeFlag;
|
||||
|
||||
/**
|
||||
@ -443,6 +449,8 @@ typedef struct wmGizmoGroup {
|
||||
|
||||
bool tag_remove;
|
||||
|
||||
bool use_fallback_keymap;
|
||||
|
||||
void *customdata;
|
||||
/** For freeing customdata from above. */
|
||||
void (*customdata_free)(void *);
|
||||
|
@ -3728,8 +3728,40 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandle
|
||||
handler->keymap_tool = NULL;
|
||||
bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL;
|
||||
if (tref_rt && tref_rt->keymap[0]) {
|
||||
const char *keymap_id = tref_rt->keymap;
|
||||
|
||||
/* Support for the gizmo owning the tool keymap. */
|
||||
if (U.experimental.use_tool_fallback) {
|
||||
if (tref_rt->gizmo_group[0] != '\0') {
|
||||
wmGizmoMap *gzmap = NULL;
|
||||
wmGizmoGroup *gzgroup = NULL;
|
||||
for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
|
||||
if (ar->gizmo_map != NULL) {
|
||||
gzmap = ar->gizmo_map;
|
||||
gzgroup = WM_gizmomap_group_find(gzmap, tref_rt->gizmo_group);
|
||||
if (gzgroup != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gzgroup != NULL) {
|
||||
if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
|
||||
/* If all are hidden, don't override. */
|
||||
if (gzgroup->use_fallback_keymap) {
|
||||
wmGizmo *highlight = wm_gizmomap_highlight_get(gzmap);
|
||||
if (highlight == NULL) {
|
||||
if (tref_rt->keymap_fallback[0]) {
|
||||
keymap_id = tref_rt->keymap_fallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
|
||||
&wm->userconf->keymaps, tref_rt->keymap, sa->spacetype, RGN_TYPE_WINDOW);
|
||||
&wm->userconf->keymaps, keymap_id, sa->spacetype, RGN_TYPE_WINDOW);
|
||||
/* We shouldn't use keymaps from unrelated spaces. */
|
||||
if (km != NULL) {
|
||||
handler->keymap_tool = sa->runtime.tool;
|
||||
|
@ -351,6 +351,25 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C,
|
||||
*tref->runtime = *tref_rt;
|
||||
}
|
||||
|
||||
/* FIXME: ideally Python could check this gizmo group flag and not
|
||||
* pass in the argument to begin with. */
|
||||
bool use_fallback_keymap = false;
|
||||
|
||||
if (U.experimental.use_tool_fallback) {
|
||||
if (tref_rt->gizmo_group[0]) {
|
||||
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(tref_rt->gizmo_group, false);
|
||||
if (gzgt) {
|
||||
if (gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
|
||||
use_fallback_keymap = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (use_fallback_keymap == false) {
|
||||
tref->runtime->idname_fallback[0] = '\0';
|
||||
tref->runtime->keymap_fallback[0] = '\0';
|
||||
}
|
||||
|
||||
toolsystem_ref_link(C, workspace, tref);
|
||||
|
||||
toolsystem_refresh_screen_from_active_tool(bmain, workspace, tref);
|
||||
|
Loading…
Reference in New Issue
Block a user