From 1f1802307f9a3b1a09b9eb8d70dadc7c849c5e2c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 13 Sep 2018 09:04:50 +1000 Subject: Gizmo: value2d utility to adjust operator values This allows any operator to interactively redo without having to manually make each operator modal. --- .../blender/editors/gizmo_library/CMakeLists.txt | 2 + .../gizmo_group_types/value2d_gizmo_group.c | 176 +++++++++++++++++++++ .../gizmo_library/gizmo_types/value2d_gizmo.c | 145 +++++++++++++++++ source/blender/editors/include/ED_gizmo_library.h | 4 + source/blender/editors/space_api/spacetypes.c | 4 + source/blender/makesrna/intern/rna_wm_gizmo.c | 2 + .../blender/windowmanager/gizmo/WM_gizmo_types.h | 2 + .../blender/windowmanager/intern/wm_event_system.c | 20 ++- .../blender/windowmanager/intern/wm_toolsystem.c | 4 +- 9 files changed, 357 insertions(+), 2 deletions(-) create mode 100644 source/blender/editors/gizmo_library/gizmo_group_types/value2d_gizmo_group.c create mode 100644 source/blender/editors/gizmo_library/gizmo_types/value2d_gizmo.c (limited to 'source/blender') diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt index f89c3c27522..0e7b2a8be0f 100644 --- a/source/blender/editors/gizmo_library/CMakeLists.txt +++ b/source/blender/editors/gizmo_library/CMakeLists.txt @@ -45,6 +45,7 @@ set(SRC geometry/geom_arrow_gizmo.c geometry/geom_cube_gizmo.c geometry/geom_dial_gizmo.c + gizmo_group_types/value2d_gizmo_group.c gizmo_types/arrow2d_gizmo.c gizmo_types/arrow3d_gizmo.c gizmo_types/blank3d_gizmo.c @@ -54,6 +55,7 @@ set(SRC gizmo_types/dial3d_gizmo.c gizmo_types/move3d_gizmo.c gizmo_types/primitive3d_gizmo.c + gizmo_types/value2d_gizmo.c ) add_definitions(${GL_DEFINITIONS}) diff --git a/source/blender/editors/gizmo_library/gizmo_group_types/value2d_gizmo_group.c b/source/blender/editors/gizmo_library/gizmo_group_types/value2d_gizmo_group.c new file mode 100644 index 00000000000..274d35269d1 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_group_types/value2d_gizmo_group.c @@ -0,0 +1,176 @@ +/* + * ***** 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 value2d_gizmo_group.c + * \ingroup edgizmolib + * + * \name 2D Value Gizmo + * + * \brief Gizmo that edits a value for operator redo. + */ + +#include "BLI_utildefines.h" + +#include "BKE_context.h" + +#include "ED_undo.h" +#include "ED_screen.h" +#include "ED_gizmo_library.h" + +#include "UI_resources.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +/* -------------------------------------------------------------------- */ +/** \name Value Gizmo + * \{ */ + +struct ValueOpRedoGroup { + wmGizmo *gizmo; + struct { + const bContext *context; /* needed for redo. */ + wmOperator *op; + } state; +}; + +static void gizmo_op_redo_exec(struct ValueOpRedoGroup *igzgroup) +{ + wmOperator *op = igzgroup->state.op; + if (op == WM_operator_last_redo((bContext *)igzgroup->state.context)) { + ED_undo_operator_repeat((bContext *)igzgroup->state.context, op); + } +} + +/* translate callbacks */ +static void gizmo_value_operator_redo_value_get( + const wmGizmo *gz, wmGizmoProperty *gz_prop, + void *value_p) +{ + float *value = value_p; + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); + + struct ValueOpRedoGroup *igzgroup = gz->parent_gzgroup->customdata; + wmOperator *op = igzgroup->state.op; + *value = RNA_property_float_get(op->ptr, op->type->prop); +} + +static void gizmo_value_operator_redo_value_set( + const wmGizmo *gz, wmGizmoProperty *gz_prop, + const void *value_p) +{ + const float *value = value_p; + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); + + struct ValueOpRedoGroup *igzgroup = gz->parent_gzgroup->customdata; + wmOperator *op = igzgroup->state.op; + RNA_property_float_set(op->ptr, op->type->prop, *value); + gizmo_op_redo_exec(igzgroup); +} + +static void WIDGETGROUP_value_operator_redo_modal_from_setup( + const bContext *C, wmGizmoGroup *gzgroup) +{ + /* Start off dragging. */ + wmWindow *win = CTX_wm_window(C); + wmGizmo *gz = gzgroup->gizmos.first; + wmGizmoMap *gzmap = gzgroup->parent_gzmap; + WM_gizmo_modal_set_from_setup( + gzmap, (bContext *)C, gz, 0, win->eventstate); +} + +static void WIDGETGROUP_value_operator_redo_setup(const bContext *C, wmGizmoGroup *gzgroup) +{ + struct ValueOpRedoGroup *igzgroup = MEM_mallocN(sizeof(struct ValueOpRedoGroup), __func__); + + igzgroup->gizmo = WM_gizmo_new("GIZMO_GT_value_2d", gzgroup, NULL); + wmGizmo *gz = igzgroup->gizmo; + + igzgroup->state.context = C; + igzgroup->state.op = WM_operator_last_redo(C); + + gzgroup->customdata = igzgroup; + + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); + + WM_gizmo_target_property_def_func( + gz, "offset", + &(const struct wmGizmoPropertyFnParams) { + .value_get_fn = gizmo_value_operator_redo_value_get, + .value_set_fn = gizmo_value_operator_redo_value_set, + .range_get_fn = NULL, + .user_data = igzgroup, + }); + + /* Become modal as soon as it's started. */ + WIDGETGROUP_value_operator_redo_modal_from_setup(C, gzgroup); +} + +static void WIDGETGROUP_value_operator_redo_refresh(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + struct ValueOpRedoGroup *igzgroup = gzgroup->customdata; + wmGizmo *gz = igzgroup->gizmo; + wmOperator *op = WM_operator_last_redo((bContext *)igzgroup->state.context); + wmGizmoMap *gzmap = gzgroup->parent_gzmap; + + /* FIXME */ + extern struct wmGizmo *wm_gizmomap_modal_get(struct wmGizmoMap *gzmap); + if ((op != igzgroup->state.op) || + (wm_gizmomap_modal_get(gzmap) != gz)) + { + WM_gizmo_group_type_unlink_delayed_ptr(gzgroup->type); + } +} + +static void WM_GGT_value_operator_redo(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Value Operator Redo"; + gzgt->idname = "WM_GGT_value_operator_redo"; + + /* FIXME, allow multiple. */ + gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_INIT; + + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; + + + gzgt->setup = WIDGETGROUP_value_operator_redo_setup; + gzgt->refresh = WIDGETGROUP_value_operator_redo_refresh; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public API + * \{ */ + +void ED_gizmogrouptypes_value_2d(void) +{ + WM_gizmogrouptype_append(WM_GGT_value_operator_redo); +} + +/** \} */ diff --git a/source/blender/editors/gizmo_library/gizmo_types/value2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/value2d_gizmo.c new file mode 100644 index 00000000000..c0c53523ea9 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_types/value2d_gizmo.c @@ -0,0 +1,145 @@ +/* + * ***** 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 value2d_gizmo.c + * \ingroup edgizmolib + * + * \name Value Gizmo + * + * \brief Gizmo that can be used to click and drag a value. + * + * Use this in cases where it may be useful to have a tool, + * but the tool doesn't relate to an on-screen handle. + * eg: smooth or randomize. + * + * Exactly how this maps X/Y axis, and draws - may change. + * The purpose here is to avoid having to write custom modal handlers for each operator. + * + * So we can use a single gizmo to make redoing an operator seem modal. + */ + +#include "MEM_guardedalloc.h" + +#include "BKE_context.h" + +#include "ED_gizmo_library.h" + +#include "WM_types.h" +#include "WM_api.h" + +/* own includes */ +#include "../gizmo_geometry.h" +#include "../gizmo_library_intern.h" + +/* -------------------------------------------------------------------- */ +/** \name Value Gizmo + * + * \{ */ + +typedef struct ValueInteraction { + float init_mval[2]; + float init_prop_value; + float range[2]; +} ValueInteraction; + +static void gizmo_value_draw(const bContext *UNUSED(C), wmGizmo *UNUSED(gz)) +{ + /* pass */ +} + +static int gizmo_value_modal( + bContext *C, wmGizmo *gz, const wmEvent *event, + eWM_GizmoFlagTweak UNUSED(tweak_flag)) +{ + ARegion *ar = CTX_wm_region(C); + ValueInteraction *inter = gz->interaction_data; + const float value_scale = 4.0f; /* Could be option. */ + const float value_range = inter->range[1] - inter->range[0]; + const float value_delta = ( + inter->init_prop_value + + (((event->mval[0] - inter->init_mval[0]) / ar->winx) * value_range)) * value_scale; + + /* set the property for the operator and call its modal function */ + wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset"); + if (WM_gizmo_target_property_is_valid(gz_prop)) { + WM_gizmo_target_property_float_set(C, gz, gz_prop, inter->init_prop_value + value_delta); + } + return OPERATOR_RUNNING_MODAL; +} + + +static int gizmo_value_invoke( + bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event) +{ + ValueInteraction *inter = MEM_callocN(sizeof(ValueInteraction), __func__); + + inter->init_mval[0] = event->mval[0]; + inter->init_mval[1] = event->mval[1]; + + wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset"); + if (WM_gizmo_target_property_is_valid(gz_prop)) { + inter->init_prop_value = WM_gizmo_target_property_float_get(gz, gz_prop); + if (!WM_gizmo_target_property_float_range_get(gz, gz_prop, inter->range)) { + inter->range[0] = 0.0f; + inter->range[1] = 1.0f; + } + } + + gz->interaction_data = inter; + + return OPERATOR_RUNNING_MODAL; +} + +static int gizmo_value_test_select( + bContext *UNUSED(C), wmGizmo *UNUSED(gz), const int UNUSED(mval[2])) +{ + return 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Value Gizmo API + * + * \{ */ + +static void GIZMO_GT_value_2d(wmGizmoType *gzt) +{ + /* identifiers */ + gzt->idname = "GIZMO_GT_value_2d"; + + /* api callbacks */ + gzt->draw = gizmo_value_draw; + gzt->invoke = gizmo_value_invoke; + gzt->modal = gizmo_value_modal; + gzt->test_select = gizmo_value_test_select; + + gzt->struct_size = sizeof(wmGizmo); + + WM_gizmotype_target_property_def(gzt, "offset", PROP_FLOAT, 1); + /* Options: relative / absolute */ +} + +void ED_gizmotypes_value_2d(void) +{ + WM_gizmotype_append(GIZMO_GT_value_2d); +} + +/** \} */ diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h index 02c5a80bf62..faf0040779f 100644 --- a/source/blender/editors/include/ED_gizmo_library.h +++ b/source/blender/editors/include/ED_gizmo_library.h @@ -42,6 +42,10 @@ void ED_gizmotypes_facemap_3d(void); void ED_gizmotypes_preselect_3d(void); void ED_gizmotypes_primitive_3d(void); void ED_gizmotypes_blank_3d(void); +void ED_gizmotypes_value_2d(void); + +/* gizmo group types */ +void ED_gizmogrouptypes_value_2d(void); struct bContext; struct Object; diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index c811e127cfe..91dff98f906 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -140,6 +140,10 @@ void ED_spacetypes_init(void) ED_gizmotypes_blank_3d(); ED_gizmotypes_cage_2d(); ED_gizmotypes_cage_3d(); + ED_gizmotypes_value_2d(); + + /* gizmo group types */ + ED_gizmogrouptypes_value_2d(); /* register types for operators and gizmos */ spacetypes = BKE_spacetypes_list(); diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c index 4cb682df05d..6a1d00b13ae 100644 --- a/source/blender/makesrna/intern/rna_wm_gizmo.c +++ b/source/blender/makesrna/intern/rna_wm_gizmo.c @@ -1241,6 +1241,8 @@ static void rna_def_gizmogroup(BlenderRNA *brna) ""}, {WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL, "SHOW_MODAL_ALL", 0, "Show Modal All", "Show all while interacting"}, + {WM_GIZMOGROUPTYPE_TOOL_INIT, "TOOL_INIT", 0, "Tool Init", + "Postpone running until tool operator run (when used with a tool)"}, {0, NULL, 0, NULL, NULL} }; prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE); diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index 46b6b85e8f2..2ab536752c3 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -106,6 +106,8 @@ typedef enum eWM_GizmoFlagGroupTypeFlag { WM_GIZMOGROUPTYPE_PERSISTENT = (1 << 4), /* Show all other gizmos when interacting. */ WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL = (1 << 5), + /* When used with tool, only run when activating the tool. */ + WM_GIZMOGROUPTYPE_TOOL_INIT = (1 << 6), } eWM_GizmoFlagGroupTypeFlag; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index cd1357e85b1..d9c8028c9bb 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2031,7 +2031,8 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand if (ot && wm_operator_check_locked_interface(C, ot)) { bool use_last_properties = true; PointerRNA tool_properties = {{0}}; - bool use_tool_properties = (handler->keymap_tool != NULL); + const bool is_tool = (handler->keymap_tool != NULL); + const bool use_tool_properties = is_tool; if (use_tool_properties) { WM_toolsystem_ref_properties_init_for_keymap(handler->keymap_tool, &tool_properties, properties, ot); @@ -2044,6 +2045,23 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand if (use_tool_properties) { WM_operator_properties_free(&tool_properties); } + + /* Link gizmo if 'WM_GIZMOGROUPTYPE_TOOL_INIT' is set. */ + if (retval & OPERATOR_FINISHED) { + if (is_tool) { + bToolRef_Runtime *tref_rt = handler->keymap_tool->runtime; + if (tref_rt->gizmo_group[0]) { + const char *idname = tref_rt->gizmo_group; + wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false); + if (gzgt != NULL) { + if ((gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_INIT) != 0) { + WM_gizmo_group_type_ensure_ptr(gzgt); + } + } + } + } + } + /* Done linking gizmo. */ } } /* Finished and pass through flag as handled */ diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c index 0aa5e16a519..15b29902eb1 100644 --- a/source/blender/windowmanager/intern/wm_toolsystem.c +++ b/source/blender/windowmanager/intern/wm_toolsystem.c @@ -176,7 +176,9 @@ static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tre const char *idname = tref_rt->gizmo_group; wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false); if (gzgt != NULL) { - WM_gizmo_group_type_ensure_ptr(gzgt); + if ((gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_INIT) == 0) { + WM_gizmo_group_type_ensure_ptr(gzgt); + } } else { CLOG_WARN(WM_LOG_TOOLS, "'%s' widget not found", idname); -- cgit v1.2.3