Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r--source/blender/windowmanager/CMakeLists.txt12
-rw-r--r--source/blender/windowmanager/WM_api.h10
-rw-r--r--source/blender/windowmanager/WM_types.h4
-rw-r--r--source/blender/windowmanager/intern/wm.c6
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c25
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c283
-rw-r--r--source/blender/windowmanager/intern/wm_files.c147
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c9
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c21
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c8
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c102
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c15
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c14
-rw-r--r--source/blender/windowmanager/intern/wm_window.c41
-rw-r--r--source/blender/windowmanager/manipulators/WM_manipulator_api.h89
-rw-r--r--source/blender/windowmanager/manipulators/WM_manipulator_types.h219
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator.c279
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c151
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_group_type.c19
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h40
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c480
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c35
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_type.c53
-rw-r--r--source/blender/windowmanager/manipulators/wm_manipulator_fn.h8
-rw-r--r--source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h13
-rw-r--r--source/blender/windowmanager/wm_event_system.h5
-rw-r--r--source/blender/windowmanager/wm_files.h2
27 files changed, 1373 insertions, 717 deletions
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index cfa97a9e177..8a6d4bc95c7 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -97,7 +97,7 @@ set(SRC
)
if(WITH_AUDASPACE)
- add_definitions(${AUDASPACE_DEFINITIONS})
+ add_definitions(-DWITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
@@ -114,16 +114,6 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
-if(WITH_CODEC_QUICKTIME)
- list(APPEND INC
- ../quicktime
- )
- list(APPEND INC_SYS
- ${QUICKTIME_INCLUDE_DIRS}
- )
- add_definitions(-DWITH_QUICKTIME)
-endif()
-
if(WITH_CODEC_FFMPEG)
list(APPEND INC_SYS
${FFMPEG_INCLUDE_DIRS}
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 3501105d404..762a6f8e8d2 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -42,9 +42,6 @@
#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
@@ -68,6 +65,7 @@ struct ImBuf;
struct ImageFormatData;
struct ARegion;
struct ScrArea;
+struct Main;
#ifdef WITH_INPUT_NDOF
struct wmNDOFMotionData;
@@ -125,6 +123,7 @@ enum {
struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
struct wmWindow *WM_window_open_temp(struct bContext *C, int x, int y, int sizex, int sizey, int type);
+void WM_window_set_dpi(wmWindow *win);
/* returns true if draw method is triple buffer */
bool WM_is_draw_triple(struct wmWindow *win);
@@ -164,6 +163,7 @@ float WM_cursor_pressure (const struct wmWindow *win);
/* event map */
int WM_userdef_event_map(int kmitype);
+int WM_userdef_event_type_from_keymap_type(int kmitype);
/* handlers */
@@ -211,8 +211,9 @@ struct wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase
/* mouse */
void WM_event_add_mousemove(struct bContext *C);
-bool WM_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
+bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
bool WM_event_is_absolute(const struct wmEvent *event);
+bool WM_event_is_last_mousemove(const struct wmEvent *event);
#ifdef WITH_INPUT_NDOF
/* 3D mouse */
@@ -378,6 +379,7 @@ bool WM_operator_pystring_abbreviate(char *str, int str_len_max);
char *WM_prop_pystring_assign(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
void WM_operator_bl_idname(char *to, const char *from);
void WM_operator_py_idname(char *to, const char *from);
+bool WM_operator_py_idname_ok_or_report(struct ReportList *reports, const char *classname, const char *idname);
/* *************** uilist types ******************** */
void WM_uilisttype_init(void);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index ad8df014902..9df9afcb064 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -121,6 +121,9 @@ struct ImBuf;
#include "wm_event_types.h"
#include "manipulators/WM_manipulator_types.h"
+/* Include external manipulator API's */
+#include "manipulators/WM_manipulator_api.h"
+
/* ************** wmOperatorType ************************ */
/* flag */
@@ -425,6 +428,7 @@ typedef struct wmGesture {
/* free pointer to use for operator allocs (if set, its freed on exit)*/
void *userdata;
+ bool userdata_free;
} wmGesture;
/* ************** wmEvent ************************ */
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index da1b5feea3d..e953f0c1712 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -430,7 +430,7 @@ void wm_clear_default_size(bContext *C)
/* on startup, it adds all data, for matching */
void wm_add_default(bContext *C)
{
- wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan");
+ wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan", 0);
wmWindow *win;
bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */
struct WorkSpace *workspace = G.main->workspaces.last;
@@ -497,6 +497,10 @@ void wm_close_and_free_all(bContext *C, ListBase *wmlist)
void WM_main(bContext *C)
{
+ /* Single refresh before handling events.
+ * This ensures we don't run operators before the depsgraph has been evaluated. */
+ wm_event_do_refresh_wm_and_depsgraph(C);
+
while (1) {
/* get events from ghost, handle window events, add to window queues */
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 7cff598e6ad..b4db8a8b3ac 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -58,6 +58,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_immediate.h"
+#include "GPU_viewport.h"
#include "RE_engine.h"
@@ -136,6 +137,7 @@ static void wm_region_test_render_do_draw(const Scene *scene, ScrArea *sa, ARegi
if (sa->spacetype == SPACE_VIEW3D) {
RegionView3D *rv3d = ar->regiondata;
RenderEngine *engine = (rv3d) ? rv3d->render_engine : NULL;
+ GPUViewport *viewport = (rv3d) ? rv3d->viewport : NULL;
if (engine && (engine->flag & RE_ENGINE_DO_DRAW)) {
View3D *v3d = sa->spacedata.first;
@@ -149,6 +151,9 @@ static void wm_region_test_render_do_draw(const Scene *scene, ScrArea *sa, ARegi
engine->flag &= ~RE_ENGINE_DO_DRAW;
}
+ else if (viewport && GPU_viewport_do_update(viewport)) {
+ ED_region_tag_redraw(ar);
+ }
}
}
@@ -869,25 +874,13 @@ static bool wm_draw_update_test_window(wmWindow *win)
static int wm_automatic_draw_method(wmWindow *win)
{
- /* Ideally all cards would work well with triple buffer, since if it works
- * well gives the least redraws and is considerably faster at partial redraw
- * for sculpting or drawing overlapping menus. For typically lower end cards
- * copy to texture is slow though and so we use overlap instead there. */
-
+ /* We assume all supported GPUs now support triple buffer well. */
if (win->drawmethod == USER_DRAW_AUTOMATIC) {
- /* Windows software driver darkens color on each redraw */
- if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE))
- return USER_DRAW_OVERLAP_FLIP;
- else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_UNIX, GPU_DRIVER_SOFTWARE))
- return USER_DRAW_OVERLAP;
- /* drawing lower color depth again degrades colors each time */
- else if (GPU_color_depth() < 24)
- return USER_DRAW_OVERLAP;
- else
- return USER_DRAW_TRIPLE;
+ return USER_DRAW_TRIPLE;
}
- else
+ else {
return win->drawmethod;
+ }
}
bool WM_is_draw_triple(wmWindow *win)
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 06bf6ff2482..f3864f7ed97 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -264,13 +264,61 @@ static void wm_notifier_clear(wmNotifier *note)
memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
}
+/**
+ * Was part of #wm_event_do_notifiers, split out so it can be called once before entering the #WM_main loop.
+ * This ensures operators don't run before the UI and depsgraph are initialized.
+ */
+void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ uint64_t win_combine_v3d_datamask = 0;
+
+ /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ const Scene *scene = WM_window_get_active_scene(win);
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ win_combine_v3d_datamask |= ED_view3d_screen_datamask(scene, screen);
+ }
+
+ /* cached: editor refresh callbacks now, they get context */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+ Scene *scene = WM_window_get_active_scene(win);
+ ScrArea *sa;
+
+ CTX_wm_window_set(C, win);
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->do_refresh) {
+ CTX_wm_area_set(C, sa);
+ ED_area_do_refresh(C, sa);
+ }
+ }
+
+ /* XXX make lock in future, or separated derivedmesh users in scene */
+ if (G.is_rendering == false) {
+ /* depsgraph & animation: update tagged datablocks */
+ Main *bmain = CTX_data_main(C);
+
+ /* copied to set's in scene_update_tagged_recursive() */
+ scene->customdata_mask = win_combine_v3d_datamask;
+
+ /* XXX, hack so operators can enforce datamasks [#26482], gl render */
+ scene->customdata_mask |= scene->customdata_mask_modal;
+
+ BKE_scene_update_tagged(bmain->eval_ctx, bmain, scene);
+ }
+ }
+
+ CTX_wm_window_set(C, NULL);
+}
+
/* called in mainloop */
void wm_event_do_notifiers(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmNotifier *note, *next;
wmWindow *win;
- uint64_t win_combine_v3d_datamask = 0;
if (wm == NULL)
return;
@@ -335,7 +383,7 @@ void wm_event_do_notifiers(bContext *C)
}
}
if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) {
- SceneLayer *sl = BKE_scene_layer_context_active(scene);
+ SceneLayer *sl = CTX_data_scene_layer(C);
ED_info_stats_clear(sl);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
}
@@ -397,44 +445,7 @@ void wm_event_do_notifiers(bContext *C)
MEM_freeN(note);
}
- /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
- for (win = wm->windows.first; win; win = win->next) {
- const Scene *scene = WM_window_get_active_scene(win);
- const bScreen *screen = WM_window_get_active_screen(win);
-
- win_combine_v3d_datamask |= ED_view3d_screen_datamask(scene, screen);
- }
-
- /* cached: editor refresh callbacks now, they get context */
- for (win = wm->windows.first; win; win = win->next) {
- const bScreen *screen = WM_window_get_active_screen(win);
- Scene *scene = WM_window_get_active_scene(win);
- ScrArea *sa;
-
- CTX_wm_window_set(C, win);
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->do_refresh) {
- CTX_wm_area_set(C, sa);
- ED_area_do_refresh(C, sa);
- }
- }
-
- /* XXX make lock in future, or separated derivedmesh users in scene */
- if (G.is_rendering == false) {
- /* depsgraph & animation: update tagged datablocks */
- Main *bmain = CTX_data_main(C);
-
- /* copied to set's in scene_update_tagged_recursive() */
- scene->customdata_mask = win_combine_v3d_datamask;
-
- /* XXX, hack so operators can enforce datamasks [#26482], gl render */
- scene->customdata_mask |= scene->customdata_mask_modal;
-
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, scene);
- }
- }
-
- CTX_wm_window_set(C, NULL);
+ wm_event_do_refresh_wm_and_depsgraph(C);
}
static int wm_event_always_pass(const wmEvent *event)
@@ -644,6 +655,16 @@ bool WM_event_is_absolute(const wmEvent *event)
return (event->tablet_data != NULL);
}
+bool WM_event_is_last_mousemove(const wmEvent *event)
+{
+ while ((event = event->next)) {
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ return false;
+ }
+ }
+ return true;
+}
+
#ifdef WITH_INPUT_NDOF
void WM_ndof_deadzone_set(float deadzone)
{
@@ -1108,6 +1129,9 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
#endif
+/**
+ * Also used for exec when 'event' is NULL.
+ */
static int wm_operator_invoke(
bContext *C, wmOperatorType *ot, wmEvent *event,
PointerRNA *properties, ReportList *reports, const bool poll_only)
@@ -1123,7 +1147,9 @@ static int wm_operator_invoke(
wmOperator *op = wm_operator_create(wm, ot, properties, reports); /* if reports == NULL, they'll be initialized */
const bool is_nested_call = (wm->op_undo_depth != 0);
- op->flag |= OP_IS_INVOKE;
+ if (event != NULL) {
+ op->flag |= OP_IS_INVOKE;
+ }
/* initialize setting from previous run */
if (!is_nested_call) { /* not called by py script */
@@ -1574,6 +1600,36 @@ int WM_userdef_event_map(int kmitype)
return kmitype;
}
+/**
+ * Use so we can check if 'wmEvent.type' is released in modal operators.
+ *
+ * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
+ */
+int WM_userdef_event_type_from_keymap_type(int kmitype)
+{
+ switch (kmitype) {
+ case SELECTMOUSE:
+ return (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE;
+ case ACTIONMOUSE:
+ return (U.flag & USER_LMOUSESELECT) ? RIGHTMOUSE : LEFTMOUSE;
+ case EVT_TWEAK_S:
+ return (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE;
+ case EVT_TWEAK_A:
+ return (U.flag & USER_LMOUSESELECT) ? RIGHTMOUSE : LEFTMOUSE;
+ case EVT_TWEAK_L:
+ return LEFTMOUSE;
+ case EVT_TWEAK_M:
+ return MIDDLEMOUSE;
+ case EVT_TWEAK_R:
+ return RIGHTMOUSE;
+ case WHEELOUTMOUSE:
+ return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
+ case WHEELINMOUSE:
+ return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
+ }
+
+ return kmitype;
+}
static int wm_eventmatch(const wmEvent *winevent, wmKeyMapItem *kmi)
{
@@ -2152,54 +2208,120 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
wmManipulatorMap *mmap = handler->manipulator_map;
wmManipulator *mpr = wm_manipulatormap_highlight_get(mmap);
+ if (region->manipulator_map != handler->manipulator_map) {
+ WM_manipulatormap_tag_refresh(handler->manipulator_map);
+ }
+
wm_manipulatormap_handler_context(C, handler);
wm_region_mouse_co(C, event);
/* handle manipulator highlighting */
- if (event->type == MOUSEMOVE && !wm_manipulatormap_active_get(mmap)) {
+ if (event->type == MOUSEMOVE && !wm_manipulatormap_modal_get(mmap)) {
int part;
mpr = wm_manipulatormap_highlight_find(mmap, C, event, &part);
wm_manipulatormap_highlight_set(mmap, C, mpr, part);
}
/* handle user configurable manipulator-map keymap */
- else if (mpr) {
- /* get user customized keymap from default one */
- const wmManipulatorGroup *highlightgroup = mpr->parent_mgroup;
- 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 {
+ /* Either we operate on a single highlighted item
+ * or groups attached to the selected manipulators.
+ * To simplify things both cases loop over an array of items. */
+ wmManipulatorGroup *mgroup_first;
+ bool is_mgroup_single;
+
+ if (ISMOUSE(event->type)) {
+ /* Keep mpr set as-is, just fake single selection. */
+ if (mpr) {
+ mgroup_first = mpr->parent_mgroup;
+ }
+ else {
+ mgroup_first = NULL;
+ }
+ is_mgroup_single = true;
+ }
+ else {
+ if (WM_manipulatormap_is_any_selected(mmap)) {
+ const ListBase *groups = WM_manipulatormap_group_list(mmap);
+ mgroup_first = groups->first;
+ }
+ else {
+ mgroup_first = NULL;
+ }
+ is_mgroup_single = false;
+ }
+
+ /* Don't use from now on. */
+ mpr = NULL;
+
+ for (wmManipulatorGroup *mgroup = mgroup_first; mgroup; mgroup = mgroup->next) {
+ /* get user customized keymap from default one */
+
+ if ((is_mgroup_single == false) &&
+ /* We might want to change the logic here and use some kind of manipulator edit-mode.
+ * For now just use keymap when a selection exists. */
+ wm_manipulatorgroup_is_any_selected(mgroup) == false)
+ {
+ continue;
+ }
+
+ const wmKeyMap *keymap = WM_keymap_active(wm, mgroup->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;
+
+ CTX_wm_manipulator_group_set(C, mgroup);
+
+ /* 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;
+
+ CTX_wm_manipulator_group_set(C, NULL);
+
+ if (action & WM_HANDLER_BREAK) {
+ if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
+ printf("%s: handled - and pass on! '%s'\n",
+ __func__, kmi->idname);
+ }
+ break;
}
else {
- PRINT("%s: un-handled '%s'\n", __func__, kmi->idname);
+ 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");
+ else {
+ PRINT("fail\n");
+ }
+
+ if (action & WM_HANDLER_BREAK) {
+ break;
+ }
+
+ if (is_mgroup_single) {
+ break;
+ }
}
}
@@ -2701,7 +2823,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
wmWindow *win = CTX_wm_window(C);
/* only allow 1 file selector open per window */
- for (handler = win->handlers.first; handler; handler = handlernext) {
+ for (handler = win->modalhandlers.first; handler; handler = handlernext) {
handlernext = handler->next;
if (handler->type == WM_HANDLER_FILESELECT) {
@@ -2715,7 +2837,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
if (sfile->op == handler->op) {
CTX_wm_area_set(C, sa);
- wm_handler_fileselect_do(C, &win->handlers, handler, EVT_FILESELECT_CANCEL);
+ wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
break;
}
}
@@ -2723,7 +2845,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
/* if not found we stop the handler without changing the screen */
if (!sa)
- wm_handler_fileselect_do(C, &win->handlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
+ wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
}
}
@@ -2734,7 +2856,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
handler->op_area = CTX_wm_area(C);
handler->op_region = CTX_wm_region(C);
- BLI_addhead(&win->handlers, handler);
+ BLI_addhead(&win->modalhandlers, handler);
/* check props once before invoking if check is available
* ensures initial properties are valid */
@@ -2784,7 +2906,8 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
{
for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) {
- if (handler->op_area == old_area) {
+ /* fileselect handler is quite special... it needs to keep old area stored in handler, so don't change it */
+ if ((handler->op_area == old_area) && (handler->type != WM_HANDLER_FILESELECT)) {
handler->op_area = new_area;
}
}
@@ -2986,7 +3109,7 @@ void WM_event_add_mousemove(bContext *C)
/* for modal callbacks, check configuration for how to interpret exit with tweaks */
-bool WM_modal_tweak_exit(const wmEvent *event, int tweak_event)
+bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
{
/* if the release-confirm userpref setting is enabled,
* tweak events can be canceled when mouse is released
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 251952f6907..3de6824c23d 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -326,7 +326,7 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
}
/* in case UserDef was read, we re-initialize all, and do versioning */
-static void wm_init_userdef(Main *bmain, const bool use_factory_settings)
+static void wm_init_userdef(Main *bmain, const bool read_userdef_from_memory)
{
/* versioning is here */
UI_init_userdef();
@@ -344,14 +344,12 @@ static void wm_init_userdef(Main *bmain, const bool use_factory_settings)
}
/* avoid re-saving for every small change to our prefs, allow overrides */
- if (use_factory_settings) {
+ if (read_userdef_from_memory) {
BLO_update_defaults_userpref_blend();
}
/* update tempdir from user preferences */
BKE_tempdir_init(U.tempdir);
-
- BKE_blender_userdef_refresh();
}
@@ -459,7 +457,7 @@ void wm_file_read_report(bContext *C)
* Logic shared between #WM_file_read & #wm_homefile_read,
* updates to make after reading a file.
*/
-static void wm_file_read_post(bContext *C, bool is_startup_file)
+static void wm_file_read_post(bContext *C, const bool is_startup_file, const bool use_userdef)
{
bool addons_loaded = false;
wmWindowManager *wm = CTX_wm_manager(C);
@@ -478,13 +476,14 @@ static void wm_file_read_post(bContext *C, bool is_startup_file)
if (is_startup_file) {
/* possible python hasn't been initialized */
if (CTX_py_init_get(C)) {
- /* Only run when we have a template path found. */
- if (BKE_appdir_app_template_any()) {
- BPY_execute_string(C, "__import__('bl_app_template_utils').reset()");
+ if (use_userdef) {
+ /* Only run when we have a template path found. */
+ if (BKE_appdir_app_template_any()) {
+ BPY_execute_string(C, "__import__('bl_app_template_utils').reset()");
+ }
+ /* sync addons, these may have changed from the defaults */
+ BPY_execute_string(C, "__import__('addon_utils').reset_all()");
}
- /* sync addons, these may have changed from the defaults */
- BPY_execute_string(C, "__import__('addon_utils').reset_all()");
-
BPY_python_reset(C);
addons_loaded = true;
}
@@ -598,7 +597,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
}
- wm_file_read_post(C, false);
+ wm_file_read_post(C, false, false);
success = true;
}
@@ -646,13 +645,15 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
*
* \param use_factory_settings: Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead.
* Used for "Restore Factory Settings".
+ * \param use_userdef: Load factory settings as well as startup file.
+ * Disabled for "File New" we don't want to reload preferences.
* \param filepath_startup_override: Optional path pointing to an alternative blend file (may be NULL).
* \param app_template_override: Template to use instead of the template defined in user-preferences.
* When not-null, this is written into the user preferences.
*/
int wm_homefile_read(
bContext *C, ReportList *reports,
- bool use_factory_settings, bool use_empty_data,
+ bool use_factory_settings, bool use_empty_data, bool use_userdef,
const char *filepath_startup_override, const char *app_template_override)
{
ListBase wmbase;
@@ -675,8 +676,8 @@ int wm_homefile_read(
*
* And in this case versioning code is to be run.
*/
- bool read_userdef_from_memory = true;
- eBLOReadSkip skip_flags = 0;
+ bool read_userdef_from_memory = false;
+ eBLOReadSkip skip_flags = use_userdef ? 0 : BLO_READ_SKIP_USERDEF;
/* options exclude eachother */
BLI_assert((use_factory_settings && filepath_startup_override) == 0);
@@ -703,7 +704,9 @@ int wm_homefile_read(
if (!use_factory_settings) {
if (cfgdir) {
BLI_path_join(filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE, NULL);
- BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ if (use_userdef) {
+ BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ }
}
else {
use_factory_settings = true;
@@ -715,15 +718,16 @@ int wm_homefile_read(
}
/* load preferences before startup.blend */
- if (!use_factory_settings && BLI_exists(filepath_userdef)) {
- UserDef *userdef = BKE_blendfile_userdef_read(filepath_userdef, NULL);
- if (userdef != NULL) {
- BKE_blender_userdef_set_data(userdef);
- MEM_freeN(userdef);
-
- read_userdef_from_memory = false;
- skip_flags |= BLO_READ_SKIP_USERDEF;
- printf("Read prefs: %s\n", filepath_userdef);
+ if (use_userdef) {
+ if (!use_factory_settings && BLI_exists(filepath_userdef)) {
+ UserDef *userdef = BKE_blendfile_userdef_read(filepath_userdef, NULL);
+ if (userdef != NULL) {
+ BKE_blender_userdef_set_data(userdef);
+ MEM_freeN(userdef);
+
+ skip_flags |= BLO_READ_SKIP_USERDEF;
+ printf("Read prefs: %s\n", filepath_userdef);
+ }
}
}
@@ -732,23 +736,23 @@ int wm_homefile_read(
if (filepath_startup_override != NULL) {
/* pass */
}
- else if (app_template_override && app_template_override[0]) {
+ else if (app_template_override) {
+ /* This may be clearing the current template by setting to an empty string. */
app_template = app_template_override;
}
else if (!use_factory_settings && U.app_template[0]) {
app_template = U.app_template;
}
- if (app_template != NULL) {
+ if ((app_template != NULL) && (app_template[0] != '\0')) {
BKE_appdir_app_template_id_search(app_template, app_template_system, sizeof(app_template_system));
- BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL);
- }
- /* insert template name into startup file */
- if (app_template != NULL) {
+ /* Insert template name into startup file. */
+
/* note that the path is being set even when 'use_factory_settings == true'
* this is done so we can load a templates factory-settings */
if (!use_factory_settings) {
+ BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL);
BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE, NULL);
if (BLI_access(filepath_startup, R_OK) != 0) {
filepath_startup[0] = '\0';
@@ -783,6 +787,13 @@ int wm_homefile_read(
success = BKE_blendfile_read_from_memory(
C, datatoc_startup_blend, datatoc_startup_blend_size,
NULL, skip_flags, true);
+ if (success) {
+ if (use_userdef) {
+ if ((skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
+ read_userdef_from_memory = true;
+ }
+ }
+ }
if (BLI_listbase_is_empty(&wmbase)) {
wm_clear_default_size(C);
}
@@ -809,20 +820,23 @@ int wm_homefile_read(
BLI_path_join(temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE, NULL);
}
- UserDef *userdef_template = NULL;
- /* just avoids missing file warning */
- if (BLI_exists(temp_path)) {
- userdef_template = BKE_blendfile_userdef_read(temp_path, NULL);
- }
- if (userdef_template == NULL) {
- /* we need to have preferences load to overwrite preferences from previous template */
- userdef_template = BKE_blendfile_userdef_read_from_memory(
- datatoc_startup_blend, datatoc_startup_blend_size, NULL);
- }
- if (userdef_template) {
- BKE_blender_userdef_set_app_template(userdef_template);
- BKE_blender_userdef_free_data(userdef_template);
- MEM_freeN(userdef_template);
+ if (use_userdef) {
+ UserDef *userdef_template = NULL;
+ /* just avoids missing file warning */
+ if (BLI_exists(temp_path)) {
+ userdef_template = BKE_blendfile_userdef_read(temp_path, NULL);
+ }
+ if (userdef_template == NULL) {
+ /* we need to have preferences load to overwrite preferences from previous template */
+ userdef_template = BKE_blendfile_userdef_read_from_memory(
+ datatoc_startup_blend, datatoc_startup_blend_size, NULL);
+ read_userdef_from_memory = true;
+ }
+ if (userdef_template) {
+ BKE_blender_userdef_set_app_template(userdef_template);
+ BKE_blender_userdef_free_data(userdef_template);
+ MEM_freeN(userdef_template);
+ }
}
}
@@ -833,9 +847,11 @@ int wm_homefile_read(
/* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise
* can remove this eventually, only in a 2.53 and older, now its not written */
G.fileflags &= ~G_FILE_RELATIVE_REMAP;
-
- /* check userdef before open window, keymaps etc */
- wm_init_userdef(CTX_data_main(C), read_userdef_from_memory);
+
+ if (use_userdef) {
+ /* check userdef before open window, keymaps etc */
+ wm_init_userdef(CTX_data_main(C), read_userdef_from_memory);
+ }
/* match the read WM with current WM */
wm_window_match_do(C, &wmbase);
@@ -843,9 +859,11 @@ int wm_homefile_read(
G.main->name[0] = '\0';
- /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
- if (!G.background) {
- GPU_default_lights();
+ if (use_userdef) {
+ /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
+ if (!G.background) {
+ GPU_default_lights();
+ }
}
/* start with save preference untitled.blend */
@@ -853,7 +871,7 @@ int wm_homefile_read(
/* disable auto-play in startup.blend... */
G.fileflags &= ~G_FILE_AUTOPLAY;
- wm_file_read_post(C, true);
+ wm_file_read_post(C, true, use_userdef);
return true;
}
@@ -982,7 +1000,7 @@ static void wm_history_file_update(void)
/* screen can be NULL */
-static ImBuf *blend_file_thumb(Scene *scene, SceneLayer *sl, bScreen *screen, BlendThumbnail **thumb_pt)
+static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, SceneLayer *sl, bScreen *screen, BlendThumbnail **thumb_pt)
{
/* will be scaled down, but gives some nice oversampling */
ImBuf *ibuf;
@@ -994,6 +1012,10 @@ static ImBuf *blend_file_thumb(Scene *scene, SceneLayer *sl, bScreen *screen, Bl
ARegion *ar = NULL;
View3D *v3d = NULL;
+ EvaluationContext eval_ctx;
+
+ CTX_data_eval_ctx(C, &eval_ctx);
+
/* In case we are given a valid thumbnail data, just generate image from it. */
if (*thumb_pt) {
thumb = *thumb_pt;
@@ -1019,14 +1041,14 @@ static ImBuf *blend_file_thumb(Scene *scene, SceneLayer *sl, bScreen *screen, Bl
/* gets scaled to BLEN_THUMB_SIZE */
if (scene->camera) {
ibuf = ED_view3d_draw_offscreen_imbuf_simple(
- scene, sl, scene->camera,
+ &eval_ctx, scene, sl, scene->camera,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, 0, false, NULL,
NULL, NULL, err_out);
}
else {
ibuf = ED_view3d_draw_offscreen_imbuf(
- scene, sl, v3d, ar,
+ &eval_ctx, scene, sl, v3d, ar,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
IB_rect, false, R_ALPHAPREMUL, 0, false, NULL,
NULL, NULL, err_out);
@@ -1122,7 +1144,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
/* Main now can store a .blend thumbnail, usefull for background mode or thumbnail customization. */
main_thumb = thumb = CTX_data_main(C)->blen_thumb;
if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) {
- ibuf_thumb = blend_file_thumb(CTX_data_scene(C), CTX_data_scene_layer(C), CTX_wm_screen(C), &thumb);
+ ibuf_thumb = blend_file_thumb(C, CTX_data_scene(C), CTX_data_scene_layer(C), CTX_wm_screen(C), &thumb);
}
/* operator now handles overwrite checks */
@@ -1571,6 +1593,7 @@ void WM_OT_read_history(wmOperatorType *ot)
static int wm_homefile_read_exec(bContext *C, wmOperator *op)
{
const bool use_factory_settings = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
+ bool use_userdef = false;
char filepath_buf[FILE_MAX];
const char *filepath = NULL;
@@ -1594,6 +1617,8 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
else {
/* always load UI for factory settings (prefs will re-init) */
G.fileflags &= ~G_FILE_NO_UI;
+ /* Always load preferences with factory settings. */
+ use_userdef = true;
}
char app_template_buf[sizeof(U.app_template)];
@@ -1605,17 +1630,15 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
if (prop_app_template && RNA_property_is_set(op->ptr, prop_app_template)) {
RNA_property_string_get(op->ptr, prop_app_template, app_template_buf);
app_template = app_template_buf;
- }
- else if (!use_factory_settings) {
- /* TODO: dont reset prefs on 'New File' */
- BLI_strncpy(app_template_buf, U.app_template, sizeof(app_template_buf));
- app_template = app_template_buf;
+
+ /* Always load preferences when switching templates. */
+ use_userdef = true;
}
else {
app_template = NULL;
}
- if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, filepath, app_template)) {
+ if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, use_userdef, filepath, app_template)) {
if (use_splash) {
WM_init_splash(C);
}
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 3c7a48662f8..af0d2be8097 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -504,9 +504,6 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* recreate dependency graph to include new objects */
DEG_scene_relations_rebuild(bmain, scene);
-
- /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
- GPU_materials_free();
/* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
BLI_strncpy(G.lib, root, FILE_MAX);
@@ -672,7 +669,8 @@ static void lib_relocate_do(
}
/* Note that in reload case, we also want to replace indirect usages. */
- const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
+ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE |
+ (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
WMLinkAppendDataItem *item = itemlink->link;
ID *old_id = item->customdata;
@@ -801,9 +799,6 @@ static void lib_relocate_do(
/* recreate dependency graph to include new objects */
DEG_scene_relations_rebuild(bmain, scene);
-
- /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
- GPU_materials_free();
}
void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 1ffe96181f0..77030fac5ea 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -71,6 +71,7 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type)
gesture->type = type;
gesture->event_type = event->type;
gesture->swinid = ar->swinid; /* means only in area-region context! */
+ gesture->userdata_free = true; /* Free if userdata is set. */
wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy);
@@ -114,7 +115,7 @@ void WM_gesture_end(bContext *C, wmGesture *gesture)
win->tweak = NULL;
BLI_remlink(&win->gesture, gesture);
MEM_freeN(gesture->customdata);
- if (gesture->userdata) {
+ if (gesture->userdata && gesture->userdata_free) {
MEM_freeN(gesture->userdata);
}
MEM_freeN(gesture);
@@ -137,7 +138,7 @@ int wm_gesture_evaluate(wmGesture *gesture)
int dx = BLI_rcti_size_x(rect);
int dy = BLI_rcti_size_y(rect);
if (abs(dx) + abs(dy) > U.tweak_threshold) {
- int theta = iroundf(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI);
+ int theta = round_fl_to_int(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI);
int val = EVT_GESTURE_W;
if (theta == 0) val = EVT_GESTURE_E;
@@ -174,7 +175,7 @@ static void wm_gesture_draw_line(wmGesture *gt)
uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
glGetFloatv(GL_VIEWPORT, viewport_size);
@@ -214,7 +215,7 @@ static void wm_gesture_draw_rect(wmGesture *gt)
shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
glGetFloatv(GL_VIEWPORT, viewport_size);
@@ -224,7 +225,7 @@ static void wm_gesture_draw_rect(wmGesture *gt)
immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
immUniform1f("dash_width", 8.0f);
- imm_draw_line_box(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, (float)rect->ymax);
+ imm_draw_box_wire_2d(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, (float)rect->ymax);
immUnbindProgram();
@@ -242,13 +243,13 @@ static void wm_gesture_draw_circle(wmGesture *gt)
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.05f);
- imm_draw_circle_fill(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40);
+ imm_draw_circle_fill_2d(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40);
immUnbindProgram();
glDisable(GL_BLEND);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
glGetFloatv(GL_VIEWPORT, viewport_size);
@@ -258,7 +259,7 @@ static void wm_gesture_draw_circle(wmGesture *gt)
immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
immUniform1f("dash_width", 4.0f);
- imm_draw_circle_wire(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40);
+ imm_draw_circle_wire_2d(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40);
immUnbindProgram();
}
@@ -355,7 +356,7 @@ static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
glGetFloatv(GL_VIEWPORT, viewport_size);
@@ -386,7 +387,7 @@ static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
glGetFloatv(GL_VIEWPORT, viewport_size);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 6ae41ab3917..8346535cd6a 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -173,6 +173,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_remove); /* screen.c */
+ BKE_region_callback_refresh_tag_manipulatormap_set(WM_manipulatormap_tag_refresh);
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 */
@@ -185,18 +186,15 @@ void WM_init(bContext *C, int argc, const char **argv)
ED_file_init(); /* for fsmenu */
ED_node_init_butfuncs();
- BLF_init(11, U.dpi); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
+ BLF_init(); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
BLT_lang_init();
- /* Enforce loading the UI for the initial homefile */
- G.fileflags &= ~G_FILE_NO_UI;
-
/* reports cant be initialized before the wm,
* but keep before file reading, since that may report errors */
wm_init_reports(C);
/* get the default database, plus a wm */
- wm_homefile_read(C, NULL, G.factory_startup, false, NULL, NULL);
+ wm_homefile_read(C, NULL, G.factory_startup, false, true, NULL, NULL);
BLT_lang_set(NULL);
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 5001fc7817f..2f12dd5b672 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -179,7 +179,7 @@ static void wm_operatortype_append__end(wmOperatorType *ot)
/* XXX All ops should have a description but for now allow them not to. */
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
@@ -401,7 +401,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
ot->description = UNDOCUMENTED_OPERATOR_TIP;
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
/* Use i18n context from ext.srna if possible (py operators). */
i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLT_I18NCONTEXT_OPERATOR_DEFAULT;
RNA_def_struct_translation_context(ot->srna, i18n_context);
@@ -435,7 +435,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *),
opfunc(ot, userdata);
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
@@ -576,6 +576,46 @@ void WM_operator_bl_idname(char *to, const char *from)
}
/**
+ * Sanity check to ensure #WM_operator_bl_idname won't fail.
+ * \returns true when there are no problems with \a idname, otherwise report an error.
+ */
+bool WM_operator_py_idname_ok_or_report(ReportList *reports, const char *classname, const char *idname)
+{
+ const char *ch = idname;
+ int dot = 0;
+ int i;
+ for (i = 0; *ch; i++, ch++) {
+ if ((*ch >= 'a' && *ch <= 'z') || (*ch >= '0' && *ch <= '9') || *ch == '_') {
+ /* pass */
+ }
+ else if (*ch == '.') {
+ dot++;
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR,
+ "Registering operator class: '%s', invalid bl_idname '%s', at position %d",
+ classname, idname, i);
+ return false;
+ }
+ }
+
+ if (i > (MAX_NAME - 3)) {
+ BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', "
+ "is too long, maximum length is %d", classname, idname,
+ MAX_NAME - 3);
+ return false;
+ }
+
+ if (dot != 1) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character",
+ classname, idname);
+ return false;
+ }
+ return true;
+}
+
+/**
* Print a string representation of the operator, with the args that it runs so python can run it again.
*
* When calling from an existing wmOperator, better to use simple version:
@@ -809,9 +849,19 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
} \
} (void)0
+#define CTX_TEST_SPACE_TYPE(space_data_type, member_full, dataptr_cmp) \
+ { \
+ const char *ctx_member_full = member_full; \
+ if (space_data->spacetype == space_data_type && ptr->data == dataptr_cmp) { \
+ member_id = ctx_member_full; \
+ break; \
+ } \
+ } (void)0
+
switch (GS(((ID *)ptr->id.data)->name)) {
case ID_SCE:
{
+ CTX_TEST_PTR_DATA_TYPE(C, "active_gpencil_brush", RNA_GPencilBrush, ptr, CTX_data_active_gpencil_brush(C));
CTX_TEST_PTR_ID(C, "scene", ptr->id.data);
break;
}
@@ -846,12 +896,22 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
{
CTX_TEST_PTR_ID(C, "screen", ptr->id.data);
- CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, CTX_wm_space_data(C));
+ SpaceLink *space_data = CTX_wm_space_data(C);
+
+ CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, space_data);
CTX_TEST_PTR_DATA_TYPE(C, "area", RNA_Area, ptr, CTX_wm_area(C));
CTX_TEST_PTR_DATA_TYPE(C, "region", RNA_Region, ptr, CTX_wm_region(C));
+ CTX_TEST_SPACE_TYPE(SPACE_IMAGE, "space_data.uv_editor", space_data);
+ CTX_TEST_SPACE_TYPE(SPACE_VIEW3D, "space_data.fx_settings", &(CTX_wm_view3d(C)->fx_settings));
+ CTX_TEST_SPACE_TYPE(SPACE_NLA, "space_data.dopesheet", CTX_wm_space_nla(C)->ads);
+ CTX_TEST_SPACE_TYPE(SPACE_IPO, "space_data.dopesheet", CTX_wm_space_graph(C)->ads);
+ CTX_TEST_SPACE_TYPE(SPACE_ACTION, "space_data.dopesheet", &(CTX_wm_space_action(C)->ads));
+ CTX_TEST_SPACE_TYPE(SPACE_FILE, "space_data.params", CTX_wm_space_file(C)->params);
break;
}
+ default:
+ break;
}
if (member_id) {
@@ -863,6 +923,7 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
}
#undef CTX_TEST_PTR_ID
#undef CTX_TEST_PTR_ID_CAST
+#undef CTX_TEST_SPACE_TYPE
}
return ret;
@@ -1826,8 +1887,8 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
if (version_suffix != NULL && version_suffix[0]) {
/* placed after the version number in the image,
* placing y is tricky to match baseline */
- int x = 260 * U.pixelsize - (2 * UI_DPI_FAC);
- int y = 242 * U.pixelsize + (4 * UI_DPI_FAC);
+ int x = 236 * U.pixelsize - (2 * UI_DPI_FAC);
+ int y = 231 * U.pixelsize + (4 * UI_DPI_FAC);
int w = 240 * U.pixelsize;
/* hack to have text draw 'text_sel' */
@@ -1840,17 +1901,32 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
#ifdef WITH_BUILDINFO
if (build_commit_timestamp != 0) {
- uiDefBut(block, UI_BTYPE_LABEL, 0, date_buf, U.pixelsize * 494 - date_width, U.pixelsize * 270, date_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, date_buf,
+ U.pixelsize * 502 - date_width, U.pixelsize * 267,
+ date_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ /* XXX, set internal flag - UI_SELECT */
+ UI_but_flag_enable(but, 1);
label_delta = 12;
}
- uiDefBut(block, UI_BTYPE_LABEL, 0, hash_buf, U.pixelsize * 494 - hash_width, U.pixelsize * (270 - label_delta), hash_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, hash_buf,
+ U.pixelsize * 502 - hash_width, U.pixelsize * (267 - label_delta),
+ hash_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ /* XXX, set internal flag - UI_SELECT */
+ UI_but_flag_enable(but, 1);
if (!STREQ(build_branch, "master")) {
char branch_buf[128] = "\0";
int branch_width;
BLI_snprintf(branch_buf, sizeof(branch_buf), "Branch: %s", build_branch);
branch_width = (int)BLF_width(style->widgetlabel.uifont_id, branch_buf, sizeof(branch_buf)) + U.widget_unit;
- uiDefBut(block, UI_BTYPE_LABEL, 0, branch_buf, U.pixelsize * 494 - branch_width, U.pixelsize * (258 - label_delta), branch_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, branch_buf,
+ U.pixelsize * 502 - branch_width, U.pixelsize * (255 - label_delta),
+ branch_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ /* XXX, set internal flag - UI_SELECT */
+ UI_but_flag_enable(but, 1);
}
#endif /* WITH_BUILDINFO */
@@ -3123,7 +3199,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
/* flat color if no texture available */
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3fvAlpha(col, alpha);
- imm_draw_circle_fill(pos, 0.0f, 0.0f, radius, 40);
+ imm_draw_circle_fill_2d(pos, 0.0f, 0.0f, radius, 40);
}
immUnbindProgram();
@@ -3230,10 +3306,10 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
}
/* draw circles on top */
- imm_draw_circle_wire(pos, 0.0f, 0.0f, r1, 40);
- imm_draw_circle_wire(pos, 0.0f, 0.0f, r2, 40);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 40);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 40);
if (rmin > 0.0f)
- imm_draw_circle_wire(pos, 0.0, 0.0f, rmin, 40);
+ imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 40);
immUnbindProgram();
BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi);
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 445516ffda7..fcb471530e0 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -77,10 +77,10 @@
#include "WM_api.h" /* only for WM_main_playanim */
#ifdef WITH_AUDASPACE
-# include AUD_DEVICE_H
-# include AUD_HANDLE_H
-# include AUD_SOUND_H
-# include AUD_SPECIAL_H
+# include <AUD_Device.h>
+# include <AUD_Handle.h>
+# include <AUD_Sound.h>
+# include <AUD_Special.h>
static AUD_Sound *source = NULL;
static AUD_Handle *playback_handle = NULL;
@@ -319,7 +319,7 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- imm_draw_checker_box(offs_x, offs_y, offs_x + span_x, offs_y + span_y);
+ imm_draw_box_checker_2d(offs_x, offs_y, offs_x + span_x, offs_y + span_y);
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
@@ -1265,7 +1265,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
immInit();
/* initialize the font */
- BLF_init(11, 72);
+ BLF_init();
ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
BLF_size(ps.fontid, 11, 72);
@@ -1437,8 +1437,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
ps.next_frame = ps.direction;
-
- while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0)) || ps.wait2) {
+ while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, ps.wait2))) {
if (hasevent) {
GHOST_DispatchEvents(g_WS.ghost_system);
}
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 1e63a0e4483..c0800705b28 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -85,13 +85,13 @@ static void wm_method_draw_stereo3d_pageflip(wmWindow *win)
static GPUInterlaceShader interlace_gpu_id_from_type(eStereo3dInterlaceType interlace_type)
{
switch (interlace_type) {
- case S3D_INTERLACE_ROW:
- return GPU_SHADER_INTERLACE_ROW;
- case S3D_INTERLACE_COLUMN:
- return GPU_SHADER_INTERLACE_COLUMN;
- case S3D_INTERLACE_CHECKERBOARD:
- default:
- return GPU_SHADER_INTERLACE_CHECKER;
+ case S3D_INTERLACE_ROW:
+ return GPU_SHADER_INTERLACE_ROW;
+ case S3D_INTERLACE_COLUMN:
+ return GPU_SHADER_INTERLACE_COLUMN;
+ case S3D_INTERLACE_CHECKERBOARD:
+ default:
+ return GPU_SHADER_INTERLACE_CHECKER;
}
}
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 66df41e5b84..09b2b50687a 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -414,9 +414,14 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
}
-static void wm_window_set_dpi(wmWindow *win)
+void WM_window_set_dpi(wmWindow *win)
{
- int auto_dpi = GHOST_GetDPIHint(win->ghostwin);
+ float auto_dpi = GHOST_GetDPIHint(win->ghostwin);
+
+ /* Clamp auto DPI to 96, since our font/interface drawing does not work well
+ * with lower sizes. The main case we are interested in supporting is higher
+ * DPI. If a smaller UI is desired it is still possible to adjust UI scale. */
+ auto_dpi = max_ff(auto_dpi, 96.0f);
/* Lazily init UI scale size, preserving backwards compatibility by
* computing UI scale from ratio of previous DPI and auto DPI */
@@ -436,17 +441,22 @@ static void wm_window_set_dpi(wmWindow *win)
/* Blender's UI drawing assumes DPI 72 as a good default following macOS
* while Windows and Linux use DPI 96. GHOST assumes a default 96 so we
* remap the DPI to Blender's convention. */
+ auto_dpi *= GHOST_GetNativePixelSize(win->ghostwin);
int dpi = auto_dpi * U.ui_scale * (72.0 / 96.0f);
/* Automatically set larger pixel size for high DPI. */
- int pixelsize = MAX2(1, dpi / 54);
+ int pixelsize = max_ii(1, (int)(dpi / 64));
+ /* User adjustment for pixel size. */
+ pixelsize = max_ii(1, pixelsize + U.ui_line_width);
/* Set user preferences globals for drawing, and for forward compatibility. */
- U.pixelsize = GHOST_GetNativePixelSize(win->ghostwin) * pixelsize;
+ U.pixelsize = pixelsize;
U.dpi = dpi / pixelsize;
U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
+ U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72;
- BKE_blender_userdef_refresh();
+ /* update font drawing */
+ BLF_default_dpi(U.pixelsize * U.dpi);
}
/* belongs to below */
@@ -506,8 +516,12 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
/* store actual window size in blender window */
bounds = GHOST_GetClientBounds(win->ghostwin);
- win->sizex = GHOST_GetWidthRectangle(bounds);
- win->sizey = GHOST_GetHeightRectangle(bounds);
+
+ /* win32: gives undefined window size when minimized */
+ if (GHOST_GetWindowState(win->ghostwin) != GHOST_kWindowStateMinimized) {
+ win->sizex = GHOST_GetWidthRectangle(bounds);
+ win->sizey = GHOST_GetHeightRectangle(bounds);
+ }
GHOST_DisposeRectangle(bounds);
#ifndef __APPLE__
@@ -522,7 +536,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
}
/* needed here, because it's used before it reads userdef */
- wm_window_set_dpi(win);
+ WM_window_set_dpi(win);
wm_window_swap_buffers(win);
@@ -1011,7 +1025,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
immActivate();
/* this can change per window */
- wm_window_set_dpi(win);
+ WM_window_set_dpi(win);
}
}
@@ -1211,7 +1225,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
WM_jobs_stop(wm, WM_window_get_active_screen(win), NULL);
}
- wm_window_set_dpi(win);
+ WM_window_set_dpi(win);
/* win32: gives undefined window size when minimized */
if (state != GHOST_kWindowStateMinimized) {
@@ -1301,11 +1315,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
case GHOST_kEventWindowDPIHintChanged:
{
- wm_window_set_dpi(win);
+ WM_window_set_dpi(win);
/* font's are stored at each DPI level, without this we can easy load 100's of fonts */
BLF_cache_clear();
- BKE_blender_userdef_refresh();
WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
break;
@@ -1391,7 +1404,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
{
// only update if the actual pixel size changes
float prev_pixelsize = U.pixelsize;
- wm_window_set_dpi(win);
+ WM_window_set_dpi(win);
if (U.pixelsize != prev_pixelsize) {
BKE_icon_changed(WM_window_get_active_screen(win)->id.icon_id);
@@ -1954,7 +1967,7 @@ void WM_window_set_active_workspace(wmWindow *win, WorkSpace *workspace)
WorkSpaceLayout *WM_window_get_active_layout(const wmWindow *win)
{
const WorkSpace *workspace = WM_window_get_active_workspace(win);
- return (LIKELY(workspace != NULL) ? BKE_workspace_active_layout_get(win->workspace_hook): NULL);
+ return (LIKELY(workspace != NULL) ? BKE_workspace_active_layout_get(win->workspace_hook) : NULL);
}
void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout)
{
diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_api.h b/source/blender/windowmanager/manipulators/WM_manipulator_api.h
index d6774333ba4..726e560a061 100644
--- a/source/blender/windowmanager/manipulators/WM_manipulator_api.h
+++ b/source/blender/windowmanager/manipulators/WM_manipulator_api.h
@@ -59,18 +59,25 @@ struct wmManipulatorMapType_Params;
struct wmManipulator *WM_manipulator_new_ptr(
const struct wmManipulatorType *wt, struct wmManipulatorGroup *mgroup,
- const char *name, struct PointerRNA *properties);
+ struct PointerRNA *properties);
struct wmManipulator *WM_manipulator_new(
const char *idname, struct wmManipulatorGroup *mgroup,
- const char *name, struct PointerRNA *properties);
-void WM_manipulator_free(
+ struct PointerRNA *properties);
+void WM_manipulator_free(struct wmManipulator *mpr);
+void WM_manipulator_unlink(
ListBase *manipulatorlist, struct wmManipulatorMap *mmap, struct wmManipulator *mpr,
struct bContext *C);
void WM_manipulator_name_set(struct wmManipulatorGroup *mgroup, struct wmManipulator *mpr, const char *name);
-struct PointerRNA *WM_manipulator_set_operator(
- struct wmManipulator *, struct wmOperatorType *ot, struct IDProperty *properties);
+bool WM_manipulator_select_unlink(struct wmManipulatorMap *mmap, struct wmManipulator *mpr);
+bool WM_manipulator_select_set(struct wmManipulatorMap *mmap, struct wmManipulator *mpr, bool select);
+
+struct wmManipulatorOpElem *WM_manipulator_operator_get(
+ struct wmManipulator *mpr, int part_index);
+struct PointerRNA *WM_manipulator_operator_set(
+ struct wmManipulator *mpr, int part_index,
+ struct wmOperatorType *ot, struct IDProperty *properties);
/* callbacks */
void WM_manipulator_set_fn_custom_modal(struct wmManipulator *mpr, wmManipulatorFnModal fn);
@@ -93,10 +100,26 @@ void WM_manipulator_set_flag(struct wmManipulator *mpr, const int flag, const bo
void WM_manipulator_set_scale(struct wmManipulator *mpr, float scale);
void WM_manipulator_set_line_width(struct wmManipulator *mpr, const float line_width);
-void WM_manipulator_get_color(const struct wmManipulator *mpr, float col[4]);
-void WM_manipulator_set_color(struct wmManipulator *mpr, const float col[4]);
-void WM_manipulator_get_color_highlight(const struct wmManipulator *mpr, float col_hi[4]);
-void WM_manipulator_set_color_highlight(struct wmManipulator *mpr, const float col[4]);
+void WM_manipulator_get_color(const struct wmManipulator *mpr, float color[4]);
+void WM_manipulator_set_color(struct wmManipulator *mpr, const float color[4]);
+void WM_manipulator_get_color_highlight(const struct wmManipulator *mpr, float color_hi[4]);
+void WM_manipulator_set_color_highlight(struct wmManipulator *mpr, const float color[4]);
+
+/**
+ * Leaving values NULL use values from #wmManipulator.
+ */
+struct WM_ManipulatorMatrixParams {
+ const float(*matrix_space)[4];
+ const float(*matrix_basis)[4];
+ const float(*matrix_offset)[4];
+ const float *scale_final;
+};
+
+void WM_manipulator_calc_matrix_final_params(
+ const struct wmManipulator *mpr, const struct WM_ManipulatorMatrixParams *params,
+ float r_mat[4][4]);
+
+void WM_manipulator_calc_matrix_final(const struct wmManipulator *mpr, float r_mat[4][4]);
/* properties */
void WM_manipulator_properties_create_ptr(struct PointerRNA *ptr, struct wmManipulatorType *wt);
@@ -113,16 +136,16 @@ void WM_manipulator_properties_free(struct PointerRNA *ptr);
const struct wmManipulatorType *WM_manipulatortype_find(const char *idname, bool quiet);
void WM_manipulatortype_append(void (*wtfunc)(struct wmManipulatorType *));
void WM_manipulatortype_append_ptr(void (*mnpfunc)(struct wmManipulatorType *, void *), void *userdata);
-bool WM_manipulatortype_remove(const char *idname);
-void WM_manipulatortype_remove_ptr(struct wmManipulatorType *wt);
+bool WM_manipulatortype_remove(struct bContext *C, struct Main *bmain, const char *idname);
+void WM_manipulatortype_remove_ptr(struct bContext *C, struct Main *bmain, struct wmManipulatorType *wt);
void WM_manipulatortype_iter(struct GHashIterator *ghi);
/* wm_manipulator_group_type.c */
struct wmManipulatorGroupType *WM_manipulatorgrouptype_find(const char *idname, bool quiet);
struct wmManipulatorGroupType *WM_manipulatorgrouptype_append(void (*wtfunc)(struct wmManipulatorGroupType *));
struct wmManipulatorGroupType *WM_manipulatorgrouptype_append_ptr(void (*mnpfunc)(struct wmManipulatorGroupType *, void *), void *userdata);
-bool WM_manipulatorgrouptype_remove(const char *idname);
-void WM_manipulatorgrouptype_remove_ptr(struct wmManipulatorGroupType *wt);
+bool WM_manipulatorgrouptype_free(const char *idname);
+void WM_manipulatorgrouptype_free_ptr(struct wmManipulatorGroupType *wt);
void WM_manipulatorgrouptype_iter(struct GHashIterator *ghi);
struct wmManipulatorGroupTypeRef *WM_manipulatorgrouptype_append_and_link(
@@ -174,10 +197,13 @@ void WM_manipulator_target_property_value_set_array(
struct bContext *C, const struct wmManipulator *mpr, struct wmManipulatorProperty *mpr_prop,
const float *value);
-void WM_manipulator_target_property_range_get(
+bool WM_manipulator_target_property_range_get(
const struct wmManipulator *mpr, struct wmManipulatorProperty *mpr_prop,
float range[2]);
+int WM_manipulator_target_property_array_length(
+ const struct wmManipulator *mpr, struct wmManipulatorProperty *mpr_prop);
+
/* definitions */
const struct wmManipulatorPropertyType *WM_manipulatortype_target_property_find(
const struct wmManipulatorType *wt, const char *idname);
@@ -202,10 +228,15 @@ struct wmManipulatorMap *WM_manipulatormap_new_from_type(
const struct wmManipulatorMapType_Params *mmap_params);
const struct ListBase *WM_manipulatormap_group_list(struct wmManipulatorMap *mmap);
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_draw(
+ struct wmManipulatorMap *mmap, const struct bContext *C, const eWM_ManipulatorMapDrawStep 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);
+bool WM_manipulatormap_is_any_selected(const struct wmManipulatorMap *mmap);
+bool WM_manipulatormap_minmax(
+ const struct wmManipulatorMap *mmap, bool use_hidden, bool use_select,
+ float r_min[3], float r_max[3]);
/* -------------------------------------------------------------------- */
/* wmManipulatorMapType */
@@ -228,6 +259,9 @@ struct wmManipulatorGroupTypeRef *WM_manipulatormaptype_group_link_ptr(
struct wmManipulatorMapType *mmap_type,
struct wmManipulatorGroupType *wgt);
+void WM_manipulatormaptype_group_init_runtime_keymap(
+ const struct Main *bmain,
+ struct wmManipulatorGroupType *wgt);
void WM_manipulatormaptype_group_init_runtime(
const struct Main *bmain, struct wmManipulatorMapType *mmap_type,
struct wmManipulatorGroupType *wgt);
@@ -238,27 +272,32 @@ void WM_manipulatormaptype_group_unlink(
void WM_manipulatormaptype_group_free(struct wmManipulatorGroupTypeRef *wgt);
/* -------------------------------------------------------------------- */
-/* Manipulator Add/Remove (High level API) */
+/* ManipulatorGroup */
-void WM_manipulator_group_add_ptr_ex(
+/* Add/Remove (High level API) */
+
+void WM_manipulator_group_type_add_ptr_ex(
struct wmManipulatorGroupType *wgt,
struct wmManipulatorMapType *mmap_type);
-void WM_manipulator_group_add_ptr(
+void WM_manipulator_group_type_add_ptr(
struct wmManipulatorGroupType *wgt);
-void WM_manipulator_group_add(const char *idname);
+void WM_manipulator_group_type_add(const char *idname);
-void WM_manipulator_group_remove_ptr_ex(
+void WM_manipulator_group_type_remove_ptr_ex(
struct Main *bmain, struct wmManipulatorGroupType *wgt,
struct wmManipulatorMapType *mmap_type);
-void WM_manipulator_group_remove_ptr(
+void WM_manipulator_group_type_remove_ptr(
struct Main *bmain, struct wmManipulatorGroupType *wgt);
-void WM_manipulator_group_remove(struct Main *bmain, const char *idname);
+void WM_manipulator_group_type_remove(struct Main *bmain, const char *idname);
-void WM_manipulator_group_remove_ptr_delayed_ex(
+void WM_manipulator_group_type_remove_ptr_delayed_ex(
struct wmManipulatorGroupType *wgt,
struct wmManipulatorMapType *mmap_type);
-void WM_manipulator_group_remove_ptr_delayed(
+void WM_manipulator_group_type_remove_ptr_delayed(
struct wmManipulatorGroupType *wgt);
-void WM_manipulator_group_remove_delayed(const char *idname);
+void WM_manipulator_group_type_remove_delayed(const char *idname);
+
+/* Utilities */
+void WM_manipulator_group_type_is_any_selected(const char *idname);
#endif /* __WM_MANIPULATOR_API_H__ */
diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_types.h b/source/blender/windowmanager/manipulators/WM_manipulator_types.h
index b1b6c5b1c0f..22f1eb68181 100644
--- a/source/blender/windowmanager/manipulators/WM_manipulator_types.h
+++ b/source/blender/windowmanager/manipulators/WM_manipulator_types.h
@@ -45,19 +45,115 @@ struct wmManipulator;
struct wmManipulatorProperty;
struct wmKeyConfig;
-#include "wm_manipulator_fn.h"
-
#include "DNA_listBase.h"
+
+/* -------------------------------------------------------------------- */
+/* Enum Typedef's */
+
+
+/**
+ * #wmManipulator.state
+ */
+typedef enum eWM_ManipulatorState {
+ WM_MANIPULATOR_STATE_HIGHLIGHT = (1 << 0), /* while hovered */
+ WM_MANIPULATOR_STATE_MODAL = (1 << 1), /* while dragging */
+ WM_MANIPULATOR_STATE_SELECT = (1 << 2),
+} eWM_ManipulatorState;
+
+
+/**
+ * #wmManipulator.flag
+ * Flags for individual manipulators.
+ */
+typedef enum eWM_ManipulatorFlag {
+ WM_MANIPULATOR_DRAW_HOVER = (1 << 0), /* draw *only* while hovering */
+ WM_MANIPULATOR_DRAW_MODAL = (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),
+ /**
+ * When set 'scale_final' value also scales the offset.
+ * Use when offset is to avoid screen-space overlap instead of absolute positioning. */
+ WM_MANIPULATOR_DRAW_OFFSET_SCALE = (1 << 4),
+ /**
+ * User should still use 'scale_final' for any handles and UI elements.
+ * This simply skips scale when calculating the final matrix.
+ * Needed when the manipulator needs to align with the interface underneath it. */
+ WM_MANIPULATOR_DRAW_NO_SCALE = (1 << 5),
+} eWM_ManipulatorFlag;
+
+/**
+ * #wmManipulatorGroupType.flag
+ * Flags that influence the behavior of all manipulators in the group.
+ */
+typedef enum eWM_ManipulatorGroupTypeFlag {
+ /* Mark manipulator-group as being 3D */
+ WM_MANIPULATORGROUPTYPE_3D = (1 << 0),
+ /* Scale manipulators as 3D object that respects zoom (otherwise zoom independent draw size).
+ * note: currently only for 3D views, 2D support needs adding. */
+ WM_MANIPULATORGROUPTYPE_SCALE = (1 << 1),
+ /* Manipulators can be depth culled with scene objects (covered by other geometry - TODO) */
+ WM_MANIPULATORGROUPTYPE_DEPTH_3D = (1 << 2),
+ /* Manipulators can be selected */
+ WM_MANIPULATORGROUPTYPE_SELECT = (1 << 3),
+ /* The manipulator group is to be kept (not removed on loading a new file for eg). */
+ WM_MANIPULATORGROUPTYPE_PERSISTENT = (1 << 4),
+ /* Show all other manipulators when interacting. */
+ WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL = (1 << 5),
+} eWM_ManipulatorGroupTypeFlag;
+
+
+/**
+ * #wmManipulatorGroup.init_flag
+ */
+typedef enum eWM_ManipulatorGroupInitFlag {
+ /* mgroup has been initialized */
+ WM_MANIPULATORGROUP_INIT_SETUP = (1 << 0),
+} eWM_ManipulatorGroupInitFlag;
+
+/**
+ * #wmManipulatorMapType.type_update_flag
+ * Manipulator-map type update flag
+ */
+typedef enum eWM_ManipulatorMapTypeUpdateFlag {
+ /* A new type has been added, needs to be initialized for all views. */
+ WM_MANIPULATORMAPTYPE_UPDATE_INIT = (1 << 0),
+ WM_MANIPULATORMAPTYPE_UPDATE_REMOVE = (1 << 1),
+
+ /* Needed because keymap may be registered before and after window initialization.
+ * So we need to keep track of keymap initialization separately. */
+ WM_MANIPULATORMAPTYPE_KEYMAP_INIT = (1 << 2),
+} eWM_ManipulatorMapTypeUpdateFlag;
+
/* -------------------------------------------------------------------- */
/* wmManipulator */
+/**
+ * \brief Manipulator tweak flag.
+ * Bitflag passed to manipulator while tweaking.
+ *
+ * \note Manipulators are responsible for handling this #wmManipulator.modal callback!.
+ */
+typedef enum {
+ /* Drag with extra precision (Shift). */
+ WM_MANIPULATOR_TWEAK_PRECISE = (1 << 0),
+ /* Drag with snap enabled (Ctrl). */
+ WM_MANIPULATOR_TWEAK_SNAP = (1 << 1),
+} eWM_ManipulatorTweak;
+
+#include "wm_manipulator_fn.h"
+
+typedef struct wmManipulatorOpElem {
+ struct wmOperatorType *type;
+ /* operator properties if manipulator spawns and controls an operator,
+ * or owner pointer if manipulator spawns and controls a property */
+ PointerRNA ptr;
+} wmManipulatorOpElem;
+
/* manipulators are set per region by registering them on manipulator-maps */
struct wmManipulator {
struct wmManipulator *next, *prev;
- char name[64 + 4]; /* MAX_NAME + 4 for unique '.001', '.002', etc suffix */
-
/* While we don't have a real type, use this to put type-like vars. */
const struct wmManipulatorType *type;
@@ -73,10 +169,13 @@ struct wmManipulator {
/* rna pointer to access properties */
struct PointerRNA *ptr;
- int flag; /* flags that influence the behavior or how the manipulators are drawn */
- short state; /* state flags (active, highlighted, selected) */
+ /* flags that influence the behavior or how the manipulators are drawn */
+ eWM_ManipulatorFlag flag;
+ /* state flags (active, highlighted, selected) */
+ eWM_ManipulatorState state;
- /* Optional ID for highlighting different parts of this manipulator. */
+ /* Optional ID for highlighting different parts of this manipulator.
+ * -1 when unset, otherwise a valid index. (Used as index to 'op_data'). */
int highlight_part;
/* Transformation of the manipulator in 2d or 3d space.
@@ -87,6 +186,10 @@ struct wmManipulator {
* besides this it's up to the manipulators internal code how the
* rotation components are used for drawing and interaction.
*/
+
+ /* The space this manipulator is being modified in. */
+ float matrix_space[4][4];
+ /* Transformation of this manipulator. */
float matrix_basis[4][4];
/* custom offset from origin */
float matrix_offset[4][4];
@@ -102,22 +205,16 @@ struct wmManipulator {
/* data used during interaction */
void *interaction_data;
- /* name of operator to spawn when activating the manipulator */
- struct {
- struct wmOperatorType *type;
- /* operator properties if manipulator spawns and controls an operator,
- * or owner pointer if manipulator spawns and controls a property */
- PointerRNA ptr;
- } op_data;
+ /* Operator to spawn when activating the manipulator (overrides property editing),
+ * an array of items (aligned with #wmManipulator.highlight_part). */
+ wmManipulatorOpElem *op_data;
+ int op_data_len;
struct IDProperty *properties;
/* over alloc target_properties after 'wmManipulatorType.struct_size' */
};
-typedef void (*wmManipulatorGroupFnInit)(
- const struct bContext *, struct wmManipulatorGroup *);
-
/* Similar to PropertyElemRNA, but has an identifier. */
typedef struct wmManipulatorProperty {
const struct wmManipulatorPropertyType *type;
@@ -133,7 +230,6 @@ typedef struct wmManipulatorProperty {
wmManipulatorPropertyFnSet value_set_fn;
wmManipulatorPropertyFnRangeGet range_get_fn;
wmManipulatorPropertyFnFree free_fn;
- const struct bContext *context;
void *user_data;
} custom_func;
} wmManipulatorProperty;
@@ -152,7 +248,6 @@ typedef struct wmManipulatorPropertyType {
} wmManipulatorPropertyType;
-
/**
* Simple utility wrapper for storing a single manipulator as wmManipulatorGroup.customdata (which gets freed).
*/
@@ -165,36 +260,6 @@ struct wmManipulatorMapType_Params {
short regionid;
};
-
-/* 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),
-};
-
-/* wmManipulator.state */
-enum {
- WM_MANIPULATOR_STATE_HIGHLIGHT = (1 << 0), /* while hovered */
- WM_MANIPULATOR_STATE_ACTIVE = (1 << 1), /* while dragging */
- WM_MANIPULATOR_STATE_SELECT = (1 << 2),
-};
-
-/**
- * \brief Manipulator tweak flag.
- * Bitflag passed to manipulator while tweaking.
- *
- * \note Manipulators are responsible for handling this #wmManipulator.modal callback!.
- */
-enum {
- /* Drag with extra precision (Shift). */
- WM_MANIPULATOR_TWEAK_PRECISE = (1 << 0),
- /* Drag with snap enabled (Ctrl). */
- WM_MANIPULATOR_TWEAK_SNAP = (1 << 1),
-};
-
typedef struct wmManipulatorType {
const char *idname; /* MAX_NAME */
@@ -212,7 +277,8 @@ typedef struct wmManipulatorType {
/* determines 3d intersection by rendering the manipulator in a selection routine. */
wmManipulatorFnDrawSelect draw_select;
- /* determine if the mouse intersects with the manipulator. The calculation should be done in the callback itself */
+ /* Determine if the mouse intersects with the manipulator.
+ * The calculation should be done in the callback itself, -1 for no seleciton. */
wmManipulatorFnTestSelect test_select;
/* handler used by the manipulator. Usually handles interaction tied to a manipulator type */
@@ -227,7 +293,7 @@ typedef struct wmManipulatorType {
* - Scale isn't applied (wmManipulator.scale/user_scale).
* - Offset isn't applied (wmManipulator.matrix_offset).
*/
- wmManipulatorFnMatrixWorldGet matrix_world_get;
+ wmManipulatorFnMatrixBasisGet matrix_basis_get;
/* activate a manipulator state when the user clicks on it */
wmManipulatorFnInvoke invoke;
@@ -238,7 +304,7 @@ typedef struct wmManipulatorType {
wmManipulatorFnCursorGet cursor_get;
/* called when manipulator selection state changes */
- wmManipulatorFnSelect select;
+ wmManipulatorFnSelectRefresh select_refresh;
/* RNA for properties */
struct StructRNA *srna;
@@ -293,10 +359,10 @@ typedef struct wmManipulatorGroupType {
/* RNA integration */
ExtensionRNA ext;
- int flag;
+ eWM_ManipulatorGroupTypeFlag flag;
- /* eManipulatorMapTypeUpdateFlags (so we know which group type to update) */
- uchar type_update_flag;
+ /* So we know which group type to update. */
+ eWM_ManipulatorMapTypeUpdateFlag type_update_flag;
/* same as manipulator-maps, so registering/unregistering goes to the correct region */
struct wmManipulatorMapType_Params mmap_params;
@@ -316,52 +382,21 @@ typedef struct wmManipulatorGroup {
void *customdata;
void (*customdata_free)(void *); /* for freeing customdata from above */
- int flag; /* private */
- int pad;
+ eWM_ManipulatorGroupInitFlag init_flag;
} wmManipulatorGroup;
-/**
- * Manipulator-map type update flag: `wmManipulatorMapType.type_update_flag`
- */
-enum eManipulatorMapTypeUpdateFlags {
- /* A new type has been added, needs to be initialized for all views. */
- WM_MANIPULATORMAPTYPE_UPDATE_INIT = (1 << 0),
- WM_MANIPULATORMAPTYPE_UPDATE_REMOVE = (1 << 1),
-};
-
-/**
- * wmManipulatorGroupType.flag
- * Flags that influence the behavior of all manipulators in the group.
- */
-enum {
- /* Mark manipulator-group as being 3D */
- WM_MANIPULATORGROUPTYPE_3D = (1 << 0),
- /* Scale manipulators as 3D object that respects zoom (otherwise zoom independent draw size).
- * note: currently only for 3D views, 2D support needs adding. */
- WM_MANIPULATORGROUPTYPE_SCALE = (1 << 1),
- /* Manipulators can be depth culled with scene objects (covered by other geometry - TODO) */
- WM_MANIPULATORGROUPTYPE_DEPTH_3D = (1 << 2),
- /* Manipulators can be selected */
- WM_MANIPULATORGROUPTYPE_SELECT = (1 << 3),
- /* The manipulator group is to be kept (not removed on loading a new file for eg). */
- WM_MANIPULATORGROUPTYPE_PERSISTENT = (1 << 4),
-};
-
-
/* -------------------------------------------------------------------- */
/* wmManipulatorMap */
/**
* 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) */
+typedef enum eWM_ManipulatorMapDrawStep {
+ /** Draw 2D manipulator-groups (#WM_MANIPULATORGROUPTYPE_3D not set). */
WM_MANIPULATORMAP_DRAWSTEP_2D = 0,
- /* Draw 3D manipulator-groups (ManipulatorGroupType.is_3d == true) */
+ /** Draw 3D manipulator-groups (#WM_MANIPULATORGROUPTYPE_3D set). */
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,
-};
+} eWM_ManipulatorMapDrawStep;
+#define WM_MANIPULATORMAP_DRAWSTEP_MAX 2
#endif /* __WM_MANIPULATOR_TYPES_H__ */
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c
index d8d530a4db9..3df4124ba65 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c
@@ -65,7 +65,7 @@
#include "wm_manipulator_intern.h"
static void wm_manipulator_register(
- wmManipulatorGroup *mgroup, wmManipulator *mpr, const char *name);
+ wmManipulatorGroup *mgroup, wmManipulator *mpr);
/**
* \note Follow #wm_operator_create convention.
@@ -94,6 +94,7 @@ static wmManipulator *wm_manipulator_create(
WM_manipulator_properties_sanitize(mpr->ptr, 0);
+ unit_m4(mpr->matrix_space);
unit_m4(mpr->matrix_basis);
unit_m4(mpr->matrix_offset);
@@ -102,11 +103,11 @@ static wmManipulator *wm_manipulator_create(
wmManipulator *WM_manipulator_new_ptr(
const wmManipulatorType *wt, wmManipulatorGroup *mgroup,
- const char *name, PointerRNA *properties)
+ PointerRNA *properties)
{
wmManipulator *mpr = wm_manipulator_create(wt, properties);
- wm_manipulator_register(mgroup, mpr, name);
+ wm_manipulator_register(mgroup, mpr);
if (mpr->type->setup != NULL) {
mpr->type->setup(mpr);
@@ -122,33 +123,10 @@ wmManipulator *WM_manipulator_new_ptr(
*/
wmManipulator *WM_manipulator_new(
const char *idname, wmManipulatorGroup *mgroup,
- const char *name, PointerRNA *properties)
+ PointerRNA *properties)
{
const wmManipulatorType *wt = WM_manipulatortype_find(idname, false);
- return WM_manipulator_new_ptr(wt, mgroup, name, properties);
-}
-
-/**
- * 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 *mpr, const char *rawname)
-{
- BLI_snprintf(mpr->name, sizeof(mpr->name), "%s_%s", mgroup->type->idname, rawname);
-
- /* ensure name is unique, append '.001', '.002', etc if not */
- BLI_uniquename(&mgroup->manipulators, mpr, "Manipulator", '.',
- offsetof(wmManipulator, name), sizeof(mpr->name));
-}
-
-void WM_manipulator_name_set(wmManipulatorGroup *mgroup, wmManipulator *mpr, const char *name)
-{
- BLI_strncpy(mpr->name, name, sizeof(mpr->name));
-
- /* ensure name is unique, append '.001', '.002', etc if not */
- BLI_uniquename(&mgroup->manipulators, mpr, "Manipulator", '.',
- offsetof(wmManipulator, name), sizeof(mpr->name));
+ return WM_manipulator_new_ptr(wt, mgroup, properties);
}
/**
@@ -173,18 +151,18 @@ static void manipulator_init(wmManipulator *mpr)
*
* \note Not to be confused with type registration from RNA.
*/
-static void wm_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *mpr, const char *name)
+static void wm_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *mpr)
{
manipulator_init(mpr);
- manipulator_unique_idname_set(mgroup, mpr, name);
wm_manipulatorgroup_manipulator_register(mgroup, mpr);
}
/**
- * Free \a manipulator and unlink from \a manipulatorlist.
- * \a manipulatorlist is allowed to be NULL.
+ * \warning this doesn't check #wmManipulatorMap (highlight, selection etc).
+ * Typical use is when freeing the windowing data,
+ * where caller can manage clearing selection, highlight... etc.
*/
-void WM_manipulator_free(ListBase *manipulatorlist, wmManipulatorMap *mmap, wmManipulator *mpr, bContext *C)
+void WM_manipulator_free(wmManipulator *mpr)
{
#ifdef WITH_PYTHON
if (mpr->py_instance) {
@@ -194,18 +172,11 @@ void WM_manipulator_free(ListBase *manipulatorlist, wmManipulatorMap *mmap, wmMa
}
#endif
- if (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) {
- wm_manipulatormap_highlight_set(mmap, C, NULL, 0);
- }
- if (mpr->state & WM_MANIPULATOR_STATE_ACTIVE) {
- wm_manipulatormap_active_set(mmap, C, NULL, NULL);
- }
- if (mpr->state & WM_MANIPULATOR_STATE_SELECT) {
- wm_manipulator_deselect(mmap, mpr);
- }
-
- if (mpr->op_data.ptr.data) {
- WM_operator_properties_free(&mpr->op_data.ptr);
+ if (mpr->op_data) {
+ for (int i = 0; i < mpr->op_data_len; i++) {
+ WM_operator_properties_free(&mpr->op_data[i].ptr);
+ }
+ MEM_freeN(mpr->op_data);
}
if (mpr->ptr != NULL) {
@@ -223,14 +194,34 @@ void WM_manipulator_free(ListBase *manipulatorlist, wmManipulatorMap *mmap, wmMa
}
}
+ MEM_freeN(mpr);
+}
+
+/**
+ * Free \a manipulator and unlink from \a manipulatorlist.
+ * \a manipulatorlist is allowed to be NULL.
+ */
+void WM_manipulator_unlink(ListBase *manipulatorlist, wmManipulatorMap *mmap, wmManipulator *mpr, bContext *C)
+{
+ if (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) {
+ wm_manipulatormap_highlight_set(mmap, C, NULL, 0);
+ }
+ if (mpr->state & WM_MANIPULATOR_STATE_MODAL) {
+ wm_manipulatormap_modal_set(mmap, C, mpr, NULL, false);
+ }
+ /* Unlink instead of setting so we don't run callbacks. */
+ if (mpr->state & WM_MANIPULATOR_STATE_SELECT) {
+ WM_manipulator_select_unlink(mmap, mpr);
+ }
+
if (manipulatorlist) {
BLI_remlink(manipulatorlist, mpr);
}
BLI_assert(mmap->mmap_context.highlight != mpr);
- BLI_assert(mmap->mmap_context.active != mpr);
+ BLI_assert(mmap->mmap_context.modal != mpr);
- MEM_freeN(mpr);
+ WM_manipulator_free(mpr);
}
/* -------------------------------------------------------------------- */
@@ -240,22 +231,38 @@ void WM_manipulator_free(ListBase *manipulatorlist, wmManipulatorMap *mmap, wmMa
*
* \{ */
+struct wmManipulatorOpElem *WM_manipulator_operator_get(
+ wmManipulator *mpr, int part_index)
+{
+ if (mpr->op_data && ((part_index >= 0) && (part_index < mpr->op_data_len))) {
+ return &mpr->op_data[part_index];
+ }
+ return NULL;
+}
-PointerRNA *WM_manipulator_set_operator(
- wmManipulator *mpr, wmOperatorType *ot, IDProperty *properties)
+PointerRNA *WM_manipulator_operator_set(
+ wmManipulator *mpr, int part_index,
+ wmOperatorType *ot, IDProperty *properties)
{
- mpr->op_data.type = ot;
+ BLI_assert(part_index < 255);
+ /* We could pre-allocate these but using multiple is such a rare thing. */
+ if (part_index >= mpr->op_data_len) {
+ mpr->op_data_len = part_index + 1;
+ mpr->op_data = MEM_recallocN(mpr->op_data, sizeof(*mpr->op_data) * mpr->op_data_len);
+ }
+ wmManipulatorOpElem *mpop = &mpr->op_data[part_index];
+ mpop->type = ot;
- if (mpr->op_data.ptr.data) {
- WM_operator_properties_free(&mpr->op_data.ptr);
+ if (mpop->ptr.data) {
+ WM_operator_properties_free(&mpop->ptr);
}
- WM_operator_properties_create_ptr(&mpr->op_data.ptr, ot);
+ WM_operator_properties_create_ptr(&mpop->ptr, ot);
if (properties) {
- mpr->op_data.ptr.data = properties;
+ mpop->ptr.data = properties;
}
- return &mpr->op_data.ptr;
+ return &mpop->ptr;
}
static void wm_manipulator_set_matrix_rotation_from_z_axis__internal(
@@ -348,13 +355,13 @@ void WM_manipulator_set_line_width(wmManipulator *mpr, const float line_width)
* \param col Normal state color.
* \param col_hi Highlighted state color.
*/
-void WM_manipulator_get_color(const wmManipulator *mpr, float col[4])
+void WM_manipulator_get_color(const wmManipulator *mpr, float color[4])
{
- copy_v4_v4(col, mpr->color);
+ copy_v4_v4(color, mpr->color);
}
-void WM_manipulator_set_color(wmManipulator *mpr, const float col[4])
+void WM_manipulator_set_color(wmManipulator *mpr, const float color[4])
{
- copy_v4_v4(mpr->color, col);
+ copy_v4_v4(mpr->color, color);
}
void WM_manipulator_get_color_highlight(const wmManipulator *mpr, float color_hi[4])
@@ -386,73 +393,67 @@ void WM_manipulator_set_fn_custom_modal(struct wmManipulator *mpr, wmManipulator
/* -------------------------------------------------------------------- */
/**
- * Remove \a manipulator from selection.
+ * Add/Remove \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_deselect(wmManipulatorMap *mmap, wmManipulator *mpr)
+bool wm_manipulator_select_set_ex(
+ wmManipulatorMap *mmap, wmManipulator *mpr, bool select,
+ bool use_array, bool use_callback)
{
- if (!mmap->mmap_context.selected)
- return false;
-
- wmManipulator ***sel = &mmap->mmap_context.selected;
- int *selected_len = &mmap->mmap_context.selected_len;
bool changed = false;
- /* caller should check! */
- BLI_assert(mpr->state & WM_MANIPULATOR_STATE_SELECT);
-
- /* remove manipulator from selected_manipulators array */
- for (int i = 0; i < (*selected_len); i++) {
- if ((*sel)[i] == mpr) {
- for (int j = i; j < ((*selected_len) - 1); j++) {
- (*sel)[j] = (*sel)[j + 1];
+ if (select) {
+ if ((mpr->state & WM_MANIPULATOR_STATE_SELECT) == 0) {
+ if (use_array) {
+ wm_manipulatormap_select_array_push_back(mmap, mpr);
}
+ mpr->state |= WM_MANIPULATOR_STATE_SELECT;
changed = true;
- break;
}
}
-
- /* update array data */
- if ((*selected_len) <= 1) {
- wm_manipulatormap_selected_clear(mmap);
- }
else {
- *sel = MEM_reallocN(*sel, sizeof(**sel) * (*selected_len));
- (*selected_len)--;
+ if (mpr->state & WM_MANIPULATOR_STATE_SELECT) {
+ if (use_array) {
+ wm_manipulatormap_select_array_remove(mmap, mpr);
+ }
+ mpr->state &= ~WM_MANIPULATOR_STATE_SELECT;
+ changed = true;
+ }
+ }
+
+ /* In the case of unlinking we only want to remove from the array
+ * and not write to the external state */
+ if (use_callback && changed) {
+ if (mpr->type->select_refresh) {
+ mpr->type->select_refresh(mpr);
+ }
}
- mpr->state &= ~WM_MANIPULATOR_STATE_SELECT;
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 *mpr)
+/* Remove from selection array without running callbacks. */
+bool WM_manipulator_select_unlink(wmManipulatorMap *mmap, wmManipulator *mpr)
{
- wmManipulator ***sel = &mmap->mmap_context.selected;
- int *selected_len = &mmap->mmap_context.selected_len;
-
- if (!mpr || (mpr->state & WM_MANIPULATOR_STATE_SELECT))
- return false;
-
- (*selected_len)++;
+ return wm_manipulator_select_set_ex(mmap, mpr, false, true, false);
+}
- *sel = MEM_reallocN(*sel, sizeof(wmManipulator *) * (*selected_len));
- (*sel)[(*selected_len) - 1] = mpr;
+bool WM_manipulator_select_set(wmManipulatorMap *mmap, wmManipulator *mpr, bool select)
+{
+ return wm_manipulator_select_set_ex(mmap, mpr, select, true, true);
+}
- mpr->state |= WM_MANIPULATOR_STATE_SELECT;
- if (mpr->type->select) {
- mpr->type->select(C, mpr, SEL_SELECT);
+bool wm_manipulator_select_and_highlight(bContext *C, wmManipulatorMap *mmap, wmManipulator *mpr)
+{
+ if (WM_manipulator_select_set(mmap, mpr, true)) {
+ wm_manipulatormap_highlight_set(mmap, C, mpr, mpr->highlight_part);
+ return true;
+ }
+ else {
+ return false;
}
- wm_manipulatormap_highlight_set(mmap, C, mpr, mpr->highlight_part);
-
- return true;
}
void wm_manipulator_calculate_scale(wmManipulator *mpr, const bContext *C)
@@ -464,15 +465,18 @@ void wm_manipulator_calculate_scale(wmManipulator *mpr, const bContext *C)
scale *= U.manipulator_size;
if (rv3d) {
/* 'ED_view3d_pixel_size' includes 'U.pixelsize', remove it. */
- if (mpr->type->matrix_world_get) {
- float matrix_world[4][4];
-
- mpr->type->matrix_world_get(mpr, matrix_world);
- scale *= ED_view3d_pixel_size(rv3d, matrix_world[3]) / U.pixelsize;
+ float matrix_world[4][4];
+ if (mpr->type->matrix_basis_get) {
+ float matrix_basis[4][4];
+ mpr->type->matrix_basis_get(mpr, matrix_basis);
+ mul_m4_m4m4(matrix_world, mpr->matrix_space, matrix_basis);
}
else {
- scale *= ED_view3d_pixel_size(rv3d, mpr->matrix_basis[3]) / U.pixelsize;
+ mul_m4_m4m4(matrix_world, mpr->matrix_space, mpr->matrix_basis);
}
+
+ /* Exclude matrix_offset from scale. */
+ scale *= ED_view3d_pixel_size(rv3d, matrix_world[3]) / U.pixelsize;
}
else {
scale *= 0.02f;
@@ -509,10 +513,10 @@ int wm_manipulator_is_visible(wmManipulator *mpr)
if (mpr->flag & WM_MANIPULATOR_HIDDEN) {
return 0;
}
- if ((mpr->state & WM_MANIPULATOR_STATE_ACTIVE) &&
- !(mpr->flag & (WM_MANIPULATOR_DRAW_ACTIVE | WM_MANIPULATOR_DRAW_VALUE)))
+ if ((mpr->state & WM_MANIPULATOR_STATE_MODAL) &&
+ !(mpr->flag & (WM_MANIPULATOR_DRAW_MODAL | WM_MANIPULATOR_DRAW_VALUE)))
{
- /* don't draw while active (while dragging) */
+ /* don't draw while modal (dragging) */
return 0;
}
if ((mpr->flag & WM_MANIPULATOR_DRAW_HOVER) &&
@@ -526,6 +530,53 @@ int wm_manipulator_is_visible(wmManipulator *mpr)
return WM_MANIPULATOR_IS_VISIBLE_UPDATE | WM_MANIPULATOR_IS_VISIBLE_DRAW;
}
+void WM_manipulator_calc_matrix_final_params(
+ const wmManipulator *mpr,
+ const struct WM_ManipulatorMatrixParams *params,
+ float r_mat[4][4])
+{
+ const float (* const matrix_space)[4] = params->matrix_space ? params->matrix_space : mpr->matrix_space;
+ const float (* const matrix_basis)[4] = params->matrix_basis ? params->matrix_basis : mpr->matrix_basis;
+ const float (* const matrix_offset)[4] = params->matrix_offset ? params->matrix_offset : mpr->matrix_offset;
+ const float *scale_final = params->scale_final ? params->scale_final : &mpr->scale_final;
+
+ float final_matrix[4][4];
+ if (params->matrix_basis == NULL && mpr->type->matrix_basis_get) {
+ mpr->type->matrix_basis_get(mpr, final_matrix);
+ }
+ else {
+ copy_m4_m4(final_matrix, matrix_basis);
+ }
+
+ if (mpr->flag & WM_MANIPULATOR_DRAW_NO_SCALE) {
+ mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
+ }
+ else {
+ if (mpr->flag & WM_MANIPULATOR_DRAW_OFFSET_SCALE) {
+ mul_mat3_m4_fl(final_matrix, *scale_final);
+ mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
+ }
+ else {
+ mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
+ mul_mat3_m4_fl(final_matrix, *scale_final);
+ }
+ }
+
+ mul_m4_m4m4(r_mat, matrix_space, final_matrix);
+}
+
+void WM_manipulator_calc_matrix_final(const wmManipulator *mpr, float r_mat[4][4])
+{
+ WM_manipulator_calc_matrix_final_params(
+ mpr,
+ &((struct WM_ManipulatorMatrixParams) {
+ .matrix_space = NULL,
+ .matrix_basis = NULL,
+ .matrix_offset = NULL,
+ .scale_final = NULL,
+ }), r_mat
+ );
+}
/** \name Manipulator Propery Access
*
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c
index f338a14dfbc..1675be861d6 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c
@@ -66,11 +66,6 @@
*
* \{ */
-/* wmManipulatorGroup.flag */
-enum {
- WM_MANIPULATORGROUP_INITIALIZED = (1 << 2), /* mgroup has been initialized */
-};
-
/**
* Create a new manipulator-group from \a wgt.
*/
@@ -91,11 +86,24 @@ wmManipulatorGroup *wm_manipulatorgroup_new_from_type(
void wm_manipulatorgroup_free(bContext *C, wmManipulatorGroup *mgroup)
{
wmManipulatorMap *mmap = mgroup->parent_mmap;
+
+ /* Similar to WM_manipulator_unlink, but only to keep mmap state correct,
+ * we don't want to run callbacks. */
+ if (mmap->mmap_context.highlight && mmap->mmap_context.highlight->parent_mgroup == mgroup) {
+ wm_manipulatormap_highlight_set(mmap, C, NULL, 0);
+ }
+ if (mmap->mmap_context.modal && mmap->mmap_context.modal->parent_mgroup == mgroup) {
+ wm_manipulatormap_modal_set(mmap, C, mmap->mmap_context.modal, NULL, false);
+ }
+
for (wmManipulator *mpr = mgroup->manipulators.first, *mpr_next; mpr; mpr = mpr_next) {
mpr_next = mpr->next;
- WM_manipulator_free(&mgroup->manipulators, mmap, mpr, C);
+ if (mmap->mmap_context.select.len) {
+ WM_manipulator_select_unlink(mmap, mpr);
+ }
+ WM_manipulator_free(mpr);
}
- BLI_assert(BLI_listbase_is_empty(&mgroup->manipulators));
+ BLI_listbase_clear(&mgroup->manipulators);
#ifdef WITH_PYTHON
if (mgroup->py_instance) {
@@ -127,7 +135,7 @@ void wm_manipulatorgroup_free(bContext *C, wmManipulatorGroup *mgroup)
*/
void wm_manipulatorgroup_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *mpr)
{
- BLI_assert(!BLI_findstring(&mgroup->manipulators, mpr->name, offsetof(wmManipulator, name)));
+ BLI_assert(BLI_findindex(&mgroup->manipulators, mpr) == -1);
BLI_addtail(&mgroup->manipulators, mpr);
mpr->parent_mgroup = mgroup;
}
@@ -138,7 +146,7 @@ wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator(
{
for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
if (mpr->type->test_select && (mpr->flag & WM_MANIPULATOR_HIDDEN) == 0) {
- if ((*r_part = mpr->type->test_select(C, mpr, event))) {
+ if ((*r_part = mpr->type->test_select(C, mpr, event)) != -1) {
return mpr;
}
}
@@ -166,7 +174,7 @@ void wm_manipulatorgroup_intersectable_manipulators_to_list(const wmManipulatorG
void wm_manipulatorgroup_ensure_initialized(wmManipulatorGroup *mgroup, const bContext *C)
{
/* prepare for first draw */
- if (UNLIKELY((mgroup->flag & WM_MANIPULATORGROUP_INITIALIZED) == 0)) {
+ if (UNLIKELY((mgroup->init_flag & WM_MANIPULATORGROUP_INIT_SETUP) == 0)) {
mgroup->type->setup(C, mgroup);
/* Not ideal, initialize keymap here, needed for RNA runtime generated manipulators. */
@@ -177,7 +185,7 @@ void wm_manipulatorgroup_ensure_initialized(wmManipulatorGroup *mgroup, const bC
BLI_assert(wgt->keymap != NULL);
}
- mgroup->flag |= WM_MANIPULATORGROUP_INITIALIZED;
+ mgroup->init_flag |= WM_MANIPULATORGROUP_INIT_SETUP;
}
}
@@ -187,21 +195,34 @@ bool wm_manipulatorgroup_is_visible(const wmManipulatorGroup *mgroup, const bCon
return (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type));
}
-bool wm_manipulatorgroup_is_visible_in_drawstep(const wmManipulatorGroup *mgroup, const int drawstep)
+bool wm_manipulatorgroup_is_visible_in_drawstep(
+ const wmManipulatorGroup *mgroup, const eWM_ManipulatorMapDrawStep drawstep)
{
switch (drawstep) {
case WM_MANIPULATORMAP_DRAWSTEP_2D:
return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) == 0;
case WM_MANIPULATORMAP_DRAWSTEP_3D:
return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D);
- case WM_MANIPULATORMAP_DRAWSTEP_IN_SCENE:
- return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_DEPTH_3D);
default:
BLI_assert(0);
return false;
}
}
+bool wm_manipulatorgroup_is_any_selected(const wmManipulatorGroup *mgroup)
+{
+ if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECT) {
+ for (const wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
+ if (mpr->state & WM_MANIPULATOR_STATE_SELECT) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/** \} */
+
/** \name Manipulator operators
*
* Basic operators for manipulator interaction with user configurable keymaps.
@@ -212,7 +233,7 @@ static int manipulator_select_invoke(bContext *C, wmOperator *op, const wmEvent
{
ARegion *ar = CTX_wm_region(C);
wmManipulatorMap *mmap = ar->manipulator_map;
- wmManipulator ***sel = &mmap->mmap_context.selected;
+ wmManipulatorMapSelectState *msel = &mmap->mmap_context.select;
wmManipulator *highlight = mmap->mmap_context.highlight;
bool extend = RNA_boolean_get(op->ptr, "extend");
@@ -221,8 +242,9 @@ static int manipulator_select_invoke(bContext *C, wmOperator *op, const wmEvent
/* deselect all first */
if (extend == false && deselect == false && toggle == false) {
- wm_manipulatormap_deselect_all(mmap, sel);
- BLI_assert(*sel == NULL && mmap->mmap_context.selected_len == 0);
+ wm_manipulatormap_deselect_all(mmap);
+ BLI_assert(msel->items == NULL && msel->len == 0);
+ UNUSED_VARS_NDEBUG(msel);
}
if (highlight) {
@@ -235,11 +257,11 @@ static int manipulator_select_invoke(bContext *C, wmOperator *op, const wmEvent
}
if (deselect) {
- if (is_selected && wm_manipulator_deselect(mmap, highlight)) {
+ if (is_selected && WM_manipulator_select_set(mmap, highlight, false)) {
redraw = true;
}
}
- else if (wm_manipulator_select(C, mmap, highlight)) {
+ else if (wm_manipulator_select_and_highlight(C, mmap, highlight)) {
redraw = true;
}
@@ -274,7 +296,7 @@ void MANIPULATORGROUP_OT_manipulator_select(wmOperatorType *ot)
typedef struct ManipulatorTweakData {
wmManipulatorMap *mmap;
- wmManipulator *active;
+ wmManipulator *mpr_modal;
int init_event; /* initial event type */
int flag; /* tweak flags */
@@ -283,17 +305,17 @@ typedef struct ManipulatorTweakData {
static void manipulator_tweak_finish(bContext *C, wmOperator *op, const bool cancel)
{
ManipulatorTweakData *mtweak = op->customdata;
- if (mtweak->active->type->exit) {
- mtweak->active->type->exit(C, mtweak->active, cancel);
+ if (mtweak->mpr_modal->type->exit) {
+ mtweak->mpr_modal->type->exit(C, mtweak->mpr_modal, cancel);
}
- wm_manipulatormap_active_set(mtweak->mmap, C, NULL, NULL);
+ wm_manipulatormap_modal_set(mtweak->mmap, C, mtweak->mpr_modal, NULL, false);
MEM_freeN(mtweak);
}
static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ManipulatorTweakData *mtweak = op->customdata;
- wmManipulator *mpr = mtweak->active;
+ wmManipulator *mpr = mtweak->mpr_modal;
if (mpr == NULL) {
BLI_assert(0);
@@ -332,11 +354,12 @@ static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *e
}
/* handle manipulator */
- if (mpr->custom_modal) {
- mpr->custom_modal(C, mpr, event, mtweak->flag);
- }
- else if (mpr->type->modal) {
- mpr->type->modal(C, mpr, event, mtweak->flag);
+ wmManipulatorFnModal modal_fn = mpr->custom_modal ? mpr->custom_modal : mpr->type->modal;
+ int retval = modal_fn(C, mpr, event, mtweak->flag);
+
+ if ((retval & OPERATOR_RUNNING_MODAL) == 0) {
+ manipulator_tweak_finish(C, op, (retval & OPERATOR_CANCELLED) != 0);
+ return OPERATOR_FINISHED;
}
/* Ugly hack to send manipulator events */
@@ -361,21 +384,26 @@ static int manipulator_tweak_invoke(bContext *C, wmOperator *op, const wmEvent *
/* activate highlighted manipulator */
- wm_manipulatormap_active_set(mmap, C, event, mpr);
+ wm_manipulatormap_modal_set(mmap, C, mpr, event, true);
/* XXX temporary workaround for modal manipulator operator
* conflicting with modal operator attached to manipulator */
- if (mpr->op_data.type) {
- if (mpr->op_data.type->modal) {
+ wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part);
+ if (mpop && mpop->type) {
+ if (mpop->type->modal) {
return OPERATOR_FINISHED;
}
}
+ /* Couldn't start the manipulator. */
+ if ((mpr->state & WM_MANIPULATOR_STATE_MODAL) == 0) {
+ return OPERATOR_PASS_THROUGH;
+ }
ManipulatorTweakData *mtweak = MEM_mallocN(sizeof(ManipulatorTweakData), __func__);
- mtweak->init_event = event->type;
- mtweak->active = mmap->mmap_context.highlight;
+ mtweak->init_event = WM_userdef_event_type_from_keymap_type(event->type);
+ mtweak->mpr_modal = mmap->mmap_context.highlight;
mtweak->mmap = mmap;
mtweak->flag = 0;
@@ -464,7 +492,7 @@ wmKeyMap *WM_manipulatorgroup_keymap_common(
/* 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, wgt->name, wgt->mmap_params.spaceid, wgt->mmap_params.regionid);
- WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", ACTIONMOUSE, KM_PRESS, KM_ANY, 0);
+ WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
manipulatorgroup_tweak_modal_keymap(config, wgt->name);
return km;
@@ -480,6 +508,7 @@ wmKeyMap *WM_manipulatorgroup_keymap_common_select(
wmKeyMap *km = WM_keymap_find(config, wgt->name, wgt->mmap_params.spaceid, wgt->mmap_params.regionid);
WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", ACTIONMOUSE, KM_PRESS, KM_ANY, 0);
+ WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", EVT_TWEAK_S, KM_ANY, 0, 0);
manipulatorgroup_tweak_modal_keymap(config, wgt->name);
wmKeyMapItem *kmi = WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_select", SELECTMOUSE, KM_PRESS, 0, 0);
@@ -553,13 +582,18 @@ wmManipulatorGroupTypeRef *WM_manipulatormaptype_group_link_ptr(
return wgt_ref;
}
-void WM_manipulatormaptype_group_init_runtime(
- const Main *bmain, wmManipulatorMapType *mmap_type,
+void WM_manipulatormaptype_group_init_runtime_keymap(
+ const Main *bmain,
wmManipulatorGroupType *wgt)
{
/* init keymap - on startup there's an extra call to init keymaps for 'permanent' manipulator-groups */
wm_manipulatorgrouptype_setup_keymap(wgt, ((wmWindowManager *)bmain->wm.first)->defaultconf);
+}
+void WM_manipulatormaptype_group_init_runtime(
+ const Main *bmain, wmManipulatorMapType *mmap_type,
+ wmManipulatorGroupType *wgt)
+{
/* 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) {
@@ -632,8 +666,13 @@ void WM_manipulatormaptype_group_unlink(
void wm_manipulatorgrouptype_setup_keymap(
wmManipulatorGroupType *wgt, wmKeyConfig *keyconf)
{
- wgt->keymap = wgt->setup_keymap(wgt, keyconf);
- wgt->keyconf = keyconf;
+ /* Use flag since setup_keymap may return NULL,
+ * in that case we better not keep calling it. */
+ if (wgt->type_update_flag & WM_MANIPULATORMAPTYPE_KEYMAP_INIT) {
+ wgt->keymap = wgt->setup_keymap(wgt, keyconf);
+ wgt->keyconf = keyconf;
+ wgt->type_update_flag &= ~WM_MANIPULATORMAPTYPE_KEYMAP_INIT;
+ }
}
/** \} */ /* wmManipulatorGroupType */
@@ -645,7 +684,7 @@ void wm_manipulatorgrouptype_setup_keymap(
*
* \note In context of manipulator API these names are a bit misleading,
* but for general use terms its OK.
- * `WM_manipulator_group_add` would be more correctly called:
+ * `WM_manipulator_group_type_add` would be more correctly called:
* `WM_manipulatormaptype_grouptype_reference_link`
* but for general purpose API this is too detailed & annoying.
*
@@ -653,7 +692,7 @@ void wm_manipulatorgrouptype_setup_keymap(
*
* \{ */
-void WM_manipulator_group_add_ptr_ex(
+void WM_manipulator_group_type_add_ptr_ex(
wmManipulatorGroupType *wgt,
wmManipulatorMapType *mmap_type)
{
@@ -662,62 +701,64 @@ void WM_manipulator_group_add_ptr_ex(
WM_manipulatorconfig_update_tag_init(mmap_type, wgt);
}
-void WM_manipulator_group_add_ptr(
+void WM_manipulator_group_type_add_ptr(
wmManipulatorGroupType *wgt)
{
wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params);
- WM_manipulator_group_add_ptr_ex(wgt, mmap_type);
+ WM_manipulator_group_type_add_ptr_ex(wgt, mmap_type);
}
-void WM_manipulator_group_add(const char *idname)
+void WM_manipulator_group_type_add(const char *idname)
{
wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false);
BLI_assert(wgt != NULL);
- WM_manipulator_group_add_ptr(wgt);
+ WM_manipulator_group_type_add_ptr(wgt);
}
-void WM_manipulator_group_remove_ptr_ex(
+
+void WM_manipulator_group_type_remove_ptr_ex(
struct Main *bmain, wmManipulatorGroupType *wgt,
wmManipulatorMapType *mmap_type)
{
WM_manipulatormaptype_group_unlink(NULL, bmain, mmap_type, wgt);
+ WM_manipulatorgrouptype_free_ptr(wgt);
}
-void WM_manipulator_group_remove_ptr(
+void WM_manipulator_group_type_remove_ptr(
struct Main *bmain, wmManipulatorGroupType *wgt)
{
wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params);
- WM_manipulator_group_remove_ptr_ex(bmain, wgt, mmap_type);
+ WM_manipulator_group_type_remove_ptr_ex(bmain, wgt, mmap_type);
}
-void WM_manipulator_group_remove(struct Main *bmain, const char *idname)
+void WM_manipulator_group_type_remove(struct Main *bmain, const char *idname)
{
wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false);
BLI_assert(wgt != NULL);
- WM_manipulator_group_remove_ptr(bmain, wgt);
+ WM_manipulator_group_type_remove_ptr(bmain, wgt);
}
/* delayed versions */
-void WM_manipulator_group_remove_ptr_delayed_ex(
+void WM_manipulator_group_type_remove_ptr_delayed_ex(
wmManipulatorGroupType *wgt,
wmManipulatorMapType *mmap_type)
{
WM_manipulatorconfig_update_tag_remove(mmap_type, wgt);
}
-void WM_manipulator_group_remove_ptr_delayed(
+void WM_manipulator_group_type_remove_ptr_delayed(
wmManipulatorGroupType *wgt)
{
wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params);
- WM_manipulator_group_remove_ptr_delayed_ex(wgt, mmap_type);
+ WM_manipulator_group_type_remove_ptr_delayed_ex(wgt, mmap_type);
}
-void WM_manipulator_group_remove_delayed(const char *idname)
+void WM_manipulator_group_type_remove_delayed(const char *idname)
{
wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false);
BLI_assert(wgt != NULL);
- WM_manipulator_group_remove_ptr_delayed(wgt);
+ WM_manipulator_group_type_remove_ptr_delayed(wgt);
}
/** \} */
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group_type.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group_type.c
index 0f21a7448b5..4c17ffda09c 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group_type.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group_type.c
@@ -90,9 +90,16 @@ static void wm_manipulatorgrouptype_append__end(wmManipulatorGroupType *wgt)
BLI_assert(wgt->name != NULL);
BLI_assert(wgt->idname != NULL);
+ wgt->type_update_flag |= WM_MANIPULATORMAPTYPE_KEYMAP_INIT;
+
/* if not set, use default */
if (wgt->setup_keymap == NULL) {
- wgt->setup_keymap = WM_manipulatorgroup_keymap_common;
+ if (wgt->flag & WM_MANIPULATORGROUPTYPE_SELECT) {
+ wgt->setup_keymap = WM_manipulatorgroup_keymap_common_select;
+ }
+ else {
+ wgt->setup_keymap = WM_manipulatorgroup_keymap_common;
+ }
}
BLI_ghash_insert(global_manipulatorgrouptype_hash, (void *)wgt->idname, wgt);
@@ -137,10 +144,14 @@ wmManipulatorGroupTypeRef *WM_manipulatorgrouptype_append_and_link(
*/
static void manipulatorgrouptype_free(wmManipulatorGroupType *wgt)
{
+ if (wgt->ext.srna) { /* python manipulator group, allocs own string */
+ MEM_freeN((void *)wgt->idname);
+ }
+
MEM_freeN(wgt);
}
-void WM_manipulatorgrouptype_remove_ptr(wmManipulatorGroupType *wgt)
+void WM_manipulatorgrouptype_free_ptr(wmManipulatorGroupType *wgt)
{
BLI_assert(wgt == WM_manipulatorgrouptype_find(wgt->idname, false));
@@ -151,7 +162,7 @@ void WM_manipulatorgrouptype_remove_ptr(wmManipulatorGroupType *wgt)
/* XXX, TODO, update the world! */
}
-bool WM_manipulatorgrouptype_remove(const char *idname)
+bool WM_manipulatorgrouptype_free(const char *idname)
{
wmManipulatorGroupType *wgt = BLI_ghash_lookup(global_manipulatorgrouptype_hash, idname);
@@ -159,7 +170,7 @@ bool WM_manipulatorgrouptype_remove(const char *idname)
return false;
}
- WM_manipulatorgrouptype_remove_ptr(wgt);
+ WM_manipulatorgrouptype_free_ptr(wgt);
return true;
}
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
index 6ddde1df9de..bf5c38b9e39 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
@@ -38,8 +38,11 @@ struct GHashIterator;
/* -------------------------------------------------------------------- */
/* wmManipulator */
-bool wm_manipulator_deselect(struct wmManipulatorMap *mmap, struct wmManipulator *mpr);
-bool wm_manipulator_select(bContext *C, struct wmManipulatorMap *mmap, struct wmManipulator *mpr);
+
+bool wm_manipulator_select_set_ex(
+ struct wmManipulatorMap *mmap, struct wmManipulator *mpr, bool select,
+ bool use_array, bool use_callback);
+bool wm_manipulator_select_and_highlight(bContext *C, struct wmManipulatorMap *mmap, struct wmManipulator *mpr);
void wm_manipulator_calculate_scale(struct wmManipulator *mpr, const bContext *C);
void wm_manipulator_update(struct wmManipulator *mpr, const bContext *C, const bool refresh_map);
@@ -73,7 +76,8 @@ 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);
+bool wm_manipulatorgroup_is_visible_in_drawstep(
+ const struct wmManipulatorGroup *mgroup, const eWM_ManipulatorMapDrawStep drawstep);
void wm_manipulatorgrouptype_setup_keymap(
struct wmManipulatorGroupType *wgt, struct wmKeyConfig *keyconf);
@@ -82,13 +86,18 @@ void wm_manipulatorgrouptype_setup_keymap(
/* -------------------------------------------------------------------- */
/* wmManipulatorMap */
+typedef struct wmManipulatorMapSelectState {
+ struct wmManipulator **items;
+ int len, len_alloc;
+} wmManipulatorMapSelectState;
+
struct wmManipulatorMap {
- struct wmManipulatorMap *next, *prev;
struct wmManipulatorMapType *type;
ListBase groups; /* wmManipulatorGroup */
- char update_flag; /* private, update tagging */
+ /* private, update tagging (enum defined in C source). */
+ char update_flag[WM_MANIPULATORMAP_DRAWSTEP_MAX];
/**
* \brief Manipulator map runtime context
@@ -99,12 +108,10 @@ struct wmManipulatorMap {
struct {
/* we redraw the manipulator-map when this changes */
struct wmManipulator *highlight;
- /* user has clicked this manipulator and it gets all input */
- struct wmManipulator *active;
- /* array for all selected manipulators
- * TODO check on using BLI_array */
- struct wmManipulator **selected;
- int selected_len;
+ /* User has clicked this manipulator and it gets all input. */
+ struct wmManipulator *modal;
+ /* array for all selected manipulators */
+ struct wmManipulatorMapSelectState select;
} mmap_context;
};
@@ -121,10 +128,13 @@ struct wmManipulatorMapType {
ListBase grouptype_refs;
/* eManipulatorMapTypeUpdateFlags */
- uchar type_update_flag;
+ eWM_ManipulatorMapTypeUpdateFlag type_update_flag;
};
-void wm_manipulatormap_selected_clear(struct wmManipulatorMap *mmap);
-bool wm_manipulatormap_deselect_all(struct wmManipulatorMap *mmap, struct wmManipulator ***sel);
+void wm_manipulatormap_select_array_clear(struct wmManipulatorMap *mmap);
+bool wm_manipulatormap_deselect_all(struct wmManipulatorMap *mmap);
+void wm_manipulatormap_select_array_shrink(struct wmManipulatorMap *mmap, int len_subtract);
+void wm_manipulatormap_select_array_push_back(struct wmManipulatorMap *mmap, wmManipulator *mpr);
+void wm_manipulatormap_select_array_remove(struct wmManipulatorMap *mmap, wmManipulator *mpr);
-#endif \ No newline at end of file
+#endif
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
index f5ef5572fd4..0d2a8f7dcc5 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
@@ -50,6 +50,8 @@
#include "WM_types.h"
#include "wm_event_system.h"
+#include "DEG_depsgraph.h"
+
/* own includes */
#include "wm_manipulator_wmapi.h"
#include "wm_manipulator_intern.h"
@@ -64,23 +66,94 @@ static ListBase manipulatormaptypes = {NULL, NULL};
* Update when manipulator-map types change.
*/
/* so operator removal can trigger update */
-enum {
+typedef enum eWM_ManipulatorGroupTypeGlobalFlag {
WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_INIT = (1 << 0),
WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_REMOVE = (1 << 1),
-};
+} eWM_ManipulatorGroupTypeGlobalFlag;
-static char wm_mmap_type_update_flag = 0;
+static eWM_ManipulatorGroupTypeGlobalFlag wm_mmap_type_update_flag = 0;
/**
* Manipulator-map update tagging.
*/
-enum eManipulatorMapUpdateFlags {
- /* Tag manipulator-map for refresh. */
- MANIPULATORMAP_REFRESH = (1 << 0),
+enum {
+ /** #manipulatormap_prepare_drawing has run */
+ MANIPULATORMAP_IS_PREPARE_DRAW = (1 << 0),
+ MANIPULATORMAP_IS_REFRESH_CALLBACK = (1 << 1),
};
/* -------------------------------------------------------------------- */
+/** \name wmManipulatorMap Selection Array API
+ *
+ * Just handle ``wm_manipulatormap_select_array_*``, not flags or callbacks.
+ *
+ * \{ */
+
+static void wm_manipulatormap_select_array_ensure_len_alloc(wmManipulatorMap *mmap, int len)
+{
+ wmManipulatorMapSelectState *msel = &mmap->mmap_context.select;
+ if (len <= msel->len_alloc) {
+ return;
+ }
+ msel->items = MEM_reallocN(msel->items, sizeof(*msel->items) * len);
+ msel->len_alloc = len;
+}
+
+void wm_manipulatormap_select_array_clear(wmManipulatorMap *mmap)
+{
+ wmManipulatorMapSelectState *msel = &mmap->mmap_context.select;
+ MEM_SAFE_FREE(msel->items);
+ msel->len = 0;
+ msel->len_alloc = 0;
+}
+
+void wm_manipulatormap_select_array_shrink(wmManipulatorMap *mmap, int len_subtract)
+{
+ wmManipulatorMapSelectState *msel = &mmap->mmap_context.select;
+ msel->len -= len_subtract;
+ if (msel->len <= 0) {
+ wm_manipulatormap_select_array_clear(mmap);
+ }
+ else {
+ if (msel->len < msel->len_alloc / 2) {
+ msel->items = MEM_reallocN(msel->items, sizeof(*msel->items) * msel->len);
+ msel->len_alloc = msel->len;
+ }
+ }
+}
+
+void wm_manipulatormap_select_array_push_back(wmManipulatorMap *mmap, wmManipulator *mpr)
+{
+ wmManipulatorMapSelectState *msel = &mmap->mmap_context.select;
+ BLI_assert(msel->len <= msel->len_alloc);
+ if (msel->len == msel->len_alloc) {
+ msel->len_alloc = (msel->len + 1) * 2;
+ msel->items = MEM_reallocN(msel->items, sizeof(*msel->items) * msel->len_alloc);
+ }
+ msel->items[msel->len++] = mpr;
+}
+
+void wm_manipulatormap_select_array_remove(wmManipulatorMap *mmap, wmManipulator *mpr)
+{
+ wmManipulatorMapSelectState *msel = &mmap->mmap_context.select;
+ /* remove manipulator from selected_manipulators array */
+ for (int i = 0; i < msel->len; i++) {
+ if (msel->items[i] == mpr) {
+ for (int j = i; j < (msel->len - 1); j++) {
+ msel->items[j] = msel->items[j + 1];
+ }
+ wm_manipulatormap_select_array_shrink(mmap, 1);
+ break;
+ }
+ }
+
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
/** \name wmManipulatorMap
*
* \{ */
@@ -96,7 +169,7 @@ wmManipulatorMap *WM_manipulatormap_new_from_type(
mmap = MEM_callocN(sizeof(wmManipulatorMap), "ManipulatorMap");
mmap->type = mmap_type;
- mmap->update_flag = MANIPULATORMAP_REFRESH;
+ WM_manipulatormap_tag_refresh(mmap);
/* create all manipulator-groups for this manipulator-map. We may create an empty one
* too in anticipation of manipulators from operators etc */
@@ -107,16 +180,10 @@ wmManipulatorMap *WM_manipulatormap_new_from_type(
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;
+ /* Clear first so further calls don't waste time trying to maintain correct array state. */
+ wm_manipulatormap_select_array_clear(mmap);
for (wmManipulatorGroup *mgroup = mmap->groups.first, *mgroup_next; mgroup; mgroup = mgroup_next) {
mgroup_next = mgroup->next;
@@ -125,8 +192,6 @@ void wm_manipulatormap_remove(wmManipulatorMap *mmap)
}
BLI_assert(BLI_listbase_is_empty(&mmap->groups));
- wm_manipulatormap_selected_clear(mmap);
-
MEM_freeN(mmap);
}
@@ -135,18 +200,47 @@ const ListBase *WM_manipulatormap_group_list(wmManipulatorMap *mmap)
return &mmap->groups;
}
+bool WM_manipulatormap_is_any_selected(const wmManipulatorMap *mmap)
+{
+ return mmap->mmap_context.select.len != 0;
+}
+
+/**
+ * \note We could use a callback to define bounds, for now just use matrix location.
+ */
+bool WM_manipulatormap_minmax(
+ const wmManipulatorMap *mmap, bool UNUSED(use_hidden), bool use_select,
+ float r_min[3], float r_max[3])
+{
+ if (use_select) {
+ int i;
+ for (i = 0; i < mmap->mmap_context.select.len; i++) {
+ minmax_v3v3_v3(r_min, r_max, mmap->mmap_context.select.items[i]->matrix_basis[3]);
+ }
+ return i != 0;
+ }
+ else {
+ bool ok = false;
+ BLI_assert(!"TODO");
+ return ok;
+ }
+}
+
/**
* 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
+ *
+ * TODO(campbell): this uses unreliable order,
+ * best we use an iterator function instead of a hash.
*/
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__);
+ GHash *hash = BLI_ghash_ptr_new(__func__);
/* collect manipulators */
for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
@@ -155,7 +249,7 @@ static GHash *WM_manipulatormap_manipulator_hash_new(
if ((include_hidden || (mpr->flag & WM_MANIPULATOR_HIDDEN) == 0) &&
(!poll || poll(mpr, data)))
{
- BLI_ghash_insert(hash, mpr->name, mpr);
+ BLI_ghash_insert(hash, mpr, mpr);
}
}
}
@@ -167,18 +261,19 @@ static GHash *WM_manipulatormap_manipulator_hash_new(
void WM_manipulatormap_tag_refresh(wmManipulatorMap *mmap)
{
if (mmap) {
- mmap->update_flag |= MANIPULATORMAP_REFRESH;
+ /* We might want only to refresh some, for tag all steps. */
+ for (int i = 0; i < WM_MANIPULATORMAP_DRAWSTEP_MAX; i++) {
+ mmap->update_flag[i] |= (
+ MANIPULATORMAP_IS_PREPARE_DRAW |
+ MANIPULATORMAP_IS_REFRESH_CALLBACK);
+ }
}
}
-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)
+ const bContext *C, ListBase *draw_manipulators,
+ const eWM_ManipulatorMapDrawStep drawstep)
{
int do_draw = wm_manipulator_is_visible(mpr);
if (do_draw == 0) {
@@ -187,7 +282,7 @@ static bool manipulator_prepare_drawing(
else {
if (do_draw & WM_MANIPULATOR_IS_VISIBLE_UPDATE) {
/* hover manipulators need updating, even if we don't draw them */
- wm_manipulator_update(mpr, C, (mmap->update_flag & MANIPULATORMAP_REFRESH) != 0);
+ wm_manipulator_update(mpr, C, (mmap->update_flag[drawstep] & MANIPULATORMAP_IS_PREPARE_DRAW) != 0);
}
if (do_draw & WM_MANIPULATOR_IS_VISIBLE_DRAW) {
BLI_addhead(draw_manipulators, BLI_genericNodeN(mpr));
@@ -203,19 +298,24 @@ static bool manipulator_prepare_drawing(
* 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)
+ wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators,
+ const eWM_ManipulatorMapDrawStep drawstep)
{
if (!mmap || BLI_listbase_is_empty(&mmap->groups))
return;
- wmManipulator *active_manipulator = mmap->mmap_context.active;
+ wmManipulator *mpr_modal = mmap->mmap_context.modal;
/* only active manipulator needs updating */
- if (active_manipulator) {
- if (manipulator_prepare_drawing(mmap, active_manipulator, C, draw_manipulators)) {
- manipulatormap_tag_updated(mmap);
+ if (mpr_modal) {
+ if ((mpr_modal->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL) == 0) {
+ if (wm_manipulatorgroup_is_visible_in_drawstep(mpr_modal->parent_mgroup, drawstep)) {
+ if (manipulator_prepare_drawing(mmap, mpr_modal, C, draw_manipulators, drawstep)) {
+ mmap->update_flag[drawstep] &= ~MANIPULATORMAP_IS_PREPARE_DRAW;
+ }
+ }
+ /* don't draw any other manipulators */
+ return;
}
- /* don't draw any other manipulators */
- return;
}
for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
@@ -230,8 +330,9 @@ static void manipulatormap_prepare_drawing(
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) {
+ if ((mmap->update_flag[drawstep] & MANIPULATORMAP_IS_REFRESH_CALLBACK) && mgroup->type->refresh) {
mgroup->type->refresh(C, mgroup);
+ /* cleared below */
}
/* prepare drawing */
if (mgroup->type->draw_prepare) {
@@ -239,11 +340,13 @@ static void manipulatormap_prepare_drawing(
}
for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
- manipulator_prepare_drawing(mmap, mpr, C, draw_manipulators);
+ manipulator_prepare_drawing(mmap, mpr, C, draw_manipulators, drawstep);
}
}
- manipulatormap_tag_updated(mmap);
+ mmap->update_flag[drawstep] &=
+ ~(MANIPULATORMAP_IS_REFRESH_CALLBACK |
+ MANIPULATORMAP_IS_PREPARE_DRAW);
}
/**
@@ -308,7 +411,9 @@ static void manipulators_draw_list(const wmManipulatorMap *mmap, const bContext
}
}
-void WM_manipulatormap_draw(wmManipulatorMap *mmap, const bContext *C, const int drawstep)
+void WM_manipulatormap_draw(
+ wmManipulatorMap *mmap, const bContext *C,
+ const eWM_ManipulatorMapDrawStep drawstep)
{
ListBase draw_manipulators = {NULL};
@@ -317,9 +422,9 @@ void WM_manipulatormap_draw(wmManipulatorMap *mmap, const bContext *C, const int
BLI_assert(BLI_listbase_is_empty(&draw_manipulators));
}
-static void manipulator_find_active_3D_loop(const bContext *C, ListBase *visible_manipulators)
+static void manipulator_draw_select_3D_loop(const bContext *C, ListBase *visible_manipulators)
{
- int selectionbase = 0;
+ int select_id = 0;
wmManipulator *mpr;
/* TODO(campbell): this depends on depth buffer being written to, currently broken for the 3D view. */
@@ -327,7 +432,7 @@ static void manipulator_find_active_3D_loop(const bContext *C, ListBase *visible
for (LinkData *link = visible_manipulators->first; link; link = link->next) {
mpr = link->data;
-
+
bool is_depth = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_DEPTH_3D) != 0;
if (is_depth == is_depth_prev) {
/* pass */
@@ -344,10 +449,10 @@ static void manipulator_find_active_3D_loop(const bContext *C, ListBase *visible
/* 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);
+ mpr->type->draw_select(C, mpr, select_id << 8);
- selectionbase++;
+ select_id++;
}
if (is_depth_prev) {
@@ -357,8 +462,9 @@ static void manipulator_find_active_3D_loop(const bContext *C, ListBase *visible
static int manipulator_find_intersected_3d_intern(
ListBase *visible_manipulators, const bContext *C, const int co[2],
- const float hotspot)
+ const int hotspot)
{
+ EvaluationContext eval_ctx;
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = sa->spacedata.first;
@@ -368,31 +474,32 @@ static int manipulator_find_intersected_3d_intern(
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;
+ BLI_rcti_init_pt_radius(&rect, co, hotspot);
+
+ CTX_data_eval_ctx(C, &eval_ctx);
- ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_scene(C), ar, v3d, NULL, NULL, &rect);
+ ED_view3d_draw_setup_view(CTX_wm_window(C), &eval_ctx, 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);
+ manipulator_draw_select_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);
+ manipulator_draw_select_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);
+ ED_view3d_draw_setup_view(CTX_wm_window(C), &eval_ctx, CTX_data_scene(C), ar, v3d, NULL, NULL, NULL);
+
+ const GLuint *hit_near = GPU_select_buffer_near(buffer, hits);
- return hits > 0 ? buffer[3] : -1;
+ return hit_near ? hit_near[3] : -1;
}
/**
@@ -403,26 +510,39 @@ static wmManipulator *manipulator_find_intersected_3d(
int *r_part)
{
wmManipulator *result = NULL;
- const float hotspot = 14.0f;
- int ret;
+ int hit = -1;
+
+ int hotspot_radii[] = {
+ 3 * U.pixelsize,
+#if 0 /* We may want to enable when selection doesn't run on mousemove! */
+ 7 * U.pixelsize,
+#endif
+ };
*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);
+ hit = -1;
- if (retsec != -1)
- ret = retsec;
+ for (int i = 0; i < ARRAY_SIZE(hotspot_radii); i++) {
+ hit = manipulator_find_intersected_3d_intern(visible_manipulators, C, co, hotspot_radii[i]);
+ if (hit != -1) {
+ break;
+ }
+ }
- link = BLI_findlink(visible_manipulators, ret >> 8);
- *r_part = ret & 255;
- result = link->data;
+ if (hit != -1) {
+ LinkData *link = BLI_findlink(visible_manipulators, hit >> 8);
+ if (link != NULL) {
+ *r_part = hit & 255;
+ result = link->data;
+ }
+ else {
+ /* All manipulators should use selection ID they're given as part of the callback,
+ * if they don't it will attempt tp lookup non-existing index. */
+ BLI_assert(0);
+ }
}
return result;
@@ -440,27 +560,64 @@ wmManipulator *wm_manipulatormap_highlight_find(
ListBase visible_3d_manipulators = {NULL};
for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
+
+ /* If it were important we could initialize here,
+ * but this only happens when events are handled before drawing,
+ * just skip to keep code-path for initializing manipulators simple. */
+ if ((mgroup->init_flag & WM_MANIPULATORGROUP_INIT_SETUP) == 0) {
+ continue;
+ }
+
if (wm_manipulatorgroup_is_visible(mgroup, C)) {
if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) {
+ if ((mmap->update_flag[WM_MANIPULATORMAP_DRAWSTEP_3D] & MANIPULATORMAP_IS_REFRESH_CALLBACK) &&
+ mgroup->type->refresh)
+ {
+ mgroup->type->refresh(C, mgroup);
+ /* cleared below */
+ }
wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators);
}
- else if ((mpr = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, r_part))) {
- break;
+ else {
+ if ((mmap->update_flag[WM_MANIPULATORMAP_DRAWSTEP_2D] & MANIPULATORMAP_IS_REFRESH_CALLBACK) &&
+ mgroup->type->refresh)
+ {
+ mgroup->type->refresh(C, mgroup);
+ /* cleared below */
+ }
+
+ 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);
+ /* 2D manipulators get priority. */
+ if (mpr == NULL) {
+ mpr = manipulator_find_intersected_3d(C, event->mval, &visible_3d_manipulators, r_part);
+ }
BLI_freelistN(&visible_3d_manipulators);
}
+ mmap->update_flag[WM_MANIPULATORMAP_DRAWSTEP_3D] &= ~MANIPULATORMAP_IS_REFRESH_CALLBACK;
+ mmap->update_flag[WM_MANIPULATORMAP_DRAWSTEP_2D] &= ~MANIPULATORMAP_IS_REFRESH_CALLBACK;
+
return mpr;
}
void WM_manipulatormap_add_handlers(ARegion *ar, wmManipulatorMap *mmap)
{
- wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "manipulator handler");
+ wmEventHandler *handler;
+
+ for (handler = ar->handlers.first; handler; handler = handler->next) {
+ if (handler->manipulator_map == mmap) {
+ return;
+ }
+ }
+
+ handler = MEM_callocN(sizeof(wmEventHandler), "manipulator handler");
BLI_assert(mmap == ar->manipulator_map);
handler->manipulator_map = mmap;
@@ -478,7 +635,7 @@ void wm_manipulatormaps_handled_modal_update(
}
wmManipulatorMap *mmap = handler->op_region->manipulator_map;
- wmManipulator *mpr = wm_manipulatormap_active_get(mmap);
+ wmManipulator *mpr = wm_manipulatormap_modal_get(mmap);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
@@ -486,21 +643,28 @@ void wm_manipulatormaps_handled_modal_update(
/* regular update for running operator */
if (modal_running) {
- if (mpr && (mpr->op_data.type != NULL) &&
- (mpr->op_data.type == handler->op->type))
- {
- if (mpr->custom_modal) {
- mpr->custom_modal(C, mpr, event, 0);
- }
- else if (mpr->type->modal) {
- mpr->type->modal(C, mpr, event, 0);
+ wmManipulatorOpElem *mpop = mpr ? WM_manipulator_operator_get(mpr, mpr->highlight_part) : NULL;
+ if (mpr && mpop && (mpop->type != NULL) && (mpop->type == handler->op->type)) {
+ wmManipulatorFnModal modal_fn = mpr->custom_modal ? mpr->custom_modal : mpr->type->modal;
+ if (modal_fn != NULL) {
+ int retval = modal_fn(C, mpr, event, 0);
+ /* The manipulator is tried to the operator, we can't choose when to exit. */
+ BLI_assert(retval & OPERATOR_RUNNING_MODAL);
+ UNUSED_VARS_NDEBUG(retval);
}
}
}
/* operator not running anymore */
else {
wm_manipulatormap_highlight_set(mmap, C, NULL, 0);
- wm_manipulatormap_active_set(mmap, C, event, NULL);
+ if (mpr) {
+ /* This isn't defined if it ends because of success of cancel, we may want to change. */
+ bool cancel = true;
+ if (mpr->type->exit) {
+ mpr->type->exit(C, mpr, cancel);
+ }
+ wm_manipulatormap_modal_set(mmap, C, mpr, NULL, false);
+ }
}
/* restore the area */
@@ -512,16 +676,19 @@ void wm_manipulatormaps_handled_modal_update(
* Deselect all selected manipulators in \a mmap.
* \return if selection has changed.
*/
-bool wm_manipulatormap_deselect_all(wmManipulatorMap *mmap, wmManipulator ***sel)
+bool wm_manipulatormap_deselect_all(wmManipulatorMap *mmap)
{
- if (*sel == NULL || mmap->mmap_context.selected_len == 0)
+ wmManipulatorMapSelectState *msel = &mmap->mmap_context.select;
+
+ if (msel->items == NULL || msel->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;
+ for (int i = 0; i < msel->len; i++) {
+ wm_manipulator_select_set_ex(mmap, msel->items[i], false, false, true);
}
- wm_manipulatormap_selected_clear(mmap);
+
+ wm_manipulatormap_select_array_clear(mmap);
/* always return true, we already checked
* if there's anything to deselect */
@@ -538,36 +705,28 @@ BLI_INLINE bool manipulator_selectable_poll(const wmManipulator *mpr, void *UNUS
* \return if selection has changed.
*/
static bool wm_manipulatormap_select_all_intern(
- bContext *C, wmManipulatorMap *mmap, wmManipulator ***sel,
- const int action)
+ bContext *C, wmManipulatorMap *mmap)
{
+ wmManipulatorMapSelectState *msel = &mmap->mmap_context.select;
/* 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;
+ int i;
bool changed = false;
- *selected_len = BLI_ghash_size(hash);
- *sel = MEM_reallocN(*sel, sizeof(**sel) * (*selected_len));
+ wm_manipulatormap_select_array_ensure_len_alloc(mmap, BLI_ghash_size(hash));
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));
+ WM_manipulator_select_set(mmap, mpr_iter, true);
}
/* highlight first manipulator */
- wm_manipulatormap_highlight_set(mmap, C, (*sel)[0], (*sel)[0]->highlight_part);
+ wm_manipulatormap_highlight_set(mmap, C, msel->items[0], msel->items[0]->highlight_part);
+
+ BLI_assert(BLI_ghash_size(hash) == msel->len);
BLI_ghash_free(hash, NULL, NULL);
return changed;
@@ -581,15 +740,14 @@ static bool wm_manipulatormap_select_all_intern(
*/
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);
+ changed = wm_manipulatormap_select_all_intern(C, mmap);
break;
case SEL_DESELECT:
- changed = wm_manipulatormap_deselect_all(mmap, sel);
+ changed = wm_manipulatormap_deselect_all(mmap);
break;
default:
BLI_assert(0);
@@ -642,12 +800,10 @@ void wm_manipulatormap_handler_context(bContext *C, wmEventHandler *handler)
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;
- }
+ 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;
@@ -661,7 +817,7 @@ void wm_manipulatormap_highlight_set(
{
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->highlight_part = -1;
}
mmap->mmap_context.highlight = mpr;
@@ -695,50 +851,57 @@ 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)
+/**
+ * Caller should call exit when (enable == False).
+ */
+void wm_manipulatormap_modal_set(
+ wmManipulatorMap *mmap, bContext *C, wmManipulator *mpr, const wmEvent *event, bool enable)
{
- if (mpr && C) {
- mpr->state |= WM_MANIPULATOR_STATE_ACTIVE;
- mmap->mmap_context.active = mpr;
+ if (enable) {
+ BLI_assert(mmap->mmap_context.modal == NULL);
- if (mpr->op_data.type) {
- /* first activate the manipulator itself */
- if (mpr->type->invoke &&
- (mpr->type->modal || mpr->custom_modal))
- {
- mpr->type->invoke(C, mpr, event);
- }
+ /* For now only grab cursor for 3D manipulators. */
+ bool grab_cursor = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) != 0;
+ int retval = OPERATOR_RUNNING_MODAL;
+
+ if (mpr->type->invoke &&
+ (mpr->type->modal || mpr->custom_modal))
+ {
+ retval = mpr->type->invoke(C, mpr, event);
+ }
+
+ if ((retval & OPERATOR_RUNNING_MODAL) == 0) {
+ return;
+ }
+
+ mpr->state |= WM_MANIPULATOR_STATE_MODAL;
+ mmap->mmap_context.modal = mpr;
- WM_operator_name_call_ptr(C, mpr->op_data.type, WM_OP_INVOKE_DEFAULT, &mpr->op_data.ptr);
+ struct wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part);
+ if (mpop && mpop->type) {
+ WM_operator_name_call_ptr(C, mpop->type, WM_OP_INVOKE_DEFAULT, &mpop->ptr);
/* 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 */
+ if (!mmap->mmap_context.modal) {
+ mpr->state &= ~WM_MANIPULATOR_STATE_MODAL;
MEM_SAFE_FREE(mpr->interaction_data);
}
return;
}
- else {
- if (mpr->type->invoke &&
- (mpr->type->modal || mpr->custom_modal))
- {
- mpr->type->invoke(C, mpr, event);
- }
+
+ if (grab_cursor) {
+ WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL);
}
- WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL);
}
else {
- mpr = mmap->mmap_context.active;
+ BLI_assert(ELEM(mmap->mmap_context.modal, NULL, mpr));
/* deactivate, manipulator but first take care of some stuff */
if (mpr) {
- mpr->state &= ~WM_MANIPULATOR_STATE_ACTIVE;
- /* first activate the manipulator itself */
+ mpr->state &= ~WM_MANIPULATOR_STATE_MODAL;
MEM_SAFE_FREE(mpr->interaction_data);
}
- mmap->mmap_context.active = NULL;
+ mmap->mmap_context.modal = NULL;
if (C) {
WM_cursor_grab_disable(CTX_wm_window(C), NULL);
@@ -748,9 +911,20 @@ void wm_manipulatormap_active_set(
}
}
-wmManipulator *wm_manipulatormap_active_get(wmManipulatorMap *mmap)
+wmManipulator *wm_manipulatormap_modal_get(wmManipulatorMap *mmap)
+{
+ return mmap->mmap_context.modal;
+}
+
+wmManipulator **wm_manipulatormap_selected_get(wmManipulatorMap *mmap, int *r_selected_len)
{
- return mmap->mmap_context.active;
+ *r_selected_len = mmap->mmap_context.select.len;
+ return mmap->mmap_context.select.items;
+}
+
+ListBase *wm_manipulatormap_groups_get(wmManipulatorMap *mmap)
+{
+ return &mmap->groups;
}
/** \} */ /* wmManipulatorMap */
@@ -837,8 +1011,8 @@ void WM_manipulatorconfig_update_tag_init(
wmManipulatorMapType *mmap_type, wmManipulatorGroupType *wgt)
{
/* tag for update on next use */
- mmap_type->type_update_flag |= WM_MANIPULATORMAPTYPE_UPDATE_INIT;
- wgt->type_update_flag |= WM_MANIPULATORMAPTYPE_UPDATE_INIT;
+ mmap_type->type_update_flag |= (WM_MANIPULATORMAPTYPE_UPDATE_INIT | WM_MANIPULATORMAPTYPE_KEYMAP_INIT);
+ wgt->type_update_flag |= (WM_MANIPULATORMAPTYPE_UPDATE_INIT | WM_MANIPULATORMAPTYPE_KEYMAP_INIT);
wm_mmap_type_update_flag |= WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_INIT;
}
@@ -877,7 +1051,9 @@ void WM_manipulatorconfig_update(struct Main *bmain)
wgt_ref = wgt_ref_next)
{
wgt_ref_next = wgt_ref->next;
- WM_manipulatormaptype_group_unlink(NULL, bmain, mmap_type, wgt_ref->type);
+ if (wgt_ref->type->type_update_flag & WM_MANIPULATORMAPTYPE_UPDATE_REMOVE) {
+ WM_manipulatormaptype_group_unlink(NULL, bmain, mmap_type, wgt_ref->type);
+ }
}
}
}
@@ -890,14 +1066,22 @@ void WM_manipulatorconfig_update(struct Main *bmain)
mmap_type;
mmap_type = mmap_type->next)
{
- if (mmap_type->type_update_flag & WM_MANIPULATORMAPTYPE_UPDATE_INIT) {
- mmap_type->type_update_flag &= ~WM_MANIPULATORMAPTYPE_UPDATE_INIT;
+ const uchar type_update_all = WM_MANIPULATORMAPTYPE_UPDATE_INIT | WM_MANIPULATORMAPTYPE_KEYMAP_INIT;
+ if (mmap_type->type_update_flag & type_update_all) {
+ mmap_type->type_update_flag &= ~type_update_all;
for (wmManipulatorGroupTypeRef *wgt_ref = mmap_type->grouptype_refs.first;
wgt_ref;
wgt_ref = wgt_ref->next)
{
- wgt_ref->type->type_update_flag &= ~WM_MANIPULATORMAPTYPE_UPDATE_INIT;
- WM_manipulatormaptype_group_init_runtime(bmain, mmap_type, wgt_ref->type);
+ if (wgt_ref->type->type_update_flag & WM_MANIPULATORMAPTYPE_KEYMAP_INIT) {
+ WM_manipulatormaptype_group_init_runtime_keymap(bmain, wgt_ref->type);
+ wgt_ref->type->type_update_flag &= ~WM_MANIPULATORMAPTYPE_KEYMAP_INIT;
+ }
+
+ if (wgt_ref->type->type_update_flag & WM_MANIPULATORMAPTYPE_UPDATE_INIT) {
+ WM_manipulatormaptype_group_init_runtime(bmain, mmap_type, wgt_ref->type);
+ wgt_ref->type->type_update_flag &= ~WM_MANIPULATORMAPTYPE_UPDATE_INIT;
+ }
}
}
}
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c
index 4a022c06613..b4f65807341 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c
@@ -45,9 +45,6 @@
#include "wm_manipulator_wmapi.h"
#include "wm_manipulator_intern.h"
-/* factor for precision tweaking */
-#define MANIPULATOR_PRECISION_FAC 0.05f
-
/* -------------------------------------------------------------------- */
/** \name Property Definition
@@ -90,7 +87,7 @@ void WM_manipulator_target_property_def_rna_ptr(
wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_at_index(mpr, mpr_prop_type->index_in_type);
/* if manipulator evokes an operator we cannot use it for property manipulation */
- mpr->op_data.type = NULL;
+ BLI_assert(mpr->op_data == NULL);
mpr_prop->type = mpr_prop_type;
@@ -119,7 +116,7 @@ void WM_manipulator_target_property_def_func_ptr(
wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_at_index(mpr, mpr_prop_type->index_in_type);
/* if manipulator evokes an operator we cannot use it for property manipulation */
- mpr->op_data.type = NULL;
+ BLI_assert(mpr->op_data == NULL);
mpr_prop->type = mpr_prop_type;
@@ -214,7 +211,7 @@ void WM_manipulator_target_property_value_get_array(
mpr_prop->custom_func.value_get_fn(mpr, mpr_prop, value);
return;
}
- return RNA_property_float_get_array(&mpr_prop->ptr, mpr_prop->prop, value);
+ RNA_property_float_get_array(&mpr_prop->ptr, mpr_prop->prop, value);
}
void WM_manipulator_target_property_value_set_array(
@@ -230,17 +227,33 @@ void WM_manipulator_target_property_value_set_array(
RNA_property_update(C, &mpr_prop->ptr, mpr_prop->prop);
}
-void WM_manipulator_target_property_range_get(
+bool WM_manipulator_target_property_range_get(
const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
float range[2])
{
- if (mpr_prop->custom_func.range_get_fn) {
- mpr_prop->custom_func.range_get_fn(mpr, mpr_prop, range);
- return;
+ if (mpr_prop->custom_func.value_get_fn) {
+ if (mpr_prop->custom_func.range_get_fn) {
+ mpr_prop->custom_func.range_get_fn(mpr, mpr_prop, range);
+ return true;
+ }
+ else {
+ return false;
+
+ }
}
float step, precision;
RNA_property_float_ui_range(&mpr_prop->ptr, mpr_prop->prop, &range[0], &range[1], &step, &precision);
+ return true;
+}
+
+int WM_manipulator_target_property_array_length(
+ const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop)
+{
+ if (mpr_prop->custom_func.value_get_fn) {
+ return mpr_prop->type->array_length;
+ }
+ return RNA_property_array_length(&mpr_prop->ptr, mpr_prop->prop);
}
/** \} */
@@ -274,4 +287,4 @@ void WM_manipulatortype_target_property_def(
BLI_addtail(&wt->target_property_defs, mpt);
}
-/** \} */ \ No newline at end of file
+/** \} */
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_type.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_type.c
index 7dabc70d69d..18944a9ab9d 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_type.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_type.c
@@ -28,6 +28,11 @@
#include "BLI_string.h"
#include "BLI_string_utils.h"
+#include "BKE_main.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
@@ -36,6 +41,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_screen.h"
+
/* only for own init/exit calls (wm_manipulatortype_init/wm_manipulatortype_free) */
#include "wm.h"
@@ -95,7 +102,7 @@ static void wm_manipulatortype_append__end(wmManipulatorType *wt)
{
BLI_assert(wt->struct_size >= sizeof(wmManipulator));
- RNA_def_struct_identifier(wt->srna, wt->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, wt->srna, wt->idname);
BLI_ghash_insert(global_manipulatortype_hash, (void *)wt->idname, wt);
}
@@ -119,20 +126,58 @@ void WM_manipulatortype_append_ptr(void (*wtfunc)(struct wmManipulatorType *, vo
*/
static void manipulatortype_free(wmManipulatorType *wt)
{
+ if (wt->ext.srna) { /* python manipulator, allocs own string */
+ MEM_freeN((void *)wt->idname);
+ }
+
BLI_freelistN(&wt->target_property_defs);
MEM_freeN(wt);
}
-void WM_manipulatortype_remove_ptr(wmManipulatorType *wt)
+/**
+ * \param C: May be NULL.
+ */
+static void manipulatortype_unlink(
+ bContext *C, Main *bmain, wmManipulatorType *wt)
+{
+ /* Free instances. */
+ 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) {
+ wmManipulatorGroup *mgroup;
+ for (mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
+ for (wmManipulator *mpr = mgroup->manipulators.first, *mpr_next; mpr; mpr = mpr_next) {
+ mpr_next = mpr->next;
+ BLI_assert(mgroup->parent_mmap == mmap);
+ if (mpr->type == wt) {
+ WM_manipulator_unlink(&mgroup->manipulators, mgroup->parent_mmap, mpr, C);
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void WM_manipulatortype_remove_ptr(bContext *C, Main *bmain, wmManipulatorType *wt)
{
BLI_assert(wt == WM_manipulatortype_find(wt->idname, false));
BLI_ghash_remove(global_manipulatortype_hash, wt->idname, NULL, NULL);
+ manipulatortype_unlink(C, bmain, wt);
+
manipulatortype_free(wt);
}
-bool WM_manipulatortype_remove(const char *idname)
+bool WM_manipulatortype_remove(bContext *C, Main *bmain, const char *idname)
{
wmManipulatorType *wt = BLI_ghash_lookup(global_manipulatortype_hash, idname);
@@ -140,7 +185,7 @@ bool WM_manipulatortype_remove(const char *idname)
return false;
}
- WM_manipulatortype_remove_ptr(wt);
+ WM_manipulatortype_remove_ptr(C, bmain, wt);
return true;
}
diff --git a/source/blender/windowmanager/manipulators/wm_manipulator_fn.h b/source/blender/windowmanager/manipulators/wm_manipulator_fn.h
index ae72e04e1c3..c54024529c3 100644
--- a/source/blender/windowmanager/manipulators/wm_manipulator_fn.h
+++ b/source/blender/windowmanager/manipulators/wm_manipulator_fn.h
@@ -50,13 +50,13 @@ typedef void (*wmManipulatorFnSetup)(struct wmManipulator *);
typedef void (*wmManipulatorFnDraw)(const struct bContext *, struct wmManipulator *);
typedef void (*wmManipulatorFnDrawSelect)(const struct bContext *, struct wmManipulator *, int);
typedef int (*wmManipulatorFnTestSelect)(struct bContext *, struct wmManipulator *, const struct wmEvent *);
-typedef void (*wmManipulatorFnModal)(struct bContext *, struct wmManipulator *, const struct wmEvent *, const int);
+typedef int (*wmManipulatorFnModal)(struct bContext *, struct wmManipulator *, const struct wmEvent *, eWM_ManipulatorTweak);
typedef void (*wmManipulatorFnPropertyUpdate)(struct wmManipulator *, struct wmManipulatorProperty *);
-typedef void (*wmManipulatorFnMatrixWorldGet)(struct wmManipulator *, float[4][4]);
-typedef void (*wmManipulatorFnInvoke)(struct bContext *, struct wmManipulator *, const struct wmEvent *);
+typedef void (*wmManipulatorFnMatrixBasisGet)(const struct wmManipulator *, float[4][4]);
+typedef int (*wmManipulatorFnInvoke)(struct bContext *, struct wmManipulator *, const struct wmEvent *);
typedef void (*wmManipulatorFnExit)(struct bContext *, struct wmManipulator *, const bool);
typedef int (*wmManipulatorFnCursorGet)(struct wmManipulator *);
-typedef void (*wmManipulatorFnSelect)(struct bContext *, struct wmManipulator *, const int);
+typedef void (*wmManipulatorFnSelectRefresh)(struct wmManipulator *);
/* wmManipulatorProperty ('value' type defined by 'wmManipulatorProperty.data_type') */
typedef void (*wmManipulatorPropertyFnGet)(
diff --git a/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h b/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h
index 61489b6a730..87cf711a60b 100644
--- a/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h
+++ b/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h
@@ -61,6 +61,8 @@ void wm_manipulatorgrouptype_init(void);
void MANIPULATORGROUP_OT_manipulator_select(struct wmOperatorType *ot);
void MANIPULATORGROUP_OT_manipulator_tweak(struct wmOperatorType *ot);
+bool wm_manipulatorgroup_is_any_selected(const struct wmManipulatorGroup *mgroup);
+
/* -------------------------------------------------------------------- */
/* wmManipulatorMap */
@@ -79,10 +81,13 @@ void wm_manipulatormap_highlight_set(
struct wmManipulatorMap *mmap, const bContext *C,
struct wmManipulator *mpr, int part);
struct wmManipulator *wm_manipulatormap_highlight_get(struct wmManipulatorMap *mmap);
-void wm_manipulatormap_active_set(
- struct wmManipulatorMap *mmap, bContext *C,
- const struct wmEvent *event, struct wmManipulator *mpr);
-struct wmManipulator *wm_manipulatormap_active_get(struct wmManipulatorMap *mmap);
+void wm_manipulatormap_modal_set(
+ struct wmManipulatorMap *mmap, bContext *C, struct wmManipulator *mpr,
+ const struct wmEvent *event, bool enable);
+
+struct wmManipulator *wm_manipulatormap_modal_get(struct wmManipulatorMap *mmap);
+struct wmManipulator **wm_manipulatormap_selected_get(wmManipulatorMap *mmap, int *r_selected_len);
+struct ListBase *wm_manipulatormap_groups_get(wmManipulatorMap *mmap);
/* -------------------------------------------------------------------- */
/* wmManipulatorMapType */
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index 2f7ebbc1def..af72a1542f2 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -52,7 +52,7 @@ typedef struct wmEventHandler {
wmKeyMap *keymap; /* pointer to builtin/custom keymaps */
const rcti *bblocal, *bbwin; /* optional local and windowspace bb */
- /* modal operator handler and WM_HANDLER_FILESELECT */
+ /* modal operator handler */
wmOperator *op; /* for derived/modal handlers */
struct ScrArea *op_area; /* for derived/modal handlers */
struct ARegion *op_region; /* for derived/modal handlers */
@@ -88,7 +88,8 @@ void wm_event_do_handlers (bContext *C);
void wm_event_add_ghostevent (wmWindowManager *wm, wmWindow *win, int type, int time, void *customdata);
-void wm_event_do_notifiers (bContext *C);
+void wm_event_do_refresh_wm_and_depsgraph(bContext *C);
+void wm_event_do_notifiers(bContext *C);
/* wm_keymap.c */
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 4fbbe3d2879..6f63e55e8ab 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -37,7 +37,7 @@ struct wmOperatorType;
void wm_history_file_read(void);
int wm_homefile_read(
struct bContext *C, struct ReportList *reports,
- bool use_factory_settings, bool use_empty_data,
+ bool use_factory_settings, bool use_empty_data, bool use_userdef,
const char *filepath_startup_override, const char *app_template_override);
void wm_file_read_report(bContext *C);