diff options
Diffstat (limited to 'source/blender/windowmanager')
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); |