2016-10-07 16:34:55 +02:00
|
|
|
/*
|
|
|
|
|
* ***** 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"
|
|
|
|
|
|
2017-04-06 21:55:58 +10:00
|
|
|
#include "DNA_manipulator_types.h"
|
|
|
|
|
|
2016-10-07 16:34:55 +02:00
|
|
|
#include "ED_screen.h"
|
|
|
|
|
#include "ED_view3d.h"
|
|
|
|
|
|
|
|
|
|
#include "GPU_glew.h"
|
2017-04-07 16:02:45 +02:00
|
|
|
#include "GPU_matrix.h"
|
2016-10-07 16:34:55 +02:00
|
|
|
#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 */
|
2017-06-10 10:42:35 +10:00
|
|
|
for (wmManipulatorGroupType *wgt = mmaptype->manipulator_grouptypes.first; wgt; wgt = wgt->next) {
|
|
|
|
|
wm_manipulatorgroup_new_from_type(mmap, wgt);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mmap;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
void wm_manipulatormap_selected_clear(wmManipulatorMap *mmap)
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
MEM_SAFE_FREE(mmap->mmap_context.selected);
|
|
|
|
|
mmap->mmap_context.selected_len = 0;
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
void wm_manipulatormap_remove(wmManipulatorMap *mmap)
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
|
|
|
|
if (!mmap)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first, *mgroup_next; mgroup; mgroup = mgroup_next) {
|
|
|
|
|
mgroup_next = mgroup->next;
|
2017-06-06 03:34:09 +10:00
|
|
|
BLI_assert(mgroup->parent_mmap == mmap);
|
|
|
|
|
wm_manipulatorgroup_free(NULL, mgroup);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
BLI_assert(BLI_listbase_is_empty(&mmap->manipulator_groups));
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
wm_manipulatormap_selected_clear(mmap);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
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)) {
|
2017-06-10 10:42:35 +10:00
|
|
|
for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
|
|
|
|
|
if ((include_hidden || (mpr->flag & WM_MANIPULATOR_HIDDEN) == 0) &&
|
|
|
|
|
(!poll || poll(mpr, data)))
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
BLI_ghash_insert(hash, mpr->name, mpr);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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(
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulatorMap *mmap, wmManipulator *mpr,
|
2016-10-07 16:34:55 +02:00
|
|
|
const bContext *C, ListBase *draw_manipulators)
|
|
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
if (!wm_manipulator_is_visible(mpr)) {
|
2016-10-07 16:34:55 +02:00
|
|
|
/* skip */
|
|
|
|
|
}
|
|
|
|
|
else {
|
2017-06-10 10:42:35 +10:00
|
|
|
wm_manipulator_update(mpr, C, (mmap->update_flag & MANIPULATORMAP_REFRESH) != 0);
|
|
|
|
|
BLI_addhead(draw_manipulators, BLI_genericNodeN(mpr));
|
2016-10-07 16:34:55 +02:00
|
|
|
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;
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulator *active_manipulator = mmap->mmap_context.active;
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
|
|
|
|
|
manipulator_prepare_drawing(mmap, mpr, C, draw_manipulators);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
2017-04-06 21:55:58 +10:00
|
|
|
const bool draw_multisample = (U.ogl_multisamples != USER_MULTISAMPLE_NONE);
|
2017-04-18 14:57:09 +02:00
|
|
|
|
|
|
|
|
/* TODO this will need it own shader probably? don't think it can be handled from that point though. */
|
|
|
|
|
/* const bool use_lighting = (U.manipulator_flag & V3D_SHADED_MANIPULATORS) != 0; */
|
2017-04-06 21:55:58 +10:00
|
|
|
|
|
|
|
|
/* enable multisampling */
|
|
|
|
|
if (draw_multisample) {
|
|
|
|
|
glEnable(GL_MULTISAMPLE);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-07 16:34:55 +02:00
|
|
|
/* draw_manipulators contains all visible manipulators - draw them */
|
|
|
|
|
for (LinkData *link = draw_manipulators->first, *link_next; link; link = link_next) {
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulator *mpr = link->data;
|
2016-10-07 16:34:55 +02:00
|
|
|
link_next = link->next;
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
mpr->type->draw(C, mpr);
|
2016-10-07 16:34:55 +02:00
|
|
|
/* free/remove manipulator link after drawing */
|
|
|
|
|
BLI_freelinkN(draw_manipulators, link);
|
|
|
|
|
}
|
2017-04-06 21:55:58 +10:00
|
|
|
|
|
|
|
|
if (draw_multisample) {
|
|
|
|
|
glDisable(GL_MULTISAMPLE);
|
|
|
|
|
}
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulator *mpr;
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
for (LinkData *link = visible_manipulators->first; link; link = link->next) {
|
2017-06-10 10:42:35 +10:00
|
|
|
mpr = link->data;
|
2016-10-07 16:34:55 +02:00
|
|
|
/* pass the selection id shifted by 8 bits. Last 8 bits are used for selected manipulator part id */
|
2017-06-10 10:42:35 +10:00
|
|
|
mpr->type->draw_select(C, mpr, selectionbase << 8);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
selectionbase++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-08 07:16:47 +10:00
|
|
|
static int manipulator_find_intersected_3d_intern(
|
2016-10-07 16:34:55 +02:00
|
|
|
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;
|
2017-03-09 16:33:20 +11:00
|
|
|
rcti rect;
|
2017-06-14 17:17:00 +10:00
|
|
|
/* Almost certainly overkill, but allow for many custom manipulators. */
|
|
|
|
|
GLuint buffer[MAXPICKBUF];
|
2016-10-07 16:34:55 +02:00
|
|
|
short hits;
|
|
|
|
|
const bool do_passes = GPU_select_query_check_active();
|
|
|
|
|
|
|
|
|
|
rect.xmin = co[0] - hotspot;
|
|
|
|
|
rect.xmax = co[0] + hotspot;
|
|
|
|
|
rect.ymin = co[1] - hotspot;
|
|
|
|
|
rect.ymax = co[1] + hotspot;
|
|
|
|
|
|
2017-05-10 15:54:23 +02:00
|
|
|
ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_scene(C), ar, v3d, NULL, NULL, &rect);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
if (do_passes)
|
2017-03-09 16:33:20 +11:00
|
|
|
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
|
2016-10-07 16:34:55 +02:00
|
|
|
else
|
2017-03-09 16:33:20 +11:00
|
|
|
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_ALL, 0);
|
2016-10-07 16:34:55 +02:00
|
|
|
/* do the drawing */
|
|
|
|
|
manipulator_find_active_3D_loop(C, visible_manipulators);
|
|
|
|
|
|
|
|
|
|
hits = GPU_select_end();
|
|
|
|
|
|
2017-06-14 17:17:00 +10:00
|
|
|
if (do_passes && (hits > 0)) {
|
2017-03-09 16:33:20 +11:00
|
|
|
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
|
2016-10-07 16:34:55 +02:00
|
|
|
manipulator_find_active_3D_loop(C, visible_manipulators);
|
|
|
|
|
GPU_select_end();
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-10 15:54:23 +02:00
|
|
|
ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_scene(C), ar, v3d, NULL, NULL, NULL);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
return hits > 0 ? buffer[3] : -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Try to find a 3D manipulator at screen-space coordinate \a co. Uses OpenGL picking.
|
|
|
|
|
*/
|
2017-06-08 07:16:47 +10:00
|
|
|
static wmManipulator *manipulator_find_intersected_3d(
|
2016-10-07 16:34:55 +02:00
|
|
|
bContext *C, const int co[2], ListBase *visible_manipulators,
|
2017-06-10 10:42:35 +10:00
|
|
|
int *r_part)
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
|
|
|
|
wmManipulator *result = NULL;
|
|
|
|
|
const float hotspot = 14.0f;
|
|
|
|
|
int ret;
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
*r_part = 0;
|
2016-10-07 16:34:55 +02:00
|
|
|
/* set up view matrices */
|
|
|
|
|
view3d_operator_needs_opengl(C);
|
|
|
|
|
|
2017-06-08 07:16:47 +10:00
|
|
|
ret = manipulator_find_intersected_3d_intern(visible_manipulators, C, co, 0.5f * hotspot);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
if (ret != -1) {
|
|
|
|
|
LinkData *link;
|
|
|
|
|
int retsec;
|
2017-06-08 07:16:47 +10:00
|
|
|
retsec = manipulator_find_intersected_3d_intern(visible_manipulators, C, co, 0.2f * hotspot);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
if (retsec != -1)
|
|
|
|
|
ret = retsec;
|
|
|
|
|
|
|
|
|
|
link = BLI_findlink(visible_manipulators, ret >> 8);
|
2017-06-10 10:42:35 +10:00
|
|
|
*r_part = ret & 255;
|
2016-10-07 16:34:55 +02:00
|
|
|
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).
|
|
|
|
|
*/
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulator *wm_manipulatormap_highlight_find(
|
2016-10-07 16:34:55 +02:00
|
|
|
wmManipulatorMap *mmap, bContext *C, const wmEvent *event,
|
2017-06-10 10:42:35 +10:00
|
|
|
int *r_part)
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulator *mpr = NULL;
|
2016-10-07 16:34:55 +02:00
|
|
|
ListBase visible_3d_manipulators = {NULL};
|
|
|
|
|
|
|
|
|
|
for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) {
|
|
|
|
|
if (wm_manipulatorgroup_is_visible(mgroup, C)) {
|
2017-06-10 10:42:35 +10:00
|
|
|
if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) {
|
2016-10-07 16:34:55 +02:00
|
|
|
wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators);
|
|
|
|
|
}
|
2017-06-10 10:42:35 +10:00
|
|
|
else if ((mpr = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, r_part))) {
|
2016-10-07 16:34:55 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!BLI_listbase_is_empty(&visible_3d_manipulators)) {
|
2017-06-10 10:42:35 +10:00
|
|
|
mpr = manipulator_find_intersected_3d(C, event->mval, &visible_3d_manipulators, r_part);
|
2016-10-07 16:34:55 +02:00
|
|
|
BLI_freelistN(&visible_3d_manipulators);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
return mpr;
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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(
|
2017-06-10 10:42:35 +10:00
|
|
|
bContext *C, wmEvent *event, wmEventHandler *handler)
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
|
|
|
|
const bool modal_running = (handler->op != NULL);
|
|
|
|
|
|
2016-10-16 19:28:12 +02:00
|
|
|
/* happens on render or when joining areas */
|
2017-06-10 10:42:35 +10:00
|
|
|
if (!handler->op_region || !handler->op_region->manipulator_map) {
|
2016-10-07 16:34:55 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-17 19:25:56 +02:00
|
|
|
wmManipulatorMap *mmap = handler->op_region->manipulator_map;
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulator *mpr = wm_manipulatormap_active_get(mmap);
|
2016-10-17 19:25:56 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
|
|
|
|
ARegion *region = CTX_wm_region(C);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
wm_manipulatormap_handler_context(C, handler);
|
|
|
|
|
|
|
|
|
|
/* regular update for running operator */
|
|
|
|
|
if (modal_running) {
|
2017-06-10 10:42:35 +10:00
|
|
|
if (mpr && mpr->opname &&
|
|
|
|
|
STREQ(mpr->opname, handler->op->idname))
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
if (mpr->custom_modal) {
|
|
|
|
|
mpr->custom_modal(C, mpr, event, 0);
|
2017-06-08 05:27:14 +10:00
|
|
|
}
|
2017-06-10 10:42:35 +10:00
|
|
|
else if (mpr->type->modal) {
|
|
|
|
|
mpr->type->modal(C, mpr, event, 0);
|
2017-06-08 05:27:14 +10:00
|
|
|
}
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* operator not running anymore */
|
|
|
|
|
else {
|
2017-06-10 10:42:35 +10:00
|
|
|
wm_manipulatormap_highlight_set(mmap, C, NULL, 0);
|
|
|
|
|
wm_manipulatormap_active_set(mmap, C, event, NULL);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
if (*sel == NULL || mmap->mmap_context.selected_len == 0)
|
2016-10-07 16:34:55 +02:00
|
|
|
return false;
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
for (int i = 0; i < mmap->mmap_context.selected_len; i++) {
|
2017-06-08 07:16:47 +10:00
|
|
|
(*sel)[i]->state &= ~WM_MANIPULATOR_STATE_SELECT;
|
2016-10-07 16:34:55 +02:00
|
|
|
(*sel)[i] = NULL;
|
|
|
|
|
}
|
2017-06-10 10:42:35 +10:00
|
|
|
wm_manipulatormap_selected_clear(mmap);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
/* always return true, we already checked
|
|
|
|
|
* if there's anything to deselect */
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
BLI_INLINE bool manipulator_selectable_poll(const wmManipulator *mpr, void *UNUSED(data))
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
return (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECT);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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;
|
2017-06-10 10:42:35 +10:00
|
|
|
int i, *selected_len = &mmap->mmap_context.selected_len;
|
2016-10-07 16:34:55 +02:00
|
|
|
bool changed = false;
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
*selected_len = BLI_ghash_size(hash);
|
|
|
|
|
*sel = MEM_reallocN(*sel, sizeof(**sel) * (*selected_len));
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
GHASH_ITER_INDEX (gh_iter, hash, i) {
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulator *mpr_iter = BLI_ghashIterator_getValue(&gh_iter);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
if ((mpr_iter->state & WM_MANIPULATOR_STATE_SELECT) == 0) {
|
2016-10-07 16:34:55 +02:00
|
|
|
changed = true;
|
|
|
|
|
}
|
2017-06-10 10:42:35 +10:00
|
|
|
mpr_iter->state |= WM_MANIPULATOR_STATE_SELECT;
|
|
|
|
|
if (mpr_iter->type->select) {
|
|
|
|
|
mpr_iter->type->select(C, mpr_iter, action);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
2017-06-10 10:42:35 +10:00
|
|
|
(*sel)[i] = mpr_iter;
|
|
|
|
|
BLI_assert(i < (*selected_len));
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
/* highlight first manipulator */
|
2017-06-10 10:42:35 +10:00
|
|
|
wm_manipulatormap_highlight_set(mmap, C, (*sel)[0], (*sel)[0]->highlight_part);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulator ***sel = &mmap->mmap_context.selected;
|
2016-10-07 16:34:55 +02:00
|
|
|
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) {
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulator *mpr = mmap->mmap_context.highlight;
|
|
|
|
|
if (mpr && mpr->type->cursor_get) {
|
|
|
|
|
WM_cursor_set(win, mpr->type->cursor_get(mpr));
|
2016-10-07 16:34:55 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
void wm_manipulatormap_highlight_set(
|
|
|
|
|
wmManipulatorMap *mmap, const bContext *C, wmManipulator *mpr, int part)
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
if ((mpr != mmap->mmap_context.highlight) ||
|
|
|
|
|
(mpr && part != mpr->highlight_part))
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
if (mmap->mmap_context.highlight) {
|
|
|
|
|
mmap->mmap_context.highlight->state &= ~WM_MANIPULATOR_STATE_HIGHLIGHT;
|
|
|
|
|
mmap->mmap_context.highlight->highlight_part = 0;
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
mmap->mmap_context.highlight = mpr;
|
2016-10-07 16:34:55 +02:00
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
if (mpr) {
|
|
|
|
|
mpr->state |= WM_MANIPULATOR_STATE_HIGHLIGHT;
|
|
|
|
|
mpr->highlight_part = part;
|
2016-10-07 16:34:55 +02:00
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
if (C && mpr->type->cursor_get) {
|
2016-10-07 16:34:55 +02:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2017-06-10 10:42:35 +10:00
|
|
|
WM_cursor_set(win, mpr->type->cursor_get(mpr));
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulator *wm_manipulatormap_highlight_get(wmManipulatorMap *mmap)
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
return mmap->mmap_context.highlight;
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
void wm_manipulatormap_active_set(
|
|
|
|
|
wmManipulatorMap *mmap, bContext *C, const wmEvent *event, wmManipulator *mpr)
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
if (mpr && C) {
|
|
|
|
|
mpr->state |= WM_MANIPULATOR_STATE_ACTIVE;
|
|
|
|
|
mmap->mmap_context.active = mpr;
|
2016-10-07 16:34:55 +02:00
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
if (mpr->opname) {
|
|
|
|
|
wmOperatorType *ot = WM_operatortype_find(mpr->opname, 0);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
if (ot) {
|
|
|
|
|
/* first activate the manipulator itself */
|
2017-06-10 10:42:35 +10:00
|
|
|
if (mpr->type->invoke &&
|
|
|
|
|
(mpr->type->modal || mpr->custom_modal))
|
2017-06-08 05:27:14 +10:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
mpr->type->invoke(C, mpr, event);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &mpr->opptr);
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
/* we failed to hook the manipulator to the operator handler or operator was cancelled, return */
|
2017-06-10 10:42:35 +10:00
|
|
|
if (!mmap->mmap_context.active) {
|
|
|
|
|
mpr->state &= ~WM_MANIPULATOR_STATE_ACTIVE;
|
2016-10-07 16:34:55 +02:00
|
|
|
/* first activate the manipulator itself */
|
2017-06-10 10:42:35 +10:00
|
|
|
MEM_SAFE_FREE(mpr->interaction_data);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
printf("Manipulator error: operator not found");
|
2017-06-10 10:42:35 +10:00
|
|
|
mmap->mmap_context.active = NULL;
|
2016-10-07 16:34:55 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2017-06-10 10:42:35 +10:00
|
|
|
if (mpr->type->invoke &&
|
|
|
|
|
(mpr->type->modal || mpr->custom_modal))
|
2017-06-08 05:27:14 +10:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
mpr->type->invoke(C, mpr, event);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2017-06-10 10:42:35 +10:00
|
|
|
mpr = mmap->mmap_context.active;
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
/* deactivate, manipulator but first take care of some stuff */
|
2017-06-10 10:42:35 +10:00
|
|
|
if (mpr) {
|
|
|
|
|
mpr->state &= ~WM_MANIPULATOR_STATE_ACTIVE;
|
2016-10-07 16:34:55 +02:00
|
|
|
/* first activate the manipulator itself */
|
2017-06-10 10:42:35 +10:00
|
|
|
MEM_SAFE_FREE(mpr->interaction_data);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
2017-06-10 10:42:35 +10:00
|
|
|
mmap->mmap_context.active = NULL;
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
if (C) {
|
|
|
|
|
WM_cursor_grab_disable(CTX_wm_window(C), NULL);
|
|
|
|
|
ED_region_tag_redraw(CTX_wm_region(C));
|
|
|
|
|
WM_event_add_mousemove(C);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulator *wm_manipulatormap_active_get(wmManipulatorMap *mmap)
|
2016-10-07 16:34:55 +02:00
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
return mmap->mmap_context.active;
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */ /* 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)
|
|
|
|
|
{
|
2017-06-10 10:42:35 +10:00
|
|
|
for (wmManipulatorMapType *mmaptype = manipulatormaptypes.first, *mmaptype_next;
|
|
|
|
|
mmaptype;
|
|
|
|
|
mmaptype = mmaptype_next)
|
|
|
|
|
{
|
|
|
|
|
mmaptype_next = mmaptype->next;
|
|
|
|
|
for (wmManipulatorGroupType *wgt = mmaptype->manipulator_grouptypes.first, *wgt_next;
|
|
|
|
|
wgt;
|
|
|
|
|
wgt = wgt_next)
|
|
|
|
|
{
|
|
|
|
|
wgt_next = wgt->next;
|
|
|
|
|
WM_manipulatorgrouptype_free(wgt);
|
|
|
|
|
}
|
|
|
|
|
MEM_freeN(mmaptype);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialize keymaps for all existing manipulator-groups
|
|
|
|
|
*/
|
|
|
|
|
void wm_manipulators_keymap(wmKeyConfig *keyconf)
|
|
|
|
|
{
|
|
|
|
|
wmManipulatorMapType *mmaptype;
|
2017-06-10 10:42:35 +10:00
|
|
|
wmManipulatorGroupType *wgt;
|
2016-10-07 16:34:55 +02:00
|
|
|
|
|
|
|
|
/* 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) {
|
2017-06-10 10:42:35 +10:00
|
|
|
for (wgt = mmaptype->manipulator_grouptypes.first; wgt; wgt = wgt->next) {
|
|
|
|
|
wm_manipulatorgrouptype_setup_keymap(wgt, keyconf);
|
2016-10-07 16:34:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */ /* wmManipulatorMapType */
|
|
|
|
|
|