Gizmo: value2d utility to adjust operator values
This allows any operator to interactively redo without having to manually make each operator modal.
This commit is contained in:
parent
26a6e58e9a
commit
1f1802307f
|
@ -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})
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue