Changeset View
Changeset View
Standalone View
Standalone View
source/blender/windowmanager/intern/wm_toolsystem.c
| Show All 22 Lines | |||||
| * | * | ||||
| * Experimental tool-system> | * Experimental tool-system> | ||||
| */ | */ | ||||
| #include <string.h> | #include <string.h> | ||||
| #include "CLG_log.h" | #include "CLG_log.h" | ||||
| #include "MEM_guardedalloc.h" | |||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_string.h" | #include "BLI_string.h" | ||||
| #include "BLI_listbase.h" | |||||
| #include "DNA_ID.h" | #include "DNA_ID.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_space_types.h" | |||||
| #include "DNA_windowmanager_types.h" | #include "DNA_windowmanager_types.h" | ||||
| #include "DNA_workspace_types.h" | #include "DNA_workspace_types.h" | ||||
| #include "DNA_object_types.h" | |||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_library.h" | #include "BKE_library.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_paint.h" | #include "BKE_paint.h" | ||||
| #include "BKE_workspace.h" | #include "BKE_workspace.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "WM_message.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); | WorkSpace *workspace = CTX_wm_workspace(C); | ||||
| wmWindowManager *wm = bmain->wm.first; | 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->tool_refs) { | |||||
| 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; | |||||
| } | |||||
| static bool toolref_ensure(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->tool_refs, 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]) { | if (tref_rt->manipulator_group[0]) { | ||||
| wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(workspace->tool.manipulator_group, false); | wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(tref_rt->manipulator_group, false); | ||||
| if (wgt != NULL) { | if (wgt != NULL) { | ||||
| bool found = false; | 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. */ | /* Check another workspace isn't using this tool. */ | ||||
| for (wmWindow *win = wm->windows.first; win; win = win->next) { | for (wmWindow *win = wm->windows.first; win; win = win->next) { | ||||
| const WorkSpace *workspace_iter = WM_window_get_active_workspace(win); | const WorkSpace *workspace_iter = WM_window_get_active_workspace(win); | ||||
| if (workspace != workspace_iter) { | if (workspace != workspace_iter) { | ||||
| if (STREQ(workspace->tool.manipulator_group, workspace_iter->tool.manipulator_group)) { | if (STREQ(workspace->tool.manipulator_group, workspace_iter->tool.manipulator_group)) { | ||||
| found = true; | found = true; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #else | |||||
| UNUSED_VARS(workspace); | |||||
| #endif | |||||
| if (!found) { | if (!found) { | ||||
| wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params); | wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params); | ||||
| WM_manipulatormaptype_group_unlink(C, bmain, mmap_type, wgt); | WM_manipulatormaptype_group_unlink(C, bmain, mmap_type, wgt); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| 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_link_ref(bContext *C, WorkSpace *workspace, bToolRef *tref) | ||||
| { | { | ||||
| if (workspace->tool.manipulator_group[0]) { | bToolRef_Runtime *tref_rt = tref->runtime; | ||||
| const char *idname = workspace->tool.manipulator_group; | if (tref_rt->manipulator_group[0]) { | ||||
| const char *idname = tref_rt->manipulator_group; | |||||
| wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false); | wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false); | ||||
| if (wgt != NULL) { | if (wgt != NULL) { | ||||
| WM_manipulator_group_type_ensure_ptr(wgt); | WM_manipulator_group_type_ensure_ptr(wgt); | ||||
| } | } | ||||
| else { | else { | ||||
| CLOG_WARN(WM_LOG_TOOLS, "'%s' widget not found", idname); | CLOG_WARN(WM_LOG_TOOLS, "'%s' widget not found", idname); | ||||
| } | } | ||||
| } | } | ||||
| if (workspace->tool.data_block[0]) { | if (tref_rt->data_block[0]) { | ||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| /* Currently only brush data-blocks supported. */ | /* 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) { | if (brush) { | ||||
| wmWindowManager *wm = bmain->wm.first; | wmWindowManager *wm = bmain->wm.first; | ||||
| for (wmWindow *win = wm->windows.first; win; win = win->next) { | for (wmWindow *win = wm->windows.first; win; win = win->next) { | ||||
| if (workspace == WM_window_get_active_workspace(win)) { | if (workspace == WM_window_get_active_workspace(win)) { | ||||
| Scene *scene = win->scene; | Scene *scene = win->scene; | ||||
| ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene); | ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene); | ||||
| Paint *paint = BKE_paint_get_active(scene, view_layer); | Paint *paint = BKE_paint_get_active(scene, view_layer); | ||||
| if (paint) { | if (paint) { | ||||
| if (brush) { | if (brush) { | ||||
| BKE_paint_brush_set(paint, brush); | BKE_paint_brush_set(paint, brush); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void WM_toolsystem_link(bContext *C, WorkSpace *workspace, const bToolKey *tkey) | |||||
| { | |||||
| bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey); | |||||
| if (tref) { | |||||
| toolsystem_link_ref(C, workspace, tref); | |||||
| } | |||||
| } | |||||
| static void toolsystem_refresh_ref(bContext *C, WorkSpace *workspace, bToolRef *tref) | |||||
| { | |||||
| /* currently same operation. */ | |||||
| toolsystem_link_ref(C, workspace, tref); | |||||
| } | |||||
| void WM_toolsystem_refresh(bContext *C, WorkSpace *workspace, const bToolKey *tkey) | |||||
| { | |||||
| bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey); | |||||
| if (tref) { | |||||
| toolsystem_refresh_ref(C, workspace, tref); | |||||
| } | |||||
| } | |||||
| void WM_toolsystem_refresh(bContext *C, WorkSpace *workspace) | /* Operate on all active tools. */ | ||||
| void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace) | |||||
| { | { | ||||
| WM_toolsystem_link(C, workspace); | LISTBASE_FOREACH (bToolRef *, tref, &workspace->tool_refs) { | ||||
| 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->tool_refs) { | |||||
| if (tref->runtime) { | |||||
| toolsystem_link_ref(C, workspace, tref); | |||||
| } | |||||
| } | |||||
| } | |||||
| void WM_toolsystem_refresh_all(struct bContext *C, struct WorkSpace *workspace) | |||||
| { | |||||
| LISTBASE_FOREACH (bToolRef *, tref, &workspace->tool_refs) { | |||||
| if (tref->runtime) { | |||||
| toolsystem_refresh_ref(C, workspace, tref); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| void WM_toolsystem_set(bContext *C, const bToolDef *tool) | void WM_toolsystem_set( | ||||
| struct bContext *C, const bToolKey *tkey, | |||||
| const bToolRef_Runtime *tref_rt, const char *idname) | |||||
| { | { | ||||
| WorkSpace *workspace = CTX_wm_workspace(C); | WorkSpace *workspace = CTX_wm_workspace(C); | ||||
| WM_toolsystem_unlink(C, workspace); | WM_toolsystem_unlink(C, workspace, tkey); | ||||
| workspace->tool.index = tool->index; | bToolRef *tref; | ||||
| workspace->tool.spacetype = tool->spacetype; | toolref_ensure(workspace, tkey, &tref); | ||||
| STRNCPY(tref->idname, idname); | |||||
| if (&workspace->tool != tool) { | if (tref->runtime == NULL) { | ||||
| STRNCPY(workspace->tool.keymap, tool->keymap); | tref->runtime = MEM_callocN(sizeof(*tref->runtime), __func__); | ||||
| STRNCPY(workspace->tool.manipulator_group, tool->manipulator_group); | |||||
| STRNCPY(workspace->tool.data_block, tool->data_block); | |||||
| workspace->tool.spacetype = tool->spacetype; | |||||
| } | } | ||||
| WM_toolsystem_link(C, workspace); | if (tref_rt != tref->runtime) { | ||||
| *tref->runtime = *tref_rt; | |||||
| } | |||||
| toolsystem_link_ref(C, workspace, tref); | |||||
| /* TODO(campbell): fix message. */ | |||||
| #if 0 | |||||
| { | { | ||||
| struct wmMsgBus *mbus = CTX_wm_message_bus(C); | struct wmMsgBus *mbus = CTX_wm_message_bus(C); | ||||
| WM_msg_publish_rna_prop( | WM_msg_publish_rna_prop( | ||||
| mbus, &workspace->id, workspace, WorkSpace, tool_keymap); | mbus, &workspace->id, workspace, WorkSpace, tool_keymap); | ||||
| } | } | ||||
| #endif | |||||
| } | } | ||||
| void WM_toolsystem_init(bContext *C) | void WM_toolsystem_init(bContext *C) | ||||
| { | { | ||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| wmWindowManager *wm = bmain->wm.first; | wmWindowManager *wm = bmain->wm.first; | ||||
| for (wmWindow *win = wm->windows.first; win; win = win->next) { | for (wmWindow *win = wm->windows.first; win; win = win->next) { | ||||
| WorkSpace *workspace = WM_window_get_active_workspace(win); | 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 (toolref_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"); | |||||
| } | } | ||||
| /** | /** | ||||
| * For paint modes to support non-brush tools. | * For paint modes to support non-brush tools. | ||||
| */ | */ | ||||
| bool WM_toolsystem_active_tool_is_brush(const bContext *C) | bool WM_toolsystem_active_tool_is_brush(const bContext *C) | ||||
| { | { | ||||
| WorkSpace *workspace = CTX_wm_workspace(C); | bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); | ||||
| /* Will need to become more comprehensive, for now check tool data-block. */ | return tref_rt->data_block[0] != '\0'; | ||||
| return workspace->tool.data_block[0] != '\0'; | |||||
| } | } | ||||
| /* Follow wmMsgNotifyFn spec */ | /* Follow wmMsgNotifyFn spec */ | ||||
| void WM_toolsystem_do_msg_notify_tag_refresh( | 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); | 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); | |||||
| } | } | ||||