diff options
29 files changed, 762 insertions, 202 deletions
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index a9d766b29e2..970eff34026 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -2335,10 +2335,21 @@ class WM_OT_tool_set_by_name(Operator): name="Text", description="Display name of the tool", ) + space_type = EnumProperty( + name="Type", + items=tuple( + (e.identifier, e.name, "", e. value) + for e in bpy.types.Space.bl_rna.properties["type"].enum_items + ), + default='EMPTY', + ) def execute(self, context): from bl_ui.space_toolsystem_common import activate_by_name - if activate_by_name(context, context.space_data.type, self.name): + space_type = self.space_type + if space_type == 'EMPTY': + space_type = context.space_data.type + if activate_by_name(context, space_type, self.name): return {'FINISHED'} else: self.report({'WARNING'}, f"Tool {self.name!r} not found.") diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py index b58bff7cf32..ad5c970a6d5 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_common.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py @@ -140,7 +140,7 @@ class ToolSelectPanelHelper: The text prefix for each key-map for this spaces tools. - tools_all(): Returns (context_mode, tools) tuple pair for all tools defined. - - tools_from_context(context): + - tools_from_context(context, mode=None): Returns tools available in this context. Each tool is a 'ToolDef' or None for a separator in the toolbar, use ``None``. @@ -230,23 +230,23 @@ class ToolSelectPanelHelper: yield item, -1 @staticmethod - def _tool_get_active(context, with_icon=False): + def _tool_get_active(context, space_type, mode, with_icon=False): """ Return the active Python tool definition and icon name. """ workspace = context.workspace - cls = ToolSelectPanelHelper._tool_class_from_space_type(workspace.tool_space_type) + cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) if cls is not None: - tool_def_active, index_active = ToolSelectPanelHelper._tool_vars_from_active_with_index(context) + tool_active_text = getattr( + ToolSelectPanelHelper._tool_active_from_context(context, space_type, mode), + "name", None) - context_mode = context.mode - for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context)): + for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context, mode)): if item is not None: - tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item, context_mode) - if (tool_def == tool_def_active): + if item.text == tool_active_text: if with_icon: - icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(icon_name) + icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon) else: icon_value = 0 return (item, icon_value) @@ -259,7 +259,6 @@ class ToolSelectPanelHelper: """ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) if cls is not None: - context_mode = context.mode for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)): if item is not None: if item.text == text: @@ -267,7 +266,7 @@ class ToolSelectPanelHelper: return None, -1 @staticmethod - def _tool_vars_from_def(item, context_mode): + def _tool_vars_from_def(item): # For now be strict about whats in this dict # prevent accidental adding unknown keys. text = item.text @@ -282,16 +281,22 @@ class ToolSelectPanelHelper: return (km_idname, mp_idname, datablock_idname), icon_name @staticmethod - def _tool_vars_from_active_with_index(context): - workspace = context.workspace - return ( - ( - workspace.tool_keymap or None, - workspace.tool_manipulator_group or None, - workspace.tool_data_block or None, - ), - workspace.tool_index, - ) + def _tool_active_from_context(context, space_type, mode=None, create=False): + if space_type == 'VIEW_3D': + if mode is None: + obj = context.active_object + mode = obj.mode if obj is not None else 'OBJECT' + tool = context.workspace.tools.from_space_view3d_mode(mode, create) + if tool is not None: + return tool + elif space_type == 'IMAGE_EDITOR': + space_data = context.space_data + if mode is None: + mode = space_data.mode + tool = context.workspace.tools.from_space_image_mode(mode, create) + if tool is not None: + return tool + return None @staticmethod def _tool_text_from_button(context): @@ -445,8 +450,11 @@ class ToolSelectPanelHelper: # - tool-tips that include multiple key shortcuts. # - ability to click and hold to expose sub-tools. - context_mode = context.mode - tool_def_active, index_active = ToolSelectPanelHelper._tool_vars_from_active_with_index(context) + space_type = context.space_data.type + tool_active_text = getattr( + ToolSelectPanelHelper._tool_active_from_context(context, space_type), + "name", None, + ) ui_gen, show_text = self._layout_generator_detect_from_region(self.layout, context.region) @@ -464,8 +472,7 @@ class ToolSelectPanelHelper: for i, sub_item in enumerate(item): if sub_item is None: continue - tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(sub_item, context_mode) - is_active = (tool_def == tool_def_active) + is_active = (sub_item.text == tool_active_text) if is_active: index = i break @@ -483,8 +490,8 @@ class ToolSelectPanelHelper: index = -1 use_menu = False - tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item, context_mode) - is_active = (tool_def == tool_def_active) + tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item) + is_active = (item.text == tool_active_text) icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(icon_name) @@ -510,7 +517,11 @@ class ToolSelectPanelHelper: @staticmethod def draw_active_tool_header(context, layout): - item, icon_value = ToolSelectPanelHelper._tool_get_active(context, with_icon=True) + # BAD DESIGN WARNING: last used tool + workspace = context.workspace + space_type = workspace.tools_space_type + mode = workspace.tools_mode + item, icon_value = ToolSelectPanelHelper._tool_get_active(context, space_type, mode, with_icon=True) if item is None: return # Note: we could show 'item.text' here but it makes the layout jitter when switcuing tools. @@ -527,7 +538,6 @@ class WM_MT_toolsystem_submenu(Menu): @staticmethod def _tool_group_from_button(context): - context_mode = context.mode # Lookup the tool definitions based on the space-type. cls = ToolSelectPanelHelper._tool_class_from_space_type(context.space_data.type) if cls is not None: @@ -540,7 +550,6 @@ class WM_MT_toolsystem_submenu(Menu): return None, None def draw(self, context): - context_mode = context.mode layout = self.layout layout.scale_y = 2.0 @@ -554,7 +563,7 @@ class WM_MT_toolsystem_submenu(Menu): if item is None: layout.separator() continue - tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item, context_mode) + tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item) icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(icon_name) layout.operator( "wm.tool_set_by_name", @@ -566,9 +575,10 @@ class WM_MT_toolsystem_submenu(Menu): def activate_by_name(context, space_type, text): item, index = ToolSelectPanelHelper._tool_get_by_name(context, space_type, text) if item is not None: - context_mode = context.mode - tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item, context_mode) - bpy.ops.wm.tool_set( + tool = ToolSelectPanelHelper._tool_active_from_context(context, space_type, create=True) + tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item) + tool.setup( + name=text, keymap=tool_def[0] or "", manipulator_group=tool_def[1] or "", data_block=tool_def[2] or "", diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index a0360c0900b..4a368bd712d 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -777,6 +777,108 @@ class _defs_weight_paint: ) +class _defs_uv_select: + + @ToolDef.from_fn + def border(): + return dict( + text="Select Border", + icon="ops.generic.select_border", + widget=None, + keymap=( + ("uv.select_border", + dict(deselect=False), + dict(type='EVT_TWEAK_A', value='ANY')), + # ("uv.select_border", + # dict(deselect=True), + # dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)), + ), + ) + + @ToolDef.from_fn + def circle(): + return dict( + text="Select Circle", + icon="ops.generic.select_circle", + widget=None, + keymap=( + ("uv.select_circle", + dict(), # dict(deselect=False), + dict(type='ACTIONMOUSE', value='PRESS')), + # ("uv.select_circle", + # dict(deselect=True), + # dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)), + ), + ) + + @ToolDef.from_fn + def lasso(): + return dict( + text="Select Lasso", + icon="ops.generic.select_lasso", + widget=None, + keymap=( + ("uv.select_lasso", + dict(deselect=False), + dict(type='EVT_TWEAK_A', value='ANY')), + # ("uv.select_lasso", + # dict(deselect=True), + # dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)), + ), + ) + + +class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel): + bl_space_type = 'IMAGE_EDITOR' + bl_region_type = 'TOOLS' + bl_category = "Tools" + bl_label = "Tools" # not visible + bl_options = {'HIDE_HEADER'} + + # Satisfy the 'ToolSelectPanelHelper' API. + keymap_prefix = "Image Editor Tool: " + + @classmethod + def tools_from_context(cls, context, mode=None): + if mode is None: + mode = context.space_data.mode + for tools in (cls._tools[None], cls._tools.get(mode, ())): + for item in tools: + if not (type(item) is ToolDef) and callable(item): + yield from item(context) + else: + yield item + + @classmethod + def tools_all(cls): + yield from cls._tools.items() + + # for reuse + _tools_select = ( + ( + _defs_uv_select.border, + _defs_uv_select.circle, + _defs_uv_select.lasso, + ), + ) + + _tools = { + None: [ + # for all modes + ], + 'VIEW': [ + *_tools_select, + + ], + 'MASK': [ + None, + ], + 'PAINT': [ + _defs_texture_paint.generate_from_brushes, + ], + } + + class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'TOOLS' @@ -788,8 +890,10 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): keymap_prefix = "3D View Tool: " @classmethod - def tools_from_context(cls, context): - for tools in (cls._tools[None], cls._tools.get(context.mode, ())): + def tools_from_context(cls, context, mode=None): + if mode is None: + mode = context.mode + for tools in (cls._tools[None], cls._tools.get(mode, ())): for item in tools: if not (type(item) is ToolDef) and callable(item): yield from item(context) @@ -934,6 +1038,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): classes = ( + IMAGE_PT_tools_active, VIEW3D_PT_tools_active, ) diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 38378f66584..fd316cb9d82 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -171,6 +171,14 @@ void BKE_workspace_free(WorkSpace *workspace) BLI_freelistN(&workspace->owner_ids); BLI_freelistN(&workspace->layouts); + + for (bToolRef *tref = workspace->tools.first, *tref_next; tref; tref = tref_next) { + tref_next = tref->next; + if (tref->runtime) { + MEM_freeN(tref->runtime); + } + } + BLI_freelistN(&workspace->tools); } /** diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9618ae432f1..42984cfefaa 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2911,6 +2911,7 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main link_list(fd, &workspace->hook_layout_relations); link_list(fd, &workspace->scene_viewlayer_relations); link_list(fd, &workspace->owner_ids); + link_list(fd, &workspace->tools); for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first; relation; @@ -2936,6 +2937,10 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main } } } + + for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) { + tref->runtime = NULL; + } } static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook *hook, ID *id) diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index bb136cb937d..507fe2e082c 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -3598,6 +3598,7 @@ static void write_workspace(WriteData *wd, WorkSpace *workspace) writelist(wd, DATA, WorkSpaceDataRelation, &workspace->hook_layout_relations); writelist(wd, DATA, WorkSpaceDataRelation, &workspace->scene_viewlayer_relations); writelist(wd, DATA, wmOwnerID, &workspace->owner_ids); + writelist(wd, DATA, bToolRef, &workspace->tools); } /* Keep it last of write_foodata functions. */ diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 2e3d0a9c675..67596ef5c8a 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -420,7 +420,10 @@ static void manipulator_mesh_extrude_orientation_matrix_set( static bool manipulator_mesh_extrude_poll(const bContext *C, wmManipulatorGroupType *wgt) { WorkSpace *workspace = CTX_wm_workspace(C); - if (!STREQ(workspace->tool.manipulator_group, "MESH_WGT_extrude") || + const bToolKey tkey = { .space_type = SPACE_VIEW3D, .mode = OB_MODE_EDIT}; + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_find(workspace, &tkey); + if ((tref_rt == NULL) || + !STREQ(wgt->idname, tref_rt->manipulator_group) || !ED_operator_editmesh_view3d((bContext *)C)) { WM_manipulator_group_type_unlink_delayed_ptr(wgt); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index e87a24b3af0..b9a7da02611 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -481,6 +481,8 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op) WM_msg_publish_rna_prop(mbus, &obact->id, obact, Object, mode); + WM_toolsystem_update_from_context_view3d(C); + return OPERATOR_FINISHED; } @@ -579,6 +581,8 @@ static int posemode_exec(bContext *C, wmOperator *op) WM_msg_publish_rna_prop(mbus, &obact->id, obact, Object, mode); + WM_toolsystem_update_from_context_view3d(C); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index e0427b4797c..6197457293f 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -4527,6 +4527,8 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op) WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); + WM_toolsystem_update_from_context_view3d(C); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index bd4381f4099..fe52e945399 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -201,8 +201,8 @@ bool ED_workspace_change( BLI_assert(BKE_workspace_view_layer_get(workspace_new, CTX_data_scene(C)) != NULL); BLI_assert(CTX_wm_workspace(C) == workspace_new); - WM_toolsystem_unlink(C, workspace_old); - WM_toolsystem_link(C, workspace_new); + WM_toolsystem_unlink_all(C, workspace_old); + WM_toolsystem_link_all(C, workspace_new); return true; } @@ -224,7 +224,7 @@ WorkSpace *ED_workspace_duplicate( bmain, workspace_old->id.name + 2, scene, BKE_workspace_view_layer_get(workspace_old, scene)); - workspace_new->tool = workspace_old->tool; + /* TODO(campbell): tools */ for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old; layout_old = layout_old->next) { WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace_new, layout_old, win); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index cbf755d26b5..6a32fdecfad 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -1136,6 +1136,8 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); + WM_toolsystem_update_from_context_view3d(C); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 196505c9542..3c3df2067ab 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1252,6 +1252,8 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); + WM_toolsystem_update_from_context_view3d(C); + return OPERATOR_FINISHED; } @@ -2386,6 +2388,8 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); + WM_toolsystem_update_from_context_view3d(C); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 048555d3fcc..709d6d4c690 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -5820,6 +5820,8 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); + WM_toolsystem_update_from_context_view3d(C); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c index 8cf27d86cfe..4342fa87f89 100644 --- a/source/blender/editors/space_topbar/space_topbar.c +++ b/source/blender/editors/space_topbar/space_topbar.c @@ -201,9 +201,10 @@ static void topbar_header_region_message_subscribe( .user_data = ar, .notify = ED_region_do_msg_notify_tag_redraw, }; + WM_msg_subscribe_rna_prop( mbus, &workspace->id, workspace, - WorkSpace, tool_keymap, &msg_sub_value_region_tag_redraw); + WorkSpace, tools, &msg_sub_value_region_tag_redraw); } static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu) diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index fa147ff1226..de2ef45247b 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1017,8 +1017,8 @@ static void view3d_main_region_listener( static void view3d_main_region_message_subscribe( const struct bContext *C, - struct WorkSpace *workspace, struct Scene *UNUSED(scene), - struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar, + struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), + struct bScreen *UNUSED(screen), struct ScrArea *sa, struct ARegion *ar, struct wmMsgBus *mbus) { /* Developer note: there are many properties that impact 3D view drawing, @@ -1091,10 +1091,10 @@ static void view3d_main_region_message_subscribe( } } - if (workspace->tool.spacetype == SPACE_VIEW3D) { + { wmMsgSubscribeValue msg_sub_value_region_tag_refresh = { .owner = ar, - .user_data = ar, + .user_data = sa, .notify = WM_toolsystem_do_msg_notify_tag_refresh, }; WM_msg_subscribe_rna_anon_prop( diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c index 9f69a33861d..d46673b4817 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c @@ -982,8 +982,10 @@ void VIEW3D_WT_ruler_item(wmManipulatorType *wt) static bool WIDGETGROUP_ruler_poll(const bContext *C, wmManipulatorGroupType *wgt) { - WorkSpace *workspace = CTX_wm_workspace(C); - if (!STREQ(wgt->idname, workspace->tool.manipulator_group)) { + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); + if ((tref_rt == NULL) || + !STREQ(wgt->idname, tref_rt->manipulator_group)) + { WM_manipulator_group_type_unlink_delayed_ptr(wgt); return false; } @@ -1030,8 +1032,9 @@ void VIEW3D_WGT_ruler(wmManipulatorGroupType *wgt) static int view3d_ruler_poll(bContext *C) { - WorkSpace *workspace = CTX_wm_workspace(C); - if (!STREQ(view3d_wgt_ruler_id, workspace->tool.manipulator_group) || + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); + if ((tref_rt == NULL) || + !STREQ(view3d_wgt_ruler_id, tref_rt->manipulator_group) || CTX_wm_region_view3d(C) == NULL) { return false; diff --git a/source/blender/editors/transform/transform_manipulator_3d.c b/source/blender/editors/transform/transform_manipulator_3d.c index 8257ad595d7..c24291953c8 100644 --- a/source/blender/editors/transform/transform_manipulator_3d.c +++ b/source/blender/editors/transform/transform_manipulator_3d.c @@ -1283,8 +1283,14 @@ static void WIDGETGROUP_manipulator_setup(const bContext *C, wmManipulatorGroup /* TODO: support mixing modes again? - it's supported but tool system makes it unobvious. */ man->twtype = 0; WorkSpace *workspace = CTX_wm_workspace(C); + Scene *scene = CTX_data_scene(C); ScrArea *sa = CTX_wm_area(C); - wmKeyMap *km = WM_keymap_find_all(C, workspace->tool.keymap, sa->spacetype, RGN_TYPE_WINDOW); + const bToolKey tkey = { + .space_type = sa->spacetype, + .mode = WM_toolsystem_mode_from_spacetype(workspace, scene, NULL, sa->spacetype), + }; + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_find(workspace, &tkey); + wmKeyMap *km = WM_keymap_find_all(C, tref_rt->keymap, sa->spacetype, RGN_TYPE_WINDOW); /* Weak, check first event */ wmKeyMapItem *kmi = km ? km->items.first : NULL; @@ -1552,8 +1558,10 @@ static bool WIDGETGROUP_manipulator_poll(const struct bContext *C, struct wmMani return false; } - WorkSpace *workspace = CTX_wm_workspace(C); - if (!STREQ(workspace->tool.manipulator_group, "TRANSFORM_WGT_manipulator")) { + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); + if ((tref_rt == NULL) || + !STREQ(wgt->idname, tref_rt->manipulator_group)) + { WM_manipulator_group_type_unlink_delayed_ptr(wgt); return false; } @@ -1596,8 +1604,8 @@ static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmManipulatorGroupTyp return false; } - WorkSpace *workspace = CTX_wm_workspace(C); - if (!STREQ(wgt->idname, workspace->tool.manipulator_group)) { + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); + if (!STREQ(wgt->idname, tref_rt->manipulator_group)) { WM_manipulator_group_type_unlink_delayed_ptr(wgt); return false; } diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h index 4cc3929b4ea..693e4f672d2 100644 --- a/source/blender/makesdna/DNA_workspace_types.h +++ b/source/blender/makesdna/DNA_workspace_types.h @@ -53,16 +53,35 @@ /* Currently testing, allow to disable. */ #define USE_WORKSPACE_TOOL -typedef struct bToolDef { +# +# +typedef struct bToolRef_Runtime { /* One of these must be defined. */ char keymap[64]; char manipulator_group[64]; char data_block[64]; - - int spacetype; /* index when a tool is a member of a group */ - int index; -} bToolDef; + int index; +} bToolRef_Runtime; + + +/* Stored per mode. */ +typedef struct bToolRef { + struct bToolRef *next, *prev; + char idname[64]; + + /** bToolKey (spacetype, mode), used in 'WM_api.h' */ + int space_type; + /** + * Value depends ont the 'space_type', object mode for 3D view, image editor has own mode too. + * RNA needs to handle using item function. + */ + int mode; + + /** Variables needed to operate the tool. */ + bToolRef_Runtime *runtime; +} bToolRef; + /** * \brief Wrapper for bScreen. @@ -97,13 +116,22 @@ typedef struct WorkSpace { /* Feature tagging (use for addons) */ ListBase owner_ids DNA_PRIVATE_WORKSPACE_READ_WRITE; /* wmOwnerID */ - int pad; - int flags DNA_PRIVATE_WORKSPACE; /* enum eWorkSpaceFlags */ + struct ViewLayer *view_layer DNA_DEPRECATED; /* should be: '#ifdef USE_WORKSPACE_TOOL'. */ - bToolDef tool; - struct ViewLayer *view_layer DNA_DEPRECATED; + /** List of #bToolRef */ + ListBase tools; + + /** + * BAD DESIGN WARNING: + * This is a workaround for the topbar not knowing which tools spac */ + char tools_space_type; + /** Type is different for each space-type. */ + char tools_mode; + + char _pad[2]; + int flags DNA_PRIVATE_WORKSPACE; /* enum eWorkSpaceFlags */ } WorkSpace; /* internal struct, but exported for read/write */ diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index d5b2493078c..447dc4ce289 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -56,6 +56,7 @@ extern const EnumPropertyItem rna_enum_curve_fit_method_items[]; extern const EnumPropertyItem rna_enum_mesh_select_mode_items[]; extern const EnumPropertyItem rna_enum_mesh_delimit_mode_items[]; extern const EnumPropertyItem rna_enum_space_type_items[]; +extern const EnumPropertyItem rna_enum_space_image_mode_items[]; extern const EnumPropertyItem rna_enum_region_type_items[]; extern const EnumPropertyItem rna_enum_object_modifier_type_items[]; extern const EnumPropertyItem rna_enum_constraint_type_items[]; diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 7bd5ad2b959..c62e8ed4da8 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -122,6 +122,7 @@ set(APISRC rna_vfont_api.c rna_wm_api.c rna_wm_manipulator_api.c + rna_workspace_api.c ) string(REGEX REPLACE "rna_([a-zA-Z0-9_-]*).c" "${CMAKE_CURRENT_BINARY_DIR}/rna_\\1_gen.c" GENSRC "${DEFSRC}") diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 0b2efe27059..4daf8b6a965 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -2831,6 +2831,10 @@ static void rna_generate_struct_prototypes(FILE *f) if (dp->prop->type == PROP_POINTER) { int a, found = 0; const char *struct_name = rna_parameter_type_name(dp->prop); + if (struct_name == NULL) { + printf("No struct found for property '%s'\n", dp->prop->identifier); + exit(1); + } for (a = 0; a < all_structures; a++) { if (STREQ(struct_name, structures[a])) { @@ -3404,7 +3408,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_vfont.c", "rna_vfont_api.c", RNA_def_vfont}, {"rna_wm.c", "rna_wm_api.c", RNA_def_wm}, {"rna_wm_manipulator.c", "rna_wm_manipulator_api.c", RNA_def_wm_manipulator}, - {"rna_workspace.c", NULL, RNA_def_workspace}, + {"rna_workspace.c", "rna_workspace_api.c", RNA_def_workspace}, {"rna_world.c", NULL, RNA_def_world}, {"rna_movieclip.c", NULL, RNA_def_movieclip}, {"rna_tracking.c", NULL, RNA_def_tracking}, diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 11ad39a2dd1..ce16cb69bbd 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -342,6 +342,8 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop); void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop); void RNA_api_sound(struct StructRNA *srna); void RNA_api_vfont(struct StructRNA *srna); +void RNA_api_workspace(struct StructRNA *srna); +void RNA_api_workspace_tool(struct StructRNA *srna); /* main collection functions */ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 12bb4dd0617..3ce799dfb88 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -103,6 +103,15 @@ const EnumPropertyItem rna_enum_space_type_items[] = { {0, NULL, 0, NULL, NULL} }; + +const EnumPropertyItem rna_enum_space_image_mode_items[] = { + {SI_MODE_VIEW, "VIEW", ICON_FILE_IMAGE, "View", "View the image and UV edit in mesh editmode"}, + {SI_MODE_PAINT, "PAINT", ICON_TPAINT_HLT, "Paint", "2D image painting mode"}, + {SI_MODE_MASK, "MASK", ICON_MOD_MASK, "Mask", "Mask editing"}, + {0, NULL, 0, NULL, NULL} +}; + + #define V3D_S3D_CAMERA_LEFT {STEREO_LEFT_ID, "LEFT", ICON_RESTRICT_RENDER_OFF, "Left", ""}, #define V3D_S3D_CAMERA_RIGHT {STEREO_RIGHT_ID, "RIGHT", ICON_RESTRICT_RENDER_OFF, "Right", ""}, #define V3D_S3D_CAMERA_S3D {STEREO_3D_ID, "S3D", ICON_CAMERA_STEREO, "3D", ""}, @@ -2950,13 +2959,6 @@ static void rna_def_space_buttons(BlenderRNA *brna) static void rna_def_space_image(BlenderRNA *brna) { - static const EnumPropertyItem image_space_mode_items[] = { - {SI_MODE_VIEW, "VIEW", ICON_FILE_IMAGE, "View", "View the image and UV edit in mesh editmode"}, - {SI_MODE_PAINT, "PAINT", ICON_TPAINT_HLT, "Paint", "2D image painting mode"}, - {SI_MODE_MASK, "MASK", ICON_MOD_MASK, "Mask", "Mask editing"}, - {0, NULL, 0, NULL, NULL} - }; - StructRNA *srna; PropertyRNA *prop; @@ -3037,7 +3039,7 @@ static void rna_def_space_image(BlenderRNA *brna) /* mode */ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mode"); - RNA_def_property_enum_items(prop, image_space_mode_items); + RNA_def_property_enum_items(prop, rna_enum_space_image_mode_items); RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, "rna_SpaceImageEditor_mode_update"); diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c index b82ca145f5f..485cb298dae 100644 --- a/source/blender/makesrna/intern/rna_workspace.c +++ b/source/blender/makesrna/intern/rna_workspace.c @@ -49,6 +49,7 @@ #include "DNA_object_types.h" #include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "RNA_access.h" @@ -107,6 +108,42 @@ static void rna_WorkSpace_owner_ids_clear( WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, workspace); } +static bToolRef *rna_WorkSpace_tools_from_tkey(WorkSpace *workspace, const bToolKey *tkey, bool create) +{ + if (create) { + bToolRef *tref; + WM_toolsystem_ref_ensure(workspace, tkey, &tref); + return tref; + } + return WM_toolsystem_ref_find(workspace, tkey); +} + +static bToolRef *rna_WorkSpace_tools_from_space_view3d_mode( + WorkSpace *workspace, int mode, int create) +{ + return rna_WorkSpace_tools_from_tkey(workspace, &(bToolKey){ .space_type = SPACE_VIEW3D, .mode = mode}, create); +} + +static bToolRef *rna_WorkSpace_tools_from_space_image_mode( + WorkSpace *workspace, int mode, int create) +{ + return rna_WorkSpace_tools_from_tkey(workspace, &(bToolKey){ .space_type = SPACE_IMAGE, .mode = mode}, create); +} + +const EnumPropertyItem *rna_WorkSpace_tools_mode_itemf( + bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *UNUSED(r_free)) +{ + WorkSpace *workspace = ptr->id.data; + + switch (workspace->tools_space_type) { + case SPACE_VIEW3D: + return rna_enum_object_mode_items; + case SPACE_IMAGE: + return rna_enum_space_image_mode_items; + } + return DummyRNA_NULL_items; +} + #else /* RNA_RUNTIME */ static void rna_def_workspace_owner(BlenderRNA *brna) @@ -159,6 +196,56 @@ static void rna_def_workspace_owner_ids(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove all tags"); } +static void rna_def_workspace_tool(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "WorkspaceTool", NULL); + RNA_def_struct_sdna(srna, "bToolRef"); + RNA_def_struct_clear_flag(srna, STRUCT_UNDO); + RNA_def_struct_ui_text(srna, "Work Space Tool", ""); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "idname"); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); + + RNA_api_workspace_tool(srna); +} + +static void rna_def_workspace_tools(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "wmTools"); + srna = RNA_def_struct(brna, "wmTools", NULL); + RNA_def_struct_sdna(srna, "WorkSpace"); + RNA_def_struct_ui_text(srna, "WorkSpace UI Tags", ""); + + /* add owner_id */ + func = RNA_def_function(srna, "from_space_view3d_mode", "rna_WorkSpace_tools_from_space_view3d_mode"); + RNA_def_function_ui_description(func, ""); + parm = RNA_def_enum(func, "mode", rna_enum_object_mode_items, 0, "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_boolean(func, "create", false, "Create", ""); + /* return type */ + parm = RNA_def_pointer(func, "result", "WorkspaceTool", "", ""); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "from_space_image_mode", "rna_WorkSpace_tools_from_space_image_mode"); + RNA_def_function_ui_description(func, ""); + parm = RNA_def_enum(func, "mode", rna_enum_space_image_mode_items, 0, "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_boolean(func, "create", false, "Create", ""); + /* return type */ + parm = RNA_def_pointer(func, "result", "WorkspaceTool", "", ""); + RNA_def_function_return(func, parm); +} + static void rna_def_workspace(BlenderRNA *brna) { StructRNA *srna; @@ -177,36 +264,29 @@ static void rna_def_workspace(BlenderRNA *brna) "rna_workspace_screens_item_get", NULL, NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Screens", "Screen layouts of a workspace"); - prop = RNA_def_property(srna, "tool_keymap", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "tool.keymap"); - RNA_def_property_ui_text(prop, "Active Tool", "Currently active tool keymap"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - - prop = RNA_def_property(srna, "tool_manipulator_group", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "tool.manipulator_group"); - RNA_def_property_ui_text(prop, "Active Tool", "Currently active tool manipulator"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - - prop = RNA_def_property(srna, "tool_data_block", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "tool.data_block"); - RNA_def_property_ui_text(prop, "Active Tool", "Currently active data-block"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + prop = RNA_def_property(srna, "owner_ids", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "wmOwnerID"); + RNA_def_property_ui_text(prop, "UI Tags", ""); + rna_def_workspace_owner_ids(brna, prop); - prop = RNA_def_property(srna, "tool_index", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "tool.index"); - RNA_def_property_ui_text(prop, "Active Tool Index", "Tool group index"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + prop = RNA_def_property(srna, "tools", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "tools", NULL); + RNA_def_property_struct_type(prop, "WorkspaceTool"); + RNA_def_property_ui_text(prop, "Tools", ""); + rna_def_workspace_tools(brna, prop); - prop = RNA_def_property(srna, "tool_space_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "tool.spacetype"); + prop = RNA_def_property(srna, "tools_space_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "tools_space_type"); RNA_def_property_enum_items(prop, rna_enum_space_type_items); RNA_def_property_ui_text(prop, "Active Tool Space", "Tool space type"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - prop = RNA_def_property(srna, "owner_ids", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "wmOwnerID"); - RNA_def_property_ui_text(prop, "UI Tags", ""); - rna_def_workspace_owner_ids(brna, prop); + prop = RNA_def_property(srna, "tools_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "tools_mode"); + RNA_def_property_enum_items(prop, rna_enum_object_mode_items); /* value is placeholder, itemf is used. */ + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_WorkSpace_tools_mode_itemf"); + RNA_def_property_ui_text(prop, "Active Tool Space", "Tool mode"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); #if 0 prop = RNA_def_property(srna, "object_mode", PROP_ENUM, PROP_NONE); @@ -221,11 +301,15 @@ static void rna_def_workspace(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Use UI Tags", "Filter the UI by tags"); RNA_def_property_update(prop, 0, "rna_window_update_all"); + + RNA_api_workspace(srna); } void RNA_def_workspace(BlenderRNA *brna) { rna_def_workspace_owner(brna); + rna_def_workspace_tool(brna); + rna_def_workspace(brna); } diff --git a/source/blender/makesrna/intern/rna_workspace_api.c b/source/blender/makesrna/intern/rna_workspace_api.c new file mode 100644 index 00000000000..4b0e2b5918e --- /dev/null +++ b/source/blender/makesrna/intern/rna_workspace_api.c @@ -0,0 +1,90 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/makesrna/intern/rna_workspace_api.c + * \ingroup RNA + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "BLI_utildefines.h" + +#include "RNA_define.h" + +#include "DNA_object_types.h" +#include "DNA_windowmanager_types.h" + +#include "rna_internal.h" /* own include */ + +#ifdef RNA_RUNTIME + +static void rna_WorkspaceTool_setup( + ID *id, + bToolRef *tref, + bContext *C, + const char *name, + /* Args for: 'bToolRef_Runtime'. */ + const char *keymap, + const char *manipulator_group, + const char *data_block, + int index) +{ + bToolRef_Runtime tref_rt = {0}; + + STRNCPY(tref_rt.keymap, keymap); + STRNCPY(tref_rt.manipulator_group, manipulator_group); + STRNCPY(tref_rt.data_block, data_block); + tref_rt.index = index; + + WM_toolsystem_ref_set_from_runtime(C, (WorkSpace *)id, tref, &tref_rt, name); +} + +#else + +void RNA_api_workspace(StructRNA *UNUSED(srna)) +{ + /* FunctionRNA *func; */ + /* PropertyRNA *parm; */ +} + +void RNA_api_workspace_tool(StructRNA *srna) +{ + PropertyRNA *parm; + FunctionRNA *func; + + func = RNA_def_function(srna, "setup", "rna_WorkspaceTool_setup"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Set the tool settings"); + + parm = RNA_def_string(func, "name", NULL, KMAP_MAX_NAME, "Name", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + /* 'bToolRef_Runtime' */ + RNA_def_string(func, "keymap", NULL, KMAP_MAX_NAME, "Key Map", ""); + RNA_def_string(func, "manipulator_group", NULL, MAX_NAME, "Manipulator Group", ""); + RNA_def_string(func, "data_block", NULL, MAX_NAME, "Data Block", ""); + RNA_def_int(func, "index", 0, INT_MIN, INT_MAX, "Index", "", INT_MIN, INT_MAX); +} + +#endif diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 9176385c40d..5562e7880fa 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -47,6 +47,7 @@ extern "C" { #endif struct bContext; +struct bToolRef_Runtime; struct GHashIterator; struct IDProperty; struct wmEvent; @@ -595,13 +596,45 @@ bool WM_event_is_ime_switch(const struct wmEvent *event); #endif /* wm_toolsystem.c */ -void WM_toolsystem_unlink(struct bContext *C, struct WorkSpace *workspace); -void WM_toolsystem_link(struct bContext *C, struct WorkSpace *workspace); -void WM_toolsystem_refresh(struct bContext *C, struct WorkSpace *workspace); -void WM_toolsystem_set(struct bContext *C, const struct bToolDef *tool); +/* Values that define a categoey of active tool. */ +typedef struct bToolKey { int space_type; int mode; } bToolKey; + +struct bToolRef *WM_toolsystem_ref_from_context(struct bContext *C); +struct bToolRef *WM_toolsystem_ref_find(struct WorkSpace *workspace, const bToolKey *tkey); +bool WM_toolsystem_ref_ensure( + struct WorkSpace *workspace, const bToolKey *tkey, + struct bToolRef **r_tref); + +struct bToolRef_Runtime *WM_toolsystem_runtime_from_context(struct bContext *C); +struct bToolRef_Runtime *WM_toolsystem_runtime_find(struct WorkSpace *workspace, const bToolKey *tkey); + +void WM_toolsystem_unlink(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey); +void WM_toolsystem_link(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey); +void WM_toolsystem_refresh(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey); + +void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace); +void WM_toolsystem_link_all(struct bContext *C, struct WorkSpace *workspace); +void WM_toolsystem_refresh_all(struct bContext *C, struct WorkSpace *workspace); + +void WM_toolsystem_ref_set_from_runtime( + struct bContext *C, struct WorkSpace *workspace, struct bToolRef *tref, + const struct bToolRef_Runtime *tool, const char *idname); + void WM_toolsystem_init(struct bContext *C); +int WM_toolsystem_mode_from_spacetype( + struct WorkSpace *workspace, struct Scene *scene, struct ScrArea *sa, + int space_type); +bool WM_toolsystem_key_from_context( + struct WorkSpace *workspace, struct Scene *scene, struct ScrArea *sa, + bToolKey *tkey); +void WM_toolsystem_update_from_context( + struct bContext *C, + struct WorkSpace *workspace, struct Scene *scene, struct ScrArea *sa); + +void WM_toolsystem_update_from_context_view3d(struct bContext *C); + bool WM_toolsystem_active_tool_is_brush(const struct bContext *C); void WM_toolsystem_do_msg_notify_tag_refresh( diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 7963bf16534..8bbbd1b60df 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2875,11 +2875,14 @@ void wm_event_do_handlers(bContext *C) wmEventHandler sneaky_handler = {NULL}; if (ar->regiontype == RGN_TYPE_WINDOW) { WorkSpace *workspace = WM_window_get_active_workspace(win); - if (workspace->tool.keymap[0] && - workspace->tool.spacetype == sa->spacetype) - { + const bToolKey tkey = { + .space_type = sa->spacetype, + .mode = WM_toolsystem_mode_from_spacetype(workspace, win->scene, sa, sa->spacetype), + }; + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_find(workspace, &tkey); + if (tref_rt && tref_rt->keymap[0]) { wmKeyMap *km = WM_keymap_find_all( - C, workspace->tool.keymap, sa->spacetype, RGN_TYPE_WINDOW); + C, tref_rt->keymap, sa->spacetype, RGN_TYPE_WINDOW); if (km != NULL) { sneaky_handler.keymap = km; /* Handle widgets first. */ diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index a154f6b83ea..22133ae1602 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1826,69 +1826,6 @@ static void WM_OT_operator_defaults(wmOperatorType *ot) ot->flag = OPTYPE_INTERNAL; } -#ifdef USE_WORKSPACE_TOOL -/* ***************** Set Active Tool ************************* */ - -/* Developers note: in it's current form this doesn't need to be an operator, - * keep this as-is for now since it may end up setting an active key-map. - */ - -static int wm_operator_tool_set_exec(bContext *C, wmOperator *op) -{ - ScrArea *sa = CTX_wm_area(C); - - bToolDef tool_def = {{0}}; - - { - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "space_type"); - if (RNA_property_is_set(op->ptr, prop)) { - tool_def.spacetype = RNA_property_enum_get(op->ptr, prop); - } - else { - if (sa == NULL) { - BKE_report(op->reports, RPT_ERROR, "Space type not set"); - return OPERATOR_CANCELLED; - } - tool_def.spacetype = sa->spacetype; - } - } - - tool_def.index = RNA_int_get(op->ptr, "index"); - RNA_string_get(op->ptr, "keymap", tool_def.keymap); - RNA_string_get(op->ptr, "manipulator_group", tool_def.manipulator_group); - RNA_string_get(op->ptr, "data_block", tool_def.data_block); - - WM_toolsystem_set(C, &tool_def); - - /* For some reason redraw fails with menus (even though 'ar' isn't the menu's region). */ - if (sa) { - ED_area_tag_redraw(sa); - } - else { - WM_event_add_notifier(C, NC_WINDOW, NULL); - } - - return OPERATOR_FINISHED; -} - -static void WM_OT_tool_set(wmOperatorType *ot) -{ - ot->name = "Set Active Tool"; - ot->idname = "WM_OT_tool_set"; - ot->description = "Set the active tool"; - - ot->exec = wm_operator_tool_set_exec; - - ot->flag = OPTYPE_INTERNAL; - - RNA_def_enum(ot->srna, "space_type", rna_enum_space_type_items + 1, SPACE_EMPTY, "Space Type", ""); - RNA_def_string(ot->srna, "keymap", NULL, KMAP_MAX_NAME, "Key Map", ""); - RNA_def_string(ot->srna, "manipulator_group", NULL, MAX_NAME, "Manipulator Group", ""); - RNA_def_string(ot->srna, "data_block", NULL, MAX_NAME, "Data Block", ""); - RNA_def_int(ot->srna, "index", 0, INT_MIN, INT_MAX, "Index", "", INT_MIN, INT_MAX); -} -#endif /* USE_WORKSPACE_TOOL */ - /* ***************** Splash Screen ************************* */ static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg)) @@ -3765,9 +3702,6 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_memory_statistics); WM_operatortype_append(WM_OT_debug_menu); WM_operatortype_append(WM_OT_operator_defaults); -#ifdef USE_WORKSPACE_TOOL - WM_operatortype_append(WM_OT_tool_set); -#endif WM_operatortype_append(WM_OT_splash); WM_operatortype_append(WM_OT_search_menu); WM_operatortype_append(WM_OT_call_menu); diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c index c351d0fd849..24b902a6a92 100644 --- a/source/blender/windowmanager/intern/wm_toolsystem.c +++ b/source/blender/windowmanager/intern/wm_toolsystem.c @@ -28,13 +28,18 @@ #include "CLG_log.h" +#include "MEM_guardedalloc.h" + #include "BLI_utildefines.h" #include "BLI_string.h" +#include "BLI_listbase.h" #include "DNA_ID.h" #include "DNA_scene_types.h" +#include "DNA_space_types.h" #include "DNA_windowmanager_types.h" #include "DNA_workspace_types.h" +#include "DNA_object_types.h" #include "BKE_context.h" #include "BKE_library.h" @@ -48,16 +53,80 @@ #include "WM_types.h" #include "WM_message.h" -void WM_toolsystem_unlink(bContext *C, WorkSpace *workspace) + +/* -------------------------------------------------------------------- */ +/** \name Tool Reference API + * \{ */ + +struct bToolRef *WM_toolsystem_ref_from_context(struct bContext *C) { - Main *bmain = CTX_data_main(C); - wmWindowManager *wm = bmain->wm.first; + WorkSpace *workspace = CTX_wm_workspace(C); + Scene *scene = CTX_data_scene(C); + ScrArea *sa = CTX_wm_area(C); + const bToolKey tkey = { + .space_type = sa->spacetype, + .mode = WM_toolsystem_mode_from_spacetype(workspace, scene, sa, sa->spacetype), + }; + return WM_toolsystem_ref_find(workspace, &tkey); +} + +struct bToolRef_Runtime *WM_toolsystem_runtime_from_context(struct bContext *C) +{ + bToolRef *tref = WM_toolsystem_ref_from_context(C); + return tref ? tref->runtime : NULL; +} + +bToolRef *WM_toolsystem_ref_find(WorkSpace *workspace, const bToolKey *tkey) +{ + LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) { + if ((tref->space_type == tkey->space_type) && + (tref->mode == tkey->mode)) + { + return tref; + } + } + return NULL; +} + +bToolRef_Runtime *WM_toolsystem_runtime_find(WorkSpace *workspace, const bToolKey *tkey) +{ + bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey); + return tref ? tref->runtime : NULL; +} + +bool WM_toolsystem_ref_ensure( + struct WorkSpace *workspace, const bToolKey *tkey, + bToolRef **r_tref) +{ + bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey); + if (tref) { + *r_tref = tref; + return false; + } + tref = MEM_callocN(sizeof(*tref), __func__); + BLI_addhead(&workspace->tools, tref); + tref->space_type = tkey->space_type; + tref->mode = tkey->mode; + *r_tref = tref; + return true; +} + +/** \} */ + + +static void toolsystem_unlink_ref(bContext *C, WorkSpace *workspace, bToolRef *tref) +{ + bToolRef_Runtime *tref_rt = tref->runtime; - if (workspace->tool.manipulator_group[0]) { - wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(workspace->tool.manipulator_group, false); + if (tref_rt->manipulator_group[0]) { + wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(tref_rt->manipulator_group, false); if (wgt != NULL) { bool found = false; + /* TODO(campbell) */ + Main *bmain = CTX_data_main(C); +#if 0 + wmWindowManager *wm = bmain->wm.first; /* Check another workspace isn't using this tool. */ for (wmWindow *win = wm->windows.first; win; win = win->next) { const WorkSpace *workspace_iter = WM_window_get_active_workspace(win); @@ -68,7 +137,9 @@ void WM_toolsystem_unlink(bContext *C, WorkSpace *workspace) } } } - +#else + UNUSED_VARS(workspace); +#endif if (!found) { wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params); WM_manipulatormaptype_group_unlink(C, bmain, mmap_type, wgt); @@ -76,11 +147,19 @@ void WM_toolsystem_unlink(bContext *C, WorkSpace *workspace) } } } +void WM_toolsystem_unlink(bContext *C, WorkSpace *workspace, const bToolKey *tkey) +{ + bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey); + if (tref && tref->runtime) { + toolsystem_unlink_ref(C, workspace, tref); + } +} -void WM_toolsystem_link(bContext *C, WorkSpace *workspace) +static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tref) { - if (workspace->tool.manipulator_group[0]) { - const char *idname = workspace->tool.manipulator_group; + bToolRef_Runtime *tref_rt = tref->runtime; + if (tref_rt->manipulator_group[0]) { + const char *idname = tref_rt->manipulator_group; wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false); if (wgt != NULL) { WM_manipulator_group_type_ensure_ptr(wgt); @@ -90,11 +169,11 @@ void WM_toolsystem_link(bContext *C, WorkSpace *workspace) } } - if (workspace->tool.data_block[0]) { + if (tref_rt->data_block[0]) { Main *bmain = CTX_data_main(C); /* Currently only brush data-blocks supported. */ - struct Brush *brush = (struct Brush *)BKE_libblock_find_name(ID_BR, workspace->tool.data_block); + struct Brush *brush = (struct Brush *)BKE_libblock_find_name(ID_BR, tref_rt->data_block); if (brush) { wmWindowManager *wm = bmain->wm.first; @@ -113,34 +192,82 @@ void WM_toolsystem_link(bContext *C, WorkSpace *workspace) } } } +void WM_toolsystem_link(bContext *C, WorkSpace *workspace, const bToolKey *tkey) +{ + bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey); + if (tref) { + toolsystem_ref_link(C, workspace, tref); + } +} -void WM_toolsystem_refresh(bContext *C, WorkSpace *workspace) +static void toolsystem_refresh_ref(bContext *C, WorkSpace *workspace, bToolRef *tref) +{ + /* currently same operation. */ + toolsystem_ref_link(C, workspace, tref); +} +void WM_toolsystem_refresh(bContext *C, WorkSpace *workspace, const bToolKey *tkey) { - WM_toolsystem_link(C, workspace); + bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey); + if (tref) { + toolsystem_refresh_ref(C, workspace, tref); + } } -void WM_toolsystem_set(bContext *C, const bToolDef *tool) +/* Operate on all active tools. */ +void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace) { - WorkSpace *workspace = CTX_wm_workspace(C); + LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) { + if (tref->runtime) { + toolsystem_unlink_ref(C, workspace, tref); + } + } +} +void WM_toolsystem_link_all(struct bContext *C, struct WorkSpace *workspace) +{ + LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) { + if (tref->runtime) { + toolsystem_ref_link(C, workspace, tref); + } + } +} +void WM_toolsystem_refresh_all(struct bContext *C, struct WorkSpace *workspace) +{ + LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) { + if (tref->runtime) { + toolsystem_refresh_ref(C, workspace, tref); + } + } +} + +void WM_toolsystem_ref_set_from_runtime( + struct bContext *C, struct WorkSpace *workspace, bToolRef *tref, + const bToolRef_Runtime *tref_rt, const char *idname) +{ + if (tref->runtime) { + toolsystem_unlink_ref(C, workspace, tref); + } - WM_toolsystem_unlink(C, workspace); + STRNCPY(tref->idname, idname); - workspace->tool.index = tool->index; - workspace->tool.spacetype = tool->spacetype; + /* BAD DESIGN WARNING: used for topbar. */ + workspace->tools_space_type = tref->space_type; + workspace->tools_mode = tref->mode; - if (&workspace->tool != tool) { - STRNCPY(workspace->tool.keymap, tool->keymap); - STRNCPY(workspace->tool.manipulator_group, tool->manipulator_group); - STRNCPY(workspace->tool.data_block, tool->data_block); - workspace->tool.spacetype = tool->spacetype; + if (tref->runtime == NULL) { + tref->runtime = MEM_callocN(sizeof(*tref->runtime), __func__); } - WM_toolsystem_link(C, workspace); + if (tref_rt != tref->runtime) { + *tref->runtime = *tref_rt; + } + toolsystem_ref_link(C, workspace, tref); + + /* TODO(campbell): fix message. */ { struct wmMsgBus *mbus = CTX_wm_message_bus(C); WM_msg_publish_rna_prop( - mbus, &workspace->id, workspace, WorkSpace, tool_keymap); + mbus, &workspace->id, workspace, WorkSpace, tools); } } @@ -151,8 +278,84 @@ void WM_toolsystem_init(bContext *C) for (wmWindow *win = wm->windows.first; win; win = win->next) { WorkSpace *workspace = WM_window_get_active_workspace(win); - WM_toolsystem_link(C, workspace); + WM_toolsystem_link_all(C, workspace); + } +} + +int WM_toolsystem_mode_from_spacetype( + WorkSpace *workspace, Scene *scene, ScrArea *sa, + int spacetype) +{ + int mode = -1; + switch (spacetype) { + case SPACE_VIEW3D: + { + /* 'sa' may be NULL in this case. */ + ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene); + Object *obact = OBACT(view_layer); + mode = obact ? obact->mode : OB_MODE_OBJECT; + break; + } + case SPACE_IMAGE: + { + SpaceImage *sima = sa->spacedata.first; + mode = sima->mode; + break; + } } + return mode; +} + +bool WM_toolsystem_key_from_context( + WorkSpace *workspace, Scene *scene, ScrArea *sa, + bToolKey *tkey) +{ + int space_type = SPACE_EMPTY; + int mode = -1; + + if (sa != NULL) { + space_type = sa->spacetype; + mode = WM_toolsystem_mode_from_spacetype(workspace, scene, sa, space_type); + } + + if (mode != -1) { + tkey->space_type = space_type; + tkey->mode = mode; + return true; + } + return false; +} + +/** + * Run after changing modes. + */ +static void toolsystem_update_with_toolref( + bContext *C, WorkSpace *workspace, const bToolKey *tkey, const char *default_tool) +{ + bToolRef *tref; + if (WM_toolsystem_ref_ensure(workspace, tkey, &tref)) { + STRNCPY(tref->idname, default_tool); + } + + wmOperatorType *ot = WM_operatortype_find("WM_OT_tool_set_by_name", false); + PointerRNA op_props; + WM_operator_properties_create_ptr(&op_props, ot); + RNA_string_set(&op_props, "name", tref->idname); + RNA_enum_set(&op_props, "space_type", tkey->space_type); + WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props); + WM_operator_properties_free(&op_props); +} + +void WM_toolsystem_update_from_context_view3d(bContext *C) +{ + WorkSpace *workspace = CTX_wm_workspace(C); + Scene *scene = CTX_data_scene(C); + int space_type = SPACE_VIEW3D; + const bToolKey tkey = { + .space_type = space_type, + .mode = WM_toolsystem_mode_from_spacetype(workspace, scene, NULL, space_type), + }; + toolsystem_update_with_toolref(C, workspace, &tkey, "Cursor"); } /** @@ -160,15 +363,21 @@ void WM_toolsystem_init(bContext *C) */ bool WM_toolsystem_active_tool_is_brush(const bContext *C) { - WorkSpace *workspace = CTX_wm_workspace(C); - /* Will need to become more comprehensive, for now check tool data-block. */ - return workspace->tool.data_block[0] != '\0'; + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); + return tref_rt->data_block[0] != '\0'; } /* Follow wmMsgNotifyFn spec */ void WM_toolsystem_do_msg_notify_tag_refresh( - bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *UNUSED(msg_val)) + bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) { WorkSpace *workspace = CTX_wm_workspace(C); - WM_toolsystem_refresh(C, workspace); + Scene *scene = CTX_data_scene(C); + ScrArea *sa = msg_val->user_data; + int space_type = sa->spacetype; + const bToolKey tkey = { + .space_type = space_type, + .mode = WM_toolsystem_mode_from_spacetype(workspace, scene, sa, sa->spacetype), + }; + WM_toolsystem_refresh(C, workspace, &tkey); } |