Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Wed, 14 Jun 2017 07:17:00 +0000 (17:17 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 14 Jun 2017 07:17:00 +0000 (17:17 +1000)
1  2 
source/blender/editors/space_view3d/view3d_view.c
source/blender/gpu/intern/gpu_select.c
source/blender/gpu/intern/gpu_select_sample_query.c
source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c

index 11b011dbc733d38c532e2a8788b731933394c203,5c13fd37dda299e40f0ed1804875bcb5d7b93474..854f71b17b3584df99130df25261cffac77d4187
@@@ -1198,19 -1191,10 +1198,19 @@@ int view3d_opengl_select
        hits = GPU_select_end();
        
        /* second pass, to get the closest object to camera */
-       if (do_passes) {
+       if (do_passes && (hits > 0)) {
                GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
  
 -              ED_view3d_draw_select_loop(vc, scene, v3d, ar, use_obedit_skip, use_nearest);
 +#ifdef WITH_OPENGL_LEGACY
 +              if (IS_VIEWPORT_LEGACY(vc->v3d)) {
 +                      ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest);
 +              }
 +              else
 +#else
 +              {
 +                      DRW_draw_select_loop(graph, ar, v3d, use_obedit_skip, use_nearest, &rect);
 +              }
 +#endif /* WITH_OPENGL_LEGACY */
  
                GPU_select_end();
        }
index 6732a4cfee978df22c2cb6f60e030c3b7320dd7f,0000000000000000000000000000000000000000..51466426d79a1078726d76343dbe9501b883e652
mode 100644,000000..100644
--- /dev/null
@@@ -1,769 -1,0 +1,770 @@@
-       GLuint buffer[64];      // max 4 items per select, so large enuf
 +/*
 + * ***** 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 "DNA_manipulator_types.h"
 +
 +#include "ED_screen.h"
 +#include "ED_view3d.h"
 +
 +#include "GPU_glew.h"
 +#include "GPU_matrix.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 *wgt = mmaptype->manipulator_grouptypes.first; wgt; wgt = wgt->next) {
 +              wm_manipulatorgroup_new_from_type(mmap, wgt);
 +      }
 +
 +      return mmap;
 +}
 +
 +void wm_manipulatormap_selected_clear(wmManipulatorMap *mmap)
 +{
 +      MEM_SAFE_FREE(mmap->mmap_context.selected);
 +      mmap->mmap_context.selected_len = 0;
 +}
 +
 +void wm_manipulatormap_remove(wmManipulatorMap *mmap)
 +{
 +      if (!mmap)
 +              return;
 +
 +      for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first, *mgroup_next; mgroup; mgroup = mgroup_next) {
 +              mgroup_next = mgroup->next;
 +              BLI_assert(mgroup->parent_mmap == mmap);
 +              wm_manipulatorgroup_free(NULL, mgroup);
 +      }
 +      BLI_assert(BLI_listbase_is_empty(&mmap->manipulator_groups));
 +
 +      wm_manipulatormap_selected_clear(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 *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
 +                              if ((include_hidden || (mpr->flag & WM_MANIPULATOR_HIDDEN) == 0) &&
 +                                  (!poll || poll(mpr, data)))
 +                              {
 +                                      BLI_ghash_insert(hash, mpr->name, mpr);
 +                              }
 +                      }
 +              }
 +      }
 +
 +      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 *mpr,
 +        const bContext *C, ListBase *draw_manipulators)
 +{
 +      if (!wm_manipulator_is_visible(mpr)) {
 +              /* skip */
 +      }
 +      else {
 +              wm_manipulator_update(mpr, C, (mmap->update_flag & MANIPULATORMAP_REFRESH) != 0);
 +              BLI_addhead(draw_manipulators, BLI_genericNodeN(mpr));
 +              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;
 +
 +      /* 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 *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
 +                      manipulator_prepare_drawing(mmap, mpr, 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));
 +
 +      const bool draw_multisample = (U.ogl_multisamples != USER_MULTISAMPLE_NONE);
 +
 +      /* 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; */
 +
 +      /* enable multisampling */
 +      if (draw_multisample) {
 +              glEnable(GL_MULTISAMPLE);
 +      }
 +
 +      /* draw_manipulators contains all visible manipulators - draw them */
 +      for (LinkData *link = draw_manipulators->first, *link_next; link; link = link_next) {
 +              wmManipulator *mpr = link->data;
 +              link_next = link->next;
 +
 +              mpr->type->draw(C, mpr);
 +              /* free/remove manipulator link after drawing */
 +              BLI_freelinkN(draw_manipulators, link);
 +      }
 +
 +      if (draw_multisample) {
 +              glDisable(GL_MULTISAMPLE);
 +      }
 +}
 +
 +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 *mpr;
 +
 +      for (LinkData *link = visible_manipulators->first; link; link = link->next) {
 +              mpr = link->data;
 +              /* pass the selection id shifted by 8 bits. Last 8 bits are used for selected manipulator part id */
 +              mpr->type->draw_select(C, mpr, 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;
 +      rcti rect;
-       if (do_passes) {
++      /* Almost certainly overkill, but allow for many custom manipulators. */
++      GLuint buffer[MAXPICKBUF];
 +      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;
 +
 +      ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_scene(C), ar, v3d, NULL, NULL, &rect);
 +
 +      if (do_passes)
 +              GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
 +      else
 +              GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_ALL, 0);
 +      /* do the drawing */
 +      manipulator_find_active_3D_loop(C, visible_manipulators);
 +
 +      hits = GPU_select_end();
 +
++      if (do_passes && (hits > 0)) {
 +              GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
 +              manipulator_find_active_3D_loop(C, visible_manipulators);
 +              GPU_select_end();
 +      }
 +
 +      ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_scene(C), ar, v3d, NULL, NULL, NULL);
 +
 +      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,
 +        int *r_part)
 +{
 +      wmManipulator *result = NULL;
 +      const float hotspot = 14.0f;
 +      int ret;
 +
 +      *r_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);
 +              *r_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_highlight_find(
 +        wmManipulatorMap *mmap, bContext *C, const wmEvent *event,
 +        int *r_part)
 +{
 +      wmManipulator *mpr = 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_3D) {
 +                              wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators);
 +                      }
 +                      else if ((mpr = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, r_part))) {
 +                              break;
 +                      }
 +              }
 +      }
 +
 +      if (!BLI_listbase_is_empty(&visible_3d_manipulators)) {
 +              mpr = manipulator_find_intersected_3d(C, event->mval, &visible_3d_manipulators, r_part);
 +              BLI_freelistN(&visible_3d_manipulators);
 +      }
 +
 +      return mpr;
 +}
 +
 +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 bool modal_running = (handler->op != NULL);
 +
 +      /* happens on render or when joining areas */
 +      if (!handler->op_region || !handler->op_region->manipulator_map) {
 +              return;
 +      }
 +
 +      wmManipulatorMap *mmap = handler->op_region->manipulator_map;
 +      wmManipulator *mpr = wm_manipulatormap_active_get(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 (mpr && mpr->opname &&
 +                  STREQ(mpr->opname, handler->op->idname))
 +              {
 +                      if (mpr->custom_modal) {
 +                              mpr->custom_modal(C, mpr, event, 0);
 +                      }
 +                      else if (mpr->type->modal) {
 +                              mpr->type->modal(C, mpr, event, 0);
 +                      }
 +              }
 +      }
 +      /* operator not running anymore */
 +      else {
 +              wm_manipulatormap_highlight_set(mmap, C, NULL, 0);
 +              wm_manipulatormap_active_set(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.selected_len == 0)
 +              return false;
 +
 +      for (int i = 0; i < mmap->mmap_context.selected_len; i++) {
 +              (*sel)[i]->state &= ~WM_MANIPULATOR_STATE_SELECT;
 +              (*sel)[i] = NULL;
 +      }
 +      wm_manipulatormap_selected_clear(mmap);
 +
 +      /* always return true, we already checked
 +       * if there's anything to deselect */
 +      return true;
 +}
 +
 +BLI_INLINE bool manipulator_selectable_poll(const wmManipulator *mpr, void *UNUSED(data))
 +{
 +      return (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECT);
 +}
 +
 +/**
 + * 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, *selected_len = &mmap->mmap_context.selected_len;
 +      bool changed = false;
 +
 +      *selected_len = BLI_ghash_size(hash);
 +      *sel = MEM_reallocN(*sel, sizeof(**sel) * (*selected_len));
 +
 +      GHASH_ITER_INDEX (gh_iter, hash, i) {
 +              wmManipulator *mpr_iter = BLI_ghashIterator_getValue(&gh_iter);
 +
 +              if ((mpr_iter->state & WM_MANIPULATOR_STATE_SELECT) == 0) {
 +                      changed = true;
 +              }
 +              mpr_iter->state |= WM_MANIPULATOR_STATE_SELECT;
 +              if (mpr_iter->type->select) {
 +                      mpr_iter->type->select(C, mpr_iter, action);
 +              }
 +              (*sel)[i] = mpr_iter;
 +              BLI_assert(i < (*selected_len));
 +      }
 +      /* highlight first manipulator */
 +      wm_manipulatormap_highlight_set(mmap, C, (*sel)[0], (*sel)[0]->highlight_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;
 +      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 *mpr = mmap->mmap_context.highlight;
 +              if (mpr && mpr->type->cursor_get) {
 +                      WM_cursor_set(win, mpr->type->cursor_get(mpr));
 +                      return true;
 +              }
 +      }
 +
 +      return false;
 +}
 +
 +void wm_manipulatormap_highlight_set(
 +        wmManipulatorMap *mmap, const bContext *C, wmManipulator *mpr, int part)
 +{
 +      if ((mpr != mmap->mmap_context.highlight) ||
 +          (mpr && part != mpr->highlight_part))
 +      {
 +              if (mmap->mmap_context.highlight) {
 +                      mmap->mmap_context.highlight->state &= ~WM_MANIPULATOR_STATE_HIGHLIGHT;
 +                      mmap->mmap_context.highlight->highlight_part = 0;
 +              }
 +
 +              mmap->mmap_context.highlight = mpr;
 +
 +              if (mpr) {
 +                      mpr->state |= WM_MANIPULATOR_STATE_HIGHLIGHT;
 +                      mpr->highlight_part = part;
 +
 +                      if (C && mpr->type->cursor_get) {
 +                              wmWindow *win = CTX_wm_window(C);
 +                              WM_cursor_set(win, mpr->type->cursor_get(mpr));
 +                      }
 +              }
 +              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_highlight_get(wmManipulatorMap *mmap)
 +{
 +      return mmap->mmap_context.highlight;
 +}
 +
 +void wm_manipulatormap_active_set(
 +        wmManipulatorMap *mmap, bContext *C, const wmEvent *event, wmManipulator *mpr)
 +{
 +      if (mpr && C) {
 +              mpr->state |= WM_MANIPULATOR_STATE_ACTIVE;
 +              mmap->mmap_context.active = mpr;
 +
 +              if (mpr->opname) {
 +                      wmOperatorType *ot = WM_operatortype_find(mpr->opname, 0);
 +
 +                      if (ot) {
 +                              /* first activate the manipulator itself */
 +                              if (mpr->type->invoke &&
 +                                  (mpr->type->modal || mpr->custom_modal))
 +                              {
 +                                      mpr->type->invoke(C, mpr, event);
 +                              }
 +
 +                              WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &mpr->opptr);
 +
 +                              /* we failed to hook the manipulator to the operator handler or operator was cancelled, return */
 +                              if (!mmap->mmap_context.active) {
 +                                      mpr->state &= ~WM_MANIPULATOR_STATE_ACTIVE;
 +                                      /* first activate the manipulator itself */
 +                                      MEM_SAFE_FREE(mpr->interaction_data);
 +                              }
 +                              return;
 +                      }
 +                      else {
 +                              printf("Manipulator error: operator not found");
 +                              mmap->mmap_context.active = NULL;
 +                              return;
 +                      }
 +              }
 +              else {
 +                      if (mpr->type->invoke &&
 +                          (mpr->type->modal || mpr->custom_modal))
 +                      {
 +                              mpr->type->invoke(C, mpr, event);
 +                      }
 +              }
 +              WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL);
 +      }
 +      else {
 +              mpr = mmap->mmap_context.active;
 +
 +              /* deactivate, manipulator but first take care of some stuff */
 +              if (mpr) {
 +                      mpr->state &= ~WM_MANIPULATOR_STATE_ACTIVE;
 +                      /* first activate the manipulator itself */
 +                      MEM_SAFE_FREE(mpr->interaction_data);
 +              }
 +              mmap->mmap_context.active = 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_active_get(wmManipulatorMap *mmap)
 +{
 +      return mmap->mmap_context.active;
 +}
 +
 +/** \} */ /* 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_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);
 +      }
 +}
 +
 +/**
 + * Initialize keymaps for all existing manipulator-groups
 + */
 +void wm_manipulators_keymap(wmKeyConfig *keyconf)
 +{
 +      wmManipulatorMapType *mmaptype;
 +      wmManipulatorGroupType *wgt;
 +
 +      /* 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 (wgt = mmaptype->manipulator_grouptypes.first; wgt; wgt = wgt->next) {
 +                      wm_manipulatorgrouptype_setup_keymap(wgt, keyconf);
 +              }
 +      }
 +}
 +
 +/** \} */ /* wmManipulatorMapType */
 +