Custom Manipulators Core Backend
This commit lands the core backend of the Custom Manipulators project onto the blender2.8 branch. It is a generic backend for managinig interactive on-screen controls that can be integrated into any 2D or 3D edito. It's also already integrated into the window-manager and editor code where needed. NOTE: The changes here should not be visible for users at all. It's really just a back-end patch. Neither does this include any RNA or Python integration. Of course, there's still lots of work ahead for custom manipulators, but this is a big milestone. WIP code that actually uses this backend can be found in the 'custom-manipulators' branch (previously called 'wiggly-widgets'). The work here isn't completely my own, all the initial work was done by @Antony Riakiotakis (psy-fi) and - although it has changed a lot since them - it's still the same in essence. He definitely deserves a big credit! Some changes in this patch were also done by @Campbell Barton (campbellbarton). Thank you guys! Merge accepted by @brecht and @merwin. Patch: https://developer.blender.org/D2232 Code documentation: https://wiki.blender.org/index.php/Dev:2.8/Source/Custom_Manipulator Main task: https://developer.blender.org/T47343 More info: https://code.blender.org/2015/09/the-custom-manipulator-project-widget-project/
This commit is contained in:
@@ -49,6 +49,7 @@ struct bScreen;
|
||||
struct uiLayout;
|
||||
struct uiList;
|
||||
struct wmKeyConfig;
|
||||
struct wmManipulatorMap;
|
||||
struct wmNotifier;
|
||||
struct wmWindow;
|
||||
struct wmWindowManager;
|
||||
@@ -96,6 +97,9 @@ typedef struct SpaceType {
|
||||
/* on startup, define dropboxes for spacetype+regions */
|
||||
void (*dropboxes)(void);
|
||||
|
||||
/* initialize manipulator-map-types and manipulator-group-types with the region */
|
||||
void (*manipulators)(void);
|
||||
|
||||
/* return context data */
|
||||
int (*context)(const struct bContext *, const char *, struct bContextDataResult *);
|
||||
|
||||
@@ -284,6 +288,8 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID
|
||||
struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar);
|
||||
void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar);
|
||||
void BKE_screen_area_free(struct ScrArea *sa);
|
||||
/* Manipulator-maps of a region need to be freed with the region. Uses callback to avoid low-level call. */
|
||||
void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManipulatorMap *));
|
||||
|
||||
struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type);
|
||||
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa);
|
||||
|
@@ -180,6 +180,7 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
|
||||
BLI_listbase_clear(&newar->panels_category_active);
|
||||
BLI_listbase_clear(&newar->ui_lists);
|
||||
newar->swinid = 0;
|
||||
newar->manipulator_map = NULL;
|
||||
newar->regiontimer = NULL;
|
||||
|
||||
/* use optional regiondata callback */
|
||||
@@ -288,6 +289,17 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Avoid bad-level calls to #WM_manipulatormap_delete.
|
||||
*/
|
||||
static void (*region_free_manipulatormap_callback)(struct wmManipulatorMap *) = NULL;
|
||||
|
||||
void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManipulatorMap *))
|
||||
{
|
||||
region_free_manipulatormap_callback = callback;
|
||||
}
|
||||
|
||||
/* not region itself */
|
||||
void BKE_area_region_free(SpaceType *st, ARegion *ar)
|
||||
{
|
||||
@@ -337,6 +349,8 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
|
||||
MEM_freeN(uilst->properties);
|
||||
}
|
||||
}
|
||||
|
||||
region_free_manipulatormap_callback(ar->manipulator_map);
|
||||
BLI_freelistN(&ar->ui_lists);
|
||||
BLI_freelistN(&ar->ui_previews);
|
||||
BLI_freelistN(&ar->panels_category);
|
||||
|
@@ -304,6 +304,7 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]);
|
||||
void ortho_v3_v3(float out[3], const float v[3]);
|
||||
void ortho_v2_v2(float out[2], const float v[2]);
|
||||
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
|
||||
void rotate_v2_v2fl(float r[2], const float p[2], const float angle);
|
||||
void rotate_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle);
|
||||
void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], const float angle);
|
||||
|
||||
|
@@ -771,6 +771,20 @@ void ortho_v2_v2(float out[2], const float v[2])
|
||||
out[1] = v[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate a point \a p by \a angle around origin (0, 0)
|
||||
*/
|
||||
void rotate_v2_v2fl(float r[2], const float p[2], const float angle)
|
||||
{
|
||||
const float co = cosf(angle);
|
||||
const float si = sinf(angle);
|
||||
|
||||
BLI_assert(r != p);
|
||||
|
||||
r[0] = co * p[0] - si * p[1];
|
||||
r[1] = si * p[0] + co * p[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
|
||||
* http://local.wasp.uwa.edu.au/~pbourke/geometry/
|
||||
|
@@ -6516,6 +6516,7 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
|
||||
ar->type = NULL;
|
||||
ar->swap = 0;
|
||||
ar->do_draw = 0;
|
||||
ar->manipulator_map = NULL;
|
||||
ar->regiontimer = NULL;
|
||||
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
|
||||
}
|
||||
|
@@ -1660,6 +1660,8 @@ void init_userdef_do_versions(void)
|
||||
U.tw_size = 25; /* percentage of window size */
|
||||
U.tw_handlesize = 16; /* percentage of widget radius */
|
||||
}
|
||||
if (U.manipulator_scale == 0)
|
||||
U.manipulator_scale = 75;
|
||||
if (U.pad_rot_angle == 0.0f)
|
||||
U.pad_rot_angle = 15.0f;
|
||||
|
||||
|
@@ -1069,6 +1069,9 @@ static void region_cursor_set(wmWindow *win, int swinid, int swin_changed)
|
||||
for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
|
||||
if (ar->swinid == swinid) {
|
||||
if (swin_changed || (ar->type && ar->type->event_cursor)) {
|
||||
if (WM_manipulatormap_cursor_set(ar->manipulator_map, win)) {
|
||||
return;
|
||||
}
|
||||
ED_region_cursor_set(win, sa, ar);
|
||||
}
|
||||
return;
|
||||
|
@@ -122,12 +122,17 @@ void ED_spacetypes_init(void)
|
||||
ED_operatortypes_view2d();
|
||||
ED_operatortypes_ui();
|
||||
|
||||
/* register operators */
|
||||
/* register types for operators and manipulators */
|
||||
spacetypes = BKE_spacetypes_list();
|
||||
for (type = spacetypes->first; type; type = type->next) {
|
||||
if (type->operatortypes)
|
||||
/* init manipulator types first, operator-types need them */
|
||||
if (type->manipulators) {
|
||||
type->manipulators();
|
||||
}
|
||||
if (type->operatortypes) {
|
||||
type->operatortypes();
|
||||
}
|
||||
}
|
||||
|
||||
/* register internal render callbacks */
|
||||
ED_render_internal_init();
|
||||
|
@@ -266,6 +266,7 @@ typedef struct ARegion {
|
||||
ListBase handlers; /* wmEventHandler */
|
||||
ListBase panels_category; /* Panel categories runtime */
|
||||
|
||||
struct wmManipulatorMap *manipulator_map; /* manipulator-map of this region */
|
||||
struct wmTimer *regiontimer; /* blend in/out */
|
||||
|
||||
char *headerstr; /* use this string to draw info */
|
||||
|
@@ -490,6 +490,7 @@ typedef struct UserDef {
|
||||
short tb_leftmouse, tb_rightmouse;
|
||||
struct SolidLight light[3];
|
||||
short tw_hotspot, tw_flag, tw_handlesize, tw_size;
|
||||
short manipulator_scale, pad3[3];
|
||||
short textimeout, texcollectrate;
|
||||
short wmdrawmethod; /* removed wmpad */
|
||||
short dragthreshold;
|
||||
@@ -782,8 +783,6 @@ typedef enum eText_Draw_Options {
|
||||
USER_TEXT_DISABLE_AA = (1 << 0),
|
||||
} eText_Draw_Options;
|
||||
|
||||
/* tw_flag (transform widget) */
|
||||
|
||||
/* gp_settings (Grease Pencil Settings) */
|
||||
typedef enum eGP_UserdefSettings {
|
||||
GP_PAINT_DOSMOOTH = (1 << 0),
|
||||
|
@@ -111,7 +111,7 @@ typedef struct RegionView3D {
|
||||
struct wmTimer *smooth_timer;
|
||||
|
||||
|
||||
/* transform widget matrix */
|
||||
/* transform manipulator matrix */
|
||||
float twmat[4][4];
|
||||
|
||||
float viewquat[4]; /* view rotation, must be kept normalized */
|
||||
@@ -202,7 +202,7 @@ typedef struct View3D {
|
||||
short gridsubdiv; /* Number of subdivisions in the grid between each highlighted grid line */
|
||||
char gridflag;
|
||||
|
||||
/* transform widget info */
|
||||
/* transform manipulator info */
|
||||
char twtype, twmode, twflag;
|
||||
|
||||
short flag3;
|
||||
|
@@ -25,6 +25,8 @@
|
||||
|
||||
set(INC
|
||||
.
|
||||
manipulators
|
||||
manipulators/intern
|
||||
../blenfont
|
||||
../blenkernel
|
||||
../blenlib
|
||||
@@ -68,6 +70,10 @@ set(SRC
|
||||
intern/wm_subwindow.c
|
||||
intern/wm_window.c
|
||||
intern/wm_stereo.c
|
||||
manipulators/intern/wm_manipulator.c
|
||||
manipulators/intern/wm_manipulatorgroup.c
|
||||
manipulators/intern/wm_manipulatormap.c
|
||||
manipulators/intern/manipulator_library/manipulator_library_utils.c
|
||||
|
||||
WM_api.h
|
||||
WM_keymap.h
|
||||
@@ -80,6 +86,11 @@ set(SRC
|
||||
wm_files.h
|
||||
wm_subwindow.h
|
||||
wm_window.h
|
||||
manipulators/WM_manipulator_api.h
|
||||
manipulators/WM_manipulator_types.h
|
||||
manipulators/wm_manipulator_wmapi.h
|
||||
manipulators/intern/wm_manipulator_intern.h
|
||||
manipulators/intern/manipulator_library/manipulator_library_intern.h
|
||||
)
|
||||
|
||||
if(WITH_AUDASPACE)
|
||||
|
@@ -42,6 +42,9 @@
|
||||
#include "WM_keymap.h"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
|
||||
/* Include external manipulator API's */
|
||||
#include "manipulators/WM_manipulator_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -70,6 +73,9 @@ struct wmNDOFMotionData;
|
||||
#endif
|
||||
|
||||
typedef struct wmJob wmJob;
|
||||
typedef struct wmManipulator wmManipulator;
|
||||
typedef struct wmManipulatorMap wmManipulatorMap;
|
||||
typedef struct wmManipulatorMapType wmManipulatorMapType;
|
||||
|
||||
/* general API */
|
||||
void WM_init_state_size_set (int stax, int stay, int sizx, int sizy);
|
||||
|
@@ -119,6 +119,7 @@ struct ImBuf;
|
||||
/* exported types for WM */
|
||||
#include "wm_cursors.h"
|
||||
#include "wm_event_types.h"
|
||||
#include "manipulators/WM_manipulator_types.h"
|
||||
|
||||
/* ************** wmOperatorType ************************ */
|
||||
|
||||
@@ -566,6 +567,9 @@ typedef struct wmOperatorType {
|
||||
/* pointer to modal keymap, do not free! */
|
||||
struct wmKeyMap *modalkeymap;
|
||||
|
||||
/* manipulator-group that is accessible while operator runs */
|
||||
wmManipulatorGroupType *mgrouptype;
|
||||
|
||||
/* python needs the operator type as well */
|
||||
int (*pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
|
@@ -1673,6 +1673,11 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
|
||||
wm_region_mouse_co(C, event);
|
||||
wm_event_modalkeymap(C, op, event, &dbl_click_disabled);
|
||||
|
||||
/* attach manipulator-map to handler if not there yet */
|
||||
if (ot->mgrouptype && !handler->manipulator_map) {
|
||||
wm_manipulatorgroup_attach_to_modal_handler(C, handler, ot->mgrouptype, op);
|
||||
}
|
||||
|
||||
if (ot->flag & OPTYPE_UNDO)
|
||||
wm->op_undo_depth++;
|
||||
|
||||
@@ -1721,6 +1726,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
|
||||
CTX_wm_region_set(C, NULL);
|
||||
}
|
||||
|
||||
/* update manipulators during modal handlers */
|
||||
wm_manipulatormaps_handled_modal_update(C, event, handler, ot);
|
||||
|
||||
/* remove modal handler, operator itself should have been canceled and freed */
|
||||
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
|
||||
WM_cursor_grab_disable(CTX_wm_window(C), NULL);
|
||||
@@ -2090,6 +2098,71 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (handler->manipulator_map) {
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
wmManipulatorMap *mmap = handler->manipulator_map;
|
||||
wmManipulator *manipulator = wm_manipulatormap_get_highlighted_manipulator(mmap);
|
||||
unsigned char part;
|
||||
|
||||
wm_manipulatormap_handler_context(C, handler);
|
||||
wm_region_mouse_co(C, event);
|
||||
|
||||
/* handle manipulator highlighting */
|
||||
if (event->type == MOUSEMOVE && !wm_manipulatormap_get_active_manipulator(mmap)) {
|
||||
manipulator = wm_manipulatormap_find_highlighted_manipulator(mmap, C, event, &part);
|
||||
wm_manipulatormap_set_highlighted_manipulator(mmap, C, manipulator, part);
|
||||
}
|
||||
/* handle user configurable manipulator-map keymap */
|
||||
else if (manipulator) {
|
||||
/* get user customized keymap from default one */
|
||||
const wmManipulatorGroup *highlightgroup = wm_manipulator_get_parent_group(manipulator);
|
||||
const wmKeyMap *keymap = WM_keymap_active(wm, highlightgroup->type->keymap);
|
||||
wmKeyMapItem *kmi;
|
||||
|
||||
PRINT("%s: checking '%s' ...", __func__, keymap->idname);
|
||||
|
||||
if (!keymap->poll || keymap->poll(C)) {
|
||||
PRINT("pass\n");
|
||||
for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
|
||||
if (wm_eventmatch(event, kmi)) {
|
||||
wmOperator *op = handler->op;
|
||||
|
||||
PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
|
||||
|
||||
/* weak, but allows interactive callback to not use rawkey */
|
||||
event->keymap_idname = kmi->idname;
|
||||
|
||||
/* handler->op is called later, we want keymap op to be triggered here */
|
||||
handler->op = NULL;
|
||||
action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
|
||||
handler->op = op;
|
||||
|
||||
if (action & WM_HANDLER_BREAK) {
|
||||
if (action & WM_HANDLER_HANDLED) {
|
||||
if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS))
|
||||
printf("%s: handled - and pass on! '%s'\n", __func__, kmi->idname);
|
||||
}
|
||||
else {
|
||||
PRINT("%s: un-handled '%s'\n", __func__, kmi->idname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
PRINT("fail\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* restore the area */
|
||||
CTX_wm_area_set(C, area);
|
||||
CTX_wm_region_set(C, region);
|
||||
|
||||
if (handler->op) {
|
||||
action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* modal, swallows all */
|
||||
action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
|
||||
|
@@ -169,6 +169,7 @@ void WM_init(bContext *C, int argc, const char **argv)
|
||||
|
||||
BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */
|
||||
BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */
|
||||
BKE_region_callback_free_manipulatormap_set(wm_manipulatormap_delete); /* screen.c */
|
||||
BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */
|
||||
BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */
|
||||
BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */
|
||||
@@ -529,6 +530,9 @@ void WM_exit_ext(bContext *C, const bool do_python)
|
||||
ED_gpencil_strokes_copybuf_free();
|
||||
BKE_node_clipboard_clear();
|
||||
|
||||
/* free manipulator-maps after freeing blender, so no deleted data get accessed during cleaning up of areas */
|
||||
wm_manipulatormaptypes_free();
|
||||
|
||||
BLF_exit();
|
||||
|
||||
#ifdef WITH_INTERNATIONAL
|
||||
|
@@ -491,6 +491,9 @@ void WM_operatortype_remove_ptr(wmOperatorType *ot)
|
||||
BLI_ghash_remove(global_ops_hash, ot->idname, NULL, NULL);
|
||||
|
||||
WM_keyconfig_update_operatortype();
|
||||
if (ot->mgrouptype) {
|
||||
WM_manipulatorgrouptype_unregister(NULL, G.main, ot->mgrouptype);
|
||||
}
|
||||
|
||||
MEM_freeN(ot);
|
||||
}
|
||||
@@ -4170,6 +4173,10 @@ void wm_operatortype_init(void)
|
||||
WM_operatortype_append(WM_OT_previews_ensure);
|
||||
WM_operatortype_append(WM_OT_previews_clear);
|
||||
WM_operatortype_append(WM_OT_doc_view_manual_ui_context);
|
||||
|
||||
/* manipulators */
|
||||
WM_operatortype_append(MANIPULATORGROUP_OT_manipulator_select);
|
||||
WM_operatortype_append(MANIPULATORGROUP_OT_manipulator_tweak);
|
||||
}
|
||||
|
||||
/* circleselect-like modal operators */
|
||||
@@ -4475,6 +4482,7 @@ void wm_window_keymap(wmKeyConfig *keyconf)
|
||||
RNA_float_set(kmi->ptr, "value", 1.0f / 1.5f);
|
||||
#endif /* WITH_INPUT_NDOF */
|
||||
|
||||
wm_manipulators_keymap(keyconf);
|
||||
gesture_circle_modal_keymap(keyconf);
|
||||
gesture_border_modal_keymap(keyconf);
|
||||
gesture_zoom_border_modal_keymap(keyconf);
|
||||
|
110
source/blender/windowmanager/manipulators/WM_manipulator_api.h
Normal file
110
source/blender/windowmanager/manipulators/WM_manipulator_api.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/windowmanager/manipulators/WM_manipulator_api.h
|
||||
* \ingroup wm
|
||||
*
|
||||
* \name Manipulator API
|
||||
* \brief API for external use of wmManipulator types.
|
||||
*
|
||||
* Only included in WM_api.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __WM_MANIPULATOR_API_H__
|
||||
#define __WM_MANIPULATOR_API_H__
|
||||
|
||||
struct ARegion;
|
||||
struct Main;
|
||||
struct wmKeyConfig;
|
||||
struct wmManipulatorGroupType;
|
||||
struct wmManipulatorMap;
|
||||
struct wmManipulatorMapType;
|
||||
struct wmManipulatorMapType_Params;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulator */
|
||||
|
||||
struct wmManipulator *WM_manipulator_new(
|
||||
void (*draw)(const struct bContext *, struct wmManipulator *),
|
||||
void (*render_3d_intersection)(const struct bContext *, struct wmManipulator *, int),
|
||||
int (*intersect)(struct bContext *, const struct wmEvent *, struct wmManipulator *),
|
||||
int (*handler)(struct bContext *, const struct wmEvent *, struct wmManipulator *, const int));
|
||||
void WM_manipulator_delete(
|
||||
ListBase *manipulatorlist, struct wmManipulatorMap *mmap, struct wmManipulator *manipulator,
|
||||
struct bContext *C);
|
||||
|
||||
void WM_manipulator_set_property(struct wmManipulator *, int slot, struct PointerRNA *ptr, const char *propname);
|
||||
struct PointerRNA *WM_manipulator_set_operator(struct wmManipulator *, const char *opname);
|
||||
void WM_manipulator_set_func_select(
|
||||
struct wmManipulator *manipulator,
|
||||
void (*select)(struct bContext *, struct wmManipulator *, const int action)); /* wmManipulatorSelectFunc */
|
||||
void WM_manipulator_set_origin(struct wmManipulator *manipulator, const float origin[3]);
|
||||
void WM_manipulator_set_offset(struct wmManipulator *manipulator, const float offset[3]);
|
||||
void WM_manipulator_set_flag(struct wmManipulator *manipulator, const int flag, const bool enable);
|
||||
void WM_manipulator_set_scale(struct wmManipulator *manipulator, float scale);
|
||||
void WM_manipulator_set_line_width(struct wmManipulator *manipulator, const float line_width);
|
||||
void WM_manipulator_set_colors(struct wmManipulator *manipulator, const float col[4], const float col_hi[4]);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulatorGroup */
|
||||
|
||||
struct wmManipulatorGroupType *WM_manipulatorgrouptype_append(
|
||||
struct wmManipulatorMapType *mmaptype,
|
||||
void (*mgrouptype_func)(struct wmManipulatorGroupType *));
|
||||
struct wmManipulatorGroupType *WM_manipulatorgrouptype_append_runtime(
|
||||
const struct Main *main, struct wmManipulatorMapType *mmaptype,
|
||||
void (*mgrouptype_func)(struct wmManipulatorGroupType *));
|
||||
void WM_manipulatorgrouptype_init_runtime(
|
||||
const struct Main *bmain, struct wmManipulatorMapType *mmaptype,
|
||||
struct wmManipulatorGroupType *mgrouptype);
|
||||
void WM_manipulatorgrouptype_unregister(
|
||||
struct bContext *C, struct Main *bmain, struct wmManipulatorGroupType *mgroup);
|
||||
|
||||
struct wmKeyMap *WM_manipulatorgroup_keymap_common(
|
||||
const struct wmManipulatorGroupType *mgrouptype, struct wmKeyConfig *config);
|
||||
struct wmKeyMap *WM_manipulatorgroup_keymap_common_sel(
|
||||
const struct wmManipulatorGroupType *mgrouptype, struct wmKeyConfig *config);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulatorMap */
|
||||
|
||||
struct wmManipulatorMapType *WM_manipulatormaptype_find(
|
||||
const struct wmManipulatorMapType_Params *mmap_params);
|
||||
struct wmManipulatorMapType *WM_manipulatormaptype_ensure(
|
||||
const struct wmManipulatorMapType_Params *mmap_params);
|
||||
|
||||
struct wmManipulatorMap *WM_manipulatormap_new_from_type(
|
||||
const struct wmManipulatorMapType_Params *mmap_params);
|
||||
void WM_manipulatormap_tag_refresh(struct wmManipulatorMap *mmap);
|
||||
void WM_manipulatormap_draw(struct wmManipulatorMap *mmap, const struct bContext *C, const int drawstep);
|
||||
void WM_manipulatormap_add_handlers(struct ARegion *ar, struct wmManipulatorMap *mmap);
|
||||
bool WM_manipulatormap_select_all(struct bContext *C, struct wmManipulatorMap *mmap, const int action);
|
||||
bool WM_manipulatormap_cursor_set(const struct wmManipulatorMap *mmap, struct wmWindow *win);
|
||||
|
||||
#endif /* __WM_MANIPULATOR_API_H__ */
|
||||
|
167
source/blender/windowmanager/manipulators/WM_manipulator_types.h
Normal file
167
source/blender/windowmanager/manipulators/WM_manipulator_types.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/windowmanager/manipulators/WM_manipulator_types.h
|
||||
* \ingroup wm
|
||||
*
|
||||
* \name Manipulator Types
|
||||
* \brief Manipulator defines for external use.
|
||||
*
|
||||
* Only included in WM_types.h and lower level files.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __WM_MANIPULATOR_TYPES_H__
|
||||
#define __WM_MANIPULATOR_TYPES_H__
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
|
||||
struct wmManipulatorGroupType;
|
||||
struct wmManipulatorGroup;
|
||||
struct wmKeyConfig;
|
||||
|
||||
typedef bool (*wmManipulatorGroupPollFunc)(const struct bContext *, struct wmManipulatorGroupType *) ATTR_WARN_UNUSED_RESULT;
|
||||
typedef void (*wmManipulatorGroupInitFunc)(const struct bContext *, struct wmManipulatorGroup *);
|
||||
typedef void (*wmManipulatorGroupRefreshFunc)(const struct bContext *, struct wmManipulatorGroup *);
|
||||
typedef void (*wmManipulatorGroupDrawPrepareFunc)(const struct bContext *, struct wmManipulatorGroup *);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulator */
|
||||
|
||||
/**
|
||||
* Simple utility wrapper for storing a single manipulator as wmManipulatorGroup.customdata (which gets freed).
|
||||
*/
|
||||
typedef struct wmManipulatorWrapper {
|
||||
struct wmManipulator *manipulator;
|
||||
} wmManipulatorWrapper;
|
||||
|
||||
/* wmManipulator.flag
|
||||
* Flags for individual manipulators. */
|
||||
enum {
|
||||
WM_MANIPULATOR_DRAW_HOVER = (1 << 0), /* draw *only* while hovering */
|
||||
WM_MANIPULATOR_DRAW_ACTIVE = (1 << 1), /* draw while dragging */
|
||||
WM_MANIPULATOR_DRAW_VALUE = (1 << 2), /* draw an indicator for the current value while dragging */
|
||||
WM_MANIPULATOR_HIDDEN = (1 << 3),
|
||||
};
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulatorGroup */
|
||||
|
||||
typedef struct wmManipulatorGroup {
|
||||
struct wmManipulatorGroup *next, *prev;
|
||||
|
||||
struct wmManipulatorGroupType *type;
|
||||
ListBase manipulators;
|
||||
|
||||
void *py_instance; /* python stores the class instance here */
|
||||
struct ReportList *reports; /* errors and warnings storage */
|
||||
|
||||
void *customdata;
|
||||
void (*customdata_free)(void *); /* for freeing customdata from above */
|
||||
int flag; /* private */
|
||||
int pad;
|
||||
} wmManipulatorGroup;
|
||||
|
||||
/* factory class for a manipulator-group type, gets called every time a new area is spawned */
|
||||
typedef struct wmManipulatorGroupType {
|
||||
struct wmManipulatorGroupType *next, *prev;
|
||||
|
||||
char idname[64]; /* MAX_NAME */
|
||||
const char *name; /* manipulator-group name - displayed in UI (keymap editor) */
|
||||
|
||||
/* poll if manipulator-map should be visible */
|
||||
wmManipulatorGroupPollFunc poll;
|
||||
/* initially create manipulators and set permanent data - stuff you only need to do once */
|
||||
wmManipulatorGroupInitFunc init;
|
||||
/* refresh data, only called if recreate flag is set (WM_manipulatormap_tag_refresh) */
|
||||
wmManipulatorGroupRefreshFunc refresh;
|
||||
/* refresh data for drawing, called before each redraw */
|
||||
wmManipulatorGroupDrawPrepareFunc draw_prepare;
|
||||
|
||||
/* keymap init callback for this manipulator-group */
|
||||
struct wmKeyMap *(*keymap_init)(const struct wmManipulatorGroupType *, struct wmKeyConfig *);
|
||||
/* keymap created with callback from above */
|
||||
struct wmKeyMap *keymap;
|
||||
|
||||
/* rna for properties */
|
||||
struct StructRNA *srna;
|
||||
|
||||
/* RNA integration */
|
||||
ExtensionRNA ext;
|
||||
|
||||
int flag;
|
||||
|
||||
/* if type is spawned from operator this is set here */
|
||||
void *op;
|
||||
|
||||
/* same as manipulator-maps, so registering/unregistering goes to the correct region */
|
||||
short spaceid, regionid;
|
||||
char mapidname[64];
|
||||
} wmManipulatorGroupType;
|
||||
|
||||
/**
|
||||
* wmManipulatorGroupType.flag
|
||||
* Flags that influence the behavior of all manipulators in the group.
|
||||
*/
|
||||
enum {
|
||||
/* Mark manipulator-group as being 3D */
|
||||
WM_MANIPULATORGROUPTYPE_IS_3D = (1 << 0),
|
||||
/* Scale manipulators as 3D object that respects zoom (otherwise zoom independent draw size) */
|
||||
WM_MANIPULATORGROUPTYPE_SCALE_3D = (1 << 1),
|
||||
/* Manipulators can be depth culled with scene objects (covered by other geometry - TODO) */
|
||||
WM_MANIPULATORGROUPTYPE_SCENE_DEPTH = (1 << 2),
|
||||
/* Manipulators can be selected */
|
||||
WM_MANIPULATORGROUPTYPE_SELECTABLE = (1 << 3),
|
||||
/* manipulator group is attached to operator, and is only accessible as long as this runs */
|
||||
WM_MANIPULATORGROUPTYPE_OP = (1 << 4),
|
||||
};
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulatorMap */
|
||||
|
||||
struct wmManipulatorMapType_Params {
|
||||
const char *idname;
|
||||
const int spaceid;
|
||||
const int regionid;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pass a value of this enum to #WM_manipulatormap_draw to tell it what to draw.
|
||||
*/
|
||||
enum {
|
||||
/* Draw 2D manipulator-groups (ManipulatorGroupType.is_3d == false) */
|
||||
WM_MANIPULATORMAP_DRAWSTEP_2D = 0,
|
||||
/* Draw 3D manipulator-groups (ManipulatorGroupType.is_3d == true) */
|
||||
WM_MANIPULATORMAP_DRAWSTEP_3D,
|
||||
/* Draw only depth culled manipulators (WM_MANIPULATOR_SCENE_DEPTH flag).
|
||||
* Note that these are expected to be 3D manipulators too. */
|
||||
WM_MANIPULATORMAP_DRAWSTEP_IN_SCENE,
|
||||
};
|
||||
|
||||
#endif /* __WM_MANIPULATOR_TYPES_H__ */
|
||||
|
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_intern.h
|
||||
* \ingroup wm
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __MANIPULATOR_LIBRARY_INTERN_H__
|
||||
#define __MANIPULATOR_LIBRARY_INTERN_H__
|
||||
|
||||
/* distance around which manipulators respond to input (and get highlighted) */
|
||||
#define MANIPULATOR_HOTSPOT 14.0f
|
||||
|
||||
/**
|
||||
* Data for common interactions. Used in manipulator_library_utils.c functions.
|
||||
*/
|
||||
typedef struct ManipulatorCommonData {
|
||||
int flag;
|
||||
|
||||
float range_fac; /* factor for arrow min/max distance */
|
||||
float offset;
|
||||
|
||||
/* property range for constrained manipulators */
|
||||
float range;
|
||||
/* min/max value for constrained manipulators */
|
||||
float min, max;
|
||||
} ManipulatorCommonData;
|
||||
|
||||
typedef struct ManipulatorInteraction {
|
||||
float init_value; /* initial property value */
|
||||
float init_origin[3];
|
||||
float init_mval[2];
|
||||
float init_offset;
|
||||
float init_scale;
|
||||
|
||||
/* offset of last handling step */
|
||||
float prev_offset;
|
||||
/* Total offset added by precision tweaking.
|
||||
* Needed to allow toggling precision on/off without causing jumps */
|
||||
float precision_offset;
|
||||
} ManipulatorInteraction;
|
||||
|
||||
/* ManipulatorCommonData->flag */
|
||||
enum {
|
||||
MANIPULATOR_CUSTOM_RANGE_SET = (1 << 0),
|
||||
};
|
||||
|
||||
|
||||
float manipulator_offset_from_value(
|
||||
ManipulatorCommonData *data, const float value,
|
||||
const bool constrained, const bool inverted);
|
||||
float manipulator_value_from_offset(
|
||||
ManipulatorCommonData *data, ManipulatorInteraction *inter, const float offset,
|
||||
const bool constrained, const bool inverted, const bool use_precision);
|
||||
|
||||
void manipulator_property_data_update(
|
||||
wmManipulator *manipulator, ManipulatorCommonData *data, const int slot,
|
||||
const bool constrained, const bool inverted);
|
||||
|
||||
void manipulator_property_value_set(
|
||||
bContext *C, const wmManipulator *manipulator,
|
||||
const int slot, const float value);
|
||||
float manipulator_property_value_get(
|
||||
const wmManipulator *manipulator, const int slot);
|
||||
void manipulator_property_value_reset(
|
||||
bContext *C, const wmManipulator *manipulator, ManipulatorInteraction *inter,
|
||||
const int slot);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
void manipulator_color_get(
|
||||
const wmManipulator *manipulator, const bool highlight,
|
||||
float r_col[]);
|
||||
|
||||
#endif /* __MANIPULATOR_LIBRARY_INTERN_H__ */
|
||||
|
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2015 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_utils.c
|
||||
* \ingroup wm
|
||||
*
|
||||
* \name Manipulator Library Utilities
|
||||
*
|
||||
* \brief This file contains functions for common behaviors of manipulators.
|
||||
*/
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
/* own includes */
|
||||
#include "WM_manipulator_types.h"
|
||||
#include "wm_manipulator_wmapi.h"
|
||||
#include "wm_manipulator_intern.h"
|
||||
#include "manipulator_library_intern.h"
|
||||
|
||||
/* factor for precision tweaking */
|
||||
#define MANIPULATOR_PRECISION_FAC 0.05f
|
||||
|
||||
|
||||
BLI_INLINE float manipulator_offset_from_value_constr(
|
||||
const float range_fac, const float min, const float range, const float value,
|
||||
const bool inverted)
|
||||
{
|
||||
return inverted ? (range_fac * (min + range - value) / range) : (range_fac * (value / range));
|
||||
}
|
||||
|
||||
BLI_INLINE float manipulator_value_from_offset_constr(
|
||||
const float range_fac, const float min, const float range, const float value,
|
||||
const bool inverted)
|
||||
{
|
||||
return inverted ? (min + range - (value * range / range_fac)) : (value * range / range_fac);
|
||||
}
|
||||
|
||||
float manipulator_offset_from_value(
|
||||
ManipulatorCommonData *data, const float value, const bool constrained, const bool inverted)
|
||||
{
|
||||
if (constrained)
|
||||
return manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float manipulator_value_from_offset(
|
||||
ManipulatorCommonData *data, ManipulatorInteraction *inter, const float offset,
|
||||
const bool constrained, const bool inverted, const bool use_precision)
|
||||
{
|
||||
const float max = data->min + data->range;
|
||||
|
||||
if (use_precision) {
|
||||
/* add delta offset of this step to total precision_offset */
|
||||
inter->precision_offset += offset - inter->prev_offset;
|
||||
}
|
||||
inter->prev_offset = offset;
|
||||
|
||||
float ofs_new = inter->init_offset + offset - inter->precision_offset * (1.0f - MANIPULATOR_PRECISION_FAC);
|
||||
float value;
|
||||
|
||||
if (constrained) {
|
||||
value = manipulator_value_from_offset_constr(data->range_fac, data->min, data->range, ofs_new, inverted);
|
||||
}
|
||||
else {
|
||||
value = ofs_new;
|
||||
}
|
||||
|
||||
/* clamp to custom range */
|
||||
if (data->flag & MANIPULATOR_CUSTOM_RANGE_SET) {
|
||||
CLAMP(value, data->min, max);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void manipulator_property_data_update(
|
||||
wmManipulator *manipulator, ManipulatorCommonData *data, const int slot,
|
||||
const bool constrained, const bool inverted)
|
||||
{
|
||||
if (!manipulator->props[slot]) {
|
||||
data->offset = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
PointerRNA ptr = manipulator->ptr[slot];
|
||||
PropertyRNA *prop = manipulator->props[slot];
|
||||
float value = manipulator_property_value_get(manipulator, slot);
|
||||
|
||||
if (constrained) {
|
||||
if ((data->flag & MANIPULATOR_CUSTOM_RANGE_SET) == 0) {
|
||||
float step, precision;
|
||||
float min, max;
|
||||
RNA_property_float_ui_range(&ptr, prop, &min, &max, &step, &precision);
|
||||
data->range = max - min;
|
||||
data->min = min;
|
||||
}
|
||||
data->offset = manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted);
|
||||
}
|
||||
else {
|
||||
data->offset = value;
|
||||
}
|
||||
}
|
||||
|
||||
void manipulator_property_value_set(
|
||||
bContext *C, const wmManipulator *manipulator,
|
||||
const int slot, const float value)
|
||||
{
|
||||
PointerRNA ptr = manipulator->ptr[slot];
|
||||
PropertyRNA *prop = manipulator->props[slot];
|
||||
|
||||
/* reset property */
|
||||
RNA_property_float_set(&ptr, prop, value);
|
||||
RNA_property_update(C, &ptr, prop);
|
||||
}
|
||||
|
||||
float manipulator_property_value_get(const wmManipulator *manipulator, const int slot)
|
||||
{
|
||||
BLI_assert(RNA_property_type(manipulator->props[slot]) == PROP_FLOAT);
|
||||
return RNA_property_float_get(&manipulator->ptr[slot], manipulator->props[slot]);
|
||||
}
|
||||
|
||||
void manipulator_property_value_reset(
|
||||
bContext *C, const wmManipulator *manipulator, ManipulatorInteraction *inter,
|
||||
const int slot)
|
||||
{
|
||||
manipulator_property_value_set(C, manipulator, slot, inter->init_value);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
void manipulator_color_get(
|
||||
const wmManipulator *manipulator, const bool highlight,
|
||||
float r_col[4])
|
||||
{
|
||||
if (highlight && !(manipulator->flag & WM_MANIPULATOR_DRAW_HOVER)) {
|
||||
copy_v4_v4(r_col, manipulator->col_hi);
|
||||
}
|
||||
else {
|
||||
copy_v4_v4(r_col, manipulator->col);
|
||||
}
|
||||
}
|
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2014 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Blender Foundation
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/windowmanager/manipulators/intern/wm_manipulator.c
|
||||
* \ingroup wm
|
||||
*/
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "ED_screen.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "GL/glew.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
/* own includes */
|
||||
#include "wm_manipulator_wmapi.h"
|
||||
#include "wm_manipulator_intern.h"
|
||||
|
||||
|
||||
/* Still unused */
|
||||
wmManipulator *WM_manipulator_new(
|
||||
void (*draw)(const bContext *C, wmManipulator *customdata),
|
||||
void (*render_3d_intersection)(const bContext *C, wmManipulator *customdata, int selectionbase),
|
||||
int (*intersect)(bContext *C, const wmEvent *event, wmManipulator *manipulator),
|
||||
int (*handler)(bContext *C, const wmEvent *event, wmManipulator *manipulator, const int flag))
|
||||
{
|
||||
wmManipulator *manipulator = MEM_callocN(sizeof(wmManipulator), "manipulator");
|
||||
|
||||
manipulator->draw = draw;
|
||||
manipulator->handler = handler;
|
||||
manipulator->intersect = intersect;
|
||||
manipulator->render_3d_intersection = render_3d_intersection;
|
||||
|
||||
/* XXX */
|
||||
// fix_linking_manipulator_arrow();
|
||||
// fix_linking_manipulator_arrow2d();
|
||||
// fix_linking_manipulator_cage();
|
||||
// fix_linking_manipulator_dial();
|
||||
// fix_linking_manipulator_facemap();
|
||||
// fix_linking_manipulator_primitive();
|
||||
|
||||
return manipulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign an idname that is unique in \a mgroup to \a manipulator.
|
||||
*
|
||||
* \param rawname: Name used as basis to define final unique idname.
|
||||
*/
|
||||
static void manipulator_unique_idname_set(wmManipulatorGroup *mgroup, wmManipulator *manipulator, const char *rawname)
|
||||
{
|
||||
if (mgroup->type->idname[0]) {
|
||||
BLI_snprintf(manipulator->idname, sizeof(manipulator->idname), "%s_%s", mgroup->type->idname, rawname);
|
||||
}
|
||||
else {
|
||||
BLI_strncpy(manipulator->idname, rawname, sizeof(manipulator->idname));
|
||||
}
|
||||
|
||||
/* ensure name is unique, append '.001', '.002', etc if not */
|
||||
BLI_uniquename(&mgroup->manipulators, manipulator, "Manipulator", '.',
|
||||
offsetof(wmManipulator, idname), sizeof(manipulator->idname));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize default values and allocate needed memory for members.
|
||||
*/
|
||||
static void manipulator_init(wmManipulator *manipulator)
|
||||
{
|
||||
const float col_default[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
manipulator->user_scale = 1.0f;
|
||||
manipulator->line_width = 1.0f;
|
||||
|
||||
/* defaults */
|
||||
copy_v4_v4(manipulator->col, col_default);
|
||||
copy_v4_v4(manipulator->col_hi, col_default);
|
||||
|
||||
/* create at least one property for interaction */
|
||||
if (manipulator->max_prop == 0) {
|
||||
manipulator->max_prop = 1;
|
||||
}
|
||||
|
||||
manipulator->props = MEM_callocN(sizeof(PropertyRNA *) * manipulator->max_prop, "manipulator->props");
|
||||
manipulator->ptr = MEM_callocN(sizeof(PointerRNA) * manipulator->max_prop, "manipulator->ptr");
|
||||
}
|
||||
|
||||
/**
|
||||
* Register \a manipulator.
|
||||
*
|
||||
* \param name: name used to create a unique idname for \a manipulator in \a mgroup
|
||||
*/
|
||||
void wm_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *manipulator, const char *name)
|
||||
{
|
||||
manipulator_init(manipulator);
|
||||
manipulator_unique_idname_set(mgroup, manipulator, name);
|
||||
wm_manipulatorgroup_manipulator_register(mgroup, manipulator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free \a manipulator and unlink from \a manipulatorlist.
|
||||
* \a manipulatorlist is allowed to be NULL.
|
||||
*/
|
||||
void WM_manipulator_delete(ListBase *manipulatorlist, wmManipulatorMap *mmap, wmManipulator *manipulator, bContext *C)
|
||||
{
|
||||
if (manipulator->state & WM_MANIPULATOR_HIGHLIGHT) {
|
||||
wm_manipulatormap_set_highlighted_manipulator(mmap, C, NULL, 0);
|
||||
}
|
||||
if (manipulator->state & WM_MANIPULATOR_ACTIVE) {
|
||||
wm_manipulatormap_set_active_manipulator(mmap, C, NULL, NULL);
|
||||
}
|
||||
if (manipulator->state & WM_MANIPULATOR_SELECTED) {
|
||||
wm_manipulator_deselect(mmap, manipulator);
|
||||
}
|
||||
|
||||
if (manipulator->opptr.data) {
|
||||
WM_operator_properties_free(&manipulator->opptr);
|
||||
}
|
||||
MEM_freeN(manipulator->props);
|
||||
MEM_freeN(manipulator->ptr);
|
||||
|
||||
if (manipulatorlist)
|
||||
BLI_remlink(manipulatorlist, manipulator);
|
||||
MEM_freeN(manipulator);
|
||||
}
|
||||
|
||||
wmManipulatorGroup *wm_manipulator_get_parent_group(const wmManipulator *manipulator)
|
||||
{
|
||||
return manipulator->mgroup;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Manipulator Creation API
|
||||
*
|
||||
* API for defining data on manipulator creation.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void WM_manipulator_set_property(wmManipulator *manipulator, const int slot, PointerRNA *ptr, const char *propname)
|
||||
{
|
||||
if (slot < 0 || slot >= manipulator->max_prop) {
|
||||
fprintf(stderr, "invalid index %d when binding property for manipulator type %s\n", slot, manipulator->idname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if manipulator evokes an operator we cannot use it for property manipulation */
|
||||
manipulator->opname = NULL;
|
||||
manipulator->ptr[slot] = *ptr;
|
||||
manipulator->props[slot] = RNA_struct_find_property(ptr, propname);
|
||||
|
||||
if (manipulator->prop_data_update)
|
||||
manipulator->prop_data_update(manipulator, slot);
|
||||
}
|
||||
|
||||
PointerRNA *WM_manipulator_set_operator(wmManipulator *manipulator, const char *opname)
|
||||
{
|
||||
wmOperatorType *ot = WM_operatortype_find(opname, 0);
|
||||
|
||||
if (ot) {
|
||||
manipulator->opname = opname;
|
||||
|
||||
if (manipulator->opptr.data) {
|
||||
WM_operator_properties_free(&manipulator->opptr);
|
||||
}
|
||||
WM_operator_properties_create_ptr(&manipulator->opptr, ot);
|
||||
|
||||
return &manipulator->opptr;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Error binding operator to manipulator: operator %s not found!\n", opname);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set manipulator select callback.
|
||||
*
|
||||
* Callback is called when manipulator gets selected/deselected.
|
||||
*/
|
||||
void WM_manipulator_set_func_select(wmManipulator *manipulator, wmManipulatorSelectFunc select)
|
||||
{
|
||||
BLI_assert(manipulator->mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECTABLE);
|
||||
manipulator->select = select;
|
||||
}
|
||||
|
||||
void WM_manipulator_set_origin(wmManipulator *manipulator, const float origin[3])
|
||||
{
|
||||
copy_v3_v3(manipulator->origin, origin);
|
||||
}
|
||||
|
||||
void WM_manipulator_set_offset(wmManipulator *manipulator, const float offset[3])
|
||||
{
|
||||
copy_v3_v3(manipulator->offset, offset);
|
||||
}
|
||||
|
||||
void WM_manipulator_set_flag(wmManipulator *manipulator, const int flag, const bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
manipulator->flag |= flag;
|
||||
}
|
||||
else {
|
||||
manipulator->flag &= ~flag;
|
||||
}
|
||||
}
|
||||
|
||||
void WM_manipulator_set_scale(wmManipulator *manipulator, const float scale)
|
||||
{
|
||||
manipulator->user_scale = scale;
|
||||
}
|
||||
|
||||
void WM_manipulator_set_line_width(wmManipulator *manipulator, const float line_width)
|
||||
{
|
||||
manipulator->line_width = line_width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set manipulator rgba colors.
|
||||
*
|
||||
* \param col Normal state color.
|
||||
* \param col_hi Highlighted state color.
|
||||
*/
|
||||
void WM_manipulator_set_colors(wmManipulator *manipulator, const float col[4], const float col_hi[4])
|
||||
{
|
||||
copy_v4_v4(manipulator->col, col);
|
||||
copy_v4_v4(manipulator->col_hi, col_hi);
|
||||
}
|
||||
|
||||
/** \} */ // Manipulator Creation API
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Remove \a manipulator from selection.
|
||||
* Reallocates memory for selected manipulators so better not call for selecting multiple ones.
|
||||
*
|
||||
* \return if the selection has changed.
|
||||
*/
|
||||
bool wm_manipulator_deselect(wmManipulatorMap *mmap, wmManipulator *manipulator)
|
||||
{
|
||||
if (!mmap->mmap_context.selected_manipulator)
|
||||
return false;
|
||||
|
||||
wmManipulator ***sel = &mmap->mmap_context.selected_manipulator;
|
||||
int *tot_selected = &mmap->mmap_context.tot_selected;
|
||||
bool changed = false;
|
||||
|
||||
/* caller should check! */
|
||||
BLI_assert(manipulator->state & WM_MANIPULATOR_SELECTED);
|
||||
|
||||
/* remove manipulator from selected_manipulators array */
|
||||
for (int i = 0; i < (*tot_selected); i++) {
|
||||
if ((*sel)[i] == manipulator) {
|
||||
for (int j = i; j < ((*tot_selected) - 1); j++) {
|
||||
(*sel)[j] = (*sel)[j + 1];
|
||||
}
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* update array data */
|
||||
if ((*tot_selected) <= 1) {
|
||||
wm_manipulatormap_selected_delete(mmap);
|
||||
}
|
||||
else {
|
||||
*sel = MEM_reallocN(*sel, sizeof(**sel) * (*tot_selected));
|
||||
(*tot_selected)--;
|
||||
}
|
||||
|
||||
manipulator->state &= ~WM_MANIPULATOR_SELECTED;
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add \a manipulator to selection.
|
||||
* Reallocates memory for selected manipulators so better not call for selecting multiple ones.
|
||||
*
|
||||
* \return if the selection has changed.
|
||||
*/
|
||||
bool wm_manipulator_select(bContext *C, wmManipulatorMap *mmap, wmManipulator *manipulator)
|
||||
{
|
||||
wmManipulator ***sel = &mmap->mmap_context.selected_manipulator;
|
||||
int *tot_selected = &mmap->mmap_context.tot_selected;
|
||||
|
||||
if (!manipulator || (manipulator->state & WM_MANIPULATOR_SELECTED))
|
||||
return false;
|
||||
|
||||
(*tot_selected)++;
|
||||
|
||||
*sel = MEM_reallocN(*sel, sizeof(wmManipulator *) * (*tot_selected));
|
||||
(*sel)[(*tot_selected) - 1] = manipulator;
|
||||
|
||||
manipulator->state |= WM_MANIPULATOR_SELECTED;
|
||||
if (manipulator->select) {
|
||||
manipulator->select(C, manipulator, SEL_SELECT);
|
||||
}
|
||||
wm_manipulatormap_set_highlighted_manipulator(mmap, C, manipulator, manipulator->highlighted_part);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wm_manipulator_calculate_scale(wmManipulator *manipulator, const bContext *C)
|
||||
{
|
||||
const RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
float scale = 1.0f;
|
||||
|
||||
if (manipulator->mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SCALE_3D) {
|
||||
if (rv3d /*&& (U.manipulator_flag & V3D_3D_MANIPULATORS) == 0*/) { /* UserPref flag might be useful for later */
|
||||
if (manipulator->get_final_position) {
|
||||
float position[3];
|
||||
|
||||
manipulator->get_final_position(manipulator, position);
|
||||
scale = ED_view3d_pixel_size(rv3d, position) * (float)U.manipulator_scale;
|
||||
}
|
||||
else {
|
||||
scale = ED_view3d_pixel_size(rv3d, manipulator->origin) * (float)U.manipulator_scale;
|
||||
}
|
||||
}
|
||||
else {
|
||||
scale = U.manipulator_scale * 0.02f;
|
||||
}
|
||||
}
|
||||
|
||||
manipulator->scale = scale * manipulator->user_scale;
|
||||
}
|
||||
|
||||
static void manipulator_update_prop_data(wmManipulator *manipulator)
|
||||
{
|
||||
/* manipulator property might have been changed, so update manipulator */
|
||||
if (manipulator->props && manipulator->prop_data_update) {
|
||||
for (int i = 0; i < manipulator->max_prop; i++) {
|
||||
if (manipulator->props[i]) {
|
||||
manipulator->prop_data_update(manipulator, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wm_manipulator_update(wmManipulator *manipulator, const bContext *C, const bool refresh_map)
|
||||
{
|
||||
if (refresh_map) {
|
||||
manipulator_update_prop_data(manipulator);
|
||||
}
|
||||
wm_manipulator_calculate_scale(manipulator, C);
|
||||
}
|
||||
|
||||
bool wm_manipulator_is_visible(wmManipulator *manipulator)
|
||||
{
|
||||
if (manipulator->flag & WM_MANIPULATOR_HIDDEN) {
|
||||
return false;
|
||||
}
|
||||
if ((manipulator->state & WM_MANIPULATOR_ACTIVE) &&
|
||||
!(manipulator->flag & (WM_MANIPULATOR_DRAW_ACTIVE | WM_MANIPULATOR_DRAW_VALUE)))
|
||||
{
|
||||
/* don't draw while active (while dragging) */
|
||||
return false;
|
||||
}
|
||||
if ((manipulator->flag & WM_MANIPULATOR_DRAW_HOVER) &&
|
||||
!(manipulator->state & WM_MANIPULATOR_HIGHLIGHT) &&
|
||||
!(manipulator->state & WM_MANIPULATOR_SELECTED)) /* still draw selected manipulators */
|
||||
{
|
||||
/* only draw on mouse hover */
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
|
||||
* \ingroup wm
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __WM_MANIPULATOR_INTERN_H__
|
||||
#define __WM_MANIPULATOR_INTERN_H__
|
||||
|
||||
struct wmKeyConfig;
|
||||
struct wmManipulatorMap;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulator */
|
||||
|
||||
/* manipulators are set per region by registering them on manipulator-maps */
|
||||
typedef struct wmManipulator {
|
||||
struct wmManipulator *next, *prev;
|
||||
|
||||
char idname[MAX_NAME + 4]; /* + 4 for unique '.001', '.002', etc suffix */
|
||||
/* pointer back to group this manipulator is in (just for quick access) */
|
||||
struct wmManipulatorGroup *mgroup;
|
||||
|
||||
/* could become wmManipulatorType */
|
||||
/* draw manipulator */
|
||||
void (*draw)(const struct bContext *, struct wmManipulator *);
|
||||
|
||||
/* determine if the mouse intersects with the manipulator. The calculation should be done in the callback itself */
|
||||
int (*intersect)(struct bContext *, const struct wmEvent *, struct wmManipulator *);
|
||||
|
||||
/* determines 3d intersection by rendering the manipulator in a selection routine. */
|
||||
void (*render_3d_intersection)(const struct bContext *, struct wmManipulator *, int);
|
||||
|
||||
/* handler used by the manipulator. Usually handles interaction tied to a manipulator type */
|
||||
int (*handler)(struct bContext *, const struct wmEvent *, struct wmManipulator *, const int);
|
||||
|
||||
/* manipulator-specific handler to update manipulator attributes based on the property value */
|
||||
void (*prop_data_update)(struct wmManipulator *, int);
|
||||
|
||||
/* returns the final position which may be different from the origin, depending on the manipulator.
|
||||
* used in calculations of scale */
|
||||
void (*get_final_position)(struct wmManipulator *, float[]);
|
||||
|
||||
/* activate a manipulator state when the user clicks on it */
|
||||
int (*invoke)(struct bContext *, const struct wmEvent *, struct wmManipulator *);
|
||||
|
||||
/* called when manipulator tweaking is done - used to free data and reset property when cancelling */
|
||||
void (*exit)(struct bContext *, struct wmManipulator *, const bool );
|
||||
|
||||
int (*get_cursor)(struct wmManipulator *);
|
||||
|
||||
/* called when manipulator selection state changes */
|
||||
wmManipulatorSelectFunc select;
|
||||
|
||||
int flag; /* flags that influence the behavior or how the manipulators are drawn */
|
||||
short state; /* state flags (active, highlighted, selected) */
|
||||
|
||||
unsigned char highlighted_part;
|
||||
|
||||
/* center of manipulator in space, 2d or 3d */
|
||||
float origin[3];
|
||||
/* custom offset from origin */
|
||||
float offset[3];
|
||||
/* runtime property, set the scale while drawing on the viewport */
|
||||
float scale;
|
||||
/* user defined scale, in addition to the original one */
|
||||
float user_scale;
|
||||
/* user defined width for line drawing */
|
||||
float line_width;
|
||||
/* manipulator colors (uses default fallbacks if not defined) */
|
||||
float col[4], col_hi[4];
|
||||
|
||||
/* data used during interaction */
|
||||
void *interaction_data;
|
||||
|
||||
/* name of operator to spawn when activating the manipulator */
|
||||
const char *opname;
|
||||
/* operator properties if manipulator spawns and controls an operator,
|
||||
* or owner pointer if manipulator spawns and controls a property */
|
||||
PointerRNA opptr;
|
||||
|
||||
/* maximum number of properties attached to the manipulator */
|
||||
int max_prop;
|
||||
/* arrays of properties attached to various manipulator parameters. As
|
||||
* the manipulator is interacted with, those properties get updated */
|
||||
PointerRNA *ptr;
|
||||
PropertyRNA **props;
|
||||
} wmManipulator;
|
||||
|
||||
/* wmManipulator.state */
|
||||
enum {
|
||||
WM_MANIPULATOR_HIGHLIGHT = (1 << 0), /* while hovered */
|
||||
WM_MANIPULATOR_ACTIVE = (1 << 1), /* while dragging */
|
||||
WM_MANIPULATOR_SELECTED = (1 << 2),
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Manipulator tweak flag.
|
||||
* Bitflag passed to manipulator while tweaking.
|
||||
*/
|
||||
enum {
|
||||
/* drag with extra precision (shift)
|
||||
* NOTE: Manipulators are responsible for handling this (manipulator->handler callback)! */
|
||||
WM_MANIPULATOR_TWEAK_PRECISE = (1 << 0),
|
||||
};
|
||||
|
||||
void wm_manipulator_register(struct wmManipulatorGroup *mgroup, struct wmManipulator *manipulator, const char *name);
|
||||
|
||||
bool wm_manipulator_deselect(struct wmManipulatorMap *mmap, struct wmManipulator *manipulator);
|
||||
bool wm_manipulator_select(bContext *C, struct wmManipulatorMap *mmap, struct wmManipulator *manipulator);
|
||||
|
||||
void wm_manipulator_calculate_scale(struct wmManipulator *manipulator, const bContext *C);
|
||||
void wm_manipulator_update(struct wmManipulator *manipulator, const bContext *C, const bool refresh_map);
|
||||
bool wm_manipulator_is_visible(struct wmManipulator *manipulator);
|
||||
|
||||
void fix_linking_manipulator_arrow(void);
|
||||
void fix_linking_manipulator_arrow2d(void);
|
||||
void fix_linking_manipulator_cage(void);
|
||||
void fix_linking_manipulator_dial(void);
|
||||
void fix_linking_manipulator_facemap(void);
|
||||
void fix_linking_manipulator_primitive(void);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulatorGroup */
|
||||
|
||||
enum {
|
||||
TWEAK_MODAL_CANCEL = 1,
|
||||
TWEAK_MODAL_CONFIRM,
|
||||
TWEAK_MODAL_PRECISION_ON,
|
||||
TWEAK_MODAL_PRECISION_OFF,
|
||||
};
|
||||
|
||||
struct wmManipulatorGroup *wm_manipulatorgroup_new_from_type(struct wmManipulatorGroupType *mgrouptype);
|
||||
void wm_manipulatorgroup_free(bContext *C, struct wmManipulatorMap *mmap, struct wmManipulatorGroup *mgroup);
|
||||
void wm_manipulatorgroup_manipulator_register(struct wmManipulatorGroup *mgroup, wmManipulator *manipulator);
|
||||
wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator(
|
||||
const struct wmManipulatorGroup *mgroup, struct bContext *C, const struct wmEvent *event,
|
||||
unsigned char *part);
|
||||
void wm_manipulatorgroup_intersectable_manipulators_to_list(
|
||||
const struct wmManipulatorGroup *mgroup, struct ListBase *listbase);
|
||||
void wm_manipulatorgroup_ensure_initialized(struct wmManipulatorGroup *mgroup, const struct bContext *C);
|
||||
bool wm_manipulatorgroup_is_visible(const struct wmManipulatorGroup *mgroup, const struct bContext *C);
|
||||
bool wm_manipulatorgroup_is_visible_in_drawstep(const struct wmManipulatorGroup *mgroup, const int drawstep);
|
||||
|
||||
void wm_manipulatorgrouptype_keymap_init(struct wmManipulatorGroupType *mgrouptype, struct wmKeyConfig *keyconf);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulatorMap */
|
||||
|
||||
typedef struct wmManipulatorMap {
|
||||
struct wmManipulatorMap *next, *prev;
|
||||
|
||||
struct wmManipulatorMapType *type;
|
||||
ListBase manipulator_groups;
|
||||
|
||||
char update_flag; /* private, update tagging */
|
||||
|
||||
/**
|
||||
* \brief Manipulator map runtime context
|
||||
*
|
||||
* Contains information about this manipulator-map. Currently
|
||||
* highlighted manipulator, currently selected manipulators, ...
|
||||
*/
|
||||
struct {
|
||||
/* we redraw the manipulator-map when this changes */
|
||||
struct wmManipulator *highlighted_manipulator;
|
||||
/* user has clicked this manipulator and it gets all input */
|
||||
struct wmManipulator *active_manipulator;
|
||||
/* array for all selected manipulators
|
||||
* TODO check on using BLI_array */
|
||||
struct wmManipulator **selected_manipulator;
|
||||
int tot_selected;
|
||||
} mmap_context;
|
||||
} wmManipulatorMap;
|
||||
|
||||
/**
|
||||
* This is a container for all manipulator types that can be instantiated in a region.
|
||||
* (similar to dropboxes).
|
||||
*
|
||||
* \note There is only ever one of these for every (area, region) combination.
|
||||
*/
|
||||
typedef struct wmManipulatorMapType {
|
||||
struct wmManipulatorMapType *next, *prev;
|
||||
char idname[64];
|
||||
short spaceid, regionid;
|
||||
/* types of manipulator-groups for this manipulator-map type */
|
||||
ListBase manipulator_grouptypes;
|
||||
} wmManipulatorMapType;
|
||||
|
||||
void wm_manipulatormap_selected_delete(wmManipulatorMap *mmap);
|
||||
bool wm_manipulatormap_deselect_all(struct wmManipulatorMap *mmap, wmManipulator ***sel);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Manipulator drawing */
|
||||
|
||||
typedef struct ManipulatorGeometryInfo {
|
||||
int nverts;
|
||||
int ntris;
|
||||
float (*verts)[3];
|
||||
float (*normals)[3];
|
||||
unsigned short *indices;
|
||||
bool init;
|
||||
} ManipulatorGeometryInfo;
|
||||
|
||||
#endif /* __WM_MANIPULATOR_INTERN_H__ */
|
||||
|
@@ -0,0 +1,586 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2014 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Blender Foundation
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/windowmanager/manipulators/intern/wm_manipulatorgroup.c
|
||||
* \ingroup wm
|
||||
*
|
||||
* \name Manipulator-Group
|
||||
*
|
||||
* Manipulator-groups store and manage groups of manipulators. They can be
|
||||
* attached to modal handlers and have own keymaps.
|
||||
*/
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BPY_extern.h"
|
||||
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
#include "wm_event_system.h"
|
||||
|
||||
/* own includes */
|
||||
#include "wm_manipulator_wmapi.h"
|
||||
#include "wm_manipulator_intern.h"
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name wmManipulatorGroup
|
||||
*
|
||||
* \{ */
|
||||
|
||||
/* wmManipulatorGroup.flag */
|
||||
enum {
|
||||
WM_MANIPULATORGROUP_INITIALIZED = (1 << 2), /* mgroup has been initialized */
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new manipulator-group from \a mgrouptype.
|
||||
*/
|
||||
wmManipulatorGroup *wm_manipulatorgroup_new_from_type(wmManipulatorGroupType *mgrouptype)
|
||||
{
|
||||
wmManipulatorGroup *mgroup = MEM_callocN(sizeof(*mgroup), "manipulator-group");
|
||||
mgroup->type = mgrouptype;
|
||||
|
||||
return mgroup;
|
||||
}
|
||||
|
||||
void wm_manipulatorgroup_free(bContext *C, wmManipulatorMap *mmap, wmManipulatorGroup *mgroup)
|
||||
{
|
||||
for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator;) {
|
||||
wmManipulator *manipulator_next = manipulator->next;
|
||||
WM_manipulator_delete(&mgroup->manipulators, mmap, manipulator, C);
|
||||
manipulator = manipulator_next;
|
||||
}
|
||||
BLI_assert(BLI_listbase_is_empty(&mgroup->manipulators));
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
if (mgroup->py_instance) {
|
||||
/* do this first in case there are any __del__ functions or
|
||||
* similar that use properties */
|
||||
BPY_DECREF_RNA_INVALIDATE(mgroup->py_instance);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mgroup->reports && (mgroup->reports->flag & RPT_FREE)) {
|
||||
BKE_reports_clear(mgroup->reports);
|
||||
MEM_freeN(mgroup->reports);
|
||||
}
|
||||
|
||||
if (mgroup->customdata_free) {
|
||||
mgroup->customdata_free(mgroup->customdata);
|
||||
}
|
||||
else {
|
||||
MEM_SAFE_FREE(mgroup->customdata);
|
||||
}
|
||||
|
||||
BLI_remlink(&mmap->manipulator_groups, mgroup);
|
||||
MEM_freeN(mgroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add \a manipulator to \a mgroup and make sure its name is unique within the group.
|
||||
*/
|
||||
void wm_manipulatorgroup_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *manipulator)
|
||||
{
|
||||
BLI_assert(!BLI_findstring(&mgroup->manipulators, manipulator->idname, offsetof(wmManipulator, idname)));
|
||||
BLI_addtail(&mgroup->manipulators, manipulator);
|
||||
manipulator->mgroup = mgroup;
|
||||
}
|
||||
|
||||
void wm_manipulatorgroup_attach_to_modal_handler(
|
||||
bContext *C, wmEventHandler *handler,
|
||||
wmManipulatorGroupType *mgrouptype, wmOperator *op)
|
||||
{
|
||||
/* maybe overly careful, but manipulator-grouptype could come from a failed creation */
|
||||
if (!mgrouptype) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* now instantiate the manipulator-map */
|
||||
mgrouptype->op = op;
|
||||
|
||||
/* try to find map in handler region that contains mgrouptype */
|
||||
if (handler->op_region && handler->op_region->manipulator_map) {
|
||||
handler->manipulator_map = handler->op_region->manipulator_map;
|
||||
ED_region_tag_redraw(handler->op_region);
|
||||
}
|
||||
|
||||
WM_event_add_mousemove(C);
|
||||
}
|
||||
|
||||
wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator(
|
||||
const wmManipulatorGroup *mgroup, bContext *C, const wmEvent *event,
|
||||
unsigned char *part)
|
||||
{
|
||||
for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator; manipulator = manipulator->next) {
|
||||
if (manipulator->intersect && (manipulator->flag & WM_MANIPULATOR_HIDDEN) == 0) {
|
||||
if ((*part = manipulator->intersect(C, event, manipulator))) {
|
||||
return manipulator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all manipulators of \a mgroup that can be selected to the head of \a listbase. Added items need freeing!
|
||||
*/
|
||||
void wm_manipulatorgroup_intersectable_manipulators_to_list(const wmManipulatorGroup *mgroup, ListBase *listbase)
|
||||
{
|
||||
for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator; manipulator = manipulator->next) {
|
||||
if ((manipulator->flag & WM_MANIPULATOR_HIDDEN) == 0) {
|
||||
if (((mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) && manipulator->render_3d_intersection) ||
|
||||
((mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) == 0 && manipulator->intersect))
|
||||
{
|
||||
BLI_addhead(listbase, BLI_genericNodeN(manipulator));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wm_manipulatorgroup_ensure_initialized(wmManipulatorGroup *mgroup, const bContext *C)
|
||||
{
|
||||
/* prepare for first draw */
|
||||
if (UNLIKELY((mgroup->flag & WM_MANIPULATORGROUP_INITIALIZED) == 0)) {
|
||||
mgroup->type->init(C, mgroup);
|
||||
mgroup->flag |= WM_MANIPULATORGROUP_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
bool wm_manipulatorgroup_is_visible(const wmManipulatorGroup *mgroup, const bContext *C)
|
||||
{
|
||||
/* Check for poll function, if manipulator-group belongs to an operator, also check if the operator is running. */
|
||||
return ((mgroup->type->flag & WM_MANIPULATORGROUPTYPE_OP) == 0 || mgroup->type->op) &&
|
||||
(!mgroup->type->poll || mgroup->type->poll(C, mgroup->type));
|
||||
}
|
||||
|
||||
bool wm_manipulatorgroup_is_visible_in_drawstep(const wmManipulatorGroup *mgroup, const int drawstep)
|
||||
{
|
||||
switch (drawstep) {
|
||||
case WM_MANIPULATORMAP_DRAWSTEP_2D:
|
||||
return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) == 0;
|
||||
case WM_MANIPULATORMAP_DRAWSTEP_3D:
|
||||
return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D);
|
||||
case WM_MANIPULATORMAP_DRAWSTEP_IN_SCENE:
|
||||
return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SCENE_DEPTH);
|
||||
default:
|
||||
BLI_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** \name Manipulator operators
|
||||
*
|
||||
* Basic operators for manipulator interaction with user configurable keymaps.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
static int manipulator_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
||||
{
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
wmManipulatorMap *mmap = ar->manipulator_map;
|
||||
wmManipulator ***sel = &mmap->mmap_context.selected_manipulator;
|
||||
wmManipulator *highlighted = mmap->mmap_context.highlighted_manipulator;
|
||||
|
||||
bool extend = RNA_boolean_get(op->ptr, "extend");
|
||||
bool deselect = RNA_boolean_get(op->ptr, "deselect");
|
||||
bool toggle = RNA_boolean_get(op->ptr, "toggle");
|
||||
|
||||
/* deselect all first */
|
||||
if (extend == false && deselect == false && toggle == false) {
|
||||
wm_manipulatormap_deselect_all(mmap, sel);
|
||||
BLI_assert(*sel == NULL && mmap->mmap_context.tot_selected == 0);
|
||||
}
|
||||
|
||||
if (highlighted) {
|
||||
const bool is_selected = (highlighted->state & WM_MANIPULATOR_SELECTED);
|
||||
bool redraw = false;
|
||||
|
||||
if (toggle) {
|
||||
/* toggle: deselect if already selected, else select */
|
||||
deselect = is_selected;
|
||||
}
|
||||
|
||||
if (deselect) {
|
||||
if (is_selected && wm_manipulator_deselect(mmap, highlighted)) {
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
else if (wm_manipulator_select(C, mmap, highlighted)) {
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
ED_region_tag_redraw(ar);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
else {
|
||||
BLI_assert(0);
|
||||
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
|
||||
}
|
||||
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
void MANIPULATORGROUP_OT_manipulator_select(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Manipulator Select";
|
||||
ot->description = "Select the currently highlighted manipulator";
|
||||
ot->idname = "MANIPULATORGROUP_OT_manipulator_select";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = manipulator_select_invoke;
|
||||
|
||||
ot->flag = OPTYPE_UNDO;
|
||||
|
||||
WM_operator_properties_mouse_select(ot);
|
||||
}
|
||||
|
||||
typedef struct ManipulatorTweakData {
|
||||
wmManipulatorMap *mmap;
|
||||
wmManipulator *active;
|
||||
|
||||
int init_event; /* initial event type */
|
||||
int flag; /* tweak flags */
|
||||
} ManipulatorTweakData;
|
||||
|
||||
static void manipulator_tweak_finish(bContext *C, wmOperator *op, const bool cancel)
|
||||
{
|
||||
ManipulatorTweakData *mtweak = op->customdata;
|
||||
if (mtweak->active->exit) {
|
||||
mtweak->active->exit(C, mtweak->active, cancel);
|
||||
}
|
||||
wm_manipulatormap_set_active_manipulator(mtweak->mmap, C, NULL, NULL);
|
||||
MEM_freeN(mtweak);
|
||||
}
|
||||
|
||||
static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ManipulatorTweakData *mtweak = op->customdata;
|
||||
wmManipulator *manipulator = mtweak->active;
|
||||
|
||||
if (!manipulator) {
|
||||
BLI_assert(0);
|
||||
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
|
||||
}
|
||||
|
||||
if (event->type == mtweak->init_event && event->val == KM_RELEASE) {
|
||||
manipulator_tweak_finish(C, op, false);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
switch (event->val) {
|
||||
case TWEAK_MODAL_CANCEL:
|
||||
manipulator_tweak_finish(C, op, true);
|
||||
return OPERATOR_CANCELLED;
|
||||
case TWEAK_MODAL_CONFIRM:
|
||||
manipulator_tweak_finish(C, op, false);
|
||||
return OPERATOR_FINISHED;
|
||||
case TWEAK_MODAL_PRECISION_ON:
|
||||
mtweak->flag |= WM_MANIPULATOR_TWEAK_PRECISE;
|
||||
break;
|
||||
case TWEAK_MODAL_PRECISION_OFF:
|
||||
mtweak->flag &= ~WM_MANIPULATOR_TWEAK_PRECISE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle manipulator */
|
||||
if (manipulator->handler) {
|
||||
manipulator->handler(C, event, manipulator, mtweak->flag);
|
||||
}
|
||||
|
||||
/* Ugly hack to send manipulator events */
|
||||
((wmEvent *)event)->type = EVT_MANIPULATOR_UPDATE;
|
||||
|
||||
/* always return PASS_THROUGH so modal handlers
|
||||
* with manipulators attached can update */
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
static int manipulator_tweak_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
wmManipulatorMap *mmap = ar->manipulator_map;
|
||||
wmManipulator *manipulator = mmap->mmap_context.highlighted_manipulator;
|
||||
|
||||
if (!manipulator) {
|
||||
/* wm_handlers_do_intern shouldn't let this happen */
|
||||
BLI_assert(0);
|
||||
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
|
||||
}
|
||||
|
||||
|
||||
/* activate highlighted manipulator */
|
||||
wm_manipulatormap_set_active_manipulator(mmap, C, event, manipulator);
|
||||
|
||||
/* XXX temporary workaround for modal manipulator operator
|
||||
* conflicting with modal operator attached to manipulator */
|
||||
if (manipulator->opname) {
|
||||
wmOperatorType *ot = WM_operatortype_find(manipulator->opname, true);
|
||||
if (ot->modal) {
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ManipulatorTweakData *mtweak = MEM_mallocN(sizeof(ManipulatorTweakData), __func__);
|
||||
|
||||
mtweak->init_event = event->type;
|
||||
mtweak->active = mmap->mmap_context.highlighted_manipulator;
|
||||
mtweak->mmap = mmap;
|
||||
mtweak->flag = 0;
|
||||
|
||||
op->customdata = mtweak;
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
void MANIPULATORGROUP_OT_manipulator_tweak(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Manipulator Tweak";
|
||||
ot->description = "Tweak the active manipulator";
|
||||
ot->idname = "MANIPULATORGROUP_OT_manipulator_tweak";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = manipulator_tweak_invoke;
|
||||
ot->modal = manipulator_tweak_modal;
|
||||
|
||||
ot->flag = OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/** \} */ // Manipulator operators
|
||||
|
||||
|
||||
static wmKeyMap *manipulatorgroup_tweak_modal_keymap(wmKeyConfig *keyconf, const char *mgroupname)
|
||||
{
|
||||
wmKeyMap *keymap;
|
||||
char name[KMAP_MAX_NAME];
|
||||
|
||||
static EnumPropertyItem modal_items[] = {
|
||||
{TWEAK_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
|
||||
{TWEAK_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
|
||||
{TWEAK_MODAL_PRECISION_ON, "PRECISION_ON", 0, "Enable Precision", ""},
|
||||
{TWEAK_MODAL_PRECISION_OFF, "PRECISION_OFF", 0, "Disable Precision", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
BLI_snprintf(name, sizeof(name), "%s Tweak Modal Map", mgroupname);
|
||||
keymap = WM_modalkeymap_get(keyconf, name);
|
||||
|
||||
/* this function is called for each spacetype, only needs to add map once */
|
||||
if (keymap && keymap->modal_items)
|
||||
return NULL;
|
||||
|
||||
keymap = WM_modalkeymap_add(keyconf, name, modal_items);
|
||||
|
||||
|
||||
/* items for modal map */
|
||||
WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL);
|
||||
WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL);
|
||||
|
||||
WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CONFIRM);
|
||||
WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CONFIRM);
|
||||
|
||||
WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_PRECISION_ON);
|
||||
WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_PRECISION_OFF);
|
||||
WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_PRECISION_ON);
|
||||
WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_PRECISION_OFF);
|
||||
|
||||
|
||||
WM_modalkeymap_assign(keymap, "MANIPULATORGROUP_OT_manipulator_tweak");
|
||||
|
||||
return keymap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common default keymap for manipulator groups
|
||||
*/
|
||||
wmKeyMap *WM_manipulatorgroup_keymap_common(const struct wmManipulatorGroupType *mgrouptype, wmKeyConfig *config)
|
||||
{
|
||||
/* Use area and region id since we might have multiple manipulators with the same name in different areas/regions */
|
||||
wmKeyMap *km = WM_keymap_find(config, mgrouptype->name, mgrouptype->spaceid, mgrouptype->regionid);
|
||||
|
||||
WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", ACTIONMOUSE, KM_PRESS, KM_ANY, 0);
|
||||
manipulatorgroup_tweak_modal_keymap(config, mgrouptype->name);
|
||||
|
||||
return km;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variation of #WM_manipulatorgroup_keymap_common but with keymap items for selection
|
||||
*/
|
||||
wmKeyMap *WM_manipulatorgroup_keymap_common_sel(const struct wmManipulatorGroupType *mgrouptype, wmKeyConfig *config)
|
||||
{
|
||||
/* Use area and region id since we might have multiple manipulators with the same name in different areas/regions */
|
||||
wmKeyMap *km = WM_keymap_find(config, mgrouptype->name, mgrouptype->spaceid, mgrouptype->regionid);
|
||||
|
||||
WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", ACTIONMOUSE, KM_PRESS, KM_ANY, 0);
|
||||
manipulatorgroup_tweak_modal_keymap(config, mgrouptype->name);
|
||||
|
||||
wmKeyMapItem *kmi = WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_select", SELECTMOUSE, KM_PRESS, 0, 0);
|
||||
RNA_boolean_set(kmi->ptr, "extend", false);
|
||||
RNA_boolean_set(kmi->ptr, "deselect", false);
|
||||
RNA_boolean_set(kmi->ptr, "toggle", false);
|
||||
kmi = WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "extend", false);
|
||||
RNA_boolean_set(kmi->ptr, "deselect", false);
|
||||
RNA_boolean_set(kmi->ptr, "toggle", true);
|
||||
|
||||
return km;
|
||||
}
|
||||
|
||||
/** \} */ /* wmManipulatorGroup */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name wmManipulatorGroupType
|
||||
*
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Use this for registering manipulators on startup. For runtime, use #WM_manipulatorgrouptype_append_runtime.
|
||||
*/
|
||||
wmManipulatorGroupType *WM_manipulatorgrouptype_append(
|
||||
wmManipulatorMapType *mmaptype, void (*mgrouptype_func)(wmManipulatorGroupType *))
|
||||
{
|
||||
wmManipulatorGroupType *mgrouptype = MEM_callocN(sizeof(wmManipulatorGroupType), "manipulator-group");
|
||||
|
||||
mgrouptype_func(mgrouptype);
|
||||
mgrouptype->spaceid = mmaptype->spaceid;
|
||||
mgrouptype->regionid = mmaptype->regionid;
|
||||
BLI_strncpy(mgrouptype->mapidname, mmaptype->idname, MAX_NAME);
|
||||
/* if not set, use default */
|
||||
if (!mgrouptype->keymap_init) {
|
||||
mgrouptype->keymap_init = WM_manipulatorgroup_keymap_common;
|
||||
}
|
||||
|
||||
/* add the type for future created areas of the same type */
|
||||
BLI_addtail(&mmaptype->manipulator_grouptypes, mgrouptype);
|
||||
return mgrouptype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this for registering manipulators on runtime.
|
||||
*/
|
||||
wmManipulatorGroupType *WM_manipulatorgrouptype_append_runtime(
|
||||
const Main *main, wmManipulatorMapType *mmaptype,
|
||||
void (*mgrouptype_func)(wmManipulatorGroupType *))
|
||||
{
|
||||
wmManipulatorGroupType *mgrouptype = WM_manipulatorgrouptype_append(mmaptype, mgrouptype_func);
|
||||
|
||||
/* Main is missing on startup when we create new areas.
|
||||
* So this is only called for manipulators initialized on runtime */
|
||||
WM_manipulatorgrouptype_init_runtime(main, mmaptype, mgrouptype);
|
||||
|
||||
return mgrouptype;
|
||||
}
|
||||
|
||||
void WM_manipulatorgrouptype_init_runtime(
|
||||
const Main *bmain, wmManipulatorMapType *mmaptype,
|
||||
wmManipulatorGroupType *mgrouptype)
|
||||
{
|
||||
/* init keymap - on startup there's an extra call to init keymaps for 'permanent' manipulator-groups */
|
||||
wm_manipulatorgrouptype_keymap_init(mgrouptype, ((wmWindowManager *)bmain->wm.first)->defaultconf);
|
||||
|
||||
/* now create a manipulator for all existing areas */
|
||||
for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
|
||||
for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
|
||||
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
|
||||
ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
|
||||
for (ARegion *ar = lb->first; ar; ar = ar->next) {
|
||||
wmManipulatorMap *mmap = ar->manipulator_map;
|
||||
if (mmap->type == mmaptype) {
|
||||
wmManipulatorGroup *mgroup = wm_manipulatorgroup_new_from_type(mgrouptype);
|
||||
|
||||
/* just add here, drawing will occur on next update */
|
||||
BLI_addtail(&mmap->manipulator_groups, mgroup);
|
||||
wm_manipulatormap_set_highlighted_manipulator(mmap, NULL, NULL, 0);
|
||||
ED_region_tag_redraw(ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WM_manipulatorgrouptype_unregister(bContext *C, Main *bmain, wmManipulatorGroupType *mgrouptype)
|
||||
{
|
||||
for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
|
||||
for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
|
||||
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
|
||||
ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
|
||||
for (ARegion *ar = lb->first; ar; ar = ar->next) {
|
||||
wmManipulatorMap *mmap = ar->manipulator_map;
|
||||
wmManipulatorGroup *mgroup, *mgroup_next;
|
||||
|
||||
for (mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup_next) {
|
||||
mgroup_next = mgroup->next;
|
||||
if (mgroup->type == mgrouptype) {
|
||||
wm_manipulatorgroup_free(C, mmap, mgroup);
|
||||
ED_region_tag_redraw(ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wmManipulatorMapType *mmaptype = WM_manipulatormaptype_find(&(const struct wmManipulatorMapType_Params) {
|
||||
mgrouptype->mapidname, mgrouptype->spaceid,
|
||||
mgrouptype->regionid});
|
||||
|
||||
BLI_remlink(&mmaptype->manipulator_grouptypes, mgrouptype);
|
||||
mgrouptype->prev = mgrouptype->next = NULL;
|
||||
|
||||
MEM_freeN(mgrouptype);
|
||||
}
|
||||
|
||||
void wm_manipulatorgrouptype_keymap_init(wmManipulatorGroupType *mgrouptype, wmKeyConfig *keyconf)
|
||||
{
|
||||
mgrouptype->keymap = mgrouptype->keymap_init(mgrouptype, keyconf);
|
||||
}
|
||||
|
||||
/** \} */ /* wmManipulatorGroupType */
|
@@ -0,0 +1,760 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2014 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Blender Foundation
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/windowmanager/manipulators/intern/wm_manipulatormap.c
|
||||
* \ingroup wm
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_ghash.h"
|
||||
|
||||
#include "ED_screen.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_select.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
#include "wm_event_system.h"
|
||||
|
||||
/* own includes */
|
||||
#include "wm_manipulator_wmapi.h"
|
||||
#include "wm_manipulator_intern.h"
|
||||
|
||||
/**
|
||||
* Store all manipulator-maps here. Anyone who wants to register a manipulator for a certain
|
||||
* area type can query the manipulator-map to do so.
|
||||
*/
|
||||
static ListBase manipulatormaptypes = {NULL, NULL};
|
||||
|
||||
/**
|
||||
* Manipulator-map update tagging.
|
||||
*/
|
||||
enum eManipulatorMapUpdateFlags {
|
||||
/* Tag manipulator-map for refresh. */
|
||||
MANIPULATORMAP_REFRESH = (1 << 0),
|
||||
};
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name wmManipulatorMap
|
||||
*
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Creates a manipulator-map with all registered manipulators for that type
|
||||
*/
|
||||
wmManipulatorMap *WM_manipulatormap_new_from_type(const struct wmManipulatorMapType_Params *mmap_params)
|
||||
{
|
||||
wmManipulatorMapType *mmaptype = WM_manipulatormaptype_ensure(mmap_params);
|
||||
wmManipulatorMap *mmap;
|
||||
|
||||
mmap = MEM_callocN(sizeof(wmManipulatorMap), "ManipulatorMap");
|
||||
mmap->type = mmaptype;
|
||||
mmap->update_flag = MANIPULATORMAP_REFRESH;
|
||||
|
||||
/* create all manipulator-groups for this manipulator-map. We may create an empty one
|
||||
* too in anticipation of manipulators from operators etc */
|
||||
for (wmManipulatorGroupType *mgrouptype = mmaptype->manipulator_grouptypes.first;
|
||||
mgrouptype;
|
||||
mgrouptype = mgrouptype->next)
|
||||
{
|
||||
wmManipulatorGroup *mgroup = wm_manipulatorgroup_new_from_type(mgrouptype);
|
||||
BLI_addtail(&mmap->manipulator_groups, mgroup);
|
||||
}
|
||||
|
||||
return mmap;
|
||||
}
|
||||
|
||||
void wm_manipulatormap_selected_delete(wmManipulatorMap *mmap)
|
||||
{
|
||||
MEM_SAFE_FREE(mmap->mmap_context.selected_manipulator);
|
||||
mmap->mmap_context.tot_selected = 0;
|
||||
}
|
||||
|
||||
void wm_manipulatormap_delete(wmManipulatorMap *mmap)
|
||||
{
|
||||
if (!mmap)
|
||||
return;
|
||||
|
||||
for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first, *mgroup_next; mgroup; mgroup = mgroup_next) {
|
||||
mgroup_next = mgroup->next;
|
||||
wm_manipulatorgroup_free(NULL, mmap, mgroup);
|
||||
}
|
||||
BLI_assert(BLI_listbase_is_empty(&mmap->manipulator_groups));
|
||||
|
||||
wm_manipulatormap_selected_delete(mmap);
|
||||
|
||||
MEM_freeN(mmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns idname hash table for (visible) manipulators in \a mmap
|
||||
*
|
||||
* \param poll Polling function for excluding manipulators.
|
||||
* \param data Custom data passed to \a poll
|
||||
*/
|
||||
static GHash *WM_manipulatormap_manipulator_hash_new(
|
||||
const bContext *C, wmManipulatorMap *mmap,
|
||||
bool (*poll)(const wmManipulator *, void *),
|
||||
void *data, const bool include_hidden)
|
||||
{
|
||||
GHash *hash = BLI_ghash_str_new(__func__);
|
||||
|
||||
/* collect manipulators */
|
||||
for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) {
|
||||
if (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type)) {
|
||||
for (wmManipulator *manipulator = mgroup->manipulators.first;
|
||||
manipulator;
|
||||
manipulator = manipulator->next)
|
||||
{
|
||||
if ((include_hidden || (manipulator->flag & WM_MANIPULATOR_HIDDEN) == 0) &&
|
||||
(!poll || poll(manipulator, data)))
|
||||
{
|
||||
BLI_ghash_insert(hash, manipulator->idname, manipulator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
void WM_manipulatormap_tag_refresh(wmManipulatorMap *mmap)
|
||||
{
|
||||
if (mmap) {
|
||||
mmap->update_flag |= MANIPULATORMAP_REFRESH;
|
||||
}
|
||||
}
|
||||
|
||||
static void manipulatormap_tag_updated(wmManipulatorMap *mmap)
|
||||
{
|
||||
mmap->update_flag = 0;
|
||||
}
|
||||
|
||||
static bool manipulator_prepare_drawing(
|
||||
wmManipulatorMap *mmap, wmManipulator *manipulator,
|
||||
const bContext *C, ListBase *draw_manipulators)
|
||||
{
|
||||
if (!wm_manipulator_is_visible(manipulator)) {
|
||||
/* skip */
|
||||
}
|
||||
else {
|
||||
wm_manipulator_update(manipulator, C, (mmap->update_flag & MANIPULATORMAP_REFRESH) != 0);
|
||||
BLI_addhead(draw_manipulators, BLI_genericNodeN(manipulator));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update manipulators of \a mmap to prepare for drawing. Adds all manipulators that
|
||||
* should be drawn to list \a draw_manipulators, note that added items need freeing.
|
||||
*/
|
||||
static void manipulatormap_prepare_drawing(
|
||||
wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators, const int drawstep)
|
||||
{
|
||||
if (!mmap || BLI_listbase_is_empty(&mmap->manipulator_groups))
|
||||
return;
|
||||
wmManipulator *active_manipulator = mmap->mmap_context.active_manipulator;
|
||||
|
||||
/* only active manipulator needs updating */
|
||||
if (active_manipulator) {
|
||||
if (manipulator_prepare_drawing(mmap, active_manipulator, C, draw_manipulators)) {
|
||||
manipulatormap_tag_updated(mmap);
|
||||
}
|
||||
/* don't draw any other manipulators */
|
||||
return;
|
||||
}
|
||||
|
||||
for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) {
|
||||
/* check group visibility - drawstep first to avoid unnecessary call of group poll callback */
|
||||
if (!wm_manipulatorgroup_is_visible_in_drawstep(mgroup, drawstep) ||
|
||||
!wm_manipulatorgroup_is_visible(mgroup, C))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* needs to be initialized on first draw */
|
||||
wm_manipulatorgroup_ensure_initialized(mgroup, C);
|
||||
/* update data if needed */
|
||||
/* XXX weak: Manipulator-group may skip refreshing if it's invisible (map gets untagged nevertheless) */
|
||||
if (mmap->update_flag & MANIPULATORMAP_REFRESH && mgroup->type->refresh) {
|
||||
mgroup->type->refresh(C, mgroup);
|
||||
}
|
||||
/* prepare drawing */
|
||||
if (mgroup->type->draw_prepare) {
|
||||
mgroup->type->draw_prepare(C, mgroup);
|
||||
}
|
||||
|
||||
for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator; manipulator = manipulator->next) {
|
||||
manipulator_prepare_drawing(mmap, manipulator, C, draw_manipulators);
|
||||
}
|
||||
}
|
||||
|
||||
manipulatormap_tag_updated(mmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw all visible manipulators in \a mmap.
|
||||
* Uses global draw_manipulators listbase.
|
||||
*/
|
||||
static void manipulators_draw_list(const wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators)
|
||||
{
|
||||
if (!mmap)
|
||||
return;
|
||||
BLI_assert(!BLI_listbase_is_empty(&mmap->manipulator_groups));
|
||||
|
||||
/* draw_manipulators contains all visible manipulators - draw them */
|
||||
for (LinkData *link = draw_manipulators->first, *link_next; link; link = link_next) {
|
||||
wmManipulator *manipulator = link->data;
|
||||
link_next = link->next;
|
||||
|
||||
manipulator->draw(C, manipulator);
|
||||
/* free/remove manipulator link after drawing */
|
||||
BLI_freelinkN(draw_manipulators, link);
|
||||
}
|
||||
}
|
||||
|
||||
void WM_manipulatormap_draw(wmManipulatorMap *mmap, const bContext *C, const int drawstep)
|
||||
{
|
||||
ListBase draw_manipulators = {NULL};
|
||||
|
||||
manipulatormap_prepare_drawing(mmap, C, &draw_manipulators, drawstep);
|
||||
manipulators_draw_list(mmap, C, &draw_manipulators);
|
||||
BLI_assert(BLI_listbase_is_empty(&draw_manipulators));
|
||||
}
|
||||
|
||||
static void manipulator_find_active_3D_loop(const bContext *C, ListBase *visible_manipulators)
|
||||
{
|
||||
int selectionbase = 0;
|
||||
wmManipulator *manipulator;
|
||||
|
||||
for (LinkData *link = visible_manipulators->first; link; link = link->next) {
|
||||
manipulator = link->data;
|
||||
/* pass the selection id shifted by 8 bits. Last 8 bits are used for selected manipulator part id */
|
||||
manipulator->render_3d_intersection(C, manipulator, selectionbase << 8);
|
||||
|
||||
selectionbase++;
|
||||
}
|
||||
}
|
||||
|
||||
static int manipulator_find_intersected_3D_intern(
|
||||
ListBase *visible_manipulators, const bContext *C, const int co[2],
|
||||
const float hotspot)
|
||||
{
|
||||
ScrArea *sa = CTX_wm_area(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
View3D *v3d = sa->spacedata.first;
|
||||
RegionView3D *rv3d = ar->regiondata;
|
||||
rctf rect, selrect;
|
||||
GLuint buffer[64]; // max 4 items per select, so large enuf
|
||||
short hits;
|
||||
const bool do_passes = GPU_select_query_check_active();
|
||||
|
||||
extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect);
|
||||
|
||||
|
||||
rect.xmin = co[0] - hotspot;
|
||||
rect.xmax = co[0] + hotspot;
|
||||
rect.ymin = co[1] - hotspot;
|
||||
rect.ymax = co[1] + hotspot;
|
||||
|
||||
selrect = rect;
|
||||
|
||||
view3d_winmatrix_set(ar, v3d, &rect);
|
||||
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
|
||||
|
||||
if (do_passes)
|
||||
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
|
||||
else
|
||||
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_ALL, 0);
|
||||
/* do the drawing */
|
||||
manipulator_find_active_3D_loop(C, visible_manipulators);
|
||||
|
||||
hits = GPU_select_end();
|
||||
|
||||
if (do_passes) {
|
||||
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
|
||||
manipulator_find_active_3D_loop(C, visible_manipulators);
|
||||
GPU_select_end();
|
||||
}
|
||||
|
||||
view3d_winmatrix_set(ar, v3d, NULL);
|
||||
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
|
||||
|
||||
return hits > 0 ? buffer[3] : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find a 3D manipulator at screen-space coordinate \a co. Uses OpenGL picking.
|
||||
*/
|
||||
static wmManipulator *manipulator_find_intersected_3D(
|
||||
bContext *C, const int co[2], ListBase *visible_manipulators,
|
||||
unsigned char *part)
|
||||
{
|
||||
wmManipulator *result = NULL;
|
||||
const float hotspot = 14.0f;
|
||||
int ret;
|
||||
|
||||
*part = 0;
|
||||
/* set up view matrices */
|
||||
view3d_operator_needs_opengl(C);
|
||||
|
||||
ret = manipulator_find_intersected_3D_intern(visible_manipulators, C, co, 0.5f * hotspot);
|
||||
|
||||
if (ret != -1) {
|
||||
LinkData *link;
|
||||
int retsec;
|
||||
retsec = manipulator_find_intersected_3D_intern(visible_manipulators, C, co, 0.2f * hotspot);
|
||||
|
||||
if (retsec != -1)
|
||||
ret = retsec;
|
||||
|
||||
link = BLI_findlink(visible_manipulators, ret >> 8);
|
||||
*part = ret & 255;
|
||||
result = link->data;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find a manipulator under the mouse position. 2D intersections have priority over
|
||||
* 3D ones (could check for smallest screen-space distance but not needed right now).
|
||||
*/
|
||||
wmManipulator *wm_manipulatormap_find_highlighted_manipulator(
|
||||
wmManipulatorMap *mmap, bContext *C, const wmEvent *event,
|
||||
unsigned char *part)
|
||||
{
|
||||
wmManipulator *manipulator = NULL;
|
||||
ListBase visible_3d_manipulators = {NULL};
|
||||
|
||||
for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) {
|
||||
if (wm_manipulatorgroup_is_visible(mgroup, C)) {
|
||||
if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) {
|
||||
wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators);
|
||||
}
|
||||
else if ((manipulator = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, part))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!BLI_listbase_is_empty(&visible_3d_manipulators)) {
|
||||
manipulator = manipulator_find_intersected_3D(C, event->mval, &visible_3d_manipulators, part);
|
||||
BLI_freelistN(&visible_3d_manipulators);
|
||||
}
|
||||
|
||||
return manipulator;
|
||||
}
|
||||
|
||||
void WM_manipulatormap_add_handlers(ARegion *ar, wmManipulatorMap *mmap)
|
||||
{
|
||||
wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "manipulator handler");
|
||||
|
||||
BLI_assert(mmap == ar->manipulator_map);
|
||||
handler->manipulator_map = mmap;
|
||||
BLI_addtail(&ar->handlers, handler);
|
||||
}
|
||||
|
||||
void wm_manipulatormaps_handled_modal_update(
|
||||
bContext *C, wmEvent *event, wmEventHandler *handler,
|
||||
const wmOperatorType *ot)
|
||||
{
|
||||
const bool modal_running = (handler->op != NULL);
|
||||
|
||||
/* happens on render */
|
||||
if (!handler->op_region || !handler->op_region->manipulator_map)
|
||||
return;
|
||||
|
||||
/* hide operator manipulators */
|
||||
if (!modal_running && ot->mgrouptype) {
|
||||
ot->mgrouptype->op = NULL;
|
||||
}
|
||||
|
||||
wmManipulatorMap *mmap = handler->op_region->manipulator_map;
|
||||
wmManipulator *manipulator = wm_manipulatormap_get_active_manipulator(mmap);
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
|
||||
wm_manipulatormap_handler_context(C, handler);
|
||||
|
||||
/* regular update for running operator */
|
||||
if (modal_running) {
|
||||
if (manipulator && manipulator->handler && manipulator->opname &&
|
||||
STREQ(manipulator->opname, handler->op->idname))
|
||||
{
|
||||
manipulator->handler(C, event, manipulator, 0);
|
||||
}
|
||||
}
|
||||
/* operator not running anymore */
|
||||
else {
|
||||
wm_manipulatormap_set_highlighted_manipulator(mmap, C, NULL, 0);
|
||||
wm_manipulatormap_set_active_manipulator(mmap, C, event, NULL);
|
||||
}
|
||||
|
||||
/* restore the area */
|
||||
CTX_wm_area_set(C, area);
|
||||
CTX_wm_region_set(C, region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deselect all selected manipulators in \a mmap.
|
||||
* \return if selection has changed.
|
||||
*/
|
||||
bool wm_manipulatormap_deselect_all(wmManipulatorMap *mmap, wmManipulator ***sel)
|
||||
{
|
||||
if (*sel == NULL || mmap->mmap_context.tot_selected == 0)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < mmap->mmap_context.tot_selected; i++) {
|
||||
(*sel)[i]->state &= ~WM_MANIPULATOR_SELECTED;
|
||||
(*sel)[i] = NULL;
|
||||
}
|
||||
wm_manipulatormap_selected_delete(mmap);
|
||||
|
||||
/* always return true, we already checked
|
||||
* if there's anything to deselect */
|
||||
return true;
|
||||
}
|
||||
|
||||
BLI_INLINE bool manipulator_selectable_poll(const wmManipulator *manipulator, void *UNUSED(data))
|
||||
{
|
||||
return (manipulator->mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECTABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select all selectable manipulators in \a mmap.
|
||||
* \return if selection has changed.
|
||||
*/
|
||||
static bool wm_manipulatormap_select_all_intern(
|
||||
bContext *C, wmManipulatorMap *mmap, wmManipulator ***sel,
|
||||
const int action)
|
||||
{
|
||||
/* GHash is used here to avoid having to loop over all manipulators twice (once to
|
||||
* get tot_sel for allocating, once for actually selecting). Instead we collect
|
||||
* selectable manipulators in hash table and use this to get tot_sel and do selection */
|
||||
|
||||
GHash *hash = WM_manipulatormap_manipulator_hash_new(C, mmap, manipulator_selectable_poll, NULL, true);
|
||||
GHashIterator gh_iter;
|
||||
int i, *tot_sel = &mmap->mmap_context.tot_selected;
|
||||
bool changed = false;
|
||||
|
||||
*tot_sel = BLI_ghash_size(hash);
|
||||
*sel = MEM_reallocN(*sel, sizeof(**sel) * (*tot_sel));
|
||||
|
||||
GHASH_ITER_INDEX (gh_iter, hash, i) {
|
||||
wmManipulator *manipulator_iter = BLI_ghashIterator_getValue(&gh_iter);
|
||||
|
||||
if ((manipulator_iter->state & WM_MANIPULATOR_SELECTED) == 0) {
|
||||
changed = true;
|
||||
}
|
||||
manipulator_iter->state |= WM_MANIPULATOR_SELECTED;
|
||||
if (manipulator_iter->select) {
|
||||
manipulator_iter->select(C, manipulator_iter, action);
|
||||
}
|
||||
(*sel)[i] = manipulator_iter;
|
||||
BLI_assert(i < (*tot_sel));
|
||||
}
|
||||
/* highlight first manipulator */
|
||||
wm_manipulatormap_set_highlighted_manipulator(mmap, C, (*sel)[0], (*sel)[0]->highlighted_part);
|
||||
|
||||
BLI_ghash_free(hash, NULL, NULL);
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select/Deselect all selectable manipulators in \a mmap.
|
||||
* \return if selection has changed.
|
||||
*
|
||||
* TODO select all by type
|
||||
*/
|
||||
bool WM_manipulatormap_select_all(bContext *C, wmManipulatorMap *mmap, const int action)
|
||||
{
|
||||
wmManipulator ***sel = &mmap->mmap_context.selected_manipulator;
|
||||
bool changed = false;
|
||||
|
||||
switch (action) {
|
||||
case SEL_SELECT:
|
||||
changed = wm_manipulatormap_select_all_intern(C, mmap, sel, action);
|
||||
break;
|
||||
case SEL_DESELECT:
|
||||
changed = wm_manipulatormap_deselect_all(mmap, sel);
|
||||
break;
|
||||
default:
|
||||
BLI_assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
WM_event_add_mousemove(C);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare context for manipulator handling (but only if area/region is
|
||||
* part of screen). Version of #wm_handler_op_context for manipulators.
|
||||
*/
|
||||
void wm_manipulatormap_handler_context(bContext *C, wmEventHandler *handler)
|
||||
{
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
|
||||
if (screen) {
|
||||
if (handler->op_area == NULL) {
|
||||
/* do nothing in this context */
|
||||
}
|
||||
else {
|
||||
ScrArea *sa;
|
||||
|
||||
for (sa = screen->areabase.first; sa; sa = sa->next)
|
||||
if (sa == handler->op_area)
|
||||
break;
|
||||
if (sa == NULL) {
|
||||
/* when changing screen layouts with running modal handlers (like render display), this
|
||||
* is not an error to print */
|
||||
if (handler->manipulator_map == NULL)
|
||||
printf("internal error: modal manipulator-map handler has invalid area\n");
|
||||
}
|
||||
else {
|
||||
ARegion *ar;
|
||||
CTX_wm_area_set(C, sa);
|
||||
for (ar = sa->regionbase.first; ar; ar = ar->next)
|
||||
if (ar == handler->op_region)
|
||||
break;
|
||||
/* XXX no warning print here, after full-area and back regions are remade */
|
||||
if (ar)
|
||||
CTX_wm_region_set(C, ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_manipulatormap_cursor_set(const wmManipulatorMap *mmap, wmWindow *win)
|
||||
{
|
||||
for (; mmap; mmap = mmap->next) {
|
||||
wmManipulator *manipulator = mmap->mmap_context.highlighted_manipulator;
|
||||
if (manipulator && manipulator->get_cursor) {
|
||||
WM_cursor_set(win, manipulator->get_cursor(manipulator));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void wm_manipulatormap_set_highlighted_manipulator(
|
||||
wmManipulatorMap *mmap, const bContext *C, wmManipulator *manipulator,
|
||||
unsigned char part)
|
||||
{
|
||||
if ((manipulator != mmap->mmap_context.highlighted_manipulator) ||
|
||||
(manipulator && part != manipulator->highlighted_part))
|
||||
{
|
||||
if (mmap->mmap_context.highlighted_manipulator) {
|
||||
mmap->mmap_context.highlighted_manipulator->state &= ~WM_MANIPULATOR_HIGHLIGHT;
|
||||
mmap->mmap_context.highlighted_manipulator->highlighted_part = 0;
|
||||
}
|
||||
|
||||
mmap->mmap_context.highlighted_manipulator = manipulator;
|
||||
|
||||
if (manipulator) {
|
||||
manipulator->state |= WM_MANIPULATOR_HIGHLIGHT;
|
||||
manipulator->highlighted_part = part;
|
||||
|
||||
if (C && manipulator->get_cursor) {
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
WM_cursor_set(win, manipulator->get_cursor(manipulator));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (C) {
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
WM_cursor_set(win, CURSOR_STD);
|
||||
}
|
||||
}
|
||||
|
||||
/* tag the region for redraw */
|
||||
if (C) {
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
ED_region_tag_redraw(ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wmManipulator *wm_manipulatormap_get_highlighted_manipulator(wmManipulatorMap *mmap)
|
||||
{
|
||||
return mmap->mmap_context.highlighted_manipulator;
|
||||
}
|
||||
|
||||
void wm_manipulatormap_set_active_manipulator(
|
||||
wmManipulatorMap *mmap, bContext *C, const wmEvent *event, wmManipulator *manipulator)
|
||||
{
|
||||
if (manipulator && C) {
|
||||
manipulator->state |= WM_MANIPULATOR_ACTIVE;
|
||||
mmap->mmap_context.active_manipulator = manipulator;
|
||||
|
||||
if (manipulator->opname) {
|
||||
wmOperatorType *ot = WM_operatortype_find(manipulator->opname, 0);
|
||||
|
||||
if (ot) {
|
||||
/* first activate the manipulator itself */
|
||||
if (manipulator->invoke && manipulator->handler) {
|
||||
manipulator->invoke(C, event, manipulator);
|
||||
}
|
||||
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &manipulator->opptr);
|
||||
|
||||
/* we failed to hook the manipulator to the operator handler or operator was cancelled, return */
|
||||
if (!mmap->mmap_context.active_manipulator) {
|
||||
manipulator->state &= ~WM_MANIPULATOR_ACTIVE;
|
||||
/* first activate the manipulator itself */
|
||||
if (manipulator->interaction_data) {
|
||||
MEM_freeN(manipulator->interaction_data);
|
||||
manipulator->interaction_data = NULL;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
printf("Manipulator error: operator not found");
|
||||
mmap->mmap_context.active_manipulator = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (manipulator->invoke && manipulator->handler) {
|
||||
manipulator->invoke(C, event, manipulator);
|
||||
}
|
||||
}
|
||||
WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL);
|
||||
}
|
||||
else {
|
||||
manipulator = mmap->mmap_context.active_manipulator;
|
||||
|
||||
|
||||
/* deactivate, manipulator but first take care of some stuff */
|
||||
if (manipulator) {
|
||||
manipulator->state &= ~WM_MANIPULATOR_ACTIVE;
|
||||
/* first activate the manipulator itself */
|
||||
if (manipulator->interaction_data) {
|
||||
MEM_freeN(manipulator->interaction_data);
|
||||
manipulator->interaction_data = NULL;
|
||||
}
|
||||
}
|
||||
mmap->mmap_context.active_manipulator = NULL;
|
||||
|
||||
if (C) {
|
||||
WM_cursor_grab_disable(CTX_wm_window(C), NULL);
|
||||
ED_region_tag_redraw(CTX_wm_region(C));
|
||||
WM_event_add_mousemove(C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wmManipulator *wm_manipulatormap_get_active_manipulator(wmManipulatorMap *mmap)
|
||||
{
|
||||
return mmap->mmap_context.active_manipulator;
|
||||
}
|
||||
|
||||
/** \} */ /* wmManipulatorMap */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name wmManipulatorMapType
|
||||
*
|
||||
* \{ */
|
||||
|
||||
wmManipulatorMapType *WM_manipulatormaptype_find(
|
||||
const struct wmManipulatorMapType_Params *mmap_params)
|
||||
{
|
||||
for (wmManipulatorMapType *mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) {
|
||||
if (mmaptype->spaceid == mmap_params->spaceid &&
|
||||
mmaptype->regionid == mmap_params->regionid &&
|
||||
STREQ(mmaptype->idname, mmap_params->idname))
|
||||
{
|
||||
return mmaptype;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wmManipulatorMapType *WM_manipulatormaptype_ensure(
|
||||
const struct wmManipulatorMapType_Params *mmap_params)
|
||||
{
|
||||
wmManipulatorMapType *mmaptype = WM_manipulatormaptype_find(mmap_params);
|
||||
|
||||
if (mmaptype) {
|
||||
return mmaptype;
|
||||
}
|
||||
|
||||
mmaptype = MEM_callocN(sizeof(wmManipulatorMapType), "manipulatortype list");
|
||||
mmaptype->spaceid = mmap_params->spaceid;
|
||||
mmaptype->regionid = mmap_params->regionid;
|
||||
BLI_strncpy(mmaptype->idname, mmap_params->idname, sizeof(mmaptype->idname));
|
||||
BLI_addhead(&manipulatormaptypes, mmaptype);
|
||||
|
||||
return mmaptype;
|
||||
}
|
||||
|
||||
void wm_manipulatormaptypes_free(void)
|
||||
{
|
||||
for (wmManipulatorMapType *mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) {
|
||||
BLI_freelistN(&mmaptype->manipulator_grouptypes);
|
||||
}
|
||||
BLI_freelistN(&manipulatormaptypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize keymaps for all existing manipulator-groups
|
||||
*/
|
||||
void wm_manipulators_keymap(wmKeyConfig *keyconf)
|
||||
{
|
||||
wmManipulatorMapType *mmaptype;
|
||||
wmManipulatorGroupType *mgrouptype;
|
||||
|
||||
/* we add this item-less keymap once and use it to group manipulator-group keymaps into it */
|
||||
WM_keymap_find(keyconf, "Manipulators", 0, 0);
|
||||
|
||||
for (mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) {
|
||||
for (mgrouptype = mmaptype->manipulator_grouptypes.first; mgrouptype; mgrouptype = mgrouptype->next) {
|
||||
wm_manipulatorgrouptype_keymap_init(mgrouptype, keyconf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */ /* wmManipulatorMapType */
|
||||
|
@@ -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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/windowmanager/manipulators/wm_manipulator_wmapi.h
|
||||
* \ingroup wm
|
||||
*
|
||||
* \name Manipulators Window Manager API
|
||||
* API for usage in window manager code only. It should contain all functionality
|
||||
* needed to hook up the manipulator system with Blender's window manager. It's
|
||||
* mostly the event system that needs to communicate with manipulator code.
|
||||
*
|
||||
* Only included in wm.h and lower level files.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __WM_MANIPULATOR_WMAPI_H__
|
||||
#define __WM_MANIPULATOR_WMAPI_H__
|
||||
|
||||
struct wmEventHandler;
|
||||
struct wmManipulatorMap;
|
||||
struct wmOperatorType;
|
||||
struct wmOperator;
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulator */
|
||||
|
||||
typedef void (*wmManipulatorSelectFunc)(struct bContext *, struct wmManipulator *, const int);
|
||||
|
||||
struct wmManipulatorGroup *wm_manipulator_get_parent_group(const struct wmManipulator *manipulator);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulatorGroup */
|
||||
|
||||
void MANIPULATORGROUP_OT_manipulator_select(struct wmOperatorType *ot);
|
||||
void MANIPULATORGROUP_OT_manipulator_tweak(struct wmOperatorType *ot);
|
||||
|
||||
void wm_manipulatorgroup_attach_to_modal_handler(
|
||||
struct bContext *C, struct wmEventHandler *handler,
|
||||
struct wmManipulatorGroupType *mgrouptype, struct wmOperator *op);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulatorMap */
|
||||
|
||||
void wm_manipulatormap_delete(struct wmManipulatorMap *mmap);
|
||||
void wm_manipulatormaptypes_free(void);
|
||||
|
||||
void wm_manipulators_keymap(struct wmKeyConfig *keyconf);
|
||||
|
||||
void wm_manipulatormaps_handled_modal_update(
|
||||
bContext *C, struct wmEvent *event, struct wmEventHandler *handler,
|
||||
const struct wmOperatorType *ot);
|
||||
void wm_manipulatormap_handler_context(bContext *C, struct wmEventHandler *handler);
|
||||
|
||||
struct wmManipulator *wm_manipulatormap_find_highlighted_manipulator(
|
||||
struct wmManipulatorMap *mmap, bContext *C,
|
||||
const struct wmEvent *event, unsigned char *part);
|
||||
void wm_manipulatormap_set_highlighted_manipulator(
|
||||
struct wmManipulatorMap *mmap, const bContext *C,
|
||||
struct wmManipulator *manipulator, unsigned char part);
|
||||
struct wmManipulator *wm_manipulatormap_get_highlighted_manipulator(struct wmManipulatorMap *mmap);
|
||||
void wm_manipulatormap_set_active_manipulator(
|
||||
struct wmManipulatorMap *mmap, bContext *C,
|
||||
const struct wmEvent *event, struct wmManipulator *manipulator);
|
||||
struct wmManipulator *wm_manipulatormap_get_active_manipulator(struct wmManipulatorMap *mmap);
|
||||
|
||||
#endif /* __WM_MANIPULATOR_WMAPI_H__ */
|
||||
|
@@ -34,6 +34,8 @@
|
||||
struct wmWindow;
|
||||
struct ReportList;
|
||||
|
||||
#include "manipulators/wm_manipulator_wmapi.h"
|
||||
|
||||
typedef struct wmPaintCursor {
|
||||
struct wmPaintCursor *next, *prev;
|
||||
|
||||
|
@@ -68,7 +68,8 @@ typedef struct wmEventHandler {
|
||||
|
||||
/* drop box handler */
|
||||
ListBase *dropboxes;
|
||||
|
||||
/* manipulator handler */
|
||||
struct wmManipulatorMap *manipulator_map;
|
||||
} wmEventHandler;
|
||||
|
||||
/* custom types for handlers, for signalling, freeing */
|
||||
|
@@ -339,6 +339,8 @@ enum {
|
||||
EVT_DROP = 0x5023,
|
||||
EVT_BUT_CANCEL = 0x5024,
|
||||
|
||||
/* could become manipulator callback */
|
||||
EVT_MANIPULATOR_UPDATE = 0x5025,
|
||||
/* ********** End of Blender internal events. ********** */
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user